[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