Implement MENU SAVE; fix COM32 setadv function syslinux-3.74-pre18
authorH. Peter Anvin <hpa@zytor.com>
Mon, 6 Apr 2009 22:19:21 +0000 (15:19 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Mon, 6 Apr 2009 22:19:21 +0000 (15:19 -0700)
Implement MENU SAVE, which allows the menu system to retain the
previous selection from one boot to another.  In the process, fix the
syslinux_setadv() function.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
NEWS
com32/include/syslinux/advconst.h
com32/lib/syslinux/setadv.c
com32/menu/menu.h
com32/menu/menumain.c
com32/menu/readconfig.c
doc/menu.txt

diff --git a/NEWS b/NEWS
index 9184559..6ffd41b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -37,6 +37,9 @@ Changes in 3.74:
          byte at offset 439 decimal.
        * Add IPAPPEND strings to com32 modules, especially needed for
          linux.c32.
+       * New MENU SAVE directive which saves the latest menu
+         selection until the next boot.  Currently only implemented for
+         EXTLINUX.
 
 Changes in 3.73:
        * Upgrade gPXE to release version 0.9.5.
index 1e1ec73..b7c775f 100644 (file)
@@ -1,6 +1,7 @@
 /* ----------------------------------------------------------------------- *
  *
  *   Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
  *
  *   Permission is hereby granted, free of charge, to any person
  *   obtaining a copy of this software and associated documentation
@@ -39,5 +40,6 @@
 
 #define ADV_END                0
 #define ADV_BOOTONCE   1
+#define ADV_MENUSAVE   2
 
 #endif /* _SYSLINUX_ADVCONST_H */
index 4af8d6e..5993df6 100644 (file)
@@ -1,6 +1,7 @@
 /* ----------------------------------------------------------------------- *
  *
  *   Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
  *
  *   Permission is hereby granted, free of charge, to any person
  *   obtaining a copy of this software and associated documentation
@@ -47,7 +48,7 @@
 int syslinux_setadv(int tag, size_t size, const void *data)
 {
   uint8_t *p, *advtmp;
-  size_t left;
+  size_t rleft, left;
 
   if ((unsigned)tag-1 > 254) {
     errno = EINVAL;
@@ -59,11 +60,11 @@ int syslinux_setadv(int tag, size_t size, const void *data)
     return -1;
   }
 
-  left = syslinux_adv_size();
+  rleft = left = syslinux_adv_size();
   p = advtmp = alloca(left);
   memcpy(p, syslinux_adv_ptr(), left); /* Make working copy */
 
-  while (left >= 2) {
+  while (rleft >= 2) {
     uint8_t ptag = p[0];
     size_t  plen = p[1]+2;
 
@@ -73,17 +74,19 @@ int syslinux_setadv(int tag, size_t size, const void *data)
     if (ptag == tag) {
       /* Found our tag.  Delete it. */
 
-      if (plen >= left) {
+      if (plen >= rleft) {
        /* Entire remainder is our tag */
        break;
       }
-      memmove(p, p+plen, left-plen);
+      memmove(p, p+plen, rleft-plen);
+      rleft -= plen;           /* Fewer bytes to read, but not to write */
     } else {
       /* Not our tag */
-      if (plen > left)
+      if (plen > rleft)
        break;                  /* Corrupt tag (overrun) - overwrite it */
 
       left -= plen;
+      rleft -= plen;
       p += plen;
     }
   }
@@ -100,6 +103,7 @@ int syslinux_setadv(int tag, size_t size, const void *data)
     *p++ = tag;
     *p++ = size;
     memcpy(p, data, size);
+    p += size;
     left -= size+2;
   }
 
index e2ffc1b..43f6594 100644 (file)
@@ -174,6 +174,7 @@ extern struct menu *root_menu, *start_menu, *hide_menu, *menu_list;
 /* These are global parameters regardless of which menu we're displaying */
 extern int shiftkey;
 extern int hiddenmenu;
+extern bool menusave;
 extern long long totaltimeout;
 
 void parse_configs(char **argv);
index f7af90a..c3da97e 100644 (file)
@@ -1,6 +1,7 @@
 /* ----------------------------------------------------------------------- *
  *
  *   Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -27,6 +28,7 @@
 #include <setjmp.h>
 #include <limits.h>
 #include <com32.h>
+#include <syslinux/adv.h>
 
 #include "menu.h"
 
@@ -875,6 +877,13 @@ run_menu(void)
          break;
        }
       }
+      if (done && !me->passwd) {
+       /* Only save a new default if we don't have a password... */
+       if (menusave && me->label) {
+         syslinux_setadv(ADV_MENUSAVE, strlen(me->label), me->label);
+         syslinux_adv_write();
+       }
+      }
       break;
 
     case KEY_UP:
index c276c0b..768591d 100644 (file)
@@ -12,6 +12,7 @@
  * ----------------------------------------------------------------------- */
 
 #include <stdio.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #include <minmax.h>
@@ -19,6 +20,7 @@
 #include <inttypes.h>
 #include <colortbl.h>
 #include <com32.h>
+#include <syslinux/adv.h>
 #include <syslinux/config.h>
 
 #include "menu.h"
@@ -33,6 +35,7 @@ struct menu *root_menu, *start_menu, *hide_menu, *menu_list;
 int shiftkey     = 0;          /* Only display menu if shift key pressed */
 int hiddenmenu   = 0;
 long long totaltimeout = 0;
+bool menusave    = false;
 
 /* Keep track of global default */
 static int has_ui = 0;         /* DEFAULT only counts if UI is found */
@@ -668,6 +671,8 @@ static void parse_config_file(FILE *f)
        }
       } else if ( looking_at(p, "shiftkey") ) {
        shiftkey = 1;
+      } else if ( looking_at(p, "save") ) {
+       menusave = true;
       } else if ( looking_at(p, "onerror") ) {
        refstr_put(m->onerror);
        m->onerror = refstrdup(skipspace(p+7));
@@ -1026,6 +1031,23 @@ void parse_configs(char **argv)
     }
   }
 
+  /* If "menu save" is active, let the ADV override the global default */
+  if (menusave) {
+    size_t len;
+    const char *lbl = syslinux_getadv(ADV_MENUSAVE, &len);
+    char *lstr;
+    if (lbl && len) {
+      lstr = refstr_alloc(len);
+      memcpy(lstr, lbl, len);  /* refstr_alloc() adds the final null */
+      me = find_label(lstr);
+      if (me && me->menu != hide_menu) {
+       me->menu->defentry = me->entry;
+       start_menu = me->menu;
+      }
+      refstr_put(lstr);
+    }
+  }
+
   /* Final per-menu initialization, with all labels known */
   for (m = menu_list; m; m = m->next) {
     m->curentry = m->defentry; /* All menus start at their defaults */
index 379df32..72bc9dc 100644 (file)
@@ -48,6 +48,12 @@ MENU HIDDEN
        All that is displayed is a timeout message.
 
 
+MENU SHIFTKEY
+
+       Exit the menu system immediately unless either the Shift or Alt
+       key is pressed, or Caps Lock or Scroll Lock is set.
+
+
 MENU SEPARATOR
 
        Insert an empty line in the menu.
@@ -269,6 +275,23 @@ DEFAULT label
        non-label.  The menu system does not support that.
 
 
+MENU SAVE
+
+       Remember the last entry selected and make that the default for
+       the next boot.  A password-protected menu entry is *not*
+       saved.  This requires the ADV data storage mechanism, which is
+       currently only implemented for EXTLINUX, although the other
+       Syslinux derivatives will accept the command (and ignore it.)
+
+       NOTE: MENU SAVE stores the LABEL tag of the selected entry;
+       this mechanism therefore relies on LABEL tags being unique.
+       On the other hand, it handles changes in the configuration
+       file gracefully.
+
+       The MENU SAVE information can be cleared with
+       "extlinux --reset-adv".
+
+
 INCLUDE filename [tagname]
 MENU INCLUDE filename [tagname]