]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/lua/menu.lua
stand/lua: Don't try to divide by 0; do nothing
[FreeBSD/FreeBSD.git] / stand / lua / menu.lua
1 --
2 -- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org>
3 -- All rights reserved.
4 --
5 -- Redistribution and use in source and binary forms, with or without
6 -- modification, are permitted provided that the following conditions
7 -- are met:
8 -- 1. Redistributions of source code must retain the above copyright
9 --    notice, this list of conditions and the following disclaimer.
10 -- 2. Redistributions in binary form must reproduce the above copyright
11 --    notice, this list of conditions and the following disclaimer in the
12 --    documentation and/or other materials provided with the distribution.
13 --
14 -- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 -- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 -- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 -- ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 -- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 -- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 -- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 -- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 -- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 -- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 -- SUCH DAMAGE.
25 --
26 -- $FreeBSD$
27 --
28
29
30 local menu = {};
31
32 local core = require("core");
33 local color = require("color");
34 local config = require("config");
35 local screen = require("screen");
36 local drawer = require("drawer");
37
38 local OnOff;
39 local skip;
40 local run;
41 local autoboot;
42 local carousel_choices = {};
43
44 --loader menu tree:
45 --rooted at menu.welcome
46 --submenu declarations:
47 local boot_options;
48 local welcome;
49
50 menu.boot_options = {
51         -- return to welcome menu
52         {
53                 entry_type = core.MENU_RETURN,
54                 name = function()
55                         return "Back to main menu"..color.highlight(" [Backspace]");
56                 end
57         },
58
59         -- load defaults
60         {
61                 entry_type = core.MENU_ENTRY,
62                 name = function()
63                         return "Load System "..color.highlight("D").."efaults";
64                 end,
65                 func = function()
66                         core.setDefaults()
67                 end,
68                 alias = {"d", "D"}
69         },
70
71         {
72                 entry_type = core.MENU_SEPARATOR,
73                 name = function()
74                         return "";
75                 end
76         },
77
78         {
79                 entry_type = core.MENU_SEPARATOR,
80                 name = function()
81                         return "Boot Options:";
82                 end
83         },
84
85         -- acpi
86         {
87                 entry_type = core.MENU_ENTRY,
88                 name = function()
89                         return OnOff(color.highlight("A").."CPI       :", core.acpi);
90                 end,
91                 func = function()
92                         core.setACPI();
93                 end,
94                 alias = {"a", "A"}
95         },
96         -- safe mode
97         {
98                 entry_type = core.MENU_ENTRY,
99                 name = function()
100                         return OnOff("Safe "..color.highlight("M").."ode  :", core.sm);
101                 end,
102                 func = function()
103                         core.setSafeMode();
104                 end,
105                 alias = {"m", "M"}
106         },
107         -- single user
108         {
109                 entry_type = core.MENU_ENTRY,
110                 name = function()
111                         return OnOff(color.highlight("S").."ingle user:", core.su);
112                 end,
113                 func = function()
114                         core.setSingleUser();
115                 end,
116                 alias = {"s", "S"}
117         },
118         -- verbose boot
119         {
120                 entry_type = core.MENU_ENTRY,
121                 name = function()
122                         return OnOff(color.highlight("V").."erbose    :", core.verbose);
123                 end,
124                 func = function()
125                         core.setVerbose();
126                 end,
127                 alias = {"v", "V"}
128         },
129 };
130
131 menu.welcome = {
132         -- boot multi user
133         {
134                 entry_type = core.MENU_ENTRY,
135                 name = function()
136                         return color.highlight("B").."oot Multi user "..color.highlight("[Enter]");
137                 end,
138                 func = function()
139                         core.setSingleUser(false);
140                         core.boot();
141                 end,
142                 alias = {"b", "B"}
143         },
144
145         -- boot single user
146         {
147                 entry_type = core.MENU_ENTRY,
148                 name = function()
149                         return "Boot "..color.highlight("S").."ingle user";
150                 end,
151                 func = function()
152                         core.setSingleUser(true);
153                         core.boot();
154                 end,
155                 alias = {"s", "S"}
156         },
157
158         -- escape to interpreter
159         {
160                 entry_type = core.MENU_RETURN,
161                 name = function()
162                         return color.highlight("Esc").."ape to loader prompt";
163                 end,
164                 func = function()
165                         loader.setenv("autoboot_delay", "NO")
166                 end,
167                 alias = {core.KEYSTR_ESCAPE}
168         },
169
170         -- reboot
171         {
172                 entry_type = core.MENU_ENTRY,
173                 name = function()
174                         return color.highlight("R").."eboot";
175                 end,
176                 func = function()
177                         loader.perform("reboot");
178                 end,
179                 alias = {"r", "R"}
180         },
181
182
183         {
184                 entry_type = core.MENU_SEPARATOR,
185                 name = function()
186                         return "";
187                 end
188         },
189
190         {
191                 entry_type = core.MENU_SEPARATOR,
192                 name = function()
193                         return "Options:";
194                 end
195         },
196
197         -- kernel options
198         {
199                 entry_type = core.MENU_CAROUSEL_ENTRY,
200                 carousel_id = "kernel",
201                 items = core.kernelList,
202                 name = function(idx, choice, all_choices)
203                         if #all_choices == 0 then
204                                 return "Kernel: ";
205                         end
206
207                         local kernel_name = color.escapef(color.GREEN) ..
208                             choice .. color.default();
209                         if (idx == 1) then
210                                 kernel_name = "default/" .. kernel_name;
211                         end
212                         return color.highlight("K").."ernel: " .. kernel_name ..
213                             " (" .. idx ..
214                             " of " .. #all_choices .. ")";
215                 end,
216                 func = function(choice)
217                         config.reload(choice);
218                 end,
219                 alias = {"k", "K"}
220         },
221
222         -- boot options
223         {
224                 entry_type = core.MENU_SUBMENU,
225                 name = function()
226                         return "Boot "..color.highlight("O").."ptions";
227                 end,
228                 submenu = function()
229                         return menu.boot_options;
230                 end,
231                 alias = {"o", "O"}
232         }
233
234 };
235
236 -- The first item in every carousel is always the default item.
237 function menu.getCarouselIndex(id)
238         local val = carousel_choices[id];
239         if (val == nil) then
240                 return 1;
241         end
242         return val;
243 end
244
245 function menu.setCarouselIndex(id, idx)
246         carousel_choices[id] = idx;
247 end
248
249 function menu.run(m)
250
251         if (menu.skip()) then
252                 core.autoboot();
253                 return false;
254         end
255
256         if (m == nil) then
257                 m = menu.welcome;
258         end
259
260         -- redraw screen
261         screen.clear();
262         screen.defcursor();
263         local alias_table = drawer.drawscreen(m);
264
265 --      menu.autoboot();
266
267         cont = true;
268         while cont do
269                 local key = io.getchar();
270
271                 -- Special key behaviors
272                 if ((key == core.KEY_BACKSPACE) or (key == core.KEY_DELETE)) and
273                     (m ~= menu.welcome) then
274                         break
275                 elseif (key == core.KEY_ENTER) then
276                         core.boot();
277                         -- Should not return
278                 end
279
280                 key = string.char(key)
281                 -- check to see if key is an alias
282                 local sel_entry = nil;
283                 for k, v in pairs(alias_table) do
284                         if (key == k) then
285                                 sel_entry = v;
286                         end
287                 end
288
289                 -- if we have an alias do the assigned action:
290                 if(sel_entry ~= nil) then
291                         if (sel_entry.entry_type == core.MENU_ENTRY) then
292                                 -- run function
293                                 sel_entry.func();
294                         elseif (sel_entry.entry_type == core.MENU_CAROUSEL_ENTRY) then
295                                 -- carousel (rotating) functionality
296                                 local carid = sel_entry.carousel_id;
297                                 local caridx = menu.getCarouselIndex(carid);
298                                 local choices = sel_entry.items();
299
300                                 if (#choices > 0) then
301                                         caridx = (caridx % #choices) + 1;
302                                         menu.setCarouselIndex(carid, caridx);
303                                         sel_entry.func(choices[caridx]);
304                                 end
305                         elseif (sel_entry.entry_type == core.MENU_SUBMENU) then
306                                 -- recurse
307                                 cont = menu.run(sel_entry.submenu());
308                         elseif (sel_entry.entry_type == core.MENU_RETURN) then
309                                 -- allow entry to have a function/side effect
310                                 if (sel_entry.func ~= nil) then
311                                         sel_entry.func();
312                                 end
313                                 -- break recurse
314                                 cont = false;
315                         end
316                         -- if we got an alias key the screen is out of date:
317                         screen.clear();
318                         screen.defcursor();
319                         alias_table = drawer.drawscreen(m);
320                 end
321         end
322
323         if (m == menu.welcome) then
324                 screen.defcursor();
325                 print("Exiting menu!");
326                 return false;
327         end
328
329         return true;
330 end
331
332 function menu.skip()
333         if core.bootserial() then
334                 return true;
335         end
336         local c = string.lower(loader.getenv("console") or "");
337         if (c:match("^efi[ ;]") or c:match("[ ;]efi[ ;]")) ~= nil then
338                 return true;
339         end
340
341         c = string.lower(loader.getenv("beastie_disable") or "");
342         print("beastie_disable", c);
343         return c == "yes";
344 end
345
346 function menu.autoboot()
347         if menu.already_autoboot == true then
348                 return;
349         end
350         menu.already_autoboot = true;
351
352         local ab = loader.getenv("autoboot_delay");
353         if ab == "NO" or ab == "no" then
354                 core.boot();
355         end
356         ab = tonumber(ab) or 10;
357
358         local x = loader.getenv("loader_menu_timeout_x") or 5;
359         local y = loader.getenv("loader_menu_timeout_y") or 22;
360
361         local endtime = loader.time() + ab;
362         local time;
363
364         repeat
365                 time = endtime - loader.time();
366                 screen.setcursor(x, y);
367                 print("Autoboot in "..time.." seconds, hit [Enter] to boot"
368                               .." or any other key to stop     ");
369                 screen.defcursor();
370                 if io.ischar() then
371                         local ch = io.getchar();
372                         if ch == core.KEY_ENTER then
373                                 break;
374                         else
375                                 -- prevent autoboot when escaping to interpreter
376                                 loader.setenv("autoboot_delay", "NO");
377                                 -- erase autoboot msg
378                                 screen.setcursor(0, y);
379                                 print("                                        "
380                                               .."                                        ");
381                                 screen.defcursor();
382                                 return;
383                         end
384                 end
385
386                 loader.delay(50000);
387         until time <= 0
388         core.boot();
389
390 end
391
392 function OnOff(str, b)
393         if (b) then
394                 return str .. color.escapef(color.GREEN).."On"..color.escapef(color.WHITE);
395         else
396                 return str .. color.escapef(color.RED).."off"..color.escapef(color.WHITE);
397         end
398 end
399
400 return menu