From: Dave Benjamin <dave@ramenlabs.com>
To: caml-list@inria.fr
Subject: Re: [Caml-list] Closing all open file descriptors
Date: Fri, 14 Sep 2007 00:32:10 -0700 [thread overview]
Message-ID: <46EA38FA.8010201@ramenlabs.com> (raw)
In-Reply-To: <20070914164810.39a4dcda.mle+ocaml@mega-nerd.com>
Erik de Castro Lopo wrote:
> Dave Benjamin wrote:
>
>> Did your program "daemonize" at all, then? Or did you use daemontools?
>
> Yes, it called Unix.fork and then in the child called Unix.setsid.
>
> Err, what's daemontools?
daemontools is a service management framework by D. J. Bernstein which
those pages you linked were partially in reference to. The basic
philosophy is that you don't write daemons at all; you write regular
programs that read from stdin and write to stdout. You don't fork, you
don't setsid, you don't worry about the environment and you don't keep
track of PID files.
(IMHO, that's why they're so worked up about closing file descriptors.
They're trying to get daemons to stop being daemons so they can be
controlled by daemontools, and this is one of the sticking points.)
The daemontools style is actually a little bit like functional
programming in its use of wrapper programs. A typical daemontools
solution to the file descriptor closing problem would be to write a tiny
C program that closes the file descriptors and then forks and execs its
argument, like this:
closefds mydaemon arg1 arg2 ...
where "closefds" closes the file descriptors and then runs "mydaemon"
with the supplied arguments. This way, "closefds" would just be another
reusable tool.
Incidentally, Linux comes with a "setsid" program that does the same
think with fork and setsid. It doesn't seem to be available for BSD,
though (though "nohup" is, which is similar as well).
> My program has passes around a logging function of type "string -> unit".
> If it not a daemon it uses print_endline for logging and if it is a daemon
> it uses a wrapper around syslog (via the debian/ubuntu libsyslog-ocaml-dev)
> package.
Makes sense to me.
>> Yeah, the whole operation could be done in a C function too, and
>> probably wouldn't be much more code to write.
>
> My daemon is only tiny, but I'm, still glad its in Ocaml.
I agree, overall the Unix module is pretty nice to use.
Here's a port of the "daemonize" C function described in APUE to OCaml,
and it's where my earlier code example came from:
(* Based on Adv. Programming in the UNIX Environment, 2nd Ed. *)
#use "topfind";;
#require "unix";;
#require "syslog";;
open Printf
let daemonize cmd =
(* Clear file creation mask. *)
ignore (Unix.umask 0);
(* Become a session leader to lose controlling TTY. *)
if Unix.fork () > 0 then exit 0;
ignore (Unix.setsid ());
(* Ensure future opens won't allocate controlling TTYs. *)
Sys.set_signal Sys.sighup Sys.Signal_ignore;
if Unix.fork () > 0 then exit 0;
(* Change the current working directory to the root so
we won't prevent file systems from being unmounted. *)
Unix.chdir "/";
(* Close all open file descriptors. *)
for fd = 0 to 1024 do
try Unix.close (Obj.magic fd : Unix.file_descr)
with Unix.Unix_error _ -> ()
done;
(* Attach file descriptors 0, 1, and 2 to /dev/null. *)
let fd0 = Unix.openfile "/dev/null" [Unix.O_RDWR] 0o666 in
let fd1 = Unix.dup fd0 in
let fd2 = Unix.dup fd0 in
(* Initialize the log file. *)
let log = Syslog.openlog cmd in
if fd0 <> Unix.stdin || fd1 <> Unix.stdout || fd2 <> U
begin
Syslog.syslog log `LOG_ERR
(sprintf "unexpected file descriptors %d %d %d"
(Obj.magic fd0 : int)
(Obj.magic fd1 : int)
(Obj.magic fd2 : int));
exit 1
end;
log
let () =
let log = daemonize "daemonize" in
Syslog.syslog log `LOG_INFO "Starting daemon";
Unix.sleep 10;
Syslog.syslog log `LOG_INFO "Farewell"
Cheers,
Dave
next prev parent reply other threads:[~2007-09-14 7:33 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-09-13 22:56 Dave Benjamin
2007-09-14 1:04 ` [Caml-list] " Erik de Castro Lopo
2007-09-14 6:35 ` Dave Benjamin
2007-09-14 6:48 ` Erik de Castro Lopo
2007-09-14 7:32 ` Dave Benjamin [this message]
2007-09-14 6:33 ` David Allsopp
2007-09-14 6:41 ` Dave Benjamin
2007-09-14 10:54 ` Andre Nathan
2007-09-14 10:00 ` Mattias Engdegård
2007-09-14 20:31 ` Dave Benjamin
2007-09-14 21:52 ` Oliver Bandel
2007-09-14 22:12 ` Markus E L
2007-09-15 9:15 ` Oliver Bandel
2007-09-15 9:26 ` Erik de Castro Lopo
2007-09-15 10:43 ` Oliver Bandel
2007-09-15 11:36 ` Mattias Engdegård
2007-09-15 11:57 ` Oliver Bandel
2007-09-15 14:27 ` Markus E L
2007-09-15 12:16 ` Oliver Bandel
2007-09-15 14:29 ` Markus E L
2007-09-15 18:04 ` skaller
2007-09-15 14:17 ` Markus E L
2007-09-15 14:16 ` Markus E L
2007-09-15 15:58 ` Eric Cooper
2007-09-15 16:17 ` Markus E L
2007-09-15 18:33 ` skaller
2007-09-15 17:44 ` skaller
2007-09-14 10:10 ` Gerd Stolpmann
2007-09-14 11:56 ` Oliver Bandel
2007-09-17 11:00 ` Ville-Pertti Keinonen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=46EA38FA.8010201@ramenlabs.com \
--to=dave@ramenlabs.com \
--cc=caml-list@inria.fr \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox