beterraba

commit d9aa32ed31338c2ca64ed8e961fc7bb4f5f726fe

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)!;
+};