[syslinux] Patch sensible callback framework

Ayvaz, James James.Ayvaz at hp.com
Mon May 3 09:20:48 PDT 2010


Resubmit with changes from Sebastian Herbszt


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-05-03 05:50:17.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,24 @@ 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) {
+    printf(".");
+}
+
 int main(int argc, char *argv[])
 {
     const char *kernel_name;
@@ -118,11 +138,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;
+

-    openconsole(&dev_null_r, &dev_stdcon_w);
+    console_ansi_raw();

     (void)argc;
     argp = argv + 1;
@@ -130,6 +153,9 @@ 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,8 +183,15 @@ 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) {
+       printf("Loading %s...", kernel_name);
+        if (opt_percent) {
+            progress_cb = register_callback(&CB_LOADFILE, &linux_percent_progress_cb);
+        }
+        else {
+            progress_cb = register_callback(&CB_LOADFILE, &linux_dot_progress_cb);
+        }
+    }
     if (loadfile(kernel_name, &kernel_data, &kernel_len)) {
        if (opt_quiet)
            printf("Loading %s ", kernel_name);
@@ -166,7 +199,7 @@ int main(int argc, char *argv[])
        goto bail;
     }
     if (!opt_quiet)
-       printf("ok\n");
+       printf("  ok\n");

     cmdline = make_cmdline(argp);
     if (!cmdline)
@@ -184,21 +217,24 @@ int main(int argc, char *argv[])
                *p = '\0';

            if (!opt_quiet)
-               printf("Loading %s... ", arg);
+               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 (!opt_quiet)
+                printf("  ok\n");
            if (p)
                *p++ = ',';
        } while ((arg = p));
     }

+    if (!opt_quiet) {
+        unregister_callback(&CB_LOADFILE, progress_cb);
+    }
+
     /* Append the DHCP info */
     if (opt_dhcpinfo &&
        !pxe_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK, &dhcpdata, &dhcplen)) {

-----Original Message-----
From: syslinux-bounces at zytor.com [mailto:syslinux-bounces at zytor.com] On Behalf Of Sebastian Herbszt
Sent: Friday, April 30, 2010 2:13 PM
To: For discussion of Syslinux and tftp-hpa
Subject: Re: [syslinux] Patch sensible callback framework

Ayvaz, James wrote:

[snip]

> 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);

Strip the colon here - it's not used below.

> +}
> +
> +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");
> +}

I think "total" can never be 0, because syslinux handles 0 byte files as non existent.
If that is correct "total" can be > 0 or -1 for unknown size. In the latter case "OK" is never printed.
That printf() can be put after the calls to loadfile() and initramfs_load_archive() if those succeed and
opt_quiet is false. This callback can then be removed.

> +
> 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 {
> +

Strip this introduced new line.

>            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) {

A printf("Loading %s ", kernel_name); is needed here in case loadfile() fails and opt_quiet is false.
Else we just get a line with "failed!".

> +        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;
>            }

printf("Loading %s ", arg);  should be kept here before initramfs_load_archive() if opt_quiet is false.

> -           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)) {
>

Sebastian

_______________________________________________
Syslinux mailing list
Submissions to Syslinux at zytor.com
Unsubscribe or set options at:
http://www.zytor.com/mailman/listinfo/syslinux
Please do not send private replies to mailing list traffic.




More information about the Syslinux mailing list