#include <sys/cdefs.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sysexits.h>
#include <errno.h>
#include <err.h>
#include <stringlist.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netgraph.h>
#define DEFAULT_HOOKNAME "debug"
#define NG_SOCK_HOOK_NAME "hook"
#define BUF_SIZE (64 * 1024)
static void WriteAscii(u_char * buf, int len);
static void Usage(void);
static void send_msgs(int, const char *);
static int outfd = STDOUT_FILENO;
static int infd = STDIN_FILENO;
static StringList *msgs;
int
main(int ac, char *av[])
{
struct ngm_connect ngc;
const char *path = NULL;
const char *hook = DEFAULT_HOOKNAME;
int csock, dsock;
int asciiFlag = 0;
int loopFlag = 0;
int noInput = 0;
int execFlag = 0;
int ch;
if ((msgs = sl_init()) == NULL)
err(EX_OSERR, NULL);
while ((ch = getopt(ac, av, "aedlm:nsS")) != -1) {
switch (ch) {
case 'a':
asciiFlag = 1;
break;
case 'd':
NgSetDebug(NgSetDebug(-1) + 1);
break;
case 'e':
execFlag = 1;
break;
case 'l':
loopFlag = 1;
break;
case 'n':
noInput = 1;
break;
case 'm':
if (sl_add(msgs, optarg) == -1)
err(EX_OSERR, NULL);
break;
case 's':
outfd = STDIN_FILENO;
break;
case 'S':
infd = STDOUT_FILENO;
break;
case '?':
default:
Usage();
}
}
ac -= optind;
av += optind;
if (execFlag) {
if (asciiFlag || loopFlag) {
fprintf(stderr, "conflicting options\n");
Usage();
}
if (ac < 3)
Usage();
path = av[0];
hook = av[1];
av += 2;
ac -= 2;
} else {
switch (ac) {
case 2:
hook = av[1];
case 1:
path = av[0];
break;
default:
Usage();
}
}
if (NgMkSockNode(NULL, &csock, &dsock) < 0)
errx(EX_OSERR, "can't get sockets");
snprintf(ngc.path, sizeof(ngc.path), "%s", path);
snprintf(ngc.ourhook, sizeof(ngc.ourhook), NG_SOCK_HOOK_NAME);
snprintf(ngc.peerhook, sizeof(ngc.peerhook), "%s", hook);
if (NgSendMsg(csock, ".",
NGM_GENERIC_COOKIE, NGM_CONNECT, &ngc, sizeof(ngc)) < 0)
errx(EX_OSERR, "can't connect to node");
if (execFlag) {
(void)close(0);
(void)close(1);
if (!noInput)
(void)dup2(dsock, 0);
(void)dup2(dsock, 1);
send_msgs(csock, path);
(void)execv(av[0], av);
err(EX_OSERR, "%s", av[0]);
} else
send_msgs(csock, path);
if (noInput)
fclose(stdin);
while (1) {
fd_set rfds;
FD_ZERO(&rfds);
if (!noInput)
FD_SET(infd, &rfds);
FD_SET(dsock, &rfds);
if (select(FD_SETSIZE, &rfds, NULL, NULL, NULL) < 0)
err(EX_OSERR, "select");
if (FD_ISSET(dsock, &rfds)) {
char buf[BUF_SIZE];
int rl, wl;
if ((rl = NgRecvData(dsock,
buf, sizeof(buf), NULL)) < 0)
err(EX_OSERR, "read(hook)");
if (rl == 0)
errx(EX_OSERR, "read EOF from hook?!");
if (asciiFlag)
WriteAscii((u_char *) buf, rl);
else if ((wl = write(outfd, buf, rl)) != rl) {
if (wl < 0) {
err(EX_OSERR, "write(stdout)");
} else {
errx(EX_OSERR,
"stdout: read %d, wrote %d",
rl, wl);
}
}
if (loopFlag) {
if (NgSendData(dsock, NG_SOCK_HOOK_NAME, buf, rl) < 0)
err(EX_OSERR, "write(hook)");
}
}
if (FD_ISSET(infd, &rfds)) {
char buf[BUF_SIZE];
int rl;
if ((rl = read(infd, buf, sizeof(buf))) < 0)
err(EX_OSERR, "read(stdin)");
if (rl == 0)
errx(EX_OSERR, "EOF(stdin)");
if (NgSendData(dsock, NG_SOCK_HOOK_NAME, buf, rl) < 0)
err(EX_OSERR, "write(hook)");
}
}
}
static void
WriteAscii(u_char *buf, int len)
{
char ch, sbuf[100];
int k, count;
for (count = 0; count < len; count += 16) {
snprintf(sbuf, sizeof(sbuf), "%04x: ", count);
for (k = 0; k < 16; k++)
if (count + k < len)
snprintf(sbuf + strlen(sbuf),
sizeof(sbuf) - strlen(sbuf),
"%02x ", buf[count + k]);
else
snprintf(sbuf + strlen(sbuf),
sizeof(sbuf) - strlen(sbuf), " ");
snprintf(sbuf + strlen(sbuf), sizeof(sbuf) - strlen(sbuf), " ");
for (k = 0; k < 16; k++)
if (count + k < len) {
ch = isprint(buf[count + k]) ?
buf[count + k] : '.';
snprintf(sbuf + strlen(sbuf),
sizeof(sbuf) - strlen(sbuf), "%c", ch);
} else
snprintf(sbuf + strlen(sbuf),
sizeof(sbuf) - strlen(sbuf), " ");
snprintf(sbuf + strlen(sbuf),
sizeof(sbuf) - strlen(sbuf), "\n");
(void) write(outfd, sbuf, strlen(sbuf));
}
ch = '\n';
write(outfd, &ch, 1);
}
static void
Usage(void)
{
fprintf(stderr, "usage: nghook [-adlnsS] path [hookname]\n");
fprintf(stderr, " or: nghook -e [-n] [-m msg]* path hookname prog "
"[args...]\n");
exit(EX_USAGE);
}
static void
send_msgs(int cs, const char *path)
{
u_int i;
for (i = 0; i < msgs->sl_cur; i++)
if (NgSendAsciiMsg(cs, path, "%s", msgs->sl_str[i]) == -1)
err(EX_OSERR, "sending message '%s'", msgs->sl_str[i]);
}