#include #include #include #include #include #include #include #include extern const char *__progname; #include "nf.h" #include "pollloop.h" #include "scm-rights.h" #include "cli.h" static int cfd; static int dfd; static unsigned char *msg; static int msgspace; static int delayfd; static int delayid; static int prompting; static int pendprompt; static void write_prompt(void) { write(1,"sim> ",5); } static void fire_delayed_reprint(void *arg __attribute__((__unused__))) { struct termios tio; remove_poll_id(delayid); close(delayfd); delayfd = -1; delayid = PL_NOID; if (pendprompt) { pendprompt = 0; write_prompt(); prompting = 1; } if (tcgetattr(0,&tio) == 0) { tio.c_lflag |= PENDIN; tcsetattr(0,TCSADRAIN|TCSASOFT,&tio); } } static void delayed_reprint(void) { struct itimerval itv; if (delayid != PL_NOID) { close(delayfd); remove_poll_id(delayid); } delayfd = socket(AF_TIMER,SOCK_STREAM,0); itv.it_value.tv_sec = 0; itv.it_value.tv_usec = 100000; itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 0; write(delayfd,&itv,sizeof(itv)); delayid = add_poll_fd(delayfd,&rwtest_always,&rwtest_never,&fire_delayed_reprint,0,0); } static void rd_cli_parent(void *arg __attribute__((__unused__))) { int rv; rv = recv(cfd,msg,msgspace,0); if (rv < 0) { fprintf(stderr,"%s: cli recvmsg: %s\n",__progname,strerror(errno)); exit(0); } if (rv == 0) { fprintf(stderr,"%s: cli empty message\n",__progname); exit(0); } switch (msg[0]) { case CLIMSG_BUFSIZE: if (rv != sizeof(int)+1) { fprintf(stderr,"%s: cli BUFSIZE msg size (%d) wrong (not %d)\n",__progname,rv,(int)sizeof(int)+1); exit(0); } bcopy(msg,&rv,sizeof(int)); if (rv > msgspace) { free(msg); msgspace = rv; msg = malloc(msgspace); } break; case CLIMSG_TEXT: if (prompting) { write(1,"\n",1); prompting = 0; pendprompt = 1; } write(1,msg+1,rv-1); delayed_reprint(); break; case CLIMSG_PROMPT: if (delayid != PL_NOID) { pendprompt = 1; } else { write_prompt(); prompting = 1; } break; default: fprintf(stderr,"%s: cli bad msg type %02x\n",__progname,msg[0]); exit(0); break; } } static void rd_cli_death(void *arg __attribute__((__unused__))) { fprintf(stderr,"%s: cli: parent death pipe readable\n",__progname); exit(0); } static void rd_cli_stdin(void *arg __attribute__((__unused__))) { unsigned char buf[8192]; int len; int msglen; unsigned char pref; struct iovec iov[2]; struct msghdr mh; len = read(0,&buf[0],sizeof(buf)); if (len < 0) { fprintf(stderr,"%s: cli: stdin read: %s\n",__progname,strerror(errno)); exit(0); } if (len == 0) { fprintf(stderr,"%s: cli: stdin EOF\n",__progname); exit(0); } if (buf[len-1] == '\n') len --; if (len < 1) { write_prompt(); return; } msglen = len + 1; pref = CLIMSG_BUFSIZE; iov[0].iov_base = &pref; iov[0].iov_len = 1; iov[1].iov_base = &msglen; iov[1].iov_len = sizeof(int); mh.msg_name = 0; mh.msg_namelen = 0; mh.msg_iov = &iov[0]; mh.msg_iovlen = 2; mh.msg_control = 0; mh.msg_controllen = 0; mh.msg_flags = 0; nf_sendmsg(cfd,&mh,0); pref = CLIMSG_TEXT; iov[0].iov_base = &pref; iov[0].iov_len = 1; iov[1].iov_base = &buf[0]; iov[1].iov_len = len; mh.msg_name = 0; mh.msg_namelen = 0; mh.msg_iov = &iov[0]; mh.msg_iovlen = 2; mh.msg_control = 0; mh.msg_controllen = 0; mh.msg_flags = 0; nf_sendmsg(cfd,&mh,0); prompting = 0; } void cli_main(int cfdarg, int dfdarg) { cfd = cfdarg; dfd = dfdarg; setproctitle("cli"); msgspace = sizeof(int) + 1; msg = malloc(msgspace); delayfd = -1; delayid = PL_NOID; prompting = 0; pendprompt = 0; init_polling(); add_poll_fd(cfd,&rwtest_always,&rwtest_never,&rd_cli_parent,0,0); add_poll_fd(dfd,&rwtest_always,&rwtest_never,&rd_cli_death,0,0); add_poll_fd(0,&rwtest_always,&rwtest_never,&rd_cli_stdin,0,0); poll_run(); _exit(0); }