[syslinux] Patch sensible callback framework

Ayvaz, James James.Ayvaz at hp.com
Mon Apr 26 20:35:58 PDT 2010


This patch adds a simple callback framework.

	Modified loadfile and floadfile to look for callbacks and call them if present

	Supports multiple callbacks

	Modified com32/modules/linux.c to demonstrate functionality (it's a little more complicated than it should be just to demonstrate multiple callbacks).  Add progress argument to display a percentage indicator when loading.

Example

boot: linux progress
Loading vmlinuz 100%
Loading initrd.img 100%


Let me know if you spot any problems.  Thanks.


diff -uprN syslinux-3.86-vanilla/com32/include/syslinux/callback.h syslinux-3.86/com32/include/syslinux/callback.h
--- syslinux-3.86-vanilla/com32/include/syslinux/callback.h	1969-12-31 18:00:00.000000000 -0600
+++ syslinux-3.86/com32/include/syslinux/callback.h	2010-04-26 09:05:45.000000000 -0500
@@ -0,0 +1,39 @@
+#ifndef LIBUTIL_CALLBACK_H
+#define LIBUTIL_CALLBACK_H
+
+#include <stddef.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+/* supported callback types */
+#define CB_LOADFILE    1
+#define CB_FLOADFILE   2
+
+/* callback erros types */
+#define CBE_SUCCESS             0
+#define CBE_FAILED              1
+#define CBE_ALREADY_REGISTERED  2
+#define CBE_NOT_REGISTERED      3
+
+/* supported callback types */
+#define CB_LOADFILE    1
+#define CB_FLOADFILE   2
+
+
+typedef struct callback_record {
+  uint16_t type;
+  void *function;
+  struct callback_record *next;
+} callback_record;
+
+typedef void (*cb_loadfile_t)(const char* file, size_t cur, size_t total);
+typedef void (*cb_floadfile_t)(size_t cur, size_t total);
+
+
+int register_callback(uint16_t type, void *callback);
+int unregister_callback(uint16_t type, void *callback);
+
+callback_record* foreach_callback(callback_record *current);
+callback_record* foreach_callback_type(callback_record *current, uint16_t type);
+
+#endif
diff -uprN syslinux-3.86-vanilla/com32/lib/Makefile syslinux-3.86/com32/lib/Makefile
--- syslinux-3.86-vanilla/com32/lib/Makefile	2010-03-31 11:24:25.000000000 -0500
+++ syslinux-3.86/com32/lib/Makefile	2010-04-26 04:57:20.000000000 -0500
@@ -102,6 +102,8 @@ LIBOBJS = \
 	syslinux/run_default.o syslinux/run_command.o			\
 	syslinux/cleanup.o syslinux/localboot.o	syslinux/runimage.o	\
 	\
+	syslinux/callback.o                                             \
+	\
 	syslinux/loadfile.o syslinux/floadfile.o syslinux/zloadfile.o	\
 	\
 	syslinux/load_linux.o syslinux/initramfs.o			\
diff -uprN syslinux-3.86-vanilla/com32/lib/syslinux/callback.c syslinux-3.86/com32/lib/syslinux/callback.c
--- syslinux-3.86-vanilla/com32/lib/syslinux/callback.c	1969-12-31 18:00:00.000000000 -0600
+++ syslinux-3.86/com32/lib/syslinux/callback.c	2010-04-26 16:39:52.000000000 -0500
@@ -0,0 +1,125 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2005-2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * callback.c
+ *
+ * generic callback handlers
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "syslinux/callback.h"
+
+callback_record *callback_head = NULL;
+
+int register_callback(uint16_t type, void *callback) {
+    callback_record *curr;
+    if (callback_head) {
+        /* check to see if we're already registered */
+        curr = callback_head;
+        while (curr->next) {
+            if (curr->type == type && curr->function == callback) {
+                return CBE_ALREADY_REGISTERED;
+            }
+            curr = curr->next;
+        }
+    }
+
+    callback_record *new = malloc(sizeof(callback_record));
+    if (!new) {
+        return CBE_FAILED;
+    }
+    memset(new, 0, sizeof(callback_record));
+
+    new->type = type;
+    new->function = callback;
+    new->next = NULL;
+
+    if (!callback_head) {
+        callback_head = new;
+    }
+    else {
+        curr = callback_head;
+        while (curr->next != NULL) {curr = curr->next;} /* go to end of list */
+        curr->next = new;
+    }
+    return CBE_SUCCESS;
+}
+
+int unregister_callback(uint16_t type, void *callback) {
+    callback_record *curr, *prev, *next;
+    bool found = false;
+    if (!callback_head)
+        return CBE_NOT_REGISTERED;
+
+    prev = NULL;
+    curr = callback_head;
+    while (curr) {
+        if (curr->type == type && curr->function == callback) {
+            found++;
+            next = curr->next;
+
+            if (prev)
+                prev->next = next;
+
+            free(curr);
+            if (callback_head == curr)
+                callback_head = next;
+            curr = next;
+        }
+        else {
+            prev = curr;
+            curr = curr->next;
+        }
+    }
+    if (!found)
+        return CBE_NOT_REGISTERED;
+    else
+        return CBE_SUCCESS;
+}
+
+callback_record* foreach_callback(callback_record *current) {
+    if (!current) {
+        return callback_head;
+    }
+
+    return current->next;
+}
+
+callback_record* foreach_callback_type(callback_record *current, uint16_t type) {
+    while((current = foreach_callback(current))) {
+        if (current->type == type) {
+            return current;
+        }
+    }
+    return current;
+}
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-26 16:40:30.000000000 -0500
@@ -38,6 +38,7 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 
+#include <syslinux/callback.h>
 #include <syslinux/loadfile.h>
 
 #define INCREMENTAL_CHUNK 1024*1024
@@ -48,13 +49,13 @@ int floadfile(FILE * f, void **ptr, size
     struct stat st;
     void *data, *dp;
     size_t alen, clen, rlen, xlen;
+    callback_record *cb = NULL;
 
     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 */
 	if (prefix_len) {
@@ -75,6 +76,11 @@ int floadfile(FILE * f, void **ptr, size
 
 	    rlen = fread((char *)data + clen, 1, alen - clen, f);
 	    clen += rlen;
+
+	    cb = NULL;
+	    while((cb = foreach_callback_type(cb, CB_FLOADFILE))) {
+	        ((cb_floadfile_t)cb->function)(clen, -1);
+	    }
 	} while (clen == alen);
 
 	*len = clen;
@@ -93,11 +99,32 @@ int floadfile(FILE * f, void **ptr, size
 
 	memcpy(data, prefix, prefix_len);
 
-	if ((off_t) fread((char *)data + prefix_len, 1, clen - prefix_len, f)
-	    != clen - prefix_len)
-	    goto err;
+        /* a callback is registered so read file in chunks */
+        if (foreach_callback_type(NULL, CB_FLOADFILE)) {
+	    clen = alen = 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;
+	        cb = NULL;
+	        while((cb = foreach_callback_type(cb, CB_FLOADFILE))) {
+	            ((cb_floadfile_t)cb->function)((clen + LOADFILE_ZERO_PAD - 1) & ~(LOADFILE_ZERO_PAD - 1), xlen);
+	        }
+	    } while (clen == alen);
+	    *ptr = data;
+        }
+        /* read whole file at once */
+        else {
+            if ((off_t) fread((char *)data + prefix_len, 1, clen - prefix_len, f)
+	        != clen - prefix_len)
+                goto err;
+        }
     }
-
     memset((char *)data + clen, 0, xlen - clen);
     return 0;
 
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-26 16:40:13.000000000 -0500
@@ -39,10 +39,21 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 
+#include <syslinux/callback.h>
 #include <syslinux/loadfile.h>
 
 #define INCREMENTAL_CHUNK 1024*1024
 
+char *curr_filename = NULL;
+
+void loadfile_cb(size_t cur, size_t total) {
+    callback_record *cb = NULL;
+    while(cb = foreach_callback_type(cb, CB_LOADFILE)) {
+        ((cb_loadfile_t)cb->function)(curr_filename, cur, total);
+    }
+}
+
+
 int loadfile(const char *filename, void **ptr, size_t * len)
 {
     FILE *f;
@@ -52,7 +63,20 @@ int loadfile(const char *filename, void
     if (!f)
 	return -1;
 
+    curr_filename = filename;
+    /*
+     * if a CB_LOADFILE callback is registered, let's register a CB_FLOADFILE callback
+     * so that we can can add the filename
+     */
+    callback_record *cb = NULL;
+    if (foreach_callback_type(cb, CB_LOADFILE)) {
+        register_callback(CB_FLOADFILE, loadfile_cb);
+    }
     rv = floadfile(f, ptr, len, NULL, 0);
+
+    /* unregister our callback */
+    unregister_callback(CB_FLOADFILE, loadfile_cb);
+
     e = errno;
 
     fclose(f);
diff -uprN syslinux-3.86-vanilla/com32/modules/linux.c syslinux-3.86/com32/modules/linux.c
--- syslinux-3.86-vanilla/com32/modules/linux.c	2010-03-31 11:24:25.000000000 -0500
+++ syslinux-3.86/com32/modules/linux.c	2010-04-26 16:52:52.000000000 -0500
@@ -43,6 +43,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <console.h>
+#include <syslinux/callback.h>
 #include <syslinux/loadfile.h>
 #include <syslinux/linux.h>
 #include <syslinux/pxe.h>
@@ -108,6 +109,32 @@ static char *make_cmdline(char **argv)
     return cmdline;
 }
 
+void linux_percent_progress_cb(const char* file, size_t cur, size_t total) {
+    int percent = (int)(((float)cur / (float)total) * 100.0);
+    clear_line();
+    move_cursor_to_column(0);
+    printf("Loading: %s %d%%", file, percent);
+}
+
+void linux_dot_progress_cb(const char* file, size_t cur, size_t total) {
+    int i = 0;
+    int percent = (int)(((float)cur / (float)total) * 100.0);
+    clear_line();
+    move_cursor_to_column(0);
+
+    printf("Loading %s", file);
+    while(i < percent) {
+        printf(".");
+        i += 5;
+    }
+}
+
+void linux_done_progress_cb(const char* file, size_t cur, size_t total) {
+    int percent = (int)(((float)cur / (float)total) * 100.0);
+    if (percent >= 100)
+        printf(" OK\n");
+}
+
 int main(int argc, char *argv[])
 {
     const char *kernel_name;
@@ -118,11 +145,13 @@ int main(int argc, char *argv[])
     size_t kernel_len;
     bool opt_dhcpinfo = false;
     bool opt_quiet = false;
+    bool opt_percent = false;
     void *dhcpdata;
     size_t dhcplen;
     char **argp, *arg, *p;
 
-    openconsole(&dev_null_r, &dev_stdcon_w);
+
+    console_ansi_raw();
 
     (void)argc;
     argp = argv + 1;
@@ -157,16 +186,23 @@ int main(int argc, char *argv[])
     if (find_boolean(argp, "quiet"))
 	opt_quiet = true;
 
-    if (!opt_quiet)
-	printf("Loading %s... ", kernel_name);
+    if (find_boolean(argp, "percent"))
+	opt_percent = true;
+    if (!opt_quiet) {
+        if (opt_percent) {
+            register_callback(CB_LOADFILE, linux_percent_progress_cb);
+        }
+        else {
+            register_callback(CB_LOADFILE, linux_dot_progress_cb);
+        }
+        register_callback(CB_LOADFILE, linux_done_progress_cb);
+    }
     if (loadfile(kernel_name, &kernel_data, &kernel_len)) {
 	if (opt_quiet)
 	    printf("Loading %s ", kernel_name);
 	printf("failed!\n");
 	goto bail;
     }
-    if (!opt_quiet)
-	printf("ok\n");
 
     cmdline = make_cmdline(argp);
     if (!cmdline)
@@ -183,22 +219,24 @@ int main(int argc, char *argv[])
 	    if (p)
 		*p = '\0';
 
-	    if (!opt_quiet)
-		printf("Loading %s... ", arg);
 	    if (initramfs_load_archive(initramfs, arg)) {
 		if (opt_quiet)
 		    printf("Loading %s ", kernel_name);
 		printf("failed!\n");
 		goto bail;
 	    }
-	    if (!opt_quiet)
-		printf("ok\n");
 
 	    if (p)
 		*p++ = ',';
 	} while ((arg = p));
     }
 
+    if (!opt_quiet) {
+        unregister_callback(CB_LOADFILE, linux_percent_progress_cb);
+        unregister_callback(CB_LOADFILE, linux_dot_progress_cb);
+        unregister_callback(CB_LOADFILE, linux_done_progress_cb);
+    }
+
     /* Append the DHCP info */
     if (opt_dhcpinfo &&
 	!pxe_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK, &dhcpdata, &dhcplen)) {







More information about the Syslinux mailing list