Author: Pedro Lucas Porcellis <porcellis@eletrotupi.com>
monitor: flesh out a simple process monitor
cmd/beterrabamon/main.ha | 129 ++++++++++++++++++++++++++++++++++++++++++ cmd/beterrabamon/ops.ha | 13 ++++
diff --git a/cmd/beterrabamon/main.ha b/cmd/beterrabamon/main.ha new file mode 100644 index 0000000000000000000000000000000000000000..48b2991c96530a6ec8e9339045364ae40ed3822c --- /dev/null +++ b/cmd/beterrabamon/main.ha @@ -0,0 +1,129 @@ +use log; +use beterraba; +use net::unix; +use net; +use fs; +use os; +use fmt; +use io; +use errors; +use path; +use dirs; +use os::exec; +use os::exec::{signal}; +use time; +use strings; + +export fn main() void = { + const name = os::args[1]; + const conn = conn(); + defer io::close(conn)!; + + const svc = retrieve(&conn, name); + let pid = boot(&svc); + announce(&conn, "started", svc.name); + + for (true) { + const exit_status = match (exec::wait(&pid)) { + case let s: exec::status => + yield s; + case let err: exec::error => + // TODO: End gracefully when daemon dies + log::printfln("Something went wrong on wait"); + abort(); + }; + + match (exec::exit(&exit_status)) { + case let s: exec::exited => + // TODO: Announce that this service has exited normally + log::printfln("Exited with status {}", exec::exitstr(s)); + case let s: exec::signaled => + if (s == signal::SIGSEGV) { + log::printfln("We need to restart"); + time::sleep(1 * time::SECOND); + // TODO: Announce that this service has crashed + pid = boot(&svc); + } else { + // TODO: Announce that this service has died + log::printfln("Died of {}", exec::exitstr(s)); + }; + }; + //wait(&pid); + }; +}; + +fn conn() net::socket = { + let buf = path::init(); + // TODO: Bubble up dirs::runtime errors + const sockpath = path::set(&buf, dirs::runtime()!, "beterrabad")!; + let conn = match (unix::connect(sockpath)) { + case let s: net::socket => + yield s; + case errors::noentry => + log::fatal("error: baterraba connection failed (is it running?)"); + case let e: net::error => + log::fatal("error:", net::strerror(e)); + }; + + return conn; +}; + +// TODO: Move socket stuff into it's own file +// Retrieve a service from the daemon given it's name +fn retrieve(conn: *net::socket, name: str) beterraba::service = { + log::println("Begin retrieving"); + let buf = path::init(); + // TODO: Bubble up dirs::runtime errors + const servname = fmt::asprintf("{}.service", name); + defer free(servname); + + const servpath = path::set(&buf, dirs::config("beterraba"), servname)!; + log::println("Service name: ", servpath); + + match(os::open(servpath)) { + case let f: io::file => + return beterraba::parse(f); + case let e: fs::error => + log::fatal("Failed to retrieve the service (moved/deleted or wrong name?)"); + }; +}; + +// Announce info regarding a given service +fn announce(sock: *io::file, ops: str, name: str) void = { + // TODO: Move into a list of valid ops + write((*sock), "started", name); +}; + +// Just forks & starts the given service +fn boot(svc: *beterraba::service) int = { + let pid = 0; + match (exec::fork()) { + case let childpid: int => + pid = childpid; + log::printfln("Starting process with PID {}", pid); + case void => + start(svc); + }; + + return pid; +}; + +// Starts a given set of commands with their args +fn start(svc: *beterraba::service) void = { + const cmd = exec::cmd(svc.definition.cmd, svc.definition.args); + + match (cmd) { + case let cmddef: exec::command => + exec::exec(&cmddef); + case exec::nocmd => + log::printfln("Couldn't build cmd"); + abort(); + case exec::error => + // TODO: Return and inform the thing + log::printfln("Couldn't execute cmd {}, error"); + abort(); + case => + log::println("Something went terrible wrong, good luck!"); + abort(); + }; +}; diff --git a/cmd/beterrabamon/ops.ha b/cmd/beterrabamon/ops.ha new file mode 100644 index 0000000000000000000000000000000000000000..6193da3bfda36b11e14413d91c3da00f8214bc52 --- /dev/null +++ b/cmd/beterrabamon/ops.ha @@ -0,0 +1,13 @@ +use fmt; +use log; +use io; +use net::unix; +use net; + +fn write(sock: io::file, op: str, svc: str) void = { + let cmd = fmt::asprintf("{} {}", op, svc); + defer free(cmd); + + fmt::fprintf(sock, cmd)!; + fmt::fprintln(sock)!; +};