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)) {
Ayvaz, James wrote:> 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 2defined twice?> + > + > +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*10241 MB chunk size is pretty huge. gfxboot currently uses 64k to display the progress.> +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 > + */can can?> + 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;Maybe use "-percent" and check it in the while loop above (same as -dhcpinfo) ? Else "percent" will be passed to the linux kernel, won't it?> + 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)) { >Sebastian
On 04/26/2010 08:35 PM, Ayvaz, James wrote:> 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. >This looks a lot better, but I think we can improve it further. In particular: a) let 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. b) 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.) First of all, it makes it easy to create new callbacks, and second, it means we don't have to walk the whole list of callbacks when we invoke it; we just walk the exact list of callbacks that we care about. c) Make the invocation points smaller, e.g. by an callbacks_invoke() helper function. d) 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. -hpa
On Tue, 27 Apr 2010, Ayvaz, James wrote:> diff -uprN syslinux-3.86-vanilla/com32/modules/linux.c syslinux-3.86/com32/modules/linux.c[...]> +void linux_percent_progress_cb(const char* file, size_t cur, size_t total) { > + int percent = (int)(((float)cur / (float)total) * 100.0);Is 'total' guaranteed to be nonzero? Steffen
On Tue, 27 Apr 2010, H. Peter Anvin wrote:> d) 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.Would it be possible to make the chunk size configurable? At least the 1MB used in code is way too big. Steffen