diff options
| author | Gleb Smirnoff <glebius@FreeBSD.org> | 2006-08-07 14:17:05 +0000 |
|---|---|---|
| committer | Gleb Smirnoff <glebius@FreeBSD.org> | 2006-08-07 14:17:05 +0000 |
| commit | b9124a7354fdd7142c710c12859b062650e1da5b (patch) | |
| tree | 2fd49f9603f6c85e9baca7a80426824c76d60251 /usr.sbin/ngctl | |
| parent | 42787b76b669e547324cc3923a3c09a0e9510f79 (diff) | |
Notes
Diffstat (limited to 'usr.sbin/ngctl')
| -rw-r--r-- | usr.sbin/ngctl/Makefile | 11 | ||||
| -rw-r--r-- | usr.sbin/ngctl/main.c | 179 |
2 files changed, 168 insertions, 22 deletions
diff --git a/usr.sbin/ngctl/Makefile b/usr.sbin/ngctl/Makefile index 364bbf7b8a7d..22122f836571 100644 --- a/usr.sbin/ngctl/Makefile +++ b/usr.sbin/ngctl/Makefile @@ -6,7 +6,18 @@ MAN= ngctl.8 SRCS= main.c mkpeer.c config.c connect.c dot.c name.c show.c list.c \ msg.c debug.c shutdown.c rmhook.c status.c types.c write.c WARNS?= 3 + +.if defined(RELEASE_CRUNCH) +NGCTL_NO_LIBEDIT= +.endif + DPADD= ${LIBNETGRAPH} LDADD= -lnetgraph +.if !defined(NGCTL_NO_LIBEDIT) +CFLAGS+= -DEDITLINE +DPADD+= ${LIBPTHREAD} ${LIBEDIT} ${LIBTERMCAP} +LDADD+= -pthread -ledit -ltermcap +.endif + .include <bsd.prog.mk> diff --git a/usr.sbin/ngctl/main.c b/usr.sbin/ngctl/main.c index a09a0cf1291d..5a11899c0dc2 100644 --- a/usr.sbin/ngctl/main.c +++ b/usr.sbin/ngctl/main.c @@ -51,6 +51,11 @@ #include <string.h> #include <sysexits.h> #include <unistd.h> +#ifdef EDITLINE +#include <signal.h> +#include <histedit.h> +#include <pthread.h> +#endif #include <netgraph.h> @@ -63,6 +68,7 @@ /* Internal functions */ static int ReadFile(FILE *fp); +static void ReadSockets(fd_set); static int DoParseCommand(char *line); static int DoCommand(int ac, char **av); static int DoInteractive(void); @@ -72,6 +78,11 @@ 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); +#ifdef EDITLINE +static sig_atomic_t unblock; +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +#endif /* List of commands */ static const struct ngcmd *const cmds[] = { @@ -211,8 +222,122 @@ ReadFile(FILE *fp) return (CMDRTN_OK); } +#ifdef EDITLINE +/* Signal handler for Monitor() thread. */ +static void +Unblock(int signal) +{ + unblock = 1; +} + /* - * Interactive mode + * Thread that monitors csock and dsock while main thread + * can be blocked in el_gets(). + */ +static void * +Monitor(void *v) +{ + struct sigaction act; + const int maxfd = MAX(csock, dsock) + 1; + + act.sa_handler = Unblock; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + sigaction(SIGUSR1, &act, NULL); + + pthread_mutex_lock(&mutex); + for (;;) { + fd_set rfds; + + /* See if any data or control messages are arriving. */ + FD_ZERO(&rfds); + FD_SET(csock, &rfds); + FD_SET(dsock, &rfds); + unblock = 0; + if (select(maxfd, &rfds, NULL, NULL, NULL) <= 0) { + if (errno == EINTR) { + if (unblock == 1) + pthread_cond_wait(&cond, &mutex); + continue; + } + err(EX_OSERR, "select"); + } + + ReadSockets(rfds); + } + + return (NULL); +} + +static char * +Prompt(EditLine *el) +{ + return PROMPT; +} + +/* + * Here we start a thread, that will monitor the netgraph + * sockets and catch any unexpected messages or data on them, + * that can arrive while user edits his/her commands. + * + * Whenever we expect data on netgraph sockets, we send signal + * to monitoring thread. The signal forces it to exit select() + * system call and sleep on condvar until we wake it. While + * monitoring thread sleeps, we can do our work with netgraph + * sockets. + */ +static int +DoInteractive(void) +{ + pthread_t monitor; + EditLine *el; + History *hist; + HistEvent hev = { 0, "" }; + + (*help_cmd.func)(0, NULL); + pthread_create(&monitor, NULL, Monitor, NULL); + el = el_init(getprogname(), stdin, stdout, stderr); + if (el == NULL) + return (CMDRTN_ERROR); + el_set(el, EL_PROMPT, Prompt); + el_set(el, EL_SIGNAL, 1); + el_set(el, EL_EDITOR, "emacs"); + hist = history_init(); + if (hist == NULL) + return (CMDRTN_ERROR); + history(hist, &hev, H_SETSIZE, 100); + history(hist, &hev, H_SETUNIQUE, 1); + el_set(el, EL_HIST, history, (const char *)hist); + el_source(el, NULL); + + for (;;) { + const char *buf; + int count; + + if ((buf = el_gets(el, &count)) == NULL) { + printf("\n"); + break; + } + history(hist, &hev, H_ENTER, buf); + pthread_kill(monitor, SIGUSR1); + pthread_mutex_lock(&mutex); + if (DoParseCommand((char *)buf) == CMDRTN_QUIT) + break; + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); + } + + history_end(hist); + el_end(el); + pthread_cancel(monitor); + + return (CMDRTN_QUIT); +} + +#else /* !EDITLINE */ + +/* + * Interactive mode w/o libedit functionality. */ static int DoInteractive(void) @@ -246,27 +371,7 @@ DoInteractive(void) printf("\n"); } - /* Display any incoming control message */ - if (FD_ISSET(csock, &rfds)) - MsgRead(); - - /* Display any incoming data packet */ - if (FD_ISSET(dsock, &rfds)) { - u_char *buf; - char hook[NG_HOOKSIZ]; - int rl; - - /* Read packet from socket */ - if ((rl = NgAllocRecvData(dsock, &buf, hook)) < 0) - err(EX_OSERR, "reading hook \"%s\"", hook); - if (rl == 0) - errx(EX_OSERR, "EOF from hook \"%s\"?", hook); - - /* Write packet to stdout */ - printf("Rec'd data packet on hook \"%s\":\n", hook); - DumpAscii(buf, rl); - free(buf); - } + ReadSockets(rfds); /* Get any user input */ if (FD_ISSET(0, &rfds)) { @@ -282,6 +387,36 @@ DoInteractive(void) } return (CMDRTN_QUIT); } +#endif /* !EDITLINE */ + +/* + * Read and process data on netgraph control and data sockets. + */ +static void +ReadSockets(fd_set rfds) +{ + /* Display any incoming control message. */ + if (FD_ISSET(csock, &rfds)) + MsgRead(); + + /* Display any incoming data packet. */ + if (FD_ISSET(dsock, &rfds)) { + char hook[NG_HOOKSIZ]; + u_char *buf; + int rl; + + /* Read packet from socket. */ + if ((rl = NgAllocRecvData(dsock, &buf, hook)) < 0) + err(EX_OSERR, "reading hook \"%s\"", hook); + if (rl == 0) + errx(EX_OSERR, "EOF from hook \"%s\"?", hook); + + /* Write packet to stdout. */ + printf("Rec'd data packet on hook \"%s\":\n", hook); + DumpAscii(buf, rl); + free(buf); + } +} /* * Parse a command line and execute the command |
