121 lines
3.1 KiB
JavaScript
121 lines
3.1 KiB
JavaScript
import Gio from "gi://Gio";
|
|
import { ExecCommand, Log, LogWarning } from './utils.js';
|
|
|
|
/**
|
|
* Represents Systemdboot
|
|
*/
|
|
export class SystemdBoot {
|
|
/**
|
|
* Get's all available boot options
|
|
* @returns {[Map, string]} Map(title, id), defaultOption
|
|
*/
|
|
static async GetBootOptions() {
|
|
let bootctl = await this.GetBinary();
|
|
if (bootctl == "") {
|
|
Log(`Failed to find bootctl binary`);
|
|
return undefined;
|
|
}
|
|
|
|
try {
|
|
let [status, stdout, stderr] = await ExecCommand([bootctl, "list"]);
|
|
if (status !== 0)
|
|
throw new Error(`Failed to get list from bootctl: ${status}\n${stdout}\n${stderr}`);
|
|
Log(`bootctl list: ${status}\n${stdout}\n${stderr}`);
|
|
let lines = String(stdout).split('\n');
|
|
let titleRx = /(?<=title:\s+).+/;
|
|
let idRx = /(?<=id:\s+).+/;
|
|
let defaultRx = /\(default\)/;
|
|
let titles = [];
|
|
let ids = []
|
|
let defaultOpt;
|
|
lines.forEach(l => {
|
|
let title = titleRx.exec(l);
|
|
let id = idRx.exec(l);
|
|
if (title && title.length) {
|
|
titles.push(String(title));
|
|
} else if (id && id.length) {
|
|
ids.push(String(id));
|
|
}
|
|
});
|
|
if (titles.length !== ids.length)
|
|
throw new Error("Number of titles and ids do not match!");
|
|
let bootOptions = new Map();
|
|
for (let i = 0; i < titles.length; i++) {
|
|
bootOptions.set(titles[i], ids[i])
|
|
}
|
|
|
|
bootOptions.forEach((id, title) => {
|
|
Log(`${id} = ${title}`);
|
|
|
|
let defaultRes = defaultRx.exec(title);
|
|
|
|
if (defaultRes) {
|
|
defaultOpt = title;
|
|
}
|
|
})
|
|
|
|
return [bootOptions, bootOptions.get(defaultOpt)];
|
|
} catch (e) {
|
|
LogWarning(e);
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set's the next boot option
|
|
* @param {string} id
|
|
* @returns True if the boot option was set, otherwise false
|
|
*/
|
|
static async SetBootOption(id) {
|
|
if (!this.IsUseable()) return false;
|
|
const [status, stdout, stderr] = await ExecCommand(['/usr/bin/pkexec', '/usr/bin/bootctl', 'set-oneshot', id],);
|
|
if (status === 0) {
|
|
Log(`Set boot option to ${id}`);
|
|
return true;
|
|
}
|
|
LogWarning("Unable to set boot option using bootctl");
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Can we use this bootloader?
|
|
* @returns True if useable otherwise false
|
|
*/
|
|
static async IsUseable() {
|
|
return await this.GetBinary() !== "";
|
|
}
|
|
|
|
/**
|
|
* Get's bootctl binary path
|
|
* @returns A string containing the location of the binary, if none is found returns a blank string
|
|
*/
|
|
static async GetBinary() {
|
|
let paths = ["/usr/sbin/bootctl", "/usr/bin/bootctl"];
|
|
|
|
let file;
|
|
|
|
for (let i = 0; i < paths.length; i++) {
|
|
file = Gio.file_new_for_path(paths[i]);
|
|
if (file.query_exists(null)) {
|
|
return paths[i];
|
|
}
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
/**
|
|
* This boot loader cannot be quick rebooted
|
|
*/
|
|
static async CanQuickReboot() {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* This boot loader cannot be quick rebooted
|
|
*/
|
|
static async QuickRebootEnabled() {
|
|
return false;
|
|
}
|
|
}
|