whenjobs initial version.
[whenjobs.git] / daemon / whenjobsd.ml
diff --git a/daemon/whenjobsd.ml b/daemon/whenjobsd.ml
new file mode 100644 (file)
index 0000000..a994279
--- /dev/null
@@ -0,0 +1,129 @@
+(* 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
+
+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. *)
+    close stdin;
+    close stdout;
+    close stderr;
+
+    (* 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: uid=%d home=%s" 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 ()