[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