]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/lua/menu.lua
stand/lua: Make CAROUSEL_ENTRY func parameters consistent with name
[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(idx, choice, all_choices)
217                         if (#all_choices > 1) then
218                                 config.reload(choice);
219                         end
220                 end,
221                 alias = {"k", "K"}
222         },
223
224         -- boot options
225         {
226                 entry_type = core.MENU_SUBMENU,
227                 name = function()
228                         return "Boot "..color.highlight("O").."ptions";
229                 end,
230                 submenu = function()
231                         return menu.boot_options;
232                 end,
233                 alias = {"o", "O"}
234         }
235
236 };
237
238 -- The first item in every carousel is always the default item.
239 function menu.getCarouselIndex(id)
240         local val = carousel_choices[id];
241         if (val == nil) then
242                 return 1;
243         end
244         return val;
245 end
246
247 function menu.setCarouselIndex(id, idx)
248         carousel_choices[id] = idx;
249 end
250
251 function menu.run(m)
252
253         if (menu.skip()) then
254                 core.autoboot();
255                 return false;
256         end
257
258         if (m == nil) then
259                 m = menu.welcome;
260         end
261
262         -- redraw screen
263         screen.clear();
264         screen.defcursor();
265         local alias_table = drawer.drawscreen(m);
266
267 --      menu.autoboot();
268
269         cont = true;
270         while cont do
271                 local key = io.getchar();
272
273                 -- Special key behaviors
274                 if ((key == core.KEY_BACKSPACE) or (key == core.KEY_DELETE)) and
275                     (m ~= menu.welcome) then
276                         break
277                 elseif (key == core.KEY_ENTER) then
278                         core.boot();
279                         -- Should not return
280                 end
281
282                 key = string.char(key)
283                 -- check to see if key is an alias
284                 local sel_entry = nil;
285                 for k, v in pairs(alias_table) do
286                         if (key == k) then
287                                 sel_entry = v;
288                         end
289                 end
290
291                 -- if we have an alias do the assigned action:
292                 if(sel_entry ~= nil) then
293                         if (sel_entry.entry_type == core.MENU_ENTRY) then
294                                 -- run function
295                                 sel_entry.func();
296                         elseif (sel_entry.entry_type == core.MENU_CAROUSEL_ENTRY) then
297                                 -- carousel (rotating) functionality
298                                 local carid = sel_entry.carousel_id;
299                                 local caridx = menu.getCarouselIndex(carid);
300                                 local choices = sel_entry.items();
301
302                                 if (#choices > 0) then
303                                         caridx = (caridx % #choices) + 1;
304                                         menu.setCarouselIndex(carid, caridx);
305                                         sel_entry.func(caridx, choices[caridx],
306                                             choices);
307                                 end
308                         elseif (sel_entry.entry_type == core.MENU_SUBMENU) then
309                                 -- recurse
310                                 cont = menu.run(sel_entry.submenu());
311                         elseif (sel_entry.entry_type == core.MENU_RETURN) then
312                                 -- allow entry to have a function/side effect
313                                 if (sel_entry.func ~= nil) then
314                                         sel_entry.func();
315                                 end
316                                 -- break recurse
317                                 cont = false;
318                         end
319                         -- if we got an alias key the screen is out of date:
320                         screen.clear();
321                         screen.defcursor();
322                         alias_table = drawer.drawscreen(m);
323                 end
324         end
325
326         if (m == menu.welcome) then
327                 screen.defcursor();
328                 print("Exiting menu!");
329                 return false;
330         end
331
332         return true;
333 end
334
335 function menu.skip()
336         if core.bootserial() then
337                 return true;
338         end
339         local c = string.lower(loader.getenv("console") or "");
340         if (c:match("^efi[ ;]") or c:match("[ ;]efi[ ;]")) ~= nil then
341                 return true;
342         end
343
344         c = string.lower(loader.getenv("beastie_disable") or "");
345         print("beastie_disable", c);
346         return c == "yes";
347 end
348
349 function menu.autoboot()
350         if menu.already_autoboot == true then
351                 return;
352         end
353         menu.already_autoboot = true;
354
355         local ab = loader.getenv("autoboot_delay");
356         if ab == "NO" or ab == "no" then
357                 core.boot();
358         end
359         ab = tonumber(ab) or 10;
360
361         local x = loader.getenv("loader_menu_timeout_x") or 5;
362         local y = loader.getenv("loader_menu_timeout_y") or 22;
363
364         local endtime = loader.time() + ab;
365         local time;
366
367         repeat
368                 time = endtime - loader.time();
369                 screen.setcursor(x, y);
370                 print("Autoboot in "..time.." seconds, hit [Enter] to boot"
371                               .." or any other key to stop     ");
372                 screen.defcursor();
373                 if io.ischar() then
374                         local ch = io.getchar();
375                         if ch == core.KEY_ENTER then
376                                 break;
377                         else
378                                 -- prevent autoboot when escaping to interpreter
379                                 loader.setenv("autoboot_delay", "NO");
380                                 -- erase autoboot msg
381                                 screen.setcursor(0, y);
382                                 print("                                        "
383                                               .."                                        ");
384                                 screen.defcursor();
385                                 return;
386                         end
387                 end
388
389                 loader.delay(50000);
390         until time <= 0
391         core.boot();
392
393 end
394
395 function OnOff(str, b)
396         if (b) then
397                 return str .. color.escapef(color.GREEN).."On"..color.escapef(color.WHITE);
398         else
399                 return str .. color.escapef(color.RED).."off"..color.escapef(color.WHITE);
400         end
401 end
402
403 return menu