(* whenjobs daemon * Copyright (C) 2012 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *) open Unix open Printf (* Ensures that Whentools module is linked to the daemon. *) let _ = Whentools.set_variable let () = (* Running the daemon as root is a mistake. It must be run as a * non-root user. *) let euid = geteuid () in if euid = 0 then ( eprintf "whenjobsd: this daemon must run as the local user, NOT root\n"; exit 1 ); (* $HOME must be defined and must exist and be a directory and must be * owned by the current user. *) let home = try getenv "HOME" with Not_found -> eprintf "whenjobsd: $HOME environment variable must be defined\n"; exit 1 in let stat = try lstat home with Unix_error (err, fn, _) -> eprintf "whenjobsd: %s: %s ($HOME): %s\n" fn home (error_message err); exit 1 in if stat.st_kind != S_DIR then ( eprintf "whenjobsd: %s ($HOME): not a directory\n" home; exit 1 ); if stat.st_uid != euid then ( eprintf "whenjobsd: %s ($HOME): not owned by the current user (uid %d)\n" home euid; exit 1 ); (* Parse the command line arguments. *) let debug = ref false in let do_fork = ref true in let display_version () = printf "%s %s\n" Config.package_name Config.package_version; exit 0 in let argspec = Arg.align [ "-d", Arg.Set debug, " Enable extra debugging messages"; "-f", Arg.Clear do_fork, " Don't fork into background"; "-V", Arg.Unit display_version, " Display version number and exit"; "--version", Arg.Unit display_version, " Display version number and exit"; ] in let anon_fun _ = raise (Arg.Bad "unknown command line argument") in let usage_msg = "\ Usage: whenjobsd [--options] For documentation see the whenjobs(1) and whenjobsd(8) man pages. Options: " in Arg.parse argspec anon_fun usage_msg; let debug = !debug in let do_fork = !do_fork in (* Make the $HOME/.whenjobs directory if it doesn't exist. *) let jobsdir = sprintf "%s/.whenjobs" home in (try mkdir jobsdir 0o700 with Unix_error _ -> ()); (* Create the socket. *) Daemon.init jobsdir debug; (* Fork into background. *) if do_fork then ( let pid = fork () in if pid > 0 then exit 0; (* chdir / so we don't prevent filesystems from being unmounted. *) chdir "/"; (* Close file descriptors, replace with /dev/null. *) close stdin; close stdout; close stderr; ignore (openfile "/dev/null" [O_RDONLY] 0); ignore (openfile "/dev/null" [O_WRONLY] 0); ignore (openfile "/dev/null" [O_WRONLY] 0); (* Create a new session. *) ignore (setsid ()); (* Ignore SIGHUP. *) Sys.set_signal Sys.sighup Sys.Signal_ignore; (* Update the PID file since we just forked. *) Whenlock.update_pid (); ); (* Start syslog. *) Syslog.notice "daemon started: version=%s uid=%d home=%s" Config.package_version euid home; (* If there is a jobs.cmo file, load it. *) let () = let file = sprintf "%s/jobs.cmo" jobsdir in if Sys.file_exists file then try Daemon.reload_file () with Failure _ -> () in (* Go into main loop. *) Daemon.main_loop ()