From owner-freebsd-bugs@FreeBSD.ORG Thu Oct 13 00:30:21 2005 Return-Path: X-Original-To: freebsd-bugs@hub.freebsd.org Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 1634A16A41F for ; Thu, 13 Oct 2005 00:30:21 +0000 (GMT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id 47EBF43D46 for ; Thu, 13 Oct 2005 00:30:20 +0000 (GMT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.13.3/8.13.3) with ESMTP id j9D0UKLn082461 for ; Thu, 13 Oct 2005 00:30:20 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.13.3/8.13.1/Submit) id j9D0UK3o082458; Thu, 13 Oct 2005 00:30:20 GMT (envelope-from gnats) Resent-Date: Thu, 13 Oct 2005 00:30:20 GMT Resent-Message-Id: <200510130030.j9D0UK3o082458@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, "Nuno Antunes" Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id C8C2416A41F for ; Thu, 13 Oct 2005 00:24:55 +0000 (GMT) (envelope-from nuno.antunes@gmail.com) Received: from www.nantunes.org (bl7-161-98.dsl.telepac.pt [85.240.161.98]) by mx1.FreeBSD.org (Postfix) with ESMTP id 01C5043D45 for ; Thu, 13 Oct 2005 00:24:54 +0000 (GMT) (envelope-from nuno.antunes@gmail.com) Received: from localhost (localhost [172.16.0.2]) by www.nantunes.org (Postfix) with ESMTP id DB87E2E4DD for ; Thu, 13 Oct 2005 01:28:32 +0100 (WEST) Received: from www.nantunes.org ([172.16.0.2]) by localhost (www.nantunes.org [172.16.0.2]) (amavisd-new, port 10024) with LMTP id 81119-09 for ; Thu, 13 Oct 2005 01:28:24 +0100 (WEST) Received: from pt1wgfdc.ip.lab (localhost [172.16.0.2]) by www.nantunes.org (Postfix) with ESMTP id F02E32E42A for ; Thu, 13 Oct 2005 01:28:23 +0100 (WEST) Message-Id: <1129163082.0@pt1wgfdc.ip.lab> Date: Thu, 13 Oct 2005 01:24:42 +0100 From: "Nuno Antunes" To: "FreeBSD gnats submit" X-Send-Pr-Version: gtk-send-pr 0.4.6 Cc: Subject: bin/87352: [PATCH] Add line edit and history support to ngctl via libedit X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 13 Oct 2005 00:30:21 -0000 >Number: 87352 >Category: bin >Synopsis: [PATCH] Add line edit and history support to ngctl via libedit >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Thu Oct 13 00:30:19 GMT 2005 >Closed-Date: >Last-Modified: >Originator: Nuno Antunes >Release: FreeBSD 6.0-BETA4 i386 >Organization: >Environment: System: FreeBSD 6.0-BETA4 #2: Sat Sep 17 10:56:38 WEST 2005 nant@pt1wgfdc.ip.lab:/usr/obj/usr/src/sys/LIFEBOOK8010 >Description: This patch group adds line editing and history facilities to ngctl via libedit while on the interactive mode tool. It now uses two threads, one to handle user interactivity and the other to handle the data/control socket operation. I'm not sure if any special syncronization is required. Only minimal syncronization was implemented (via a signal). >How-To-Repeat: >Fix: --- Makefile.diff begins here --- --- usr.sbin/ngctl/Makefile.orig Wed Oct 12 23:18:02 2005 +++ usr.sbin/ngctl/Makefile Tue Oct 11 23:13:21 2005 @@ -7,6 +7,6 @@ msg.c debug.c shutdown.c rmhook.c status.c types.c write.c WARNS?= 3 DPADD= ${LIBNETGRAPH} -LDADD= -lnetgraph +LDADD= -lnetgraph -ledit -ltermcap -lpthread .include --- Makefile.diff ends here --- --- ngctl.h.diff begins here --- --- usr.sbin/ngctl/ngctl.h.orig Mon Oct 10 22:51:59 2005 +++ usr.sbin/ngctl/ngctl.h Wed Oct 12 23:26:24 2005 @@ -52,6 +52,8 @@ #include #include #include +#include +#include #include #include @@ -66,6 +68,14 @@ const char *desc; /* description */ const char *help; /* help text */ const char *aliases[MAX_CMD_ALIAS]; /* command aliases */ +}; + +/* Data to be passed to the threads. */ +struct thread_data { + EditLine *el; /* EditLine cookie */ + History *hist; /* History cookie */ + HistEvent he; /* History event */ + pthread_t interact; }; /* Command return values */ --- ngctl.h.diff ends here --- --- main.c.diff begins here --- --- usr.sbin/ngctl/main.c.orig Fri Feb 4 20:09:11 2005 +++ usr.sbin/ngctl/main.c Wed Oct 12 23:26:09 2005 @@ -49,13 +49,15 @@ static int ReadFile(FILE *fp); static int DoParseCommand(char *line); static int DoCommand(int ac, char **av); -static int DoInteractive(void); +static void * DoInteractive(void *); +static void * DoMonitor(void *); static const struct ngcmd *FindCommand(const char *string); static int MatchCommand(const struct ngcmd *cmd, const char *s); static void Usage(const char *msg); static int ReadCmd(int ac, char **av); static int HelpCmd(int ac, char **av); static int QuitCmd(int ac, char **av); +static const char *GetPrompt(EditLine *); /* List of commands */ static const struct ngcmd *const cmds[] = { @@ -152,7 +154,45 @@ if (fp != NULL) { rtn = ReadFile(fp); } else if (interactive) { - rtn = DoInteractive(); + pthread_t monitor; + struct thread_data td; + void *thread_rtn; + + /* Initialize libedit stuff */ + td.el = el_init(getprogname(), stdin, stdout, stderr); + if (td.el == NULL) + return CMDRTN_ERROR; + td.hist = history_init(); + if (td.hist != NULL) { + history(td.hist, &td.he, H_SETSIZE, 100); + el_set(td.el, EL_HIST, history, td.hist); + } + else printf("no history!!!\n"); + + el_set(td.el, EL_PROMPT, GetPrompt); + el_set(td.el, EL_SIGNAL, 1); + el_set(td.el, EL_EDITOR, "emacs"); + el_source(td.el, NULL); + + /* + * Now we create two threads. The Interactive thread to + * handle the interactive stuff and the Monitor thread + * to print data as it arrives on the socket. + */ + pthread_create(&td.interact, NULL, DoInteractive, &td); + pthread_create(&monitor, NULL, DoMonitor, &td); + + + /* Wait for the Interactive thread to finish */ + pthread_join(td.interact, &thread_rtn); + rtn = *(int *)thread_rtn; + + pthread_cancel(monitor); + + /* Destroy libedit stuff */ + el_end(td.el); + if (td.hist != NULL) + history_end(td.hist); } else Usage("no command specified"); } else { @@ -198,38 +238,66 @@ /* * Interactive mode */ -static int -DoInteractive(void) +static void * +DoInteractive(void *vp) { - const int maxfd = MAX(csock, dsock) + 1; + struct thread_data *td = (struct thread_data *)vp; + static int rtn; (*help_cmd.func)(0, NULL); + while (1) { - struct timeval tv; - fd_set rfds; + char buf[LINE_MAX]; + const char *line = NULL; + int count = 0; + + if ((line = el_gets(td->el, &count)) != NULL) { + int len; + + strncpy(buf, line, LINE_MAX - 1); + buf[LINE_MAX] = '\0';/* In case len(line) >= LINE_MAX */ + len = strlen(buf); + if (buf[--len] == '\n') + buf[len] = '\0'; + if ((rtn = DoParseCommand(buf)) == CMDRTN_QUIT) + break; + history(td->hist, &td->he, H_ENTER, buf); + } + } + + return(&rtn); +} + +/* + * Monitor thread + */ +static void * +DoMonitor(void *vp) +{ + const int maxfd = MAX(csock, dsock) + 1; + struct thread_data *td = (struct thread_data *)vp; + fd_set rfds; + while (1) { /* See if any data or control messages are arriving */ FD_ZERO(&rfds); FD_SET(csock, &rfds); FD_SET(dsock, &rfds); - memset(&tv, 0, sizeof(tv)); - if (select(maxfd, &rfds, NULL, NULL, &tv) <= 0) { - - /* Issue prompt and wait for anything to happen */ - printf("%s", PROMPT); - fflush(stdout); - FD_ZERO(&rfds); - FD_SET(0, &rfds); - FD_SET(csock, &rfds); - FD_SET(dsock, &rfds); - if (select(maxfd, &rfds, NULL, NULL, NULL) < 0) - err(EX_OSERR, "select"); - - /* If not user input, print a newline first */ - if (!FD_ISSET(0, &rfds)) - printf("\n"); +again: + if (select(maxfd, &rfds, NULL, NULL, NULL) < 0) { + if (errno == EINTR) /* Allow signals */ + goto again; + err(EX_OSERR, "select"); } + /* Save current line */ + + + + /* Print a newline before echoing anything */ + printf("\n"); + fflush(stdout); + /* Display any incoming control message */ if (FD_ISSET(csock, &rfds)) MsgRead(); @@ -252,19 +320,14 @@ free(buf); } - /* Get any user input */ - if (FD_ISSET(0, &rfds)) { - char buf[LINE_MAX]; + /* Restore the prompt to a known state */ + el_reset(td->el); + printf("%s", GetPrompt(td->el)); + fflush(stdout); + pthread_kill(td->interact, SIGCONT); + } /* while */ - if (fgets(buf, sizeof(buf), stdin) == NULL) { - printf("\n"); - break; - } - if (DoParseCommand(buf) == CMDRTN_QUIT) - break; - } - } - return(CMDRTN_QUIT); + return NULL; } /* @@ -493,6 +556,13 @@ } printf("%s\n", sbuf); } +} + +static const char * +GetPrompt(EditLine *el) +{ + (void) el; + return PROMPT; } /* --- main.c.diff ends here --- >Release-Note: >Audit-Trail: >Unformatted: