rpm: Add BR pcre-devel.
[whenjobs.git] / daemon / whenjobsd.ml
1 (* whenjobs daemon
2  * Copyright (C) 2012 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  *)
18
19 open Unix
20 open Printf
21
22 (* Ensures that Whentools module is linked to the daemon. *)
23 let _ = Whentools.set_variable
24
25 let () =
26   (* Running the daemon as root is a mistake.  It must be run as a
27    * non-root user.
28    *)
29   let euid = geteuid () in
30   if euid = 0 then (
31     eprintf "whenjobsd: this daemon must run as the local user, NOT root\n";
32     exit 1
33   );
34
35   (* $HOME must be defined and must exist and be a directory and must be
36    * owned by the current user.
37    *)
38   let home =
39     try getenv "HOME"
40     with Not_found ->
41       eprintf "whenjobsd: $HOME environment variable must be defined\n";
42       exit 1 in
43
44   let stat =
45     try lstat home
46     with Unix_error (err, fn, _) ->
47       eprintf "whenjobsd: %s: %s ($HOME): %s\n" fn home (error_message err);
48       exit 1 in
49   if stat.st_kind != S_DIR then (
50     eprintf "whenjobsd: %s ($HOME): not a directory\n" home;
51     exit 1
52   );
53
54   if stat.st_uid != euid then (
55     eprintf "whenjobsd: %s ($HOME): not owned by the current user (uid %d)\n"
56       home euid;
57     exit 1
58   );
59
60   (* Parse the command line arguments. *)
61   let debug = ref false in
62   let do_fork = ref true in
63
64   let display_version () =
65     printf "%s %s\n" Config.package_name Config.package_version;
66     exit 0
67   in
68
69   let argspec = Arg.align [
70     "-d", Arg.Set debug, " Enable extra debugging messages";
71     "-f", Arg.Clear do_fork, " Don't fork into background";
72     "-V", Arg.Unit display_version, " Display version number and exit";
73     "--version", Arg.Unit display_version, " Display version number and exit";
74   ] in
75
76   let anon_fun _ = raise (Arg.Bad "unknown command line argument") in
77
78   let usage_msg = "\
79 Usage:
80   whenjobsd [--options]
81
82 For documentation see the whenjobs(1) and whenjobsd(8) man pages.
83
84 Options:
85 " in
86
87   Arg.parse argspec anon_fun usage_msg;
88
89   let debug = !debug in
90   let do_fork = !do_fork in
91
92   (* Make the $HOME/.whenjobs directory if it doesn't exist. *)
93   let jobsdir = sprintf "%s/.whenjobs" home in
94   (try mkdir jobsdir 0o700 with Unix_error _ -> ());
95
96   (* Create the socket. *)
97   Daemon.init jobsdir debug;
98
99   (* Fork into background. *)
100   if do_fork then (
101     let pid = fork () in
102     if pid > 0 then exit 0;
103
104     (* chdir / so we don't prevent filesystems from being unmounted. *)
105     chdir "/";
106
107     (* Close file descriptors, replace with /dev/null. *)
108     close stdin;
109     close stdout;
110     close stderr;
111     ignore (openfile "/dev/null" [O_RDONLY] 0);
112     ignore (openfile "/dev/null" [O_WRONLY] 0);
113     ignore (openfile "/dev/null" [O_WRONLY] 0);
114
115     (* Create a new session. *)
116     ignore (setsid ());
117
118     (* Ignore SIGHUP. *)
119     Sys.set_signal Sys.sighup Sys.Signal_ignore;
120
121     (* Update the PID file since we just forked. *)
122     Whenlock.update_pid ();
123   );
124
125   (* Start syslog. *)
126   Syslog.notice "daemon started: version=%s uid=%d home=%s"
127     Config.package_version euid home;
128
129   (* If there is a jobs.cmo file, load it. *)
130   let () =
131     let file = sprintf "%s/jobs.cmo" jobsdir in
132     if Sys.file_exists file then
133       try Daemon.reload_files () with Failure _ -> () in
134
135   (* Go into main loop. *)
136   Daemon.main_loop ()