[syslinux] Path simple menu integrated progress indicator

Ayvaz, James James.Ayvaz at hp.com
Fri Apr 23 08:41:55 PDT 2010


This patch modifies the simple menu com32 program to include integrated load progress.  It also adds new options to the simple menu configuration

MENU LOADMSG -- allows the user to specify the text to display when loading
MENU LOADMSGROW -- controls where the text is written

Example configuration:
MENU LOADMSG Booting
MENU LOADMSGROW 25


It works with my setup, please let me know if you find any bugs or spot any problems.  Thank you.


diff -uprN syslinux-3.86-vanilla//com32/include/syslinux/loadfile.h syslinux-3.86/com32/include/syslinux/loadfile.h
--- syslinux-3.86-vanilla//com32/include/syslinux/loadfile.h    2010-03-31 11:24:25.000000000 -0500
+++ syslinux-3.86/com32/include/syslinux/loadfile.h     2010-04-15 10:14:24.000000000 -0500
@@ -9,7 +9,9 @@
 #define LOADFILE_ZERO_PAD      64

 int loadfile(const char *, void **, size_t *);
+int loadfile_w_callback(const char *filename, void **ptr, size_t *len, void (*callback)(const char* file, size_t cur, size_t total));
 int zloadfile(const char *, void **, size_t *);
 int floadfile(FILE *, void **, size_t *, const void *, size_t);
-
+int floadfile_w_callback(FILE *f, void **ptr, size_t *len, const void *prefix,
+              size_t prefix_len, const char *filename, void (*callback)(const char* file, size_t cur, size_t total));
 #endif
diff -uprN syslinux-3.86-vanilla//com32/include/syslinux/vesacon.h syslinux-3.86/com32/include/syslinux/vesacon.h
--- syslinux-3.86-vanilla//com32/include/syslinux/vesacon.h     2010-03-31 11:24:25.000000000 -0500
+++ syslinux-3.86/com32/include/syslinux/vesacon.h      2010-04-15 08:21:00.000000000 -0500
@@ -32,6 +32,7 @@

 int vesacon_default_background(void);
 void vesacon_set_resolution(int, int);
+void vesacon_get_resolution(int *, int *);
 int vesacon_load_background(const char *);
 int vesacon_set_background(unsigned int);
 void vesacon_cursor_enable(bool);
diff -uprN syslinux-3.86-vanilla//com32/lib/sys/vesacon_write.c syslinux-3.86/com32/lib/sys/vesacon_write.c
--- syslinux-3.86-vanilla//com32/lib/sys/vesacon_write.c        2010-03-31 11:24:25.000000000 -0500
+++ syslinux-3.86/com32/lib/sys/vesacon_write.c 2010-04-15 08:20:46.000000000 -0500
@@ -85,6 +85,15 @@ void vesacon_set_resolution(int x, int y
     vesacon_resolution.y = y;
 }

+/* Get current resolution */
+void vesacon_get_resolution(int *x, int *y)
+{
+    x = vesacon_resolution.x;
+    y = vesacon_resolution.y;
+}
+
+
+
 /* Common setup */
 int __vesacon_open(struct file_info *fp)
 {
diff -uprN syslinux-3.86-vanilla//com32/lib/syslinux/floadfile.c syslinux-3.86/com32/lib/syslinux/floadfile.c
--- syslinux-3.86-vanilla//com32/lib/syslinux/floadfile.c       2010-03-31 11:24:25.000000000 -0500
+++ syslinux-3.86/com32/lib/syslinux/floadfile.c        2010-04-15 10:15:10.000000000 -0500
@@ -106,3 +106,64 @@ err:
        free(data);
     return -1;
 }
+
+int floadfile_w_callback(FILE *f, void **ptr, size_t *len, const void *prefix,
+             size_t prefix_len, const char *filename, void (*callback)(const char *name, size_t cur, size_t total))
+{
+  struct stat st;
+  void *data, *dp;
+  size_t alen, clen, rlen, xlen, flen;
+
+  clen = alen = 0;
+  data = NULL;
+
+  if ( fstat(fileno(f), &st) )
+    goto err;
+
+
+  if (!S_ISREG(st.st_mode)) {
+    /* Not a regular file, we can't assume we know the file size */
+    flen = -1;
+  }
+  else {
+    flen = st.st_size + prefix_len - ftell(f);
+  }
+
+  if (prefix_len) {
+    clen = alen = prefix_len;
+    data = malloc(prefix_len);
+    if (!data)
+      goto err;
+
+    memcpy(data, prefix, prefix_len);
+  }
+
+  do {
+    alen += INCREMENTAL_CHUNK;
+    dp = realloc(data, alen);
+    if (!dp)
+      goto err;
+    data = dp;
+
+    rlen = fread((char *)data+clen, 1, alen-clen, f);
+    clen += rlen;
+    callback(filename, clen, flen);
+  } while (clen == alen);
+
+  *len = clen;
+  xlen = (clen + LOADFILE_ZERO_PAD-1) & ~(LOADFILE_ZERO_PAD-1);
+  dp = realloc(data, xlen);
+  if (dp)
+    data = dp;
+  *ptr = data;
+
+  memset((char *)data + clen, 0, xlen-clen);
+  return 0;
+
+ err:
+  if (data)
+    free(data);
+  return -1;
+}
+
+
diff -uprN syslinux-3.86-vanilla//com32/lib/syslinux/loadfile.c syslinux-3.86/com32/lib/syslinux/loadfile.c
--- syslinux-3.86-vanilla//com32/lib/syslinux/loadfile.c        2010-03-31 11:24:25.000000000 -0500
+++ syslinux-3.86/com32/lib/syslinux/loadfile.c 2010-04-15 10:12:32.000000000 -0500
@@ -61,3 +61,24 @@ int loadfile(const char *filename, void
        errno = e;
     return rv;
 }
+
+int loadfile_w_callback(const char *filename, void **ptr, size_t *len, void (*callback)(const char* name, size_t cur, size_t total))
+{
+  FILE *f;
+  int rv, e;
+
+  f = fopen(filename, "r");
+  if ( !f )
+    return -1;
+
+  rv = floadfile_w_callback(f, ptr, len, NULL, 0, filename, callback);
+  e = errno;
+
+  fclose(f);
+
+  if (rv)
+    errno = e;
+  return rv;
+}
+
+
diff -uprN syslinux-3.86-vanilla//com32/menu/execute.c syslinux-3.86/com32/menu/execute.c
--- syslinux-3.86-vanilla//com32/menu/execute.c 2010-03-31 11:24:25.000000000 -0500
+++ syslinux-3.86/com32/menu/execute.c  2010-04-15 10:10:29.000000000 -0500
@@ -10,20 +10,123 @@
  *
  * ----------------------------------------------------------------------- */

+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <syslinux/linux.h>
+
 #include <com32.h>
 #include "menu.h"

+bool opt_quiet = false;
+
+static const char *refdup_word(char **p)
+{
+    char *sp = *p;
+    char *ep = sp;
+
+    while (*ep && !my_isspace(*ep))
+       ep++;
+
+    *p = ep;
+    return refstrndup(sp, ep - sp);
+}
+
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+char *skip_spaces(char *s)
+{
+  while(*s && (*s == ' ' || *s == '\t')) s++;
+
+  return s;
+}
+
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+char *skip_nonspaces(char *s)
+{
+  while(*s && *s != ' ' && *s != '\t') s++;
+
+  return s;
+}
+
+/* Search for a boolean argument; return its position, or 0 if not present */
+static int find_boolean(char **argv, const char *argument)
+{
+    char **arg;
+
+    for (arg = argv; *arg; arg++) {
+       if (!strcmp(*arg, argument))
+           return (arg - argv) + 1;
+    }
+
+    return 0;
+}
+
+/*
+ * Find the last instance of a particular command line argument
+ * (which should include the final =; do not use for boolean arguments)
+ * Note: the resulting string is typically not null-terminated.
+ */
+const char *find_argument(const char *cmdline, const char *argument)
+{
+    const char *found = NULL;
+    const char *p = cmdline;
+    bool was_space = true;
+    size_t la = strlen(argument);
+
+    while (*p) {
+       if (my_isspace(*p)) {
+           was_space = true;
+       } else if (was_space) {
+           if (!memcmp(p, argument, la))
+               found = p + la;
+           was_space = false;
+       }
+       p++;
+    }
+
+    return found;
+}
+
+void console_prepare(void)
+{
+  fputs("\033[0m\033[25l", stdout);
+}
+
+void console_cleanup(void)
+{
+  /* For the serial console, be nice and clean up */
+  fputs("\033[0m", stdout);
+}
+
+void
+clear_screen(void)
+{
+  fputs("\033e\033%@\033)0\033(B\1#0\033[?25l\033[2J", stdout);
+}
+
+int initramfs_load_archive_w_callback(struct initramfs *ihead, const char *filename, void (*callback)(const char* name, size_t cur, size_t total))
+{
+  void *data;
+  size_t len;
+
+  if (loadfile_w_callback(filename, &data, &len, callback))
+    return -1;
+
+  return initramfs_add_data(ihead, data, len, len, 4);
+}
+
+
 void execute(const char *cmdline, enum kernel_type type)
 {
     com32sys_t ireg;
-    const char *p, *const *pp;
+    char *p, *const *pp;
     char *q = __com32.cs_bounce;
     const char *kernel, *args;

-    memset(&ireg, 0, sizeof ireg);
-
     kernel = q;
     p = cmdline;
     while (*p && !my_isspace(*p)) {
@@ -48,22 +151,60 @@ void execute(const char *cmdline, enum k
     }

     if (type == KT_LOCALBOOT) {
-       ireg.eax.w[0] = 0x0014; /* Local boot */
-       ireg.edx.w[0] = strtoul(kernel, NULL, 0);
+        syslinux_local_boot(strtoul(kernel,NULL,0));
     } else {
-       if (type < KT_KERNEL)
-           type = KT_KERNEL;

-       ireg.eax.w[0] = 0x0016; /* Run kernel image */
-       ireg.esi.w[0] = OFFS(kernel);
-       ireg.ds = SEG(kernel);
-       ireg.ebx.w[0] = OFFS(args);
-       ireg.es = SEG(args);
-       ireg.edx.l = type - KT_KERNEL;
-       /* ireg.ecx.l    = 0; *//* We do ipappend "manually" */
+        size_t kernel_size = 0, initrd_size = 0;
+        char* kernel_name;
+        void* kernel_data, *initrd_buf;
+        char *s, *s0, *t, *initrd_arg;
+        struct initramfs *initramfs = NULL;
+
+        char *arg;
+        opt_quiet = false;
+
+       kernel_name = refdup_word(&cmdline);
+       loadfile(kernel_name, &kernel_data, &kernel_size);
+       if(!kernel_data) {
+         fprintf(stdout, "%s: read error\n", kernel_name);
+         return;               /* Error! */
+       }
+
+        char *cmdline2 = malloc(strlen(cmdline) + strlen(kernel_name) + 12);
+        memset(cmdline2, 0, (strlen(cmdline) + strlen(kernel_name) + 12));
+        strcat(cmdline2, kernel_name);
+        strcat(cmdline2, " ");
+        strcat(cmdline2, cmdline);
+
+        /* Initialize the initramfs chain */
+        initramfs = initramfs_init();
+        if (!initramfs)
+            return;
+
+
+        if ((arg = find_argument(cmdline2, "initrd="))) {
+            do {
+                char* initrdarg = refdup_word(&arg);
+               p = strchr(initrdarg, ',');
+                if (p)
+                    *p = '\0';
+
+                if (initramfs_load_archive_w_callback(initramfs, initrdarg, draw_progress)) {
+                    printf("failed!\n");
+                   return 1;
+                }
+
+                if (p)
+                    *p++ = ',';
+            } while ((arg = p));
+        }
+
+        console_cleanup();
+        console_prepare();
+
+       syslinux_boot_linux(kernel_data, kernel_size, initramfs, cmdline2);
     }

-    __intcall(0x22, &ireg, NULL);

     /* If this returns, something went bad; return to menu */
 }
diff -uprN syslinux-3.86-vanilla//com32/menu/menu.c syslinux-3.86/com32/menu/menu.c
--- syslinux-3.86-vanilla//com32/menu/menu.c    2010-03-31 11:24:25.000000000 -0500
+++ syslinux-3.86/com32/menu/menu.c     2010-04-15 10:07:34.000000000 -0500
@@ -42,3 +42,25 @@ void start_console(void)
 {
     console_ansi_raw();
 }
+
+void draw_progress(const char *file, size_t cur, size_t total)
+{
+    static bool once = true;
+    float percent;
+    percent = ((float)cur / (float)total) * 100.0;
+
+    if (opt_quiet)
+        return;
+
+    if (once) {
+        printf("Loading %s", file);
+        once = false;
+    }
+
+    printf(".");
+
+    if (percent>=100)
+        printf("ok\n");
+}
+
+
diff -uprN syslinux-3.86-vanilla//com32/menu/menu.h syslinux-3.86/com32/menu/menu.h
--- syslinux-3.86-vanilla//com32/menu/menu.h    2010-03-31 11:24:25.000000000 -0500
+++ syslinux-3.86/com32/menu/menu.h     2010-04-15 10:08:01.000000000 -0500
@@ -97,6 +97,7 @@ enum parameter_number {
     P_PASSWD_MARGIN,
     P_MENU_ROWS,
     P_TABMSG_ROW,
+    P_LOADMSG_ROW,
     P_CMDLINE_ROW,
     P_END_ROW,
     P_PASSWD_ROW,
@@ -115,6 +116,7 @@ enum message_number {
     MSG_TITLE,
     MSG_AUTOBOOT,
     MSG_TAB,
+    MSG_LOAD,
     MSG_NOTAB,
     MSG_PASSPROMPT,

@@ -188,6 +190,7 @@ int draw_background(const char *filename
 void set_resolution(int x, int y);
 void start_console(void);
 void local_cursor_enable(bool);
+void draw_progress(const char *file, size_t cur, size_t total);

 static inline int my_isspace(char c)
 {
@@ -227,4 +230,27 @@ void execute(const char *cmdline, enum k
 /* drain.c */
 void drain_keyboard(void);

+extern bool opt_quiet;
+
+/* The symbol "cm" always refers to the current menu across this file... */
+extern struct menu *cm;
+
+/* These macros assume "cm" is a pointer to the current menu */
+#define WIDTH          (cm->mparm[P_WIDTH])
+#define MARGIN         (cm->mparm[P_MARGIN])
+#define PASSWD_MARGIN  (cm->mparm[P_PASSWD_MARGIN])
+#define MENU_ROWS      (cm->mparm[P_MENU_ROWS])
+#define TABMSG_ROW     (cm->mparm[P_TABMSG_ROW]+VSHIFT)
+#define LOADMSG_ROW    (cm->mparm[P_LOADMSG_ROW]+VSHIFT)
+#define CMDLINE_ROW    (cm->mparm[P_CMDLINE_ROW]+VSHIFT)
+#define END_ROW                (cm->mparm[P_END_ROW])
+#define PASSWD_ROW     (cm->mparm[P_PASSWD_ROW]+VSHIFT)
+#define TIMEOUT_ROW    (cm->mparm[P_TIMEOUT_ROW]+VSHIFT)
+#define HELPMSG_ROW    (cm->mparm[P_HELPMSG_ROW]+VSHIFT)
+#define HELPMSGEND_ROW (cm->mparm[P_HELPMSGEND_ROW])
+#define HSHIFT         (cm->mparm[P_HSHIFT])
+#define VSHIFT         (cm->mparm[P_VSHIFT])
+#define HIDDEN_ROW     (cm->mparm[P_HIDDEN_ROW])
+
+
 #endif /* MENU_H */
diff -uprN syslinux-3.86-vanilla//com32/menu/menumain.c syslinux-3.86/com32/menu/menumain.c
--- syslinux-3.86-vanilla//com32/menu/menumain.c        2010-03-31 11:24:25.000000000 -0500
+++ syslinux-3.86/com32/menu/menumain.c 2010-04-15 13:08:03.000000000 -0500
@@ -29,11 +29,13 @@
 #include <limits.h>
 #include <com32.h>
 #include <syslinux/adv.h>
+#include <console.h>

 #include "menu.h"

 /* The symbol "cm" always refers to the current menu across this file... */
-static struct menu *cm;
+//static struct menu *cm;
+struct menu *cm;

 const struct menu_parameter mparm[NPARAMS] = {
     [P_WIDTH] = {"width", 0},
@@ -41,6 +43,7 @@ const struct menu_parameter mparm[NPARAM
     [P_PASSWD_MARGIN] = {"passwordmargin", 3},
     [P_MENU_ROWS] = {"rows", 12},
     [P_TABMSG_ROW] = {"tabmsgrow", 18},
+    [P_LOADMSG_ROW] = {"loadmsgrow", 18},
     [P_CMDLINE_ROW] = {"cmdlinerow", 18},
     [P_END_ROW] = {"endrow", -1},
     [P_PASSWD_ROW] = {"passwordrow", 11},
@@ -52,22 +55,6 @@ const struct menu_parameter mparm[NPARAM
     [P_HIDDEN_ROW] = {"hiddenrow", -2},
 };

-/* These macros assume "cm" is a pointer to the current menu */
-#define WIDTH          (cm->mparm[P_WIDTH])
-#define MARGIN         (cm->mparm[P_MARGIN])
-#define PASSWD_MARGIN  (cm->mparm[P_PASSWD_MARGIN])
-#define MENU_ROWS      (cm->mparm[P_MENU_ROWS])
-#define TABMSG_ROW     (cm->mparm[P_TABMSG_ROW]+VSHIFT)
-#define CMDLINE_ROW    (cm->mparm[P_CMDLINE_ROW]+VSHIFT)
-#define END_ROW                (cm->mparm[P_END_ROW])
-#define PASSWD_ROW     (cm->mparm[P_PASSWD_ROW]+VSHIFT)
-#define TIMEOUT_ROW    (cm->mparm[P_TIMEOUT_ROW]+VSHIFT)
-#define HELPMSG_ROW    (cm->mparm[P_HELPMSG_ROW]+VSHIFT)
-#define HELPMSGEND_ROW (cm->mparm[P_HELPMSGEND_ROW])
-#define HSHIFT         (cm->mparm[P_HSHIFT])
-#define VSHIFT         (cm->mparm[P_VSHIFT])
-#define HIDDEN_ROW     (cm->mparm[P_HIDDEN_ROW])
-
 static char *pad_line(const char *text, int align, int width)
 {
     static char buffer[MAX_CMDLINE_LEN];
diff -uprN syslinux-3.86-vanilla//com32/menu/readconfig.c syslinux-3.86/com32/menu/readconfig.c
--- syslinux-3.86-vanilla//com32/menu/readconfig.c      2010-03-31 11:24:25.000000000 -0500
+++ syslinux-3.86/com32/menu/readconfig.c       2010-04-15 09:36:23.000000000 -0500
@@ -49,6 +49,7 @@ static struct menu_entry **all_entries_e
 static const struct messages messages[MSG_COUNT] = {
     [MSG_AUTOBOOT] = {"autoboot", "Automatic boot in # second{,s}..."},
     [MSG_TAB] = {"tabmsg", "Press [Tab] to edit options"},
+    [MSG_LOAD] = {"loadmsg", "Loading"},
     [MSG_NOTAB] = {"notabmsg", ""},
     [MSG_PASSPROMPT] = {"passprompt", "Password required"},
 };
diff -uprN syslinux-3.86-vanilla//com32/menu/vesamenu.c syslinux-3.86/com32/menu/vesamenu.c
--- syslinux-3.86-vanilla//com32/menu/vesamenu.c        2010-03-31 11:24:25.000000000 -0500
+++ syslinux-3.86/com32/menu/vesamenu.c 2010-04-15 13:05:52.000000000 -0500
@@ -22,6 +22,7 @@

 #include <stdio.h>
 #include <console.h>
+#include <syslinux/video.h>
 #include <syslinux/vesacon.h>

 #include "menu.h"
@@ -50,3 +51,17 @@ void start_console(void)
 {
     openconsole(&dev_rawcon_r, &dev_vesaserial_w);
 }
+
+void draw_progress(const char *file, size_t cur, size_t total)
+{
+    int i;
+    float percent, bars, fill;
+    percent = ((float)cur / (float)total) * 100.0;
+
+    const char* loadmsg = cm->messages[MSG_LOAD];
+    int loadmsg_len = strlen(loadmsg);
+
+    printf("\033[%d;%dH\2#14%s %d%%",
+          LOADMSG_ROW, 1 + HSHIFT + ((WIDTH - loadmsg_len) >> 1), loadmsg, (int)percent);
+}
+




More information about the Syslinux mailing list