aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/ngctl
diff options
context:
space:
mode:
authorGleb Smirnoff <glebius@FreeBSD.org>2006-08-07 14:17:05 +0000
committerGleb Smirnoff <glebius@FreeBSD.org>2006-08-07 14:17:05 +0000
commitb9124a7354fdd7142c710c12859b062650e1da5b (patch)
tree2fd49f9603f6c85e9baca7a80426824c76d60251 /usr.sbin/ngctl
parent42787b76b669e547324cc3923a3c09a0e9510f79 (diff)
Notes
Diffstat (limited to 'usr.sbin/ngctl')
-rw-r--r--usr.sbin/ngctl/Makefile11
-rw-r--r--usr.sbin/ngctl/main.c179
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