[syslinux] Patch sensible callback framework
Ayvaz, James
James.Ayvaz at hp.com
Thu Apr 29 14:01:51 PDT 2010
Resubmit:
refactor according to hpa's suggestions:
>register_callback() return a callback record pointer, (or NULL on
>failure). This pointer can then be passed to unregister_callback() instead of doing a linear search.
>Instead of using an integer type for the callback type, make it the
>head of a callback list (which is just exported as a normal variable.)
> Make the invocation points smaller, e.g. by an callbacks_invoke()
> helper function.
> I suspect we need to pass a few options to the callback. In
> particular, we should have a user argument (typically a void *) which is
> passed in at register_callback() time, and probably information from the
> invocation point, e.g. the file descriptor/file pointer.
from Sebastian Herbszt
typos
use -percent argument to switch to percentage mode
from Steffen Winterfeldt
check for total > 0
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-29 10:12:59.000000000 -0500
@@ -0,0 +1,24 @@
+#ifndef LIBUTIL_CALLBACK_H
+#define LIBUTIL_CALLBACK_H
+
+#include <stddef.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+struct callback_record;
+
+typedef void (*callback_t)(va_list ap);
+
+typedef struct callback_record {
+ callback_t function;
+ struct callback_record *prev;
+ struct callback_record *next;
+} callback_record;
+
+
+
+callback_record* register_callback(callback_record **type, callback_t callback);
+int unregister_callback(callback_record **head, callback_record *cb);
+int invoke_callbacks(callback_record **head, ...);
+
+#endif
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-29 09:42:07.000000000 -0500
@@ -4,10 +4,19 @@
#include <stddef.h>
#include <stdio.h>
+#include <syslinux/callback.h>
+
/* loadfile() returns the true size of the file, but will guarantee valid,
zero-padded memory out to this boundary. */
#define LOADFILE_ZERO_PAD 64
+/*
+ * loadfile callbacks
+ */
+
+extern callback_record *CB_LOADFILE;
+extern callback_record *CB_FLOADFILE;
+
int loadfile(const char *, void **, size_t *);
int zloadfile(const char *, void **, size_t *);
int floadfile(FILE *, void **, size_t *, const void *, size_t);
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-29 10:13:29.000000000 -0500
@@ -0,0 +1,132 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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 <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "syslinux/callback.h"
+
+callback_record* register_callback(callback_record **type, callback_t callback) {
+ callback_record *curr, *new;
+ if (type == NULL)
+ return NULL;
+ if (*type == NULL) {
+ /* type is the head of the list */
+ new = malloc(sizeof(callback_record));
+ if (!new) {
+ return NULL;
+ }
+ memset(new, 0, sizeof(callback_record));
+ new->function = callback;
+ new->prev = NULL;
+ new->next = NULL;
+ *type = new;
+ return *type;
+ }
+ else {
+ /* check to see if we're already registered */
+ curr = *type;
+ while (curr->next) {
+ if (curr->function == callback) {
+ return curr;
+ }
+ curr = curr->next;
+ }
+ /* add new callback entry to list */
+ new = malloc(sizeof(callback_record));
+ if (!new) {
+ return NULL;
+ }
+
+ memset(new, 0, sizeof(callback_record));
+ new->function = callback;
+ new->prev = curr;
+ new->next = NULL;
+ curr->next = new;
+ return new;
+ }
+}
+
+int unregister_callback(callback_record **head, callback_record *cb) {
+ callback_record *curr;
+ if (!head)
+ return -1;
+ if (!*head)
+ return -1;
+ if (!cb)
+ return -1;
+
+ curr = *head;
+ /* adjust links */
+ if (!cb->prev) {
+ *head = cb->next;
+ }
+ else {
+ cb->prev->next = cb->next;
+ }
+
+ if (cb->next)
+ cb->next->prev = cb->prev;
+
+
+ free(cb);
+ return 0;
+}
+
+
+int invoke_callbacks(callback_record **head, ...) {
+ va_list ap;
+ callback_record *curr;
+ if (!head) {
+ return -1;
+ }
+ if (!*head) {
+ return -1;
+ }
+
+ curr = *head;
+ do {
+ if (curr->function) {
+ va_start(ap, head);
+ curr->function(ap);
+ va_end(ap);
+ }
+
+ curr = curr->next;
+ } while(curr);
+}
+
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-29 10:15:19.000000000 -0500
@@ -38,10 +38,13 @@
#include <fcntl.h>
#include <sys/stat.h>
+#include <syslinux/callback.h>
#include <syslinux/loadfile.h>
#define INCREMENTAL_CHUNK 1024*1024
+callback_record *CB_FLOADFILE = NULL;
+
int floadfile(FILE * f, void **ptr, size_t * len, const void *prefix,
size_t prefix_len)
{
@@ -54,7 +57,6 @@ int floadfile(FILE * f, void **ptr, size
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 +77,10 @@ int floadfile(FILE * f, void **ptr, size
rlen = fread((char *)data + clen, 1, alen - clen, f);
clen += rlen;
+
+ if (CB_FLOADFILE) {
+ invoke_callbacks(&CB_FLOADFILE, clen, -1);
+ }
} while (clen == alen);
*len = clen;
@@ -93,11 +99,29 @@ 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 (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;
+ invoke_callbacks(&CB_FLOADFILE, (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-29 10:15:30.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;
+callback_record *CB_LOADFILE;
+
+void loadfile_cb(va_list ap) {
+ size_t cur = va_arg(ap, size_t);
+ size_t total = va_arg(ap, size_t);
+ invoke_callbacks(&CB_LOADFILE, curr_filename, cur, total);
+}
+
+
int loadfile(const char *filename, void **ptr, size_t * len)
{
FILE *f;
@@ -52,7 +63,22 @@ 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 add the filename
+ */
+ callback_record *cb = NULL;
+ if (CB_LOADFILE) {
+ cb = register_callback(&CB_FLOADFILE, &loadfile_cb);
+ }
rv = floadfile(f, ptr, len, NULL, 0);
+
+ /* unregister our callback */
+ if (cb) {
+ unregister_callback(&CB_FLOADFILE, 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-29 10:17:19.000000000 -0500
@@ -43,11 +43,13 @@
#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>
const char *progname = "linux.c32";
+callback_record *CB_LOADFILE = NULL;
/* Find the last instance of a particular command line argument
(which should include the final =; do not use for boolean arguments) */
@@ -108,6 +110,53 @@ static char *make_cmdline(char **argv)
return cmdline;
}
+void linux_percent_progress_cb(va_list ap) {
+ char *file = va_arg(ap, char*);
+ size_t cur = va_arg(ap, size_t);
+ size_t total = va_arg(ap, size_t);
+ int percent = 0;
+
+ if (total > 0) {
+ 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(va_list ap) {
+ char *file = va_arg(ap, char*);
+ size_t cur = va_arg(ap, size_t);
+ size_t total = va_arg(ap, size_t);
+ int percent = 0;
+ int i = 0;
+ if (total > 0) {
+ 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(va_list ap) {
+ char *file = va_arg(ap, char*);
+ size_t cur = va_arg(ap, size_t);
+ size_t total = va_arg(ap, size_t);
+ int percent = 0;
+ if (total > 0) {
+ 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 +167,14 @@ 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;
+ callback_record *progress_cb, *complete_cb;
+
- openconsole(&dev_null_r, &dev_stdcon_w);
+ console_ansi_raw();
(void)argc;
argp = argv + 1;
@@ -130,7 +182,11 @@ int main(int argc, char *argv[])
while ((arg = *argp) && arg[0] == '-') {
if (!strcmp("-dhcpinfo", arg)) {
opt_dhcpinfo = true;
+ }
+ else if (!strcmp("-percent", arg)) {
+ opt_percent = true;
} else {
+
fprintf(stderr, "%s: unknown option: %s\n", progname, arg);
return 1;
}
@@ -157,16 +213,21 @@ int main(int argc, char *argv[])
if (find_boolean(argp, "quiet"))
opt_quiet = true;
- if (!opt_quiet)
- printf("Loading %s... ", kernel_name);
+ if (!opt_quiet) {
+ if (opt_percent) {
+ progress_cb = register_callback(&CB_LOADFILE, &linux_percent_progress_cb);
+ }
+ else {
+ progress_cb = register_callback(&CB_LOADFILE, &linux_dot_progress_cb);
+ }
+ complete_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 +244,23 @@ 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, progress_cb);
+ unregister_callback(&CB_LOADFILE, complete_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