1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
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;
}
}
|