summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhpa <hpa>2005-08-30 22:36:49 +0000
committerhpa <hpa>2005-08-30 22:36:49 +0000
commitda20539a79fe070350a43503b8db954c50980e18 (patch)
tree06f9d61e1253191b4489bab57893ab03ae219a40
parentdeec9eeabdb560545f94198686b2f93ec6d20839 (diff)
downloadsyslinux-da20539a79fe070350a43503b8db954c50980e18.tar.gz
New "totaltimeout" option; change the menu behaviour on timeout.
-rw-r--r--NEWS2
-rw-r--r--com32/include/klibc/archsetjmp.h19
-rw-r--r--com32/include/setjmp.h43
-rw-r--r--com32/lib/Makefile2
-rw-r--r--com32/lib/setjmp.S5
-rw-r--r--com32/modules/menu.c97
-rw-r--r--com32/modules/menu.h11
-rw-r--r--com32/modules/readconfig.c13
-rw-r--r--keywords1
-rw-r--r--keywords.inc3
-rw-r--r--parseconfig.inc27
-rw-r--r--syslinux.doc16
-rw-r--r--ui.inc89
13 files changed, 256 insertions, 72 deletions
diff --git a/NEWS b/NEWS
index ccec82a9..b175768e 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,8 @@ Changes in 3.11:
physical floppy disk is present in the system.
* Enable the 16550A FIFOs, if present, when doing serial
console.
+ * New "totaltimeout" command establishes a timeout without
+ regard for any user input.
Changes in 3.10:
* gcc 4.0.1 compilation fixes.
diff --git a/com32/include/klibc/archsetjmp.h b/com32/include/klibc/archsetjmp.h
new file mode 100644
index 00000000..db04314b
--- /dev/null
+++ b/com32/include/klibc/archsetjmp.h
@@ -0,0 +1,19 @@
+/*
+ * arch/i386/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+ unsigned int __ebx;
+ unsigned int __esp;
+ unsigned int __ebp;
+ unsigned int __esi;
+ unsigned int __edi;
+ unsigned int __eip;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _SETJMP_H */
diff --git a/com32/include/setjmp.h b/com32/include/setjmp.h
new file mode 100644
index 00000000..b504eb6d
--- /dev/null
+++ b/com32/include/setjmp.h
@@ -0,0 +1,43 @@
+/*
+ * setjmp.h
+ */
+
+#ifndef _SETJMP_H
+#define _SETJMP_H
+
+#include <klibc/extern.h>
+#include <klibc/compiler.h>
+#include <stddef.h>
+#include <signal.h>
+
+#include <klibc/archsetjmp.h>
+
+__extern int setjmp(jmp_buf);
+__extern __noreturn longjmp(jmp_buf, int);
+
+/*
+ Whose bright idea was it to add unrelated functionality to just about
+ the only function in the standard C library (setjmp) which cannot be
+ wrapped by an ordinary function wrapper? Anyway, the damage is done,
+ and therefore, this wrapper *must* be inline. However, gcc will
+ complain if this is an inline function for unknown reason, and
+ therefore sigsetjmp() needs to be a macro.
+*/
+
+struct __sigjmp_buf {
+ jmp_buf __jmpbuf;
+ sigset_t __sigs;
+};
+
+typedef struct __sigjmp_buf sigjmp_buf[1];
+
+#define sigsetjmp(__env, __save) \
+({ \
+ struct __sigjmp_buf *__e = (__env); \
+ sigprocmask(0, NULL, &__e->__sigs); \
+ setjmp(__e->__jmpbuf); \
+})
+
+__extern __noreturn siglongjmp(sigjmp_buf, int);
+
+#endif /* _SETJMP_H */
diff --git a/com32/lib/Makefile b/com32/lib/Makefile
index af64950b..3aa0a620 100644
--- a/com32/lib/Makefile
+++ b/com32/lib/Makefile
@@ -4,7 +4,7 @@ include MCONFIG
LIBOBJS = \
abort.o atexit.o atoi.o atol.o atoll.o calloc.o creat.o \
ctypes.o errno.o fgetc.o fgets.o fopen.o fprintf.o fputc.o \
- putchar.o \
+ putchar.o setjmp.o \
fputs.o fread2.o fread.o free.o fwrite2.o fwrite.o getopt.o \
lrand48.o malloc.o stack.o memccpy.o memchr.o memcmp.o \
memcpy.o memmem.o memmove.o memset.o memswap.o exit.o onexit.o \
diff --git a/com32/lib/setjmp.S b/com32/lib/setjmp.S
index bea900c5..5c5fbeae 100644
--- a/com32/lib/setjmp.S
+++ b/com32/lib/setjmp.S
@@ -16,6 +16,11 @@
.text
.align 4
+
+ .globl _setjmp
+ .type _setjmp, @function
+_setjmp: # gcc 4.0.1 wants this as an alias?
+
.globl setjmp
.type setjmp, @function
setjmp:
diff --git a/com32/modules/menu.c b/com32/modules/menu.c
index 357ac9aa..eee81f56 100644
--- a/com32/modules/menu.c
+++ b/com32/modules/menu.c
@@ -26,9 +26,8 @@
#include <consoles.h>
#include <getkey.h>
#include <minmax.h>
-#include <time.h>
-#include <sys/times.h>
-#include <unistd.h>
+#include <setjmp.h>
+#include <limits.h>
#include <sha1.h>
#include <base64.h>
#ifdef __COM32__
@@ -216,6 +215,42 @@ passwd_compare(const char *passwd, const char *entry)
return !memcmp(sha1, pwdsha1, 20);
}
+static jmp_buf timeout_jump;
+
+static int mygetkey(clock_t timeout)
+{
+ clock_t t0, t;
+ clock_t tto, to;
+ int key;
+
+ if ( !totaltimeout )
+ return get_key(stdin, timeout);
+
+ for (;;) {
+ tto = min(totaltimeout, INT_MAX);
+ to = timeout ? min(tto, timeout) : tto;
+
+ t0 = times(NULL);
+ key = get_key(stdin, to);
+ t = times(NULL) - t0;
+
+ if ( totaltimeout <= t )
+ longjmp(timeout_jump, 1);
+
+ totaltimeout -= t;
+
+ if ( key != KEY_NONE )
+ return key;
+
+ if ( timeout ) {
+ if ( timeout <= t )
+ return KEY_NONE;
+
+ timeout -= t;
+ }
+ }
+}
+
static int
ask_passwd(const char *menu_entry)
{
@@ -248,7 +283,7 @@ ask_passwd(const char *menu_entry)
p = user_passwd;
while ( !done ) {
- key = get_key(stdin, 0);
+ key = mygetkey(0);
switch ( key ) {
case KEY_ENTER:
@@ -377,7 +412,7 @@ edit_cmdline(char *input, int top)
redraw = 0;
}
- key = get_key(stdin, 0);
+ key = mygetkey(0);
switch( key ) {
case KEY_CTRL('L'):
@@ -504,15 +539,28 @@ run_menu(void)
{
int key;
int done = 0;
- int entry = defentry, prev_entry = -1;
+ volatile int entry = defentry, prev_entry = -1;
int top = 0, prev_top = -1;
int clear = 1, to_clear;
const char *cmdline = NULL;
- clock_t key_timeout, timeout_left, this_timeout;
+ volatile clock_t key_timeout, timeout_left, this_timeout;
- /* Convert timeout from deciseconds to clock ticks */
/* Note: for both key_timeout and timeout == 0 means no limit */
- timeout_left = key_timeout = (clock_t)(CLK_TCK*timeout+9)/10;
+ timeout_left = key_timeout = timeout;
+
+ /* Handle both local and global timeout */
+ if ( setjmp(timeout_jump) ) {
+ entry = defentry;
+
+ if ( top < 0 || top < entry-MENU_ROWS+1 )
+ top = max(0, entry-MENU_ROWS+1);
+ else if ( top > entry || top > max(0,nentries-MENU_ROWS) )
+ top = min(entry, max(0,nentries-MENU_ROWS));
+
+ draw_menu(ontimeout ? -1 : entry, top, 1);
+ cmdline = ontimeout ? ontimeout : menu_entries[entry].cmdline;
+ done = 1;
+ }
while ( !done ) {
if ( entry < 0 )
@@ -544,7 +592,11 @@ run_menu(void)
prev_entry = entry; prev_top = top;
- if ( key_timeout && entry == defentry ) {
+ /* Cursor movement cancels timeout */
+ if ( entry != defentry )
+ key_timeout = 0;
+
+ if ( key_timeout ) {
int tol = timeout_left/CLK_TCK;
int nc = snprintf(NULL, 0, " Automatic boot in %d seconds ", tol);
printf("\033[%d;%dH%s Automatic boot in %s%d%s seconds ",
@@ -557,8 +609,8 @@ run_menu(void)
to_clear = 0;
}
- this_timeout = min(timeout_left, CLK_TCK);
- key = get_key(stdin, this_timeout);
+ this_timeout = min(min(key_timeout, timeout_left), CLK_TCK);
+ key = mygetkey(this_timeout);
if ( key != KEY_NONE ) {
timeout_left = key_timeout;
@@ -573,16 +625,11 @@ run_menu(void)
Warning: a timeout will boot the default entry without any
password! */
- timeout_left -= this_timeout;
-
- if ( timeout_left == 0 ) {
- if ( entry != defentry ) {
- entry = defentry;
- timeout_left = key_timeout;
- } else {
- cmdline = menu_entries[defentry].cmdline;
- done = 1;
- }
+ if ( key_timeout ) {
+ if ( timeout_left <= this_timeout )
+ longjmp(timeout_jump, 1);
+
+ timeout_left -= this_timeout;
}
break;
@@ -592,6 +639,7 @@ run_menu(void)
case KEY_ENTER:
case KEY_CTRL('J'):
+ key_timeout = 0; /* Cancels timeout */
if ( menu_entries[entry].passwd ) {
clear = 1;
done = ask_passwd(menu_entries[entry].passwd);
@@ -661,6 +709,7 @@ run_menu(void)
if ( allowedit ) {
int ok = 1;
+ key_timeout = 0; /* Cancels timeout */
draw_row(entry-top+4, -1, top, 0, 0);
if ( to_clear ) {
@@ -691,6 +740,7 @@ run_menu(void)
if ( allowedit ) {
done = 1;
clear = 1;
+ key_timeout = 0;
draw_row(entry-top+4, -1, top, 0, 0);
@@ -702,6 +752,7 @@ run_menu(void)
if ( key > 0 && key < 0xFF ) {
key &= ~0x20; /* Upper case */
if ( menu_hotkeys[key] ) {
+ key_timeout = 0;
entry = menu_hotkeys[key] - menu_entries;
/* Should we commit at this point? */
}
@@ -759,7 +810,7 @@ execute(const char *cmdline)
/* If this returns, something went bad; return to menu */
#else
/* For testing... */
- printf("\n>>> %s\n", cmdline);
+ printf("\n\033[0m>>> %s\n", cmdline);
exit(0);
#endif
}
diff --git a/com32/modules/menu.h b/com32/modules/menu.h
index 0d4bd001..78a553c6 100644
--- a/com32/modules/menu.h
+++ b/com32/modules/menu.h
@@ -20,6 +20,16 @@
#ifndef MENU_H
#define MENU_H
+#include <time.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#ifndef CLK_TCK
+# define CLK_TCK sysconf(_SC_CLK_TCK)
+#endif
+
struct menu_entry {
char *displayname;
char *label;
@@ -46,6 +56,7 @@ extern int nentries;
extern int defentry;
extern int allowedit;
extern int timeout;
+extern long long totaltimeout;
extern char *menu_title;
extern char *ontimeout;
diff --git a/com32/modules/readconfig.c b/com32/modules/readconfig.c
index 3c69979f..16bb136f 100644
--- a/com32/modules/readconfig.c
+++ b/com32/modules/readconfig.c
@@ -23,10 +23,11 @@
#include "menu.h"
-int nentries = 0;
-int defentry = 0;
-int allowedit = 1; /* Allow edits of the command line */
-int timeout = 0;
+int nentries = 0;
+int defentry = 0;
+int allowedit = 1; /* Allow edits of the command line */
+int timeout = 0;
+long long totaltimeout = 0;
char *menu_title = "";
char *ontimeout = NULL;
@@ -259,7 +260,9 @@ void parse_config(const char *filename)
ld.kernel = strdup(skipspace(p+6));
}
} else if ( looking_at(p, "timeout") ) {
- timeout = atoi(skipspace(p+7));
+ timeout = (atoi(skipspace(p+7))*CLK_TCK+9)/10;
+ } else if ( looking_at(p, "totaltimeout") ) {
+ totaltimeout = (atoll(skipspace(p+13))*CLK_TCK+9)/10;
} else if ( looking_at(p, "ontimeout") ) {
ontimeout = strdup(skipspace(p+9));
} else if ( looking_at(p, "allowoptions") ) {
diff --git a/keywords b/keywords
index 1fa8c9cc..bfcbc2a4 100644
--- a/keywords
+++ b/keywords
@@ -14,6 +14,7 @@ say
serial
console
timeout
+totaltimeout
allowoptions
ontimeout
onerror
diff --git a/keywords.inc b/keywords.inc
index e880154a..e507e437 100644
--- a/keywords.inc
+++ b/keywords.inc
@@ -57,7 +57,8 @@ keywd_table:
keyword say, pc_say
keyword serial, pc_serial
keyword console, pc_setint16, DisplayCon
- keyword timeout, pc_timeout
+ keyword timeout, pc_timeout, KbdTimeout
+ keyword totaltimeout, pc_timeout, TotalTimeout
keyword ontimeout, pc_ontimeout
keyword onerror, pc_onerror
keyword allowoptions, pc_setint16, AllowOptions
diff --git a/parseconfig.inc b/parseconfig.inc
index 450af29a..122a2308 100644
--- a/parseconfig.inc
+++ b/parseconfig.inc
@@ -110,16 +110,26 @@ pc_kernel: cmp byte [VKernel],0
.err: ret
;
-; "timeout" command
+; "timeout", "totaltimeout" command
;
-pc_timeout: call getint
+; N.B. 1/10 s ~ 1.D2162AABh clock ticks
+;
+pc_timeout: push ax
+ call getint
+ pop si
jc .err
- mov ax,0D215h ; There are approx 1.D215h
- mul bx ; clock ticks per 1/10 s
- add bx,dx
- mov [KbdTimeOut],bx
+ mov eax,0D2162AABh
+ mul ebx ; clock ticks per 1/10 s
+ add ebx,edx
+ mov [si],ebx
.err: ret
+
+;
+; "totaltimeout" command
+;
+pc_totaltimeout:
+
;
; Generic integer variable setting commands:
; "prompt", "implicit"
@@ -366,11 +376,12 @@ commit_vk:
section .data
vk_overflow_msg db 'Out of memory parsing config file', CR, LF, 0
- align 2, db 0
+ align 4, db 0
+KbdTimeout dd 0 ; Keyboard timeout (if any)
+TotalTimeout dd 0 ; Total timeout (if any)
AppendLen dw 0 ; Bytes in append= command
OntimeoutLen dw 0 ; Bytes in ontimeout command
OnerrorLen dw 0 ; Bytes in onerror command
-KbdTimeOut dw 0 ; Keyboard timeout (if any)
CmdLinePtr dw cmd_line_here ; Command line advancing pointer
ForcePrompt dw 0 ; Force prompt
NoEscape dw 0 ; No escape
diff --git a/syslinux.doc b/syslinux.doc
index 3da76afc..37cfdd24 100644
--- a/syslinux.doc
+++ b/syslinux.doc
@@ -226,8 +226,20 @@ TIMEOUT timeout
begun. A timeout of zero will disable the timeout completely,
this is also the default.
- NOTE: The maximum possible timeout value is 35996; corresponding to
- just below one hour.
+TOTALTIMEOUT timeout
+ Indicates how long to wait until booting automatically, in
+ units of 1/10 s. This timeout is *not* cancelled by user
+ input, and can thus be used to deal with serial port glitches
+ or "the user walked away" type situations. A timeout of zero
+ will disable the timeout completely, this is also the default.
+
+ Both TIMEOUT and TOTALTIMEOUT can be used together, for
+ example:
+
+ # Wait 5 seconds unless the user types something, but
+ # always boot after 15 minutes.
+ TIMEOUT 50
+ TOTALTIMEOUT 9000
ONTIMEOUT kernel options...
Sets the command line invoked on a timeout. Normally this is
diff --git a/ui.inc b/ui.inc
index c656a0c1..c2c9e83f 100644
--- a/ui.inc
+++ b/ui.inc
@@ -34,6 +34,7 @@ enter_command:
mov byte [FuncFlag],0 ; <Ctrl-F> not pressed
mov di,command_line
+
;
; get the very first character -- we can either time
; out, or receive a character press at this time. Some dorky BIOSes stuff
@@ -45,40 +46,20 @@ clear_buffer: mov ah,11h ; Check for pending char
mov ah,10h ; Get char
int 16h
jmp short clear_buffer
-get_char_time:
- call vgashowcursor
- RESET_IDLE
- mov cx,[KbdTimeOut]
- and cx,cx
- jz get_char ; Timeout == 0 -> no timeout
- inc cx ; The first loop will happen
- ; immediately as we don't
- ; know the appropriate DX value
-time_loop: push cx
-tick_loop: push dx
- call pollchar
- jnz get_char_pop
- mov dx,[BIOS_timer] ; Get time "of day"
- pop ax
- cmp dx,ax ; Has the timer advanced?
- je tick_loop
- pop cx
- DO_IDLE
- loop time_loop ; If so, decrement counter
- ; Timeout!!!!
- call vgahidecursor
- mov si,Ontimeout ; Copy ontimeout command
- mov cx,[OntimeoutLen] ; if we have one...
- rep movsb
-.stddefault:
- jmp command_done
+ ; For the first character, both KbdTimeout and
+ ; TotalTimeout apply; after that, only TotalTimeout.
+
+get_char_time:
+ mov eax,[TotalTimeout]
+ mov [ThisTotalTo],eax
+ mov eax,[KbdTimeout]
+ mov [ThisKbdTo],eax
-get_char_pop: pop eax ; Clear stack
get_char:
- call vgashowcursor
- call getchar
- call vgahidecursor
+ call getchar_timeout
+ and dword [ThisKbdTo],0 ; For the next time...
+
and al,al
jz func_key
@@ -422,6 +403,48 @@ on_error:
;
kernel_corrupt: mov si,err_notkernel
jmp abort_load
+
+;
+; Get a key, observing ThisKbdTO and ThisTotalTO -- those are timeouts
+; which can be adjusted by the caller based on the corresponding
+; master variables; on return they're updated.
+;
+; This cheats. If we say "no timeout" we actually get a timeout of
+; 7.5 years.
+;
+getchar_timeout:
+ call vgashowcursor
+ RESET_IDLE
+
+.loop:
+ push word [BIOS_timer]
+ call pollchar
+ jnz .got_char
+ pop ax
+ cmp ax,[BIOS_timer] ; Has the timer advanced?
+ je .loop
+ DO_IDLE
+
+ dec dword [ThisKbdTo]
+ jz .timeout
+ dec dword [ThisTotalTo]
+ jnz .loop
+
+.timeout:
+ ; Timeout!!!!
+ pop cx ; Discard return address
+ call vgahidecursor
+ mov si,Ontimeout ; Copy ontimeout command
+ mov cx,[OntimeoutLen] ; if we have one...
+ rep movsb
+ jmp command_done
+
+.got_char:
+ pop cx ; Discard
+ call getchar
+ call vgahidecursor
+ ret
+
;
; This is it! We have a name (and location on the disk)... let's load
; that sucker!! First we have to decide what kind of file this is; base
@@ -515,7 +538,9 @@ kernel_good:
; Otherwise Linux kernel
section .bss
- alignb 2
+ alignb 4
+ThisKbdTo resd 1 ; Temporary holder for KbdTimeout
+ThisTotalTo resd 1 ; Temporary holder for TotalTimeout
KernelExtPtr resw 1 ; During search, final null pointer
CmdOptPtr resw 1 ; Pointer to first option on cmd line
KbdFlags resb 1 ; Check for keyboard escapes