Annotation of libaitcli/src/aitcli.c, revision 1.2.2.2
1.1 misho 1: /*************************************************************************
2: * (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
3: * by Michael Pounov <misho@openbsd-bg.org>
4: *
5: * $Author: misho $
1.2.2.2 ! misho 6: * $Id: aitcli.c,v 1.2.2.1 2010/06/04 11:46:40 misho Exp $
1.1 misho 7: *
8: *************************************************************************/
9: #include "global.h"
10:
11:
12: #pragma GCC visibility push(hidden)
13:
1.2.2.2 ! misho 14: /*
! 15: commands_t cli_stdCmds[] = {
1.1 misho 16: { "test", cli_Cmd_Unsupported, "Test - Don`t use default command structure!", "test <cr>", cli_Comp_Filename },
17: { "-------", NULL, "---------------------", NULL, NULL },
18: { "help", cli_Cmd_Help, "Help screen", "help [command] <cr>", NULL },
19: { "exit", cli_Cmd_Exit, "Exit from console", "exit <cr>", NULL },
20: { NULL, NULL, NULL, NULL }
21: };
1.2.2.2 ! misho 22: */
1.1 misho 23:
24: // ------------------------------------------------
25:
26: int cli_Errno;
27: char cli_Error[STRSIZ];
28:
29: #pragma GCC visibility pop
30:
31: // cli_GetErrno() Get error code of last operation
1.2.2.2 ! misho 32: inline int
! 33: cli_GetErrno()
1.1 misho 34: {
35: return cli_Errno;
36: }
37:
38: // io_GetError() Get error text of last operation
1.2.2.2 ! misho 39: inline const char *
! 40: cli_GetError()
1.1 misho 41: {
42: return cli_Error;
43: }
44:
45: // cli_SetErr() Set error to variables for internal use!!!
1.2.2.2 ! misho 46: inline void
! 47: cli_SetErr(int eno, char *estr, ...)
1.1 misho 48: {
49: va_list lst;
50:
51: cli_Errno = eno;
52: memset(cli_Error, 0, STRSIZ);
53: va_start(lst, estr);
54: vsnprintf(cli_Error, STRSIZ, estr, lst);
55: va_end(lst);
56: }
57:
58: // ------------------------------------------------------------
59:
1.2.2.2 ! misho 60: static inline void
! 61: clrscrEOL(linebuffer_t * __restrict buf)
1.1 misho 62: {
1.2.2.2 ! misho 63: register int i;
1.1 misho 64:
1.2.2.2 ! misho 65: if (buf) {
! 66: write(buf->line_out, K_CR, 1);
1.1 misho 67:
1.2.2.2 ! misho 68: for (i = 0; i < buf->line_len; i++)
! 69: write(buf->line_out, K_SPACE, 1);
! 70: }
1.1 misho 71: }
72:
1.2.2.2 ! misho 73: static inline void
! 74: printfEOL(linebuffer_t * __restrict buf, int len, int prompt)
1.2 misho 75: {
1.2.2.2 ! misho 76: if (buf) {
! 77: write(buf->line_out, K_CR, 1);
1.2 misho 78:
1.2.2.2 ! misho 79: if (prompt && buf->line_prompt)
! 80: write(buf->line_out, buf->line_prompt, buf->line_bol);
1.2 misho 81:
1.2.2.2 ! misho 82: write(buf->line_out, buf->line_buf, len == -1 ? buf->line_eol - buf->line_bol: len);
! 83: }
1.2 misho 84: }
85:
1.2.2.2 ! misho 86: static inline void
! 87: printfCR(linebuffer_t * __restrict buf, int prompt)
1.2 misho 88: {
1.2.2.2 ! misho 89: if (buf) {
! 90: write(buf->line_out, K_CR, 1);
! 91:
! 92: if (prompt)
! 93: if (prompt && buf->line_prompt)
! 94: write(buf->line_out, buf->line_prompt, buf->line_bol);
! 95: }
1.2 misho 96: }
97:
1.2.2.2 ! misho 98: static inline void
! 99: printfCLI(linebuffer_t * __restrict buf, const unsigned char *text, int textlen, int prompt)
1.2 misho 100: {
1.2.2.2 ! misho 101: if (buf && text && textlen) {
! 102: if (prompt && buf->line_prompt)
! 103: write(buf->line_out, buf->line_prompt, buf->line_bol);
1.2 misho 104:
1.2.2.2 ! misho 105: write(buf->line_out, text, textlen);
! 106: }
1.2 misho 107: }
108:
1.2.2.2 ! misho 109: // ------------------------------------------------------------
! 110:
1.2 misho 111: /*
112: * cliNetInit() Initialize Readline if CLI bind to socket
113: * @csProg = program name
114: * @pty = Master pty
115: * @term = stdin termios
116: * return: none
117: */
1.2.2.2 ! misho 118: /*
1.2 misho 119: void cliNetInit(const char *csProg, int pty, struct termios *term)
120: {
121: struct termios t;
122: int on = 1;
123:
124: memset(&t, 0, sizeof t);
125: if (term)
126: t = *term;
127: else {
128: t.c_lflag = TTYDEF_LFLAG;
129: t.c_iflag = TTYDEF_IFLAG;
130: t.c_oflag = TTYDEF_OFLAG;
131: t.c_cflag = TTYDEF_CFLAG;
132: cfsetspeed(&t, B9600);
133: }
134:
135: t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO | ECHOCTL | ECHOE | ECHOK | ECHOKE | ECHONL | ECHOPRT);
136: // t.c_iflag &= ~(ICRNL | BRKINT | INPCK | ISTRIP | IXON);
137: t.c_iflag &= ~ICRNL;
138: t.c_iflag |= IGNBRK;
139: t.c_cc[VMIN] = 1;
140: t.c_cc[VTIME] = 0;
141: tcsetattr(pty, TCSANOW, &t);
142:
143: ioctl(pty, TIOCPKT, &on);
144:
145: rl_readline_name = csProg;
146: rl_variable_bind("editing-mode", "emacs");
147:
148: rl_instream = fdopen(pty, "r");
149: rl_outstream = NULL;
150: }
1.2.2.2 ! misho 151: */
1.2 misho 152: /*
153: * cliNetExec() Execute net CLI main loop
154: * @cmdList = Commands list
155: * @csPrompt = Prompt text
156: * @sock = client socket
157: * @term = stdin termios
158: * @win = window size of tty
159: * return: -1 error, 0 = exit w/^+D, 1 done.
160: */
1.2.2.1 misho 161: int
1.2.2.2 ! misho 162: cliNetExec(commands_t *cmdList, const char *csPrompt, int sock, struct termios *term, struct winsize *win)
1.2 misho 163: {
164: int pty, ret = 0, r, s, alen, attrlen, flg;
165: fd_set fds;
166: struct timeval tv = { DEFAULT_SOCK_TIMEOUT, 0 };
167: u_char buf[BUFSIZ];
168: struct telnetAttrs *a, Attr[10];
169:
170: switch (forkpty(&pty, NULL, term, win)) {
171: case -1:
172: LOGERR;
173: return -1;
174: case 0:
175: close(sock);
176:
177: ret = cliExec(cmdList, csPrompt) < 0 ? 1 : 0;
178: /* spawn Shell mode */
179: /*
180: execl("/bin/tcsh", "tcsh", NULL);
181: */
182: _exit(ret);
183: default:
184: /* spawn Shell mode */
185: telnet_SetCmd(Attr + 0, DO, TELOPT_TTYPE);
186: telnet_SetCmd(Attr + 1, WILL, TELOPT_ECHO);
187: telnet_Set_SubOpt(Attr + 2, TELOPT_LFLOW, LFLOW_OFF, NULL, 0);
188: telnet_Set_SubOpt(Attr + 3, TELOPT_LFLOW, LFLOW_RESTART_XON, NULL, 0);
189: telnet_SetCmd(Attr + 4, DO, TELOPT_LINEMODE);
190: if ((ret = telnetSend(sock, Attr, 5, NULL, 0, 0)) == -1) {
191: cli_Errno = telnet_GetErrno();
192: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
193: return -1;
194: } else
195: flg = 0;
196:
197: while (42) {
198: FD_ZERO(&fds);
199: FD_SET(sock, &fds);
200: FD_SET(pty, &fds);
201: if ((ret = select(FD_SETSIZE, &fds, NULL, NULL, &tv)) < 1) {
202: if (!ret)
203: cli_SetErr(ETIMEDOUT, "Client session timeout ...");
204:
205: break;
206: }
207:
208: r = FD_ISSET(sock, &fds) ? sock : pty;
209: s = FD_ISSET(sock, &fds) ? pty : sock;
210:
211: if ((ret = telnetRecv(r, &a, &alen, buf, BUFSIZ)) < 0) {
212: if (a)
213: free(a);
214:
215: if (-2 == ret)
216: continue;
217: // EOF
218: if (-3 == ret)
219: shutdown(r, SHUT_RD);
220: else {
221: cli_Errno = telnet_GetErrno();
222: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
223: }
224: break;
225: }
226: attrlen = 0;
227: if (1 == flg && alen) {
228: telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_SGA);
229: telnet_SetCmd(&Attr[attrlen++], DO, TELOPT_ECHO);
230: }
231: if (2 == flg && alen) {
232: telnet_SetCmd(&Attr[attrlen++], WILL, TELOPT_ECHO);
233: telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW,
234: LFLOW_OFF, NULL, 0);
235: telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW,
236: LFLOW_RESTART_XON, NULL, 0);
237: telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_LINEMODE);
238: }
239: if (a)
240: free(a);
241:
242: if ((ret = telnetSend(s, Attr, pty == s ? 0 : attrlen, buf, ret, 0)) == -1) {
243: cli_Errno = telnet_GetErrno();
244: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
245: break;
246: } else
247: flg++;
248: }
249:
250: close(pty);
251: }
252:
253: return ret;
254: }
255:
256: /*
1.1 misho 257: * cliExec() Execute CLI main loop
258: * @cmdList = Commands list
259: * @csPrompt = Prompt text
260: * return: -1 error, 0 = exit w/^+D, 1 done.
261: */
1.2.2.2 ! misho 262: /*
1.2 misho 263: int cliExec(cliCommands_t *cmdList, const char *csPrompt)
1.1 misho 264: {
265: char *line, *s, *t, **app, *items[MAX_PROMPT_ITEMS];
266: int ret = 0;
267: register int i;
268: cliCommands_t *cmd = NULL;
1.2 misho 269: FILE *out;
1.1 misho 270:
271: inline int inline_help()
272: {
273: cli_Cmd_Help(cmdList ? cmdList : cli_stdCmds, -1, out, NULL);
274: rl_on_new_line();
275: return 0;
276: }
277:
278: char **cli_stdCompletion(const char *text, int start, int end)
279: {
280: register int i;
281: char **matches = NULL;
282:
283: char *cmdCompGet(const char *text, int state)
284: {
285: int len = strlen(text);
286:
287: for (i = state; cmdList[i].cmd_name; i++) {
288: if (strncmp(cmdList[i].cmd_name, "---", 3) &&
289: !strncmp(cmdList[i].cmd_name, text, len))
290: return strdup(cmdList[i].cmd_name);
291: }
292:
293: return NULL;
294: }
295:
296: if (!start)
297: matches = rl_completion_matches(text, cmdCompGet);
298: else
299: for (i = 0; cmdList[i].cmd_name; i++) {
300: if (!cmdList[i].cmd_comp)
301: continue;
302: if (!strncmp(rl_line_buffer, cmdList[i].cmd_name, strlen(cmdList[i].cmd_name)))
303: matches = rl_completion_matches(text, cmdList[i].cmd_comp);
304: }
305:
306: return matches;
307: }
308: char *cli_stdCompEntry(const char *ignore, int invoking_key)
309: {
310: return NULL;
311: }
1.2.2.2 ! misho 312: */
1.1 misho 313: /* --- main body of CLI --- */
1.2.2.2 ! misho 314: /*
1.2 misho 315: out = rl_outstream;
316: if (!out)
317: out = stdout;
318:
1.1 misho 319: rl_bind_key('?', inline_help);
320: if (!rl_attempted_completion_function)
321: cliComp(cli_stdCompletion, cli_stdCompEntry);
322:
323: do {
324: line = readline(csPrompt);
325: if (!line) { // ^+d
326: cli_Printf(out, "\n");
327: break;
328: }
329: // clear whitespaces
330: for (s = line; isspace(*s); s++);
331: if (*s) {
332: for (t = s + strlen(s) - 1; t > s && isspace(*t); t--);
333: *++t = 0;
334: }
335:
336: if (*s) {
337: add_history(s);
338:
339: memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
340: for (app = items; app < items + MAX_PROMPT_ITEMS - 1 && (*app = strsep(&s, " \t"));
341: *app ? app++ : app);
342:
343: // exec_cmd ...
344: for (cmd = NULL, i = 0; cmdList[i].cmd_name; i++)
345: if (*items[0] && !strncmp(cmdList[i].cmd_name, items[0], strlen(items[0]))) {
346: cmd = &cmdList[i];
347: break;
348: }
349: if (!cmd) {
350: cli_Printf(out, "Command '%s' not found!\n", items[0]);
351: ret = -1;
352: } else
353: ret = cmd->cmd_func(cmdList, i, out, items);
354: }
355:
356: free(line);
357: } while (ret < 1);
358:
359: return ret;
360: }
1.2.2.2 ! misho 361: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>