options: fix setting network-specific options from command-line
[mldonkey.git] / src / daemon / driver / driverMain.ml
blob81d0eedcccd77970bbfd02079968a05762833b01
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 CommonTypes
29 open CommonOptions
30 open CommonUserDb
31 open CommonGlobals
32 open CommonNetwork
34 open DriverInterface
36 open Gettext (* open last as most modules redefine _s and _b *)
38 let _s x = _s "DriverMain" x
39 let _b x = _b "DriverMain" x
41 let log_prefix = "[dMain]"
43 let lprintf_nl fmt =
44 lprintf_nl2 log_prefix fmt
46 let lprintf_n fmt =
47 lprintf2 log_prefix fmt
49 let pid = ref ""
51 let do_daily () =
52 incr CommonWeb.days
54 let minute_timer () =
55 DriverInteractive.hdd_check ();
56 CommonUploads.upload_credit_timer ();
57 CommonInteractive.force_download_quotas ();
58 CommonResult.dummy_result.result_time <- last_time ();
59 (try
60 CommonSwarming.verify_some_chunks ()
61 with _ -> ());
62 CommonClient.clear_upload_slots ()
64 let hourly_timer timer =
65 incr CommonWeb.hours;
66 CommonWeb.load_web_infos false false;
67 if !CommonWeb.hours mod !!compaction_delay = 0 then Gc.compact ();
68 if !!backup_options_delay <> 0
69 && !CommonWeb.hours mod !!backup_options_delay = 0 then
70 CommonComplexOptions.backup_options ();
71 DriverControlers.check_calendar ();
72 CommonFile.propose_filenames ()
74 let ten_second_timer timer =
75 if !!auto_commit then
76 List.iter (fun file ->
77 file_commit file
78 ) !!CommonComplexOptions.done_files
80 let second_timer timer =
81 (try
82 update_link_stats ()
83 with e ->
84 lprintf_nl (_b "Exception %s") (Printexc2.to_string e));
85 (try
86 CommonUploads.refill_upload_slots ()
87 with e ->
88 lprintf_nl (_b "Exception %s") (Printexc2.to_string e));
89 CommonUploads.shared_files_timer ();
92 let start_interfaces () =
94 (* option_hook(s) are not called when ini files are created the first time
95 force re-load of allowed_ips to call option_hook which fills the IP blocklist *)
97 match !created_new_base_directory with
98 None -> ()
99 | Some dir -> allowed_ips =:= !!allowed_ips
102 if !!http_port <> 0 then begin
104 ignore (DriverControlers.create_http_handler ());
105 with e ->
106 lprintf_nl (_b "Exception %s while starting HTTP interface")
107 (Printexc2.to_string e);
108 end;
110 if !!telnet_port <> 0 then begin
112 ignore (find_port "telnet server" !!telnet_bind_addr
113 telnet_port DriverControlers.telnet_handler);
114 with e ->
115 lprintf_nl (_b "Exception %s while starting Telnet interface")
116 (Printexc2.to_string e);
117 end;
119 if !!gui_port <> 0 then begin
121 ignore (find_port "gui server" !!gui_bind_addr
122 gui_port gui_handler);
123 with e ->
124 lprintf_nl (_b "Exception %s while starting GUI interface")
125 (Printexc2.to_string e);
126 end;
128 if !!gift_port <> 0 then begin
130 ignore (find_port "gift server" !!gui_bind_addr
131 gift_port gift_handler);
132 with e ->
133 lprintf_nl (_b "Exception %s while starting GUI interface")
134 (Printexc2.to_string e);
135 end;
137 add_infinite_option_timer update_gui_delay DriverInterface.update_gui_info;
138 add_infinite_timer 1. second_timer
141 let save_mlsubmit_reg () =
143 (* Generate the mlsubmit.reg file *)
145 let file = Printf.sprintf
147 "Windows Registry Editor Version 5.00
149 [HKEY_CLASSES_ROOT\\ed2k]
150 @=\"URL: ed2k Protocol\"
151 \"URL Protocol\"=\"\"
153 [HKEY_CLASSES_ROOT\\ed2k\\shell]
155 [HKEY_CLASSES_ROOT\\ed2k\\shell\\open]
157 [HKEY_CLASSES_ROOT\\ed2k\\shell\\open\\command]
158 @=\"\\\"IEXPLORE.EXE\\\" \\\"http://%s:%s@%s:%d/submit?q=dllink+%%1\\\"\"
161 "admin" "" (Ip.to_string (client_ip None)) !!http_port
163 File.from_string (Filename.concat file_basedir "mlsubmit.reg") file;
165 (* Generate the mldonkey_submit file *)
167 let file = Printf.sprintf
169 "#!%s
171 # Submit an eDonkey download request to mldonkey
173 # Argument(s): An ed2k URI of the form:
175 # ed2k://|file|<filename>|<filesize>|<MD4-sum|
176 use LWP::UserAgent;
178 ($#ARGV >= 0) || die \"Usage: mldonkey_submit <ed2kURI> ...\n\";
180 $vars{'HTTPURL'} = \"http://%s:%d\";
181 $vars{'HTTPUSER'} = \"%s\";
182 $vars{'HTTPPASS'} = \"%s\";
184 my $ua = LWP::UserAgent->new;
186 while (my $uri = shift @ARGV) {
187 $_ = URI::Escape::uri_unescape($uri);
188 if (/^ed2k:\\/\\/\\|file\\|[^|]+\\|(\\d+)\\|([\\dabcdef]+)\\|$/) {
189 my $size = $1;
190 my $md4 = $2;
191 my $req = HTTP::Request->new(
192 GET => \"$vars{'HTTPURL'}/submit?q=dllink+$uri\"
194 if (($vars{'HTTPUSER'}) && ($vars{'HTTPPASS'})) {
195 $req->authorization_basic($vars{'HTTPUSER'},
196 $vars{'HTTPPASS'});
198 my $response = $ua->request($req);
199 if (!($response->is_success)) {
200 print $response->error_as_HTML;
201 exit 1;
203 } else {
204 print \"Not an ed2k URI: $_\n\";
208 Autoconf.perl_path
209 (Ip.to_string (client_ip None)) !!http_port
210 "admin" ""
212 File.from_string (Filename.concat file_basedir "mldonkey_submit") file;
213 Unix2.chmod (Filename.concat file_basedir "mldonkey_submit") 0o755
215 let load_config () =
217 DriverInterface.install_hooks ();
219 (**** LOAD OPTIONS ****)
221 let exists_downloads_ini =
222 Sys.file_exists (options_file_name downloads_ini) in
223 let exists_users_ini =
224 Sys.file_exists (options_file_name users_ini)
226 if not exists_users_ini && exists_downloads_ini then
227 begin
228 lprintf_nl "No config file (users.ini) found. Importing users from downloads.ini.";
229 ( try Unix2.copy "downloads.ini" "users.ini" with _ -> () );
230 end;
232 let ini_files_exist = Sys.file_exists (options_file_name downloads_ini) in
234 (try
235 Options.load downloads_ini;
236 Options.load users_ini;
237 DriverInteractive.hdd_check ()
238 with e ->
239 lprintf_nl "Exception %s during options load" (Printexc2.to_string e);
240 exit 70);
242 (* Here, we try to update options when a new version of mldonkey is
243 used. For example, we can add new web_infos... *)
244 CommonOptions.update_options ();
246 CommonMessages.load_message_file ();
247 if !!html_mods then begin
248 if !!html_mods_style > 0 && !!html_mods_style < Array.length CommonMessages.styles then
249 commands_frame_height =:= CommonMessages.styles.(!!html_mods_style).CommonMessages.frame_height;
250 CommonMessages.colour_changer ();
251 end;
252 networks_iter_all (fun r ->
253 (* lprintf "(n) loading network config file\n"; *)
254 List.iter (fun opfile ->
256 Options.load opfile
257 with Sys_error _ ->
258 Options.save_with_help opfile
260 r.network_config_file
264 (**** PARSE ARGUMENTS ***)
266 let more_args = ref [] in
269 more_args := !more_args
270 @ (Options.simple_args "" downloads_ini);
271 more_args := !more_args
272 @ (Options.simple_args "" users_ini);
274 networks_iter_all (fun r ->
275 List.iter (fun opfile ->
276 let prefix = r.network_shortname ^ "-" in
277 let args = simple_args prefix opfile in
278 let args = List2.tail_map (fun (arg, spec, help) ->
279 (Printf.sprintf "-%s" arg, spec, help)) args
281 more_args := !more_args @ args
282 ) r.network_config_file
285 Arg.parse ([
286 "-v", Arg.Unit (fun _ ->
287 lprintf_nl "%s" (CommonGlobals.version ());
288 exit 0), _s " : print version number and exit";
289 "-exit", Arg.Unit (fun _ -> exit 0), ": exit immediatly";
290 "-format", Arg.String (fun file ->
291 ignore (CommonMultimedia.get_info file)),
292 _s " <filename> : check file format";
293 "-test_ip", Arg.String (fun ip ->
294 lprintf_nl "%s = %s" ip (Ip.to_string (Ip.of_string ip));
295 exit 0), _s "<ip> : undocumented";
296 "-check_impl", Arg.Unit (fun _ ->
297 CommonNetwork.check_network_implementations ();
298 CommonClient.check_client_implementations ();
299 CommonServer.check_server_implementations ();
300 CommonFile.check_file_implementations ();
301 (* CommonResult.check_result_implementations (); *)
302 lprint_newline ();
303 exit 0),
304 _s " : display information on the implementations";
305 "-stdout", Arg.Unit (fun _ ->
306 lprintf_original_output := (Some stdout);
307 log_to_file stdout
309 _s ": keep output to stdout after startup";
310 "-stderr", Arg.Unit (fun _ ->
311 lprintf_original_output := (Some stderr);
312 log_to_file stderr
314 _s ": keep output to stderr after startup";
315 "-daemon", Arg.Unit (fun _ ->
316 (* Removed due to savannah bug #11514 . *)
317 lprintf_nl "\n\nOption -daemon was removed.\nUse 'mlnet > /dev/null 2>&1 &' instead. Exiting...";
318 exit 64), _s " : this argument was removed, core will exit";
319 "-find_port", Arg.Set find_other_port,
320 _s " : find another port when one is already used";
321 "-pid", Arg.String (fun s -> pid := s;
323 _s ": directory for pid file";
324 "-useradd", Arg.Rest (fun s ->
325 (match String2.split s ' ' with
326 | user :: pass :: _ ->
327 if user2_user_exists user then
328 begin
329 user2_user_set_password (user2_user_find user) pass;
330 Printf.printf "%sPassword of user %s changed\n%!" (log_time ()) user
332 else
333 begin
334 user2_user_add user (Md4.Md4.string pass) ();
335 Printf.printf "%sUser %s added\n%!" (log_time ()) user
336 end;
337 Options.save_with_help_private users_ini;
338 Printf.printf "%sSaved changes to users.ini\n%!" (log_time ())
339 | _ -> raise (Arg.Bad "invalid syntax"));
340 exit 0), _s "\"<user> <pass>\" : create user/change password";
342 !more_args
344 !main_options)
345 (fun file -> ()
346 (* Files.dump_file file; exit 0 *)
347 ) "";
349 if not ini_files_exist && not (keep_console_output ()) then log_file =:= "mlnet.log";
351 (**** CREATE DIRS ****)
353 List.iter (fun s ->
354 Unix2.safe_mkdir s.shdir_dirname;
355 if s.shdir_strategy = "incoming_directories" ||
356 s.shdir_strategy = "incoming_files" then
357 Unix2.can_write_to_directory s.shdir_dirname
358 ) !!CommonComplexOptions.shared_directories;
359 Unix2.safe_mkdir "searches";
360 Unix2.can_write_to_directory "searches";
361 Unix2.safe_mkdir "web_infos";
362 Unix2.can_write_to_directory "web_infos";
363 Unix2.safe_mkdir !!temp_directory;
364 Unix2.can_write_to_directory !!temp_directory
366 let _ =
368 let t = Unix.localtime (Unix.time ()) in
369 if (t.Unix.tm_year<=104) then
370 begin
371 lprintf_nl (_b "\n\n\nYour system has a system date earlier than 2004, please correct it.");
372 lprintf_nl (_b "MLdonkey can not work with such a system date, exiting...");
373 CommonGlobals.exit_properly 71
374 end;
376 ( let resolve_name hostname =
378 ignore (Ip.from_name hostname);
379 true
380 with _ -> false
382 let hostnames =
383 ["mldonkey.sf.net"; "www.google.com"]
385 DriverInteractive.dns_works := List.exists resolve_name hostnames;
387 if not !DriverInteractive.dns_works then lprintf "
388 The core therefore is unable to get eDonkey serverlists and loading
389 .torrent files via dllink from websites is also impossible.
390 If you are using MLDonkey in a chroot environment you should
391 consider reading this article to get DNS support back:
392 http://mldonkey.sourceforge.net/Chroot\n\n");
394 let real_glibc_version = MlUnix.glibc_version_num () in
395 if real_glibc_version <> Autoconf.glibc_version
396 && real_glibc_version <> "" then
397 lprintf (_b"
398 Attention!
399 This core is running with glibc %s but it was compiled with glibc %s.
400 This can lead to unexpected behaviour. Consider compiling the core yourself
401 or getting a binary compiled with glibc %s.\n\n")
402 real_glibc_version Autoconf.glibc_version Autoconf.glibc_version
405 if Autoconf.magic then begin
406 (if Sys.file_exists "./magic/magic" then
407 try Unix.putenv "MAGIC" "./magic/magic" with _ -> ());
408 if Magic.M.magic_works () then
409 begin
410 Autoconf.magic_works := true;
411 lprintf_nl (_b "Libmagic file-type recognition database present")
413 else
414 begin
415 Autoconf.magic_works := false;
416 lprintf_nl (_b "Libmagic file-type recognition database not present")
420 if not !Charset.Locale.conversion_enabled then
421 lprintf_nl (_b "Self-test failed, charset conversion disabled.");
423 load_config ();
425 add_infinite_option_timer download_sample_rate CommonFile.sample_timer;
427 (* lprintf "(1) CommonComplexOptions.load\n"; *)
428 CommonComplexOptions.load ();
429 CommonUploads.load ();
430 CommonStats.load ();
432 (* lprintf "(2) CommonComplexOptions.load done\n"; *)
433 begin
434 let old_save_results = !!save_results in
435 save_results =:= 0;
436 CommonComplexOptions.save ();
437 CommonUploads.save ();
438 save_results =:= old_save_results;
439 end;
441 CommonGlobals.is_startup_phase := false;
443 (* before activating network modules load all local files from web_infos/
444 to avoid security holes, especially for IP blocking *)
445 Hashtbl.iter (fun key w ->
446 let file = Filename.concat "web_infos" (Filename.basename w.url) in
447 if Sys.file_exists file then
449 lprintf_nl "loading %s from %s" w.kind file;
450 ((List.assoc w.kind !CommonWeb.file_kinds).f w.url) file;
451 w.state <- Some FileLoaded;
452 with _ -> ()
453 ) web_infos_table;
455 discover_ip false;
457 lprintf_nl (_b "Check http://mldonkey.sf.net for updates");
458 networks_iter (fun r -> network_load_complex_options r);
459 lprintf_nl (_b "enabling networks: ");
460 if (upnp_port_forwarding ()) then
461 UpnpClient.init_maps ();
462 let add_upnp_port p s=
463 lprintf_nl "using port %d (%s)" p s;
464 if ((upnp_port_forwarding ())) then
465 match String2.split_simplify s ' ' with
466 | [ "client_port" ; tcpudp ]
467 | [ "tracker_port" ; tcpudp ]
468 | [ "dht_port" ; tcpudp ]
469 | [ "overnet_port" ; tcpudp ]
470 | [ "kademlia_port" ; tcpudp ] ->
471 if (String2.contains tcpudp "TCP") then
472 begin
473 UpnpClient.maps_add_item 1 p p 1 "" ;
474 lprintf_nl "add upnp port forwarding %d TCP" p;
475 end;
476 if (String2.contains tcpudp "UDP") then
477 begin
478 UpnpClient.maps_add_item 1 p p 0 "" ;
479 lprintf_nl "add upnp port forwarding %d UDP" p;
481 | _ -> ()
483 networks_iter (fun r ->
484 lprintf_nl (_b "---- enabling %s ----") r.network_name;
485 network_enable r;
486 List.iter (fun (p,s) -> if p <> 0 then add_upnp_port p s) (network_ports r);
487 (* are there drawbacks to start recover_temp unconditionally here ? *)
488 if !!recover_temp_on_startup then
489 network_recover_temp r;
491 lprintf_nl (_b "---- enabling interfaces ----");
492 List.iter (fun (p,s) -> if p <> 0 then lprintf_nl "using port %d (%s)" p s)
493 (network_ports (network_find_by_name "Global Shares"));
494 lprintf (_b "%s[dMain] disabled networks: ") (log_time ());
495 let found = ref false in
496 networks_iter_all (fun r ->
497 if not (network_is_enabled r) then
498 begin
499 found := true;
500 lprintf (_b "%s ") r.network_name
501 end);
502 if not !found then lprintf (_b "none");
503 lprint_newline ();
504 if (upnp_port_forwarding ()) then
505 UpnpClient.job_start ();
506 networks_iter_all (fun n -> network_update_options n);
507 CommonOptions.start_running_plugins := true;
508 CommonInteractive.force_download_quotas ();
510 TcpBufferedSocket.set_max_connections_per_second
511 (fun _ -> !!max_connections_per_second);
513 add_infinite_option_timer save_options_delay (fun timer ->
514 DriverInteractive.save_config ());
515 start_interfaces ();
517 add_infinite_timer 60. minute_timer;
518 add_infinite_timer 10. ten_second_timer;
519 add_infinite_timer 3600. hourly_timer;
520 add_infinite_timer 0.1 CommonUploads.upload_download_timer;
521 add_infinite_timer !!buffer_writes_delay (fun _ -> Unix32.flush ());
523 if !!share_scan_interval <> 0 then
524 add_infinite_timer ((float_of_int !!share_scan_interval) *. 60.)
525 (fun _ -> CommonShared.shared_check_files ());
526 CommonShared.shared_check_files ();
528 history_timeflag := (Unix.time());
529 update_download_history ();
530 update_upload_history ();
531 history_h_timeflag := (Unix.time());
532 update_h_download_history ();
533 update_h_upload_history ();
534 history_size_for_h_graph := history_size * !!html_mods_vd_gfx_h_intervall / 60;
535 history_h_step := 60 * !!html_mods_vd_gfx_h_intervall;
537 add_infinite_timer (float_of_int history_step) (fun timer ->
538 history_timeflag := (Unix.time());
539 update_download_history ();
540 update_upload_history ());
542 add_infinite_timer (float_of_int !history_h_step) (fun timer ->
543 history_h_timeflag := (Unix.time());
544 update_h_download_history ();
545 update_h_upload_history ());
547 if Autoconf.system = "mingw" then
548 add_infinite_timer 1. (fun timer ->
549 MlUnix.set_console_title (DriverInteractive.console_topic ()));
551 List.iter
552 CommonShared.shared_add_directory
553 !!CommonComplexOptions.shared_directories;
555 add_infinite_timer 1800. (fun timer ->
556 DriverInteractive.browse_friends ());
558 Options.prune_file downloads_ini;
559 Options.prune_file users_ini;
560 add_timer 1. (fun _ -> try CommonWeb.load_web_infos true false with _ -> ());
561 if !!telnet_port <> 0 then lprintf_nl (_b "To command: telnet %s %d")
562 (if !!telnet_bind_addr = Ip.any then "127.0.0.1"
563 else Ip.to_string !!telnet_bind_addr) !!telnet_port;
564 if !!http_port <> 0 then begin
565 lprintf_nl (_b "Or with browser: http://%s:%d")
566 (if !!http_bind_addr = Ip.any then "127.0.0.1"
567 else Ip.to_string !!http_bind_addr) !!http_port;
568 lprintf_nl (_b "For a GUI check out http://sancho-gui.sourceforge.net")
569 end;
570 if !!gui_port <> 0 then lprintf_nl (_b "Connect to IP %s, port %d")
571 (if !!gui_bind_addr = Ip.any then "127.0.0.1"
572 else Ip.to_string !!gui_bind_addr) !!gui_port;
573 lprintf_nl (_b "If you connect from a remote machine adjust allowed_ips");
574 if Autoconf.system = "cygwin" && not (keep_console_output ()) then lprintf (_b "%s") win_message;
576 add_init_hook (fun _ ->
577 if not !gui_included && ( !!start_gui || !!ask_for_gui ) then
578 (try
579 let _ = Sys.getenv("DISPLAY") in
580 if !!start_gui && Sys.file_exists !!mldonkey_gui then
581 ignore (Sys.command (Printf.sprintf "%s &" !!mldonkey_gui))
582 else
583 let asker = Filename.concat !!mldonkey_bin "mlguistarter" in
584 if !!ask_for_gui && Sys.file_exists !!mldonkey_gui &&
585 Sys.file_exists asker then
586 ignore (Sys.command (Printf.sprintf "%s %s&" asker !!mldonkey_gui));
587 with Not_found ->
588 lprintf_nl (_b "Not running under X, not trying to start the GUI")
592 if !!run_as_group <> "" then begin
594 let new_gr = Unix.getgrnam !!run_as_group in
595 MlUnix.setgid new_gr.Unix.gr_gid;
596 let gr = Unix.getgrgid (Unix.getgid()) in
597 lprintf_nl (_b "mldonkey is now running as group %s") gr.Unix.gr_name;
598 with e ->
599 lprintf_nl (_b "Exception %s trying to set group_gid [%s]")
600 (Printexc2.to_string e) !!run_as_group;
601 exit 67
602 end;
604 if !!run_as_groupgid <> 0 then begin
606 MlUnix.setgid !!run_as_groupgid;
607 lprintf_nl (_b "mldonkey is now running as gid %d") !!run_as_groupgid;
608 with e ->
609 lprintf_nl (_b "Exception %s trying to set group_gid [%d]")
610 (Printexc2.to_string e) !!run_as_groupgid;
611 exit 67
612 end;
614 if !!run_as_user <> "" then begin
616 let new_pw = Unix.getpwnam !!run_as_user in
617 MlUnix.setuid new_pw.Unix.pw_uid;
618 let pw = Unix.getpwuid (Unix.getuid()) in
619 lprintf_nl (_b "mldonkey is now running as user %s") pw.Unix.pw_name;
620 with e ->
621 lprintf_nl (_b "Exception %s trying to set user_uid [%s]")
622 (Printexc2.to_string e) !!run_as_user;
623 exit 67
624 end;
626 if !!run_as_useruid <> 0 then begin
628 MlUnix.setuid !!run_as_useruid;
629 lprintf_nl (_b "mldonkey is now running as uid %d") !!run_as_useruid;
630 with e ->
631 lprintf_nl (_b "Exception %s trying to set user_uid [%d]")
632 (Printexc2.to_string e) !!run_as_useruid;
633 exit 67
634 end;
636 if !!create_mlsubmit then save_mlsubmit_reg ();
637 DriverInteractive.initialization_completed := true;
638 DriverInteractive.save_config ();
640 if not Autoconf.windows then
641 MlUnix.set_signal Sys.sigchld
642 (Sys.Signal_handle (fun _ -> if !verbose then lprintf_nl (_b "Received SIGCHLD, doing nothing")));
644 if not Autoconf.windows then
645 MlUnix.set_signal Sys.sighup
646 (Sys.Signal_handle (fun _ -> lprintf_nl (_b "Received SIGHUP, closing all files and client/server sockets, start IP discovery");
647 networks_iter (fun r -> CommonNetwork.network_reset r); (* stop_all_bt *)
648 CommonServer.disconnect_all_servers ();
649 CommonClient.disconnect_all_clients ();
650 Unix32.close_all (); (* close all files *)
651 discover_ip false;
654 if not Autoconf.windows then
655 MlUnix.set_signal Sys.sigpipe
656 (Sys.Signal_handle (fun _ -> if !verbose then lprintf_nl (_b "Received SIGPIPE, doing nothing")));
658 MlUnix.set_signal Sys.sigint
659 (Sys.Signal_handle (fun _ -> lprintf_nl (_b "Received SIGINT, stopping MLDonkey...");
660 CommonInteractive.clean_exit 0));
662 MlUnix.set_signal Sys.sigterm
663 (Sys.Signal_handle (fun _ -> lprintf_nl (_b "Received SIGTERM, stopping MLDonkey...");
664 CommonInteractive.clean_exit 0));
666 if not Autoconf.windows then
667 MlUnix.set_signal Sys.sigusr1
668 (Sys.Signal_handle (fun _ -> lprintf_nl (_b "Received SIGUSR1, saving options...");
669 DriverInteractive.save_config ()));
671 if not Autoconf.windows then
672 MlUnix.set_signal Sys.sigusr2
673 (Sys.Signal_handle (fun _ -> lprintf_n (_b "Received SIGUSR2, starting garbage collection...");
674 Gc.compact ();
675 lprintf " finished";
676 lprint_newline ()));
678 if !verbose then lprintf_nl (_b "Activated system signal handling")
680 let _ =
681 let security_space_oc = ref None in
682 begin
683 (* Create a 'config_files_security_space' megabytes file to protect some space
684 for config files at the end. *)
686 let oc = Unix.openfile security_space_filename [Unix.O_WRONLY; Unix.O_CREAT] 0o600 in
687 let len = 32768 in
688 let s = String.make len ' ' in
689 let pos = ref zero in
690 for i = 1 to !!config_files_security_space do
691 for j = 1 to 32 do (* 32 = 1 MB / 32kB *)
692 ignore(Unix2.c_seek64 oc !pos Unix.SEEK_SET);
693 Unix2.really_write oc s 0 len;
694 pos := !pos ++ (Int64.of_int len)
695 done
696 done;
697 ignore(Unix2.c_seek64 oc zero Unix.SEEK_SET);
698 (try Unix.lockf oc Unix.F_LOCK (!!config_files_security_space * 1024 * 1024) with _ -> ());
699 security_space_oc := Some oc
700 with e ->
701 lprintf_nl (_b "Cannot create Security space file: %s") (Printexc2.to_string e);
702 lprintf_nl (_b " not enough space on device or bad permissions");
703 lprintf_nl (_b "Exiting...");
704 exit 73;
705 end;
706 Unix32.external_start ();
709 let pid_file, s =
710 Filename.concat !pid pid_filename,
711 Printf.sprintf "%s\n" (string_of_int(Unix.getpid()))
713 Unix2.tryopen_write pid_file (fun oc -> output_string oc s);
714 CommonGlobals.do_at_exit (fun _ -> try Sys.remove pid_file with _ -> ());
715 if !verbose then
716 lprintf_nl (_b "Starting with pid %s") (string_of_int(Unix.getpid ()))
719 (* When a core is spawned from a gui, the only way to know the startup has
720 succeeded is the string token "Core started". *)
721 if not (keep_console_output ()) then
722 begin
724 Printf.eprintf "%s[dMain] Core started\n%!" (log_time ());
725 with _ -> ()
726 end;
728 lprintf_nl (_b "Core started");
729 core_included := true;
731 CommonGlobals.do_at_exit (fun _ ->
732 (* If we have an error with too many file-descriptors,
733 just close all of them *)
734 (try
735 BasicSocket.close_all ();
736 with e ->
737 lprintf_nl "Exception %s in do_at_exit while closing sockets."
738 (Printexc2.to_string e);
740 DriverGraphics.G.remove_files ();
741 (* In case we have no more space on filesystem for
742 config files, remove the security space file *)
743 (match !security_space_oc with
744 None -> ()
745 | Some oc -> Unix.close oc);
746 (try Sys.remove security_space_filename with _ -> ());
747 CommonComplexOptions.allow_saving_ini_files := true;
748 DriverInteractive.save_config ();
749 CommonComplexOptions.save_sources ();
750 CommonComplexOptions.backup_options ();
751 Geoip.close ();
752 Unix32.external_exit ();
753 lprintf_nl (_b "Core stopped")
756 if not (keep_console_output ()) then
757 if !!log_file = "" then
758 begin
759 lprintf_nl (_b "Option log_file is empty, disable logging completely...");
760 lprintf_nl (_b "Disabling output to console, to enable: stdout true");
761 log_to_file stdout;
762 close_log ()