// Initialize the bottle, if necessary, then run a command in it. public static int ExecHandler(bool verbose, IEnumerable <string> command) { // Get the bottle state. var state = GetBottleState(verbose); // If already inside, just execute it. if (state.startedWithin) { return(Helpers.RunAndWait(command.First(), command.Skip(1).ToArray())); } using (var r = new RootPrivilege()) { if (!state.existedAtStart) { InitializeBottle(verbose); } // At this point, we should be inside an existing bottle, one way or another. RunCommand(verbose, command.ToArray()); } return(0); }
// Initialize the bottle, if necessary, then start a login prompt in it. public static int LoginHandler(bool verbose) { // Get the bottle state. var state = GetBottleState(verbose); if (state.startedWithin) { Console.WriteLine("genie: already inside the bottle; cannot start login prompt!"); return(EINVAL); } using (var r = new RootPrivilege()) { if (!state.existedAtStart) { InitializeBottle(verbose); } // At this point, we should be outside an existing bottle, one way or another. // It shouldn't matter whether we have setuid here, since we start the shell with // a login prompt, which reassigns uid appropriately. StartLogin(verbose); } return(0); }
// Initialize the bottle (if necessary) only public static int InitializeHandler(bool verbose) { // Get the bottle state. var state = GetBottleState(verbose); // If a bottle exists, we have succeeded already. Exit and report success. if (state.existedAtStart) { if (verbose) { Console.WriteLine("genie: bottle already exists (no need to initialize)."); } return(0); } // Daemonize expects real uid root as well as effective uid root. using (var r = new RootPrivilege()) { // Init the bottle. InitializeBottle(verbose); } return(0); }
// Shut down the bottle and clean up. public static int ShutdownHandler(bool verbose) { // Get the bottle state. var state = GetBottleState(verbose); if (!state.existedAtStart) { Console.WriteLine("genie: no bottle exists."); return(EINVAL); } if (state.startedWithin) { Console.WriteLine("genie: cannot shut down bottle from inside bottle; exiting."); return(EINVAL); } using (var r = new RootPrivilege()) { if (verbose) { Console.WriteLine("genie: running systemctl poweroff within bottle"); } var systemdPid = Helpers.GetSystemdPid(); var sd = Process.GetProcessById(systemdPid); Helpers.Chain("nsenter", new string[] { "-t", systemdPid.ToString(), "-m", "-p", "systemctl", "poweroff" }, "running command failed; nsenter"); Console.Write("Waiting for systemd exit..."); // Wait for systemd to exit. int timeout = Config.SystemdStartupTimeout; while (!sd.WaitForExit(1000)) { Console.Write("."); timeout--; if (timeout < 0) { Console.WriteLine("\n\nTimed out waiting for systemd to exit.\nThis may indicate a systemd configuration error.\nAttempting to continue."); break; } } Console.WriteLine(); if (Config.UpdateHostname) { Thread.Sleep(500); Helpers.DropHostname(verbose); } } return(0); }
// Shut down the bottle and clean up. public static int ShutdownHandler(bool verbose) { // Get the bottle state. var state = GetBottleState(verbose); if (!state.existedAtStart) { Console.WriteLine("genie: no bottle exists."); return(EINVAL); } if (state.startedWithin) { Console.WriteLine("genie: cannot shut down bottle from inside bottle; exiting."); return(EINVAL); } using (var r = new RootPrivilege()) { if (verbose) { Console.WriteLine("genie: running systemctl poweroff within bottle"); } var systemdPid = Helpers.GetSystemdPid(); var sd = Process.GetProcessById(systemdPid); Helpers.Chain("nsenter", new string[] { "-t", systemdPid.ToString(), "-m", "-p", "systemctl", "poweroff" }, "running command failed; nsenter"); if (verbose) { Console.WriteLine("genie: waiting for systemd to exit"); } // Wait for systemd to exit (maximum 16 s). sd.WaitForExit(16000); if (Config.UpdateHostname) { Thread.Sleep(500); Helpers.DropHostname(verbose); } } return(0); }
// Shut down the bottle and clean up. public static int ShutdownHandler(bool verbose) { // Get the bottle state. var state = GetBottleState(verbose); if (!state.existedAtStart) { Console.WriteLine("genie: no bottle exists."); return(EINVAL); } if (state.startedWithin) { Console.WriteLine("genie: cannot shut down bottle from inside bottle; exiting."); return(EINVAL); } using (var r = new RootPrivilege()) { if (verbose) { Console.WriteLine("genie: running systemctl poweroff within bottle"); } var systemdPid = Helpers.GetSystemdPid(); var sd = Process.GetProcessById(systemdPid); Helpers.Chain("nsenter", new string[] { "-t", systemdPid.ToString(), "-m", "-p", "systemctl", "poweroff" }, "running command failed; nsenter"); Console.Write("Waiting for systemd exit..."); // Wait for systemd to exit. int timeout = Config.SystemdStartupTimeout; while (!sd.WaitForExit(1000)) { Console.Write("."); timeout--; if (timeout < 0) { Console.WriteLine("\n\nTimed out waiting for systemd to exit.\nThis may indicate a systemd configuration error.\nAttempting to continue."); break; } } Console.WriteLine(); // Having unmounted the binfmts fs before starting systemd, we remount it now as // a courtesy. But remember, genie is not guaranteed to be idempotent, so don't // rely on this, for the love of Thompson and Ritchie! if (!Directory.Exists("/proc/sys/fs/binfmt_misc")) { if (verbose) { Console.WriteLine("genie: remounting binfmt_misc filesystem as a courtesy"); } if (!MountHelpers.Mount("binfmt_misc", "/proc/sys/fs/binfmt_misc", FsType.BinaryFormats)) { Console.WriteLine("genie: failed to remount binfmt_misc filesystem; attempting to continue"); } } if (Config.ResolvedStub) { Helpers.RemoveResolvSymlink(verbose); } if (Config.UpdateHostname) { Thread.Sleep(500); Helpers.DropHostname(verbose); } } return(0); }