diff --git a/lib/std/os.zig b/lib/std/os.zig index 74ffd4de12..e69a2a7943 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -366,6 +366,56 @@ pub fn fchown(fd: fd_t, owner: ?uid_t, group: ?gid_t) FChownError!void { } } +pub const RebootError = error{ + PermissionDenied, +} || UnexpectedError; + +pub const RebootCommand = switch (builtin.os.tag) { + .linux => union(linux.LINUX_REBOOT.CMD) { + RESTART: void, + HALT: void, + CAD_ON: void, + CAD_OFF: void, + POWER_OFF: void, + RESTART2: [*:0]const u8, + SW_SUSPEND: void, + KEXEC: void, + }, + else => @compileError("Unsupported OS"), +}; + +pub fn reboot(cmd: RebootCommand) RebootError!void { + switch (builtin.os.tag) { + .linux => { + switch (system.getErrno(linux.reboot( + .MAGIC1, + .MAGIC2, + @as(linux.LINUX_REBOOT.CMD, cmd), + switch (cmd) { + .RESTART2 => |s| s, + else => null, + }, + ))) { + .SUCCESS => {}, + .PERM => return error.PermissionDenied, + else => |err| return std.os.unexpectedErrno(err), + } + switch (cmd) { + .CAD_OFF => {}, + .CAD_ON => {}, + .SW_SUSPEND => {}, + + .HALT => unreachable, + .KEXEC => unreachable, + .POWER_OFF => unreachable, + .RESTART => unreachable, + .RESTART2 => unreachable, + } + }, + else => @compileError("Unsupported OS"), + } +} + pub const GetRandomError = OpenError; /// Obtain a series of random bytes. These bytes can be used to seed user-space diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 8ca20bc330..f98cd828c0 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -804,6 +804,63 @@ pub fn exit_group(status: i32) noreturn { unreachable; } +/// flags for the `reboot' system call. +pub const LINUX_REBOOT = struct { + /// First magic value required to use _reboot() system call. + pub const MAGIC1 = enum(u32) { + MAGIC1 = 0xfee1dead, + _, + }; + + /// Second magic value required to use _reboot() system call. + pub const MAGIC2 = enum(u32) { + MAGIC2 = 672274793, + MAGIC2A = 85072278, + MAGIC2B = 369367448, + MAGIC2C = 537993216, + _, + }; + + /// Commands accepted by the _reboot() system call. + pub const CMD = enum(u32) { + /// Restart system using default command and mode. + RESTART = 0x01234567, + + /// Stop OS and give system control to ROM monitor, if any. + HALT = 0xCDEF0123, + + /// Ctrl-Alt-Del sequence causes RESTART command. + CAD_ON = 0x89ABCDEF, + + /// Ctrl-Alt-Del sequence sends SIGINT to init task. + CAD_OFF = 0x00000000, + + /// Stop OS and remove all power from system, if possible. + POWER_OFF = 0x4321FEDC, + + /// Restart system using given command string. + RESTART2 = 0xA1B2C3D4, + + /// Suspend system using software suspend if compiled in. + SW_SUSPEND = 0xD000FCE2, + + /// Restart system using a previously loaded Linux kernel + KEXEC = 0x45584543, + + _, + }; +}; + +pub fn reboot(magic: LINUX_REBOOT.MAGIC1, magic2: LINUX_REBOOT.MAGIC2, cmd: LINUX_REBOOT.CMD, arg: ?*const anyopaque) usize { + return std.os.linux.syscall4( + .reboot, + @enumToInt(magic), + @enumToInt(magic2), + @enumToInt(cmd), + @ptrToInt(arg), + ); +} + pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize { return syscall3(.getrandom, @ptrToInt(buf), count, flags); }