X-Git-Url: http://git.annexia.org/?p=whenjobs.git;a=blobdiff_plain;f=daemon%2Fdaemon.ml;h=6ccfcce983606075b6457c7c433763fdf4ab8da6;hp=a6cc2fa7e75346756efdcc295fb17c12652af71f;hb=0bfe72d06b55b0db076c900c6c2173b59c8b75f3;hpb=28d4576308b10064eda39827c419aa33e1041041 diff --git a/daemon/daemon.ml b/daemon/daemon.ml index a6cc2fa..6ccfcce 100644 --- a/daemon/daemon.ml +++ b/daemon/daemon.ml @@ -18,6 +18,7 @@ open Whenutils +open Big_int open Unix open Printf @@ -80,7 +81,12 @@ let rec init j d = ); (* Handle SIGCHLD to clean up jobs. *) - Sys.set_signal Sys.sigchld (Sys.Signal_handle handle_sigchld) + Sys.set_signal Sys.sigchld (Sys.Signal_handle handle_sigchld); + + (* Initialize the variables. XXX Eventually this will be saved + * and loaded from a persistent store. + *) + variables := StringMap.add "JOBSERIAL" (T_int zero_big_int) !variables and proc_reload_file () = if !debug then Syslog.notice "remote call: reload_file"; @@ -91,12 +97,35 @@ and proc_reload_file () = and proc_set_variable (name, value) = if !debug then Syslog.notice "remote call: set_variable %s" name; - let value = variable_of_rpc value in - variables := StringMap.add name value !variables; + try + (* Don't permit certain names. *) + if name = "JOBSERIAL" then + failwith "JOBSERIAL variable cannot be set"; + + let len = String.length name in + if len = 0 then + failwith "variable name is an empty string"; + if name.[0] <> '_' && not (isalpha name.[0]) then + failwith "variable name must start with alphabetic character or underscore"; + + let rec loop i = + if i >= len then () + else if name.[i] <> '_' && not (isalnum name.[i]) then + failwith "variable name contains non-alphanumeric non-underscore character" + else loop (i+1) + in + loop 1; + + let value = variable_of_rpc value in + variables := StringMap.add name value !variables; + + (* Which jobs need to be re-evaluated? *) + let jobnames = try StringMap.find name !dependencies with Not_found -> [] in + reevaluate_whenjobs jobnames; - (* Which jobs need to be re-evaluated? *) - let jobnames = try StringMap.find name !dependencies with Not_found -> [] in - reevaluate_whenjobs jobnames + `ok + with + Failure msg -> `error msg and proc_get_variable name = if !debug then Syslog.notice "remote call: get_variable %s" name; @@ -169,7 +198,7 @@ and reload_file () = dependencies := map in (* Re-evaluate all when jobs. *) - reevaluate_whenjobs (StringMap.keys !jobs); + reevaluate_whenjobs ~onload:true (StringMap.keys !jobs); (* Schedule the next every job to run. *) schedule_next_everyjob () @@ -178,7 +207,7 @@ and reload_file () = * a fixpoint. Run those that need to be run. every-statement jobs * are ignored here. *) -and reevaluate_whenjobs jobnames = +and reevaluate_whenjobs ?(onload=false) jobnames = let rec loop set jobnames = let set' = List.fold_left ( @@ -189,7 +218,7 @@ and reevaluate_whenjobs jobnames = assert (jobname = job.job_name); let r, job' = - try job_evaluate job !variables + try job_evaluate job !variables onload with Invalid_argument err | Failure err -> Syslog.error "error evaluating job %s (at %s): %s" jobname (Camlp4.PreCast.Ast.Loc.to_string job.job_loc) err; @@ -291,7 +320,18 @@ and string_of_time_t t = tm.tm_hour tm.tm_min tm.tm_sec and run_job job = - Syslog.notice "running %s" job.job_name; + let () = + (* Increment JOBSERIAL. *) + let serial = + match StringMap.find "JOBSERIAL" !variables with + | T_int serial -> + let serial = succ_big_int serial in + variables := StringMap.add "JOBSERIAL" (T_int serial) !variables; + serial + | _ -> assert false in + + Syslog.notice "running %s (JOBSERIAL=%s)" + job.job_name (string_of_big_int serial) in (* Create a temporary directory. The current directory of the job * will be in this directory. The directory is removed when the @@ -313,12 +353,15 @@ and run_job job = (* Create a temporary file containing the shell script fragment. *) let script = dir // "script" in let chan = open_out script in + fprintf chan "set -e\n"; (* So that jobs exit on error. *) output_string chan job.job_script.sh_script; close_out chan; chmod script 0o700; + let shell = try getenv "SHELL" with Not_found -> "/bin/sh" in + (* Execute the shell script. *) - (try execvp "bash" [| "bash"; "-c"; script |]; + (try execvp shell [| shell; "-c"; script |]; with Unix_error (err, fn, _) -> Syslog.error "%s failed: %s: %s" fn script (error_message err) );