From 3ae497eab281eab5f98770e6a3d5992b9d37325e Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 16 Mar 2003 06:26:25 -0500 Subject: [PATCH] Add to the ss (subsystem) library the ability to dynamically link to the readline library if it is present in the system. --- ChangeLog | 4 ++ configure.in | 8 ++++ debian/control | 40 ++++++++++++++--- debugfs/ChangeLog | 8 ++++ debugfs/Makefile.in | 4 +- debugfs/debugfs.c | 1 + lib/ss/ChangeLog | 20 +++++++++ lib/ss/Makefile.in | 11 ++--- lib/ss/get_readline.c | 65 +++++++++++++++++++++++++++ lib/ss/invocation.c | 17 +++++++ lib/ss/listen.c | 101 ++++++++++++++++++++++++++++++++++++------ lib/ss/ss.h | 2 + lib/ss/ss_internal.h | 11 +++++ 13 files changed, 266 insertions(+), 26 deletions(-) create mode 100644 lib/ss/get_readline.c diff --git a/ChangeLog b/ChangeLog index 606572e8..1656b939 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2003-03-16 Theodore Ts'o + + * configure.in: Check to see if libdl exists for the sake of dlopen + 2003-03-14 Theodore Ts'o * configure.in: Add support for Apple/Darwin shared libraries. diff --git a/configure.in b/configure.in index 4047f493..53bb7162 100644 --- a/configure.in +++ b/configure.in @@ -625,6 +625,14 @@ SOCKET_LIB='' AC_CHECK_LIB(socket, socket, [SOCKET_LIB=-lsocket]) AC_SUBST(SOCKET_LIB) dnl +dnl Check to see if libdl exists for the sake of dlopen +dnl +DLOPEN_LIB='' +AC_CHECK_LIB(dl, dlopen, +[DLOPEN_LIB=-ldl +AC_DEFINE(HAVE_DLOPEN)]) +AC_SUBST(DLOPEN_LIB) +dnl dnl See if optreset exists dnl AC_MSG_CHECKING(for optreset) diff --git a/debian/control b/debian/control index 91f9ff95..f5fe2e40 100644 --- a/debian/control +++ b/debian/control @@ -11,7 +11,7 @@ Priority: optional Depends: e2fsprogs (= ${Source-Version}), ${misc:Depends} Recommends: sash | zsh-static | busybox-static | zsh30-static Architecture: any -Description: A statically-linked version of the ext2 filesystem checker. +Description: A statically-linked version of the ext2 filesystem checker This may be of some help to you if your filesystem gets corrupted enough to break the shared libraries used by the dynamically linked checker. . @@ -28,7 +28,7 @@ Depends: ${libcdev:Depends}, libcomerr2, ${misc:Depends} Suggests: doc-base Conflicts: e2fsprogs (<< 1.10-6) Architecture: any -Description: The Common Error Description library - headers and static libraries. +Description: The Common Error Description library - headers and static libraries libcomerr is an attempt to present a common error-handling mechanism to manipulate the most common form of error code in a fashion that does not have the problems identified with mechanisms commonly in use. @@ -39,7 +39,7 @@ Priority: extra Depends: ${libcdev:Depends}, libss2, ${misc:Depends} Conflicts: e2fsprogs (<< 1.10-6) Architecture: any -Description: Command-line interface parsing library - headers and static libraries. +Description: Command-line interface parsing library - headers and static libraries This package includes a tool that parses a command table to generate a simple command-line interface parser, the include files needed to compile and use it, and the static libs. @@ -53,7 +53,7 @@ Depends: ${libcdev:Depends}, e2fsprogs (= ${Source-Version}), ${misc:Depends} Conflicts: e2fsprogs (<< 1.10-6) Replaces: e2fslibs-dev (<< 1.15) Architecture: any -Description: Universally unique id library - headers and static libraries. +Description: Universally unique id library - headers and static libraries libuuid generates and parses 128-bit universally unique id's (UUID's), using a standard which is blessed by both Microsoft and DCE, and is being proposed as an internet standard. See the internet-draft: @@ -62,6 +62,32 @@ Description: Universally unique id library - headers and static libraries. . for more information. +Package: libblkid +Section: libs +Priority: required +Depends: ${libcdev:Depends} +Architecture: any +Description: Block device id library + The blkid library which allows system programs like fsck and + mount to quickly and easily find block devices by filesystem UUID and + LABEL. This allows system administrators to avoid specifiying + filesystems by hard-coded device names, but via a logical naming + system instead. + +Package: libblkid-dev +Section: devel +Priority: extra +Depends: libblkid (= ${Source-Version}) +Architecture: any +Description: Block device id library - headers and static libraries + The blkid library which allows system programs like fsck and + mount to quickly and easily find block devices by filesystem UUID and + LABEL. This allows system administrators to avoid specifiying + filesystems by hard-coded device names, but via a logical naming + system instead. + . + This package contains the development environment for the blkid library. + Package: e2fsprogs-bf Section: devel Priority: extra @@ -91,12 +117,12 @@ Description: A stripped-down versions of e2fsprogs, for debian-installer Package: e2fsprogs Essential: yes Pre-Depends: ${shlibs:Depends} -Depends: ${misc:Depends} +Depends: ${misc:Depends}, libblkid Suggests: gpart, parted, e2fsck-static Conflicts: e2fslibsg, dump (<< 0.4b4-4), quota (<< 1.55-8.1) Provides: libcomerr2, libss2, libext2fs2, libe2p2, libuuid1 Architecture: any -Description: The EXT2 file system utilities and libraries. +Description: The EXT2 file system utilities and libraries EXT2 stands for "Extended Filesystem", version 2. It's the main filesystem type used for hard disks on Debian and other Linux systems. . @@ -111,7 +137,7 @@ Suggests: doc-base Provides: ext2fs-dev, e2p-dev Conflicts: e2fsprogs (<< 1.10-6) Architecture: any -Description: The headers and static libraries for ext2fs-aware tools-development. +Description: The headers and static libraries for ext2fs-aware tools-development EXT2FS stands for "Extended Filesystem", version 2. It's the filesystem type used for hard disks on Debian and other Linux systems. . diff --git a/debugfs/ChangeLog b/debugfs/ChangeLog index 88583a61..dc0a8399 100644 --- a/debugfs/ChangeLog +++ b/debugfs/ChangeLog @@ -1,3 +1,11 @@ +2003-03-16 Theodore Ts'o + + * Makefile.in (DLOPEN_LIB): Link in the libdl library if it is + present on the system. + + * debugfs.c (main): Call ss_get_readline() to attempt to pull in + the readline library. + 2003-03-06 Theodore Tso * debugfs.c (do_open_filesys, do_show_super_stats), diff --git a/debugfs/Makefile.in b/debugfs/Makefile.in index 6362a93b..1412f569 100644 --- a/debugfs/Makefile.in +++ b/debugfs/Makefile.in @@ -8,6 +8,7 @@ VPATH = @srcdir@ top_builddir = .. my_dir = debugfs INSTALL = @INSTALL@ +DLOPEN_LIB = @DLOPEN_LIB@ @MCONFIG@ @@ -24,7 +25,8 @@ SRCS= debug_cmds.c $(srcdir)/debugfs.c $(srcdir)/util.c $(srcdir)/ls.c \ $(srcdir)/dump.c $(srcdir)/setsuper.c ${srcdir}/logdump.c \ $(srcdir)/htree.c -LIBS= $(LIBEXT2FS) $(LIBE2P) $(LIBSS) $(LIBCOM_ERR) $(LIBBLKID) $(LIBUUID) +LIBS= $(LIBEXT2FS) $(LIBE2P) $(LIBSS) $(LIBCOM_ERR) $(LIBBLKID) \ + $(LIBUUID) $(DLOPEN_LIB) DEPLIBS= $(LIBEXT2FS) $(LIBE2P) $(LIBSS) $(LIBCOM_ERR) $(LIBBLKID) $(DEPLIBUUID) .c.o: diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c index a9a6c63d..e6bcdbae 100644 --- a/debugfs/debugfs.c +++ b/debugfs/debugfs.c @@ -1576,6 +1576,7 @@ int main(int argc, char **argv) ss_perror(sci_idx, retval, "creating invocation"); exit(1); } + ss_get_readline(sci_idx); (void) ss_add_request_table (sci_idx, &ss_std_requests, 1, &retval); if (retval) { diff --git a/lib/ss/ChangeLog b/lib/ss/ChangeLog index 214f5268..8a7c1c81 100644 --- a/lib/ss/ChangeLog +++ b/lib/ss/ChangeLog @@ -1,3 +1,23 @@ +2003-03-16 Theodore Ts'o + + * Makefile.in (DLOPEN_LIB): Include the dlopen library if it is + present on shared libraries. + + * ss_internal.h: Add pointers to dynamic readline functions in the + ss_info data structure. + + * listen.c (ss_listen): Use readline instead of fgets if the + readline library is present. Define helper functions to + provide command completion from the ss request tables. + + * invocation.c (ss_create_invocation, ss_delete_invocation): If + HAVE_DLOPEN is defined, call ss_get_readline() to automatically + try to load the readline library. + + * get_readline.c (ss_get_readline): New function which uses dlopen() + to dynamically load the readline library if it is present + on the system. + 2002-11-09 Theodore Ts'o * Release of E2fsprogs 1.32 diff --git a/lib/ss/Makefile.in b/lib/ss/Makefile.in index 38c2750d..19a4c9b6 100644 --- a/lib/ss/Makefile.in +++ b/lib/ss/Makefile.in @@ -8,6 +8,7 @@ VPATH = @srcdir@ top_builddir = ../.. my_dir = lib/ss INSTALL = @INSTALL@ +DLOPEN_LIB = @DLOPEN_LIB@ @MCONFIG@ @@ -20,7 +21,7 @@ DLL_GOTSIZE = 0x1000 DLL_VERSION = 1.0 DLL_IMAGE = libss DLL_STUB = libss -DLL_LIBS = -L../.. -lcom_err +DLL_LIBS = -L../.. -lcom_err $(DLOPEN_LIB) DLL_MYDIR = ss DLL_INSTALL_DIR = $(root_libdir) @@ -29,7 +30,7 @@ ELF_SO_VERSION = 2 ELF_IMAGE = libss ELF_MYDIR = ss ELF_INSTALL_DIR = $(root_libdir) -ELF_OTHER_LIBS = -L../.. -lcom_err +ELF_OTHER_LIBS = -L../.. -lcom_err $(DLOPEN_LIB) BSDLIB_VERSION = 1.0 BSDLIB_IMAGE = libss @@ -51,7 +52,7 @@ XTRA_CFLAGS=-DPOSIX_SIGNALS -I$(srcdir)/../et @CHECKER_CMT@ $(CC) $(ALL_CFLAGS) -checker -g -o checker/$*.o -c $< @DLL_CMT@ (export JUMP_DIR=`pwd`/jump; $(CC) -B$(JUMP_PREFIX) \ @DLL_CMT@ $(ALL_CFLAGS) -o jump/$*.o -c $<) -@ELF_CMT@ $(CC) $(ALL_CFLAGS) -fPIC -o elfshared/$*.o -c $< +@ELF_CMT@ $(CC) $(ALL_CFLAGS) -DSHARED_ELF_LIB -fPIC -o elfshared/$*.o -c $< @BSDLIB_CMT@ $(CC) $(ALL_CFLAGS) -fpic -o pic/$*.o -c $< # for the library @@ -65,13 +66,13 @@ OBJS= ss_err.o \ invocation.o help.o \ execute_cmd.o listen.o parse.o error.o prompt.o \ request_tbl.o list_rqs.o pager.o requests.o \ - data.o + data.o get_readline.o SRCS= $(srcdir)/invocation.c $(srcdir)/help.c \ $(srcdir)/execute_cmd.c $(srcdir)/listen.c $(srcdir)/parse.c \ $(srcdir)/error.c $(srcdir)/prompt.c $(srcdir)/request_tbl.c \ $(srcdir)/list_rqs.c $(srcdir)/pager.c $(srcdir)/requests.c \ - $(srcdir)/data.c + $(srcdir)/data.c $(srcdir)/get_readline.c all:: mk_cmds diff --git a/lib/ss/get_readline.c b/lib/ss/get_readline.c new file mode 100644 index 00000000..2ec5ac20 --- /dev/null +++ b/lib/ss/get_readline.c @@ -0,0 +1,65 @@ +/* + * Copyright 2003 by MIT Student Information Processing Board + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose is hereby granted, provided that + * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. M.I.T. and the + * M.I.T. S.I.P.B. make no representations about the suitability of + * this software for any purpose. It is provided "as is" without + * express or implied warranty. + */ + +#ifdef HAS_STDLIB_H +#include +#endif +#include "ss_internal.h" +#define size sizeof(ss_data *) +#ifdef HAVE_DLOPEN +#include +#endif + +static void ss_release_readline(ss_data *info) +{ +#ifdef HAVE_DLOPEN + if (!info->readline_handle) + return; + + info->readline = 0; + info->add_history = 0; + info->redisplay = 0; + info->rl_completion_matches = 0; + dlclose(info->readline_handle); + info->readline_handle = 0; +#endif +} + +void ss_get_readline(int sci_idx) +{ +#ifdef HAVE_DLOPEN + void *handle; + ss_data *info = ss_info(sci_idx); + const char **t; + char **(**completion_func)(const char *, int, int); + + if (info->readline_handle || + getenv("SS_NO_READLINE") || + ((handle = dlopen("libreadline.so", RTLD_NOW)) == NULL)) + return; + + info->readline_handle = handle; + info->readline = dlsym(handle, "readline"); + info->add_history = dlsym(handle, "add_history"); + info->redisplay = dlsym(handle, "rl_forced_update_display"); + info->rl_completion_matches = dlsym(handle, "rl_completion_matches"); + if ((t = dlsym(handle, "rl_readline_name")) != NULL) + *t = info->subsystem_name; + if ((completion_func = + dlsym(handle, "rl_attempted_completion_function")) != NULL) + *completion_func = ss_rl_completion; + info->readline_shutdown = ss_release_readline; +#endif +} + + diff --git a/lib/ss/invocation.c b/lib/ss/invocation.c index 81c70e48..748886fa 100644 --- a/lib/ss/invocation.c +++ b/lib/ss/invocation.c @@ -16,6 +16,9 @@ #endif #include "ss_internal.h" #define size sizeof(ss_data *) +#ifdef HAVE_DLOPEN +#include +#endif int ss_create_invocation(subsystem_name, version_string, info_ptr, request_table_ptr, code_ptr) @@ -27,6 +30,7 @@ int ss_create_invocation(subsystem_name, version_string, info_ptr, register int sci_idx; register ss_data *new_table; register ss_data **table; + void *handle; *code_ptr = 0; table = _ss_table; @@ -66,7 +70,16 @@ int ss_create_invocation(subsystem_name, version_string, info_ptr, (ss_request_table **) calloc(2, sizeof(ss_request_table *)); *(new_table->rqt_tables) = request_table_ptr; *(new_table->rqt_tables+1) = (ss_request_table *) NULL; + + new_table->readline_handle = 0; + new_table->readline = 0; + new_table->add_history = 0; + new_table->redisplay = 0; + new_table->rl_completion_matches = 0; _ss_table = table; +#if defined(HAVE_DLOPEN) && defined(SHARED_ELF_LIB) + ss_get_readline(sci_idx); +#endif return(sci_idx); } @@ -83,5 +96,9 @@ ss_delete_invocation(sci_idx) while(t->info_dirs[0] != (char *)NULL) ss_delete_info_dir(sci_idx, t->info_dirs[0], &ignored_code); free((char *)t->info_dirs); +#if defined(HAVE_DLOPEN) && defined(SHARED_ELF_LIB) + if (t->readline_shutdown) + (*t->readline_shutdown)(t); +#endif free((char *)t); } diff --git a/lib/ss/listen.c b/lib/ss/listen.c index 04b83024..07314183 100644 --- a/lib/ss/listen.c +++ b/lib/ss/listen.c @@ -48,8 +48,12 @@ static sigret_t print_prompt(int sig) } } #endif - (void) fputs(current_info->prompt, stdout); - (void) fflush(stdout); + if (current_info->redisplay) + (*current_info->redisplay)(); + else { + (void) fputs(current_info->prompt, stdout); + (void) fflush(stdout); + } } static sigret_t listen_int_handler(int sig) @@ -73,6 +77,7 @@ int ss_listen (int sci_idx) int code; jmp_buf old_jmpb; ss_data *old_info = current_info; + char *line; current_info = info = ss_info(sci_idx); sig_cont = (sigret_t (*)(int)) 0; @@ -93,29 +98,40 @@ int ss_listen (int sci_idx) (void) sigsetmask(mask); #endif while(!info->abort) { - print_prompt(0); old_sig_cont = sig_cont; sig_cont = signal(SIGCONT, print_prompt); if (sig_cont == print_prompt) sig_cont = old_sig_cont; - if (fgets(input, BUFSIZ, stdin) != input) { - code = SS_ET_EOF; - (void) signal(SIGCONT, sig_cont); - goto egress; - } - input[BUFSIZ-1] = 0; + if (info->readline) { + line = (*info->readline)(current_info->prompt); + } else { + print_prompt(0); + if (fgets(input, BUFSIZ, stdin) == input) + line = input; + else + line = NULL; - cp = strchr(input, '\n'); + input[BUFSIZ-1] = 0; + } + if (line == NULL) { + code = SS_ET_EOF; + (void) signal(SIGCONT, sig_cont); + goto egress; + } + + cp = strchr(line, '\n'); if (cp) { *cp = '\0'; - if (cp == input) + if (cp == line) continue; } (void) signal(SIGCONT, sig_cont); + if (info->add_history) + (*info->add_history)(line); - code = ss_execute_line (sci_idx, input); + code = ss_execute_line (sci_idx, line); if (code == SS_ET_COMMAND_NOT_FOUND) { - register char *c = input; + register char *c = line; while (*c == ' ' || *c == '\t') c++; cp = strchr (c, ' '); @@ -128,6 +144,8 @@ int ss_listen (int sci_idx) "Unknown request \"%s\". Type \"?\" for a request list.", c); } + if (info->readline) + free(line); } code = 0; egress: @@ -148,3 +166,60 @@ void ss_quit(int argc, const char * const *argv, int sci_idx, pointer infop) { ss_abort_subsystem(sci_idx, 0); } + +#ifdef HAVE_DLOPEN +#define get_request(tbl,idx) ((tbl) -> requests + (idx)) + +static char *cmd_generator(const char *text, int state) +{ + static int len; + static ss_request_table **rqtbl; + static int curr_rqt; + static char const * const * name; + ss_request_entry *request; + char *ret; + + if (state == 0) { + len = strlen(text); + rqtbl = current_info->rqt_tables; + if (!rqtbl || !*rqtbl) + return 0; + curr_rqt = 0; + name = 0; + } + + while (1) { + if (!name || !*name) { + request = get_request(*rqtbl, curr_rqt++); + name = request->command_names; + if (!name) { + rqtbl++; + if (*rqtbl) { + curr_rqt = 0; + continue; + } else + break; + } + } + if (strncmp(*name, text, len) == 0) { + ret = malloc(strlen(*name)+1); + if (ret) + strcpy(ret, *name); + name++; + return ret; + } + name++; + } + + return 0; +} + +char **ss_rl_completion(const char *text, int start, int end) +{ + if ((start == 0) && current_info->rl_completion_matches) + return (*current_info->rl_completion_matches) + (text, cmd_generator); + return 0; +} +#endif + diff --git a/lib/ss/ss.h b/lib/ss/ss.h index 80f393ad..805e1f14 100644 --- a/lib/ss/ss.h +++ b/lib/ss/ss.h @@ -85,6 +85,7 @@ void ss_unimplemented(int argc, const char * const *argv, int sci_idx, void *infop); void ss_set_prompt(int sci_idx, char *new_prompt); char *ss_get_prompt(int sci_idx); +void ss_get_readline(int sci_idx); #else char *ss_name(); void ss_error (); @@ -103,6 +104,7 @@ void ss_subsystem_version(); void ss_unimplemented(); void ss_set_prompt; char *ss_get_prompt; +void ss_get_readline(); #endif extern ss_request_table ss_std_requests; #endif /* _ss_h */ diff --git a/lib/ss/ss_internal.h b/lib/ss/ss_internal.h index ab155864..ce84477d 100644 --- a/lib/ss/ss_internal.h +++ b/lib/ss/ss_internal.h @@ -95,6 +95,16 @@ typedef struct _ss_data { /* init values */ unsigned int escape_disabled : 1, abbrevs_disabled : 1; } flags; + /* + * Dynamic usage of readline library if present + */ + void *readline_handle; + void (*readline_shutdown)(struct _ss_data *info); + char *(*readline)(const char *); + void (*add_history)(const char *); + void (*redisplay)(); + char **(*rl_completion_matches)(const char *, + char *(*completer)(const char *, int)); /* to get out */ int abort; /* exit subsystem */ int exit_status; @@ -116,6 +126,7 @@ void ss_page_stdin(NOARGS); void ss_list_requests PROTOTYPE((int, char const * const *, int, pointer)); int ss_execute_command PROTOTYPE((int sci_idx, char *argv[])); int ss_pager_create(NOARGS); +char **ss_rl_completion(const char *text, int start, int end); extern ss_data **_ss_table; extern char *ss_et_msgs[];