Annotation of libaitcli/src/aitcli.c, revision 1.2.2.14
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.14! misho 6: * $Id: aitcli.c,v 1.2.2.13 2010/06/07 23:38:39 misho Exp $
1.1 misho 7: *
8: *************************************************************************/
9: #include "global.h"
1.2.2.7 misho 10: #include "cli.h"
1.1 misho 11:
12:
13: #pragma GCC visibility push(hidden)
14:
15: // ------------------------------------------------
16:
17: int cli_Errno;
18: char cli_Error[STRSIZ];
19:
20: #pragma GCC visibility pop
21:
22: // cli_GetErrno() Get error code of last operation
1.2.2.2 misho 23: inline int
24: cli_GetErrno()
1.1 misho 25: {
26: return cli_Errno;
27: }
28:
29: // io_GetError() Get error text of last operation
1.2.2.2 misho 30: inline const char *
31: cli_GetError()
1.1 misho 32: {
33: return cli_Error;
34: }
35:
36: // cli_SetErr() Set error to variables for internal use!!!
1.2.2.2 misho 37: inline void
38: cli_SetErr(int eno, char *estr, ...)
1.1 misho 39: {
40: va_list lst;
41:
42: cli_Errno = eno;
43: memset(cli_Error, 0, STRSIZ);
44: va_start(lst, estr);
45: vsnprintf(cli_Error, STRSIZ, estr, lst);
46: va_end(lst);
47: }
48:
49: // ------------------------------------------------------------
50:
1.2.2.2 misho 51: static inline void
52: clrscrEOL(linebuffer_t * __restrict buf)
1.1 misho 53: {
1.2.2.2 misho 54: register int i;
1.1 misho 55:
1.2.2.2 misho 56: if (buf) {
57: write(buf->line_out, K_CR, 1);
1.1 misho 58:
1.2.2.2 misho 59: for (i = 0; i < buf->line_len; i++)
60: write(buf->line_out, K_SPACE, 1);
61: }
1.1 misho 62: }
63:
1.2.2.2 misho 64: static inline void
65: printfEOL(linebuffer_t * __restrict buf, int len, int prompt)
1.2 misho 66: {
1.2.2.2 misho 67: if (buf) {
68: write(buf->line_out, K_CR, 1);
1.2 misho 69:
1.2.2.2 misho 70: if (prompt && buf->line_prompt)
71: write(buf->line_out, buf->line_prompt, buf->line_bol);
1.2 misho 72:
1.2.2.2 misho 73: write(buf->line_out, buf->line_buf, len == -1 ? buf->line_eol - buf->line_bol: len);
74: }
1.2 misho 75: }
76:
1.2.2.2 misho 77: static inline void
78: printfCR(linebuffer_t * __restrict buf, int prompt)
1.2 misho 79: {
1.2.2.2 misho 80: if (buf) {
81: write(buf->line_out, K_CR, 1);
82:
83: if (prompt)
84: if (prompt && buf->line_prompt)
85: write(buf->line_out, buf->line_prompt, buf->line_bol);
86: }
1.2 misho 87: }
88:
1.2.2.2 misho 89: static inline void
1.2.2.4 misho 90: printfNL(linebuffer_t * __restrict buf, int prompt)
91: {
92: if (buf) {
93: write(buf->line_out, K_ENTER, 1);
94:
95: if (prompt)
96: if (prompt && buf->line_prompt)
97: write(buf->line_out, buf->line_prompt, buf->line_bol);
98: }
99: }
100:
1.2.2.2 misho 101: // ------------------------------------------------------------
102:
1.2.2.3 misho 103: static int
104: bufCHAR(int idx, void * __restrict buffer)
105: {
106: linebuffer_t *buf = buffer;
107: int pos;
108:
109: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
110: return RETCODE_ERR;
111:
112: pos = buf->line_eol - buf->line_bol;
113:
114: if (buf->line_mode == LINEMODE_INS)
115: memmove(buf->line_buf + pos + buf->line_keys[idx].key_len, buf->line_buf + pos,
116: buf->line_len - buf->line_eol);
117: if (buf->line_mode == LINEMODE_INS || buf->line_eol == buf->line_len - 1)
118: buf->line_len += buf->line_keys[idx].key_len;
119: buf->line_eol += buf->line_keys[idx].key_len;
120:
121: memcpy(buf->line_buf + pos, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
122: buf->line_buf[buf->line_len - 1] = 0;
123:
124: write(buf->line_out, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
125:
126: if (buf->line_mode == LINEMODE_INS) {
1.2.2.12 misho 127: write(buf->line_out, (const u_char*) buf->line_buf + pos + buf->line_keys[idx].key_len,
128: buf->line_len - buf->line_eol);
1.2.2.3 misho 129: printfEOL(buf, -1, 1);
130: }
131: return RETCODE_OK;
132: }
133:
134: static int
135: bufEOL(int idx, void * __restrict buffer)
136: {
137: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
138: return RETCODE_ERR;
139:
140: printfCR(buffer, 1);
141: return RETCODE_EOL;
142: }
143:
144: static int
145: bufEOF(int idx, void * __restrict buffer)
146: {
1.2.2.12 misho 147: /*
1.2.2.3 misho 148: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
149: return RETCODE_ERR;
1.2.2.12 misho 150: */
1.2.2.3 misho 151:
152: return RETCODE_EOF;
153: }
154:
155: static int
156: bufUP(int idx, void * __restrict buffer)
157: {
158: linebuffer_t *buf = buffer;
159: int pos;
160:
161: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
162: return RETCODE_ERR;
163:
164: if (!buf->line_h)
165: buf->line_h = TAILQ_FIRST(&buf->line_history);
166: else
167: buf->line_h = TAILQ_NEXT(buf->line_h, hist_next);
168: if (!buf->line_h)
169: return RETCODE_OK;
170:
171: clrscrEOL(buf);
172: cli_freeLine(buf);
173:
174: pos = buf->line_eol - buf->line_bol;
175:
176: buf->line_len += buf->line_h->hist_len;
177: buf->line_eol += buf->line_h->hist_len;
178:
179: memcpy(buf->line_buf + pos, buf->line_h->hist_line, buf->line_h->hist_len);
180: buf->line_buf[buf->line_len - 1] = 0;
181:
182: printfEOL(buf, -1, 1);
183: return RETCODE_OK;
184: }
185:
186: static int
187: bufDOWN(int idx, void * __restrict buffer)
188: {
189: linebuffer_t *buf = buffer;
190: int pos;
191:
192: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
193: return RETCODE_ERR;
194:
195: if (!buf->line_h)
196: buf->line_h = TAILQ_LAST(&buf->line_history, tqHistoryHead);
197: else
198: buf->line_h = TAILQ_PREV(buf->line_h, tqHistoryHead, hist_next);
199: if (!buf->line_h)
200: return RETCODE_OK;
201:
202: clrscrEOL(buf);
203: cli_freeLine(buf);
204:
205: pos = buf->line_eol - buf->line_bol;
206:
207: buf->line_len += buf->line_h->hist_len;
208: buf->line_eol += buf->line_h->hist_len;
209:
210: memcpy(buf->line_buf + pos, buf->line_h->hist_line, buf->line_h->hist_len);
211: buf->line_buf[buf->line_len - 1] = 0;
212:
213: printfEOL(buf, -1, 1);
214: return RETCODE_OK;
215: }
216:
217: static int
218: bufCLR(int idx, void * __restrict buffer)
219: {
220: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
221: return RETCODE_ERR;
222:
223: clrscrEOL(buffer);
224: cli_freeLine(buffer);
225:
226: printfCR(buffer, 1);
227: return RETCODE_OK;
228: }
229:
230: static int
231: bufBS(int idx, void * __restrict buffer)
232: {
233: linebuffer_t *buf = buffer;
234:
235: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
236: return RETCODE_ERR;
237:
238: if (buf->line_bol < buf->line_eol) {
239: clrscrEOL(buf);
240:
241: buf->line_eol--;
242: buf->line_len--;
243: memmove(buf->line_buf + buf->line_eol - buf->line_bol,
244: buf->line_buf + buf->line_eol - buf->line_bol + 1,
245: buf->line_len - buf->line_eol);
246: buf->line_buf[buf->line_len - 1] = 0;
247:
248: printfEOL(buf, buf->line_len - 1, 1);
249: printfEOL(buf, -1, 1);
250: }
251:
252: return RETCODE_OK;
253: }
254:
255: static int
256: bufBTAB(int idx, void * __restrict buffer)
257: {
258: linebuffer_t *buf = buffer;
259:
260: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
261: return RETCODE_ERR;
262:
263: if (buf->line_bol < buf->line_eol) {
264: clrscrEOL(buf);
265:
266: buf->line_len = buf->line_eol - buf->line_bol + 1;
267: buf->line_buf[buf->line_len - 1] = 0;
268:
269: printfEOL(buf, -1, 1);
270: }
271:
272: return RETCODE_OK;
273: }
274:
275: static int
276: bufMODE(int idx, void * __restrict buffer)
277: {
278: linebuffer_t *buf = buffer;
279:
280: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
281: return RETCODE_ERR;
282:
283: buf->line_mode = !buf->line_mode ? LINEMODE_OVER : LINEMODE_INS;
284: return RETCODE_OK;
285: }
286:
287: static int
288: bufBEGIN(int idx, void * __restrict buffer)
289: {
290: linebuffer_t *buf = buffer;
291:
292: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
293: return RETCODE_ERR;
294:
295: buf->line_eol = buf->line_bol;
296:
297: printfCR(buf, 1);
298: return RETCODE_OK;
299: }
300:
301: static int
302: bufEND(int idx, void * __restrict buffer)
303: {
304: linebuffer_t *buf = buffer;
305:
306: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
307: return RETCODE_ERR;
308:
309: buf->line_eol = buf->line_len - 1;
310:
311: printfEOL(buf, -1, 1);
312: return RETCODE_OK;
313: }
314:
315: static int
316: bufLEFT(int idx, void * __restrict buffer)
317: {
318: linebuffer_t *buf = buffer;
319:
320: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
321: return RETCODE_ERR;
322:
323: if (buf->line_bol < buf->line_eol)
324: printfEOL(buf, --buf->line_eol - buf->line_bol, 1);
325:
326: return RETCODE_OK;
327: }
328:
329: static int
330: bufRIGHT(int idx, void * __restrict buffer)
331: {
332: linebuffer_t *buf = buffer;
333:
334: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
335: return RETCODE_ERR;
336:
337: if (buf->line_eol < buf->line_len - 1)
338: printfEOL(buf, ++buf->line_eol - buf->line_bol, 1);
339:
340: return RETCODE_OK;
341: }
342:
343: static int
344: bufDEL(int idx, void * __restrict buffer)
345: {
346: linebuffer_t *buf = buffer;
347:
348: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
349: return RETCODE_ERR;
350:
351: clrscrEOL(buf);
352:
353: buf->line_len--;
354: memmove(buf->line_buf + buf->line_eol - buf->line_bol,
355: buf->line_buf + buf->line_eol - buf->line_bol + 1,
356: buf->line_len - buf->line_eol);
357: buf->line_buf[buf->line_len - 1] = 0;
358:
359: printfEOL(buf, buf->line_len - 1, 1);
360: printfEOL(buf, -1, 1);
361:
362: return RETCODE_OK;
363: }
364:
1.2.2.8 misho 365: static int
366: bufComp(int idx, void * __restrict buffer)
367: {
368: linebuffer_t *buf = buffer;
1.2.2.12 misho 369: char *str, *s, **app, *items[MAX_PROMPT_ITEMS], szLine[STRSIZ];
370: register int i, j;
371: struct tagCommand *cmd, *c;
372: int pos, ret = RETCODE_OK;
1.2.2.8 misho 373:
374: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
375: return RETCODE_ERR;
376:
1.2.2.9 misho 377: str = strdup(buf->line_buf);
378: if (!str)
379: return RETCODE_ERR;
380: else {
381: s = str;
382: io_TrimStr((u_char*) s);
383: }
384:
1.2.2.12 misho 385: i = j = 0;
386: c = NULL;
387: memset(szLine, 0, STRSIZ);
1.2.2.9 misho 388: if (*s) {
389: memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
390: for (app = items, i = 0; app < items + MAX_PROMPT_ITEMS - 1 && (*app = strsep(&s, " \t"));
391: *app ? i++ : i, *app ? app++ : app);
392:
1.2.2.12 misho 393: if (i) {
394: SLIST_FOREACH(cmd, &buf->line_cmds, cmd_next)
395: if (cmd->cmd_level == buf->line_level &&
396: !strncmp(cmd->cmd_name, items[0], strlen(items[0]))) {
397: j++;
398: c = cmd;
399: strlcat(szLine, " ", STRSIZ);
400: strlcat(szLine, cmd->cmd_name, STRSIZ);
401: }
402:
1.2.2.13 misho 403: if (i > 1 && c) {
404: /* we are on argument of command and has complition info */
405: j++; // always must be j > 1 ;) for arguments
406: strlcpy(szLine, c->cmd_info, STRSIZ);
1.2.2.12 misho 407: }
408: } else {
409: /* we have valid char but i == 0, this case is illegal */
410: ret = RETCODE_ERR;
411: goto endcomp;
412: }
413: } else {
414: /* we on 0 position of prompt, show commands for this level */
415: SLIST_FOREACH(cmd, &buf->line_cmds, cmd_next) {
416: if (cmd->cmd_level == buf->line_level)
417: j++;
418: c = cmd;
419: strlcat(szLine, " ", STRSIZ);
420: strlcat(szLine, cmd->cmd_name, STRSIZ);
421: }
422: }
423:
424: /* completion show actions ... */
425: if (j > 1 && c) {
426: printfNL(buf, 0);
427: write(buf->line_out, szLine, strlen(szLine));
428: printfNL(buf, 1);
1.2.2.13 misho 429: printfEOL(buf, buf->line_len - 1, 1);
430: printfEOL(buf, -1, 1);
1.2.2.12 misho 431: }
432: if (j == 1 && c) {
433: clrscrEOL(buf);
434: cli_freeLine(buf);
435:
436: pos = buf->line_eol - buf->line_bol;
437:
438: buf->line_len += c->cmd_len + 1;
439: buf->line_eol += c->cmd_len + 1;
440:
441: memcpy(buf->line_buf + pos, c->cmd_name, c->cmd_len);
442: buf->line_buf[pos + c->cmd_len] = (u_char) *K_SPACE;
443: buf->line_buf[buf->line_len - 1] = 0;
444:
445: printfEOL(buf, -1, 1);
1.2.2.9 misho 446: }
447:
1.2.2.12 misho 448: endcomp:
1.2.2.9 misho 449: free(str);
1.2.2.12 misho 450: return ret;
1.2.2.8 misho 451: }
452:
453: static int
454: bufHelp(int idx, void * __restrict buffer)
455: {
456: linebuffer_t *buf = buffer;
457:
458: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
459: return RETCODE_ERR;
460:
461: cli_Cmd_Help(buf, -1, NULL);
1.2.2.13 misho 462:
463: printfEOL(buf, buf->line_len - 1, 1);
464: printfEOL(buf, -1, 1);
1.2.2.8 misho 465: return RETCODE_OK;
466: }
467:
1.2.2.3 misho 468: // ---------------------------------------------------------------
469:
470: /*
1.2.2.4 misho 471: * cli_Printf() Send message to CLI session
472: * @buffer = CLI buffer
473: * @fmt = printf format string
474: * @... = arguments defined in fmt
475: * return: none
476: */
477: inline void
478: cli_Printf(linebuffer_t * __restrict buffer, char *fmt, ...)
479: {
480: va_list lst;
481: FILE *f;
482:
483: if (fmt) {
484: f = fdopen(buffer->line_out, "a");
485: if (!f) {
486: LOGERR;
487: return;
488: }
489:
490: va_start(lst, fmt);
491: vfprintf(f, fmt, lst);
492: va_end(lst);
493: } else
494: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
495: }
496:
497: /*
1.2.2.14! misho 498: * cli_PrintHelp() Print help screen
! 499: * @buffer = CLI buffer
! 500: * return: none
! 501: */
! 502: inline void
! 503: cli_PrintHelp(linebuffer_t * __restrict buffer)
! 504: {
! 505: if (buffer)
! 506: bufHelp(0, buffer);
! 507: else
! 508: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
! 509: }
! 510:
! 511:
! 512: /*
1.2.2.3 misho 513: * cli_BindKey() Bind function to key
514: * @key = key structure
515: * @buffer = CLI buffer
516: * return: RETCODE_ERR error, RETCODE_OK ok, >0 bind at position
517: */
518: int
519: cli_BindKey(bindkey_t * __restrict key, linebuffer_t * __restrict buffer)
520: {
521: register int i;
522:
523: if (!key || !buffer) {
524: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
525: return RETCODE_ERR;
526: }
527:
528: for (i = 0; i < MAX_BINDKEY; i++)
529: if (key->key_len == buffer->line_keys[i].key_len &&
530: !memcmp(key->key_ch, buffer->line_keys[i].key_ch, key->key_len)) {
531: buffer->line_keys[i].key_func = key->key_func;
532: return i;
533: }
534:
535: return RETCODE_OK;
536: }
537:
538:
539: /*
1.2.2.6 misho 540: * cli_addCommand() Add command to CLI session
541: * @buffer = CLI buffer
542: * @csCmd = Command name
543: * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
544: * @funcCmd = Callback function when user call command
545: * @csInfo = Inline information for command
546: * @csHelp = Help line when call help
547: * return: RETCODE_ERR error, RETCODE_OK ok
548: */
549: int
550: cli_addCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel, cmd_func_t funcCmd,
1.2.2.13 misho 551: const char *csInfo, const char *csHelp)
1.2.2.6 misho 552: {
553: struct tagCommand *cmd;
554:
1.2.2.14! misho 555: if (!buffer || !csCmd) {
1.2.2.6 misho 556: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
557: return RETCODE_ERR;
558: }
559:
560: cmd = malloc(sizeof(struct tagCommand));
561: if (!cmd) {
562: LOGERR;
563: return RETCODE_ERR;
564: } else
565: memset(cmd, 0, sizeof(struct tagCommand));
566:
567: cmd->cmd_level = cliLevel;
568: cmd->cmd_func = funcCmd;
569: cmd->cmd_len = strlcpy(cmd->cmd_name, csCmd, STRSIZ);
570: if (csInfo)
571: strlcpy(cmd->cmd_info, csInfo, STRSIZ);
572: if (csHelp)
573: strlcpy(cmd->cmd_help, csHelp, STRSIZ);
574: SLIST_INSERT_HEAD(&buffer->line_cmds, cmd, cmd_next);
575: return RETCODE_OK;
576: }
577:
578: /*
579: * cli_delCommand() Delete command from CLI session
580: * @buffer = CLI buffer
581: * @csCmd = Command name
582: * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
583: * return: RETCODE_ERR error, RETCODE_OK ok
584: */
585: int
586: cli_delCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel)
587: {
588: struct tagCommand *cmd;
589: int ret = RETCODE_OK;
590:
591: if (!buffer || !csCmd) {
592: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
593: return RETCODE_ERR;
594: }
595:
596: SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next)
597: if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
598: ret = 1;
599: SLIST_REMOVE(&buffer->line_cmds, cmd, tagCommand, cmd_next);
600: free(cmd);
601: break;
602: }
603:
604: return ret;
605: }
606:
607: /*
608: * cli_updCommand() Update command in CLI session
609: * @buffer = CLI buffer
610: * @csCmd = Command name
611: * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
612: * @funcCmd = Callback function when user call command
613: * @csInfo = Inline information for command
614: * @csHelp = Help line when call help
615: * return: RETCODE_ERR error, RETCODE_OK ok
616: */
617: int
618: cli_updCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel, cmd_func_t funcCmd,
1.2.2.13 misho 619: const char *csInfo, const char *csHelp)
1.2.2.6 misho 620: {
621: struct tagCommand *cmd;
622: int ret = RETCODE_OK;
623:
624: if (!buffer || !csCmd) {
625: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
626: return RETCODE_ERR;
627: }
628:
629: SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next)
630: if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
631: ret = 1;
632:
1.2.2.13 misho 633: if (funcCmd)
1.2.2.6 misho 634: cmd->cmd_func = funcCmd;
635: if (csInfo)
636: strlcpy(cmd->cmd_info, csInfo, STRSIZ);
637: if (csHelp)
638: strlcpy(cmd->cmd_help, csHelp, STRSIZ);
639:
640: break;
641: }
642:
643: return ret;
644: }
645:
646:
647: /*
1.2.2.3 misho 648: * cli_addHistory() Add line to history
649: * @buffer = CLI buffer
1.2.2.4 misho 650: * @str = Add custom text or if NULL use readed line from CLI buffer
1.2.2.3 misho 651: * return: RETCODE_ERR error, RETCODE_OK ok
652: */
653: int
654: cli_addHistory(linebuffer_t * __restrict buffer, const char * __restrict str)
655: {
656: struct tagHistory *h;
657:
658: if (!buffer) {
659: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
660: return RETCODE_ERR;
661: }
662:
663: if (!(h = malloc(sizeof(struct tagHistory)))) {
664: LOGERR;
665: return RETCODE_ERR;
666: } else
667: memset(h, 0, sizeof(struct tagHistory));
668:
669: if (str) {
670: if (!*str) {
671: free(h);
672: return RETCODE_OK;
673: }
674:
675: h->hist_len = strlcpy(h->hist_line, str, BUFSIZ);
676: } else {
677: if (!*buffer->line_buf || buffer->line_len < 2) {
678: free(h);
679: return RETCODE_OK;
680: }
681:
682: memcpy(h->hist_line, buffer->line_buf, (h->hist_len = buffer->line_len));
683: io_TrimStr((u_char*) h->hist_line);
684: h->hist_len = strlen(h->hist_line);
685: }
686:
687: TAILQ_INSERT_HEAD(&buffer->line_history, h, hist_next);
688: return h->hist_len;
689: }
690:
691: /*
692: * cli_saveHistory() Save history to file
693: * @buffer = CLI buffer
694: * @histfile = History filename, if NULL will be use default name
695: * @lines = Maximum history lines to save
696: * return: RETCODE_ERR error, RETCODE_OK ok
697: */
698: int
699: cli_saveHistory(linebuffer_t * __restrict buffer, const char *histfile, int lines)
700: {
701: FILE *f;
702: mode_t mode;
703: char szFName[MAXPATHLEN];
704: struct tagHistory *h;
705:
706: if (!buffer) {
707: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
708: return RETCODE_ERR;
709: }
710: if (!histfile)
711: strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
712: else
713: strlcpy(szFName, histfile, MAXPATHLEN);
714:
715: mode = umask(0177);
716: f = fopen(szFName, "w");
717: if (!f) {
718: LOGERR;
719: return RETCODE_ERR;
720: }
721:
722: TAILQ_FOREACH(h, &buffer->line_history, hist_next) {
723: fprintf(f, "%s\n", h->hist_line);
724:
725: if (lines)
726: lines--;
727: else
728: break;
729: }
730:
731: fclose(f);
732: umask(mode);
733:
734: return RETCODE_OK;
735: }
736:
737: /*
738: * cli_loadHistory() Load history from file
739: * @buffer = CLI buffer
740: * @histfile = History filename, if NULL will be use default name
741: * return: RETCODE_ERR error, RETCODE_OK ok
742: */
743: int
744: cli_loadHistory(linebuffer_t * __restrict buffer, const char *histfile)
745: {
746: FILE *f;
747: char szFName[MAXPATHLEN], buf[BUFSIZ];
748: struct tagHistory *h;
749:
750: if (!buffer) {
751: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
752: return RETCODE_ERR;
753: }
754: if (!histfile)
755: strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
756: else
757: strlcpy(szFName, histfile, MAXPATHLEN);
758:
759: f = fopen(szFName, "r");
1.2.2.4 misho 760: if (!f)
761: return RETCODE_OK;
1.2.2.3 misho 762:
763: while (fgets(buf, BUFSIZ, f)) {
764: if (!*buf || *buf == '#')
765: continue;
766: else
767: io_TrimStr((u_char*) buf);
768:
769: if (!(h = malloc(sizeof(struct tagHistory)))) {
770: LOGERR;
771: fclose(f);
772: return RETCODE_ERR;
773: } else
774: memset(h, 0, sizeof(struct tagHistory));
775:
776: h->hist_len = strlcpy(h->hist_line, buf, BUFSIZ);
777: TAILQ_INSERT_TAIL(&buffer->line_history, h, hist_next);
778: }
779:
780: fclose(f);
781:
782: return RETCODE_OK;
783: }
784:
785: /*
786: * cli_resetHistory() Reset history search in CLI session
787: * @buffer = CLI buffer
788: * return: none
789: */
790: inline void
791: cli_resetHistory(linebuffer_t * __restrict buffer)
792: {
793: buffer->line_h = NULL;
794: }
795:
796:
797: /*
798: * cli_freeLine() Clear entire line
799: * @buffer = CLI buffer
800: * return: RETCODE_ERR error, RETCODE_OK ok
801: */
802: inline int
803: cli_freeLine(linebuffer_t * __restrict buffer)
804: {
805: int code = RETCODE_ERR;
806:
807: if (buffer) {
808: if (buffer->line_buf)
809: free(buffer->line_buf);
810:
811: buffer->line_buf = malloc(BUFSIZ);
812: if (buffer->line_buf) {
813: memset(buffer->line_buf, 0, BUFSIZ);
814: buffer->line_eol = buffer->line_bol;
815: buffer->line_len = 1 + buffer->line_eol;
816:
817: code = RETCODE_OK;
818: } else
819: LOGERR;
820: } else
821: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
822:
823: return code;
824: }
825:
826: /*
827: * cli_setPrompt() Set new prompt for CLI session
828: * @buffer = CLI buffer
829: * @prompt = new text for prompt or if NULL disable prompt
830: * return: none
831: */
832: inline void
833: cli_setPrompt(linebuffer_t * __restrict buffer, const char *prompt)
834: {
835: if (buffer) {
836: if (buffer->line_prompt) {
837: free(buffer->line_prompt);
838: buffer->line_prompt = NULL;
839: buffer->line_bol = 0;
840: }
841:
842: if (prompt) {
843: buffer->line_prompt = strdup(prompt);
844: if (buffer->line_prompt) {
845: buffer->line_bol = strlen(buffer->line_prompt);
846: buffer->line_eol = buffer->line_bol;
847: buffer->line_len = 1 + buffer->line_eol;
848: } else
849: LOGERR;
850: }
851: } else
852: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
853: }
854:
855:
856: /*
857: * cliEnd() Clear data, Free resources and close CLI session
858: * @buffer = CLI buffer
859: * return: RETCODE_ERR error, RETCODE_OK ok
860: */
861: void
862: cliEnd(linebuffer_t * __restrict buffer)
863: {
864: struct tagHistory *h;
1.2.2.4 misho 865: struct tagCommand *c;
1.2.2.3 misho 866:
867: if (buffer) {
1.2.2.4 misho 868: while ((c = SLIST_FIRST(&buffer->line_cmds))) {
869: SLIST_REMOVE_HEAD(&buffer->line_cmds, cmd_next);
870: free(c);
871: }
1.2.2.3 misho 872: while ((h = TAILQ_FIRST(&buffer->line_history))) {
873: TAILQ_REMOVE(&buffer->line_history, h, hist_next);
874: free(h);
875: }
876:
877: if (buffer->line_prompt)
878: free(buffer->line_prompt);
879:
880: if (buffer->line_keys)
881: free(buffer->line_keys);
882: if (buffer->line_buf)
883: free(buffer->line_buf);
884:
885: free(buffer);
886: buffer = NULL;
887: } else
888: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
889: }
890:
891: /*
892: * cliInit() Start CLI session, allocate memory for resources and bind keys
893: * @fin = Input device handle
894: * @fout = Output device handle
895: * @prompt = text for prompt, if NULL disable prompt
896: * return: NULL if error or !=NULL CLI buffer
897: */
898: linebuffer_t *
899: cliInit(int fin, int fout, const char *prompt)
900: {
901: linebuffer_t *buffer;
902: bindkey_t *keys;
903: register int i;
904: struct termios t;
905:
906: memset(&t, 0, sizeof t);
907: /* init buffer */
908: buffer = malloc(sizeof (linebuffer_t));
909: if (!buffer) {
910: LOGERR;
911: return NULL;
912: } else {
913: memset(buffer, 0, sizeof(linebuffer_t));
914:
915: buffer->line_in = fin;
916: buffer->line_out = fout;
917:
918: TAILQ_INIT(&buffer->line_history);
1.2.2.4 misho 919: SLIST_INIT(&buffer->line_cmds);
1.2.2.3 misho 920:
921: if (prompt) {
922: buffer->line_prompt = strdup(prompt);
923: if (!buffer->line_prompt) {
924: LOGERR;
925: free(buffer);
926: return NULL;
927: } else
928: buffer->line_eol = buffer->line_bol = strlen(buffer->line_prompt);
929: }
930: }
931: buffer->line_buf = malloc(BUFSIZ);
932: if (!buffer->line_buf) {
933: LOGERR;
934: if (buffer->line_prompt)
935: free(buffer->line_prompt);
936: free(buffer);
937: return NULL;
938: } else {
939: memset(buffer->line_buf, 0, BUFSIZ);
940: buffer->line_len = 1 + buffer->line_eol;
941: }
942: keys = calloc(MAX_BINDKEY + 1, sizeof(bindkey_t));
943: if (!keys) {
944: LOGERR;
945: if (buffer->line_prompt)
946: free(buffer->line_prompt);
947: free(buffer->line_buf);
948: free(buffer);
949: return NULL;
950: } else
951: memset(keys, 0, sizeof(bindkey_t) * (MAX_BINDKEY + 1));
952:
1.2.2.7 misho 953: /* add helper functions */
1.2.2.13 misho 954: cli_addCommand(buffer, "exit", 0, cli_Cmd_Exit, "exit <cr>", "Exit from console");
955: cli_addCommand(buffer, "help", 0, cli_Cmd_Help, "help [command] <cr>", "Help screen");
1.2.2.7 misho 956:
1.2.2.3 misho 957: /* fill key bindings */
958: // ascii chars & ctrl+chars
959: for (i = 0; i < 256; i++) {
960: *keys[i].key_ch = (u_char) i;
961: keys[i].key_len = 1;
962:
963: if (!i || i == *K_CTRL_D)
964: keys[i].key_func = bufEOF;
965: if (i == *K_CTRL_M || i == *K_CTRL_J)
966: keys[i].key_func = bufEOL;
967: if (i == *K_CTRL_H || i == *K_BACKSPACE)
968: keys[i].key_func = bufBS;
969: if (i == *K_CTRL_C)
970: keys[i].key_func = bufCLR;
971: if (i == *K_CTRL_A)
972: keys[i].key_func = bufBEGIN;
973: if (i == *K_CTRL_E)
974: keys[i].key_func = bufEND;
1.2.2.8 misho 975: if (i == *K_TAB)
976: keys[i].key_func = bufComp;
1.2.2.3 misho 977: if (i >= *K_SPACE && i < *K_BACKSPACE)
978: keys[i].key_func = bufCHAR;
979: if (i > *K_BACKSPACE && i < 0xff)
980: keys[i].key_func = bufCHAR;
1.2.2.8 misho 981: if (i == '?')
982: keys[i].key_func = bufHelp;
1.2.2.3 misho 983: }
984: // alt+chars
985: for (i = 256; i < 512; i++) {
986: keys[i].key_ch[0] = 0x1b;
987: keys[i].key_ch[1] = (u_char) i - 256;
988: keys[i].key_len = 2;
989: }
990:
991: // 3 bytes
992: keys[i].key_len = sizeof K_F1 - 1;
993: memcpy(keys[i].key_ch, K_F1, keys[i].key_len);
994: i++;
995: keys[i].key_len = sizeof K_F2 - 1;
996: memcpy(keys[i].key_ch, K_F2, keys[i].key_len);
997: i++;
998: keys[i].key_len = sizeof K_F3 - 1;
999: memcpy(keys[i].key_ch, K_F3, keys[i].key_len);
1000: i++;
1001: keys[i].key_len = sizeof K_F4 - 1;
1002: memcpy(keys[i].key_ch, K_F4, keys[i].key_len);
1003: i++;
1004: keys[i].key_len = sizeof K_CTRL_SH_F1 - 1;
1005: memcpy(keys[i].key_ch, K_CTRL_SH_F1, keys[i].key_len);
1006: i++;
1007: keys[i].key_len = sizeof K_CTRL_SH_F2 - 1;
1008: memcpy(keys[i].key_ch, K_CTRL_SH_F2, keys[i].key_len);
1009: i++;
1010: keys[i].key_len = sizeof K_CTRL_SH_F3 - 1;
1011: memcpy(keys[i].key_ch, K_CTRL_SH_F3, keys[i].key_len);
1012: i++;
1013: keys[i].key_len = sizeof K_CTRL_SH_F4 - 1;
1014: memcpy(keys[i].key_ch, K_CTRL_SH_F4, keys[i].key_len);
1015: i++;
1016: keys[i].key_len = sizeof K_CTRL_SH_F5 - 1;
1017: memcpy(keys[i].key_ch, K_CTRL_SH_F5, keys[i].key_len);
1018: i++;
1019: keys[i].key_len = sizeof K_CTRL_SH_F6 - 1;
1020: memcpy(keys[i].key_ch, K_CTRL_SH_F6, keys[i].key_len);
1021: i++;
1022: keys[i].key_len = sizeof K_CTRL_SH_F7 - 1;
1023: memcpy(keys[i].key_ch, K_CTRL_SH_F7, keys[i].key_len);
1024: i++;
1025: keys[i].key_len = sizeof K_CTRL_SH_F8 - 1;
1026: memcpy(keys[i].key_ch, K_CTRL_SH_F8, keys[i].key_len);
1027: i++;
1028: keys[i].key_len = sizeof K_CTRL_SH_F9 - 1;
1029: memcpy(keys[i].key_ch, K_CTRL_SH_F9, keys[i].key_len);
1030: i++;
1031: keys[i].key_len = sizeof K_CTRL_SH_F10 - 1;
1032: memcpy(keys[i].key_ch, K_CTRL_SH_F10, keys[i].key_len);
1033: i++;
1034: keys[i].key_len = sizeof K_CTRL_SH_F11 - 1;
1035: memcpy(keys[i].key_ch, K_CTRL_SH_F11, keys[i].key_len);
1036: i++;
1037: keys[i].key_len = sizeof K_CTRL_SH_F12 - 1;
1038: memcpy(keys[i].key_ch, K_CTRL_SH_F12, keys[i].key_len);
1039: i++;
1040: keys[i].key_len = sizeof K_CTRL_F1 - 1;
1041: memcpy(keys[i].key_ch, K_CTRL_F1, keys[i].key_len);
1042: i++;
1043: keys[i].key_len = sizeof K_CTRL_F2 - 1;
1044: memcpy(keys[i].key_ch, K_CTRL_F2, keys[i].key_len);
1045: i++;
1046: keys[i].key_len = sizeof K_CTRL_F3 - 1;
1047: memcpy(keys[i].key_ch, K_CTRL_F3, keys[i].key_len);
1048: i++;
1049: keys[i].key_len = sizeof K_CTRL_F4 - 1;
1050: memcpy(keys[i].key_ch, K_CTRL_F4, keys[i].key_len);
1051: i++;
1052: keys[i].key_len = sizeof K_CTRL_F5 - 1;
1053: memcpy(keys[i].key_ch, K_CTRL_F5, keys[i].key_len);
1054: i++;
1055: keys[i].key_len = sizeof K_CTRL_F6 - 1;
1056: memcpy(keys[i].key_ch, K_CTRL_F6, keys[i].key_len);
1057: i++;
1058: keys[i].key_len = sizeof K_CTRL_F7 - 1;
1059: memcpy(keys[i].key_ch, K_CTRL_F7, keys[i].key_len);
1060: i++;
1061: keys[i].key_len = sizeof K_CTRL_F8 - 1;
1062: memcpy(keys[i].key_ch, K_CTRL_F8, keys[i].key_len);
1063: i++;
1064: keys[i].key_len = sizeof K_CTRL_F9 - 1;
1065: memcpy(keys[i].key_ch, K_CTRL_F9, keys[i].key_len);
1066: i++;
1067: keys[i].key_len = sizeof K_CTRL_F10 - 1;
1068: memcpy(keys[i].key_ch, K_CTRL_F10, keys[i].key_len);
1069: i++;
1070: keys[i].key_len = sizeof K_CTRL_F11 - 1;
1071: memcpy(keys[i].key_ch, K_CTRL_F11, keys[i].key_len);
1072: i++;
1073: keys[i].key_len = sizeof K_CTRL_F12 - 1;
1074: memcpy(keys[i].key_ch, K_CTRL_F12, keys[i].key_len);
1075: i++;
1076: keys[i].key_len = sizeof K_HOME - 1;
1077: keys[i].key_func = bufBEGIN;
1078: memcpy(keys[i].key_ch, K_HOME, keys[i].key_len);
1079: i++;
1080: keys[i].key_len = sizeof K_END - 1;
1081: keys[i].key_func = bufEND;
1082: memcpy(keys[i].key_ch, K_END, keys[i].key_len);
1083: i++;
1084: keys[i].key_len = sizeof K_UP - 1;
1085: keys[i].key_func = bufUP;
1086: memcpy(keys[i].key_ch, K_UP, keys[i].key_len);
1087: i++;
1088: keys[i].key_len = sizeof K_DOWN - 1;
1089: keys[i].key_func = bufDOWN;
1090: memcpy(keys[i].key_ch, K_DOWN, keys[i].key_len);
1091: i++;
1092: keys[i].key_len = sizeof K_RIGHT - 1;
1093: keys[i].key_func = bufRIGHT;
1094: memcpy(keys[i].key_ch, K_RIGHT, keys[i].key_len);
1095: i++;
1096: keys[i].key_len = sizeof K_LEFT - 1;
1097: keys[i].key_func = bufLEFT;
1098: memcpy(keys[i].key_ch, K_LEFT, keys[i].key_len);
1099: i++;
1100: keys[i].key_len = sizeof K_BTAB - 1;
1101: keys[i].key_func = bufBTAB;
1102: memcpy(keys[i].key_ch, K_BTAB, keys[i].key_len);
1103: i++;
1104: // 4 bytes
1105: keys[i].key_len = sizeof K_INS - 1;
1106: keys[i].key_func = bufMODE;
1107: memcpy(keys[i].key_ch, K_INS, keys[i].key_len);
1108: i++;
1109: keys[i].key_len = sizeof K_DEL - 1;
1110: keys[i].key_func = bufDEL;
1111: memcpy(keys[i].key_ch, K_DEL, keys[i].key_len);
1112: i++;
1113: keys[i].key_len = sizeof K_PGUP - 1;
1114: memcpy(keys[i].key_ch, K_PGUP, keys[i].key_len);
1115: i++;
1116: keys[i].key_len = sizeof K_PGDN - 1;
1117: memcpy(keys[i].key_ch, K_PGDN, keys[i].key_len);
1118: i++;
1119: // 5 bytes
1120: keys[i].key_len = sizeof K_F5 - 1;
1121: memcpy(keys[i].key_ch, K_F5, keys[i].key_len);
1122: i++;
1123: keys[i].key_len = sizeof K_F6 - 1;
1124: memcpy(keys[i].key_ch, K_F6, keys[i].key_len);
1125: i++;
1126: keys[i].key_len = sizeof K_F7 - 1;
1127: memcpy(keys[i].key_ch, K_F7, keys[i].key_len);
1128: i++;
1129: keys[i].key_len = sizeof K_F8 - 1;
1130: memcpy(keys[i].key_ch, K_F8, keys[i].key_len);
1131: i++;
1132: keys[i].key_len = sizeof K_F9 - 1;
1133: memcpy(keys[i].key_ch, K_F9, keys[i].key_len);
1134: i++;
1135: keys[i].key_len = sizeof K_F10 - 1;
1136: memcpy(keys[i].key_ch, K_F10, keys[i].key_len);
1137: i++;
1138: keys[i].key_len = sizeof K_F11 - 1;
1139: memcpy(keys[i].key_ch, K_F11, keys[i].key_len);
1140: i++;
1141: keys[i].key_len = sizeof K_F12 - 1;
1142: memcpy(keys[i].key_ch, K_F12, keys[i].key_len);
1143: i++;
1144:
1145: tcgetattr(buffer->line_in, &t);
1146: t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO | ECHOCTL | ECHOE | ECHOK | ECHOKE | ECHONL | ECHOPRT);
1147: t.c_iflag |= IGNBRK;
1148: t.c_cc[VMIN] = 1;
1149: t.c_cc[VTIME] = 0;
1150: tcsetattr(buffer->line_in, TCSANOW, &t);
1151:
1152: buffer->line_keys = keys;
1153: return buffer;
1154: }
1155:
1.2 misho 1156: /*
1.2.2.4 misho 1157: * cliReadLine() Read line from opened CLI session
1158: * @buffer = CLI buffer
1159: * return: NULL if error or !=NULL readed line, must be free after use!
1.2 misho 1160: */
1.2.2.4 misho 1161: char *
1162: cliReadLine(linebuffer_t * __restrict buffer)
1.2 misho 1163: {
1.2.2.4 misho 1164: int code, readLen;
1165: register int i;
1166: struct pollfd fds;
1167: char buf[BUFSIZ], *str = NULL;
1.2 misho 1168:
1.2.2.4 misho 1169: if (!buffer) {
1170: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
1171: return NULL;
1.2 misho 1172: }
1173:
1.2.2.4 misho 1174: memset(&fds, 0, sizeof fds);
1175: fds.fd = buffer->line_in;
1176: fds.events = POLLIN;
1177:
1178: printfCR(buffer, 1);
1179: while (42) {
1180: if (poll(&fds, 1, -1) < 1) {
1181: LOGERR;
1182: return str;
1183: }
1.2 misho 1184:
1.2.2.4 misho 1185: memset(buf, 0, sizeof buf);
1186: readLen = read(buffer->line_in, buf, BUFSIZ);
1187: if (readLen == -1) {
1188: LOGERR;
1189: return str;
1190: }
1191: if (!readLen) {
1192: if (buffer->line_buf)
1193: str = strdup(buffer->line_buf);
1194: else
1195: cli_SetErr(EPIPE, "Error:: unknown state ...");
1196: return str;
1197: }
1.2 misho 1198:
1.2.2.4 misho 1199: recheck:
1200: for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--)
1201: if (readLen >= buffer->line_keys[i].key_len &&
1202: !memcmp(buffer->line_keys[i].key_ch, buf,
1203: buffer->line_keys[i].key_len)) {
1204: readLen -= buffer->line_keys[i].key_len;
1205: if (readLen)
1206: memmove(buf, buf + buffer->line_keys[i].key_len, readLen);
1207: else
1208: memset(buf, 0, buffer->line_keys[i].key_len);
1209:
1210: if (buffer->line_keys[i].key_func)
1211: if ((code = buffer->line_keys[i].key_func(i, buffer)))
1212: readLen = 0;
1213:
1214: if (readLen)
1215: goto recheck;
1216: else
1217: break;
1218: }
1.2 misho 1219:
1.2.2.4 misho 1220: if (code)
1221: break;
1222: }
1223:
1.2.2.5 misho 1224: if (code != RETCODE_ERR && code != RETCODE_EOF && buffer->line_buf)
1.2.2.4 misho 1225: str = strdup(buffer->line_buf);
1226: return str;
1.2 misho 1227: }
1.2.2.4 misho 1228:
1229:
1.2 misho 1230: /*
1.2.2.4 misho 1231: * cliNetLoop() CLI network main loop binded to socket
1232: * @buffer = CLI buffer
1233: * @csHistFile = History file name
1.2 misho 1234: * @sock = client socket
1235: * @term = stdin termios
1236: * @win = window size of tty
1.2.2.4 misho 1237: * return: RETCODE_ERR error, RETCODE_OK ok
1.2 misho 1238: */
1.2.2.1 misho 1239: int
1.2.2.4 misho 1240: cliNetLoop(linebuffer_t * __restrict buffer, const char *csHistFile, int sock,
1241: struct termios *term, struct winsize *win)
1.2 misho 1242: {
1.2.2.4 misho 1243: u_char buf[BUFSIZ];
1244: int pty, r, s, alen, attrlen, flg, ret = 0;
1.2 misho 1245: fd_set fds;
1246: struct timeval tv = { DEFAULT_SOCK_TIMEOUT, 0 };
1247: struct telnetAttrs *a, Attr[10];
1248:
1249: switch (forkpty(&pty, NULL, term, win)) {
1250: case -1:
1251: LOGERR;
1252: return -1;
1253: case 0:
1254: close(sock);
1255:
1.2.2.14! misho 1256: if (buffer)
1.2.2.8 misho 1257: ret = cliLoop(buffer, csHistFile) < 0 ? 1 : 0;
1.2.2.14! misho 1258: else
1.2.2.8 misho 1259: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
1.2.2.4 misho 1260:
1.2 misho 1261: /* spawn Shell mode */
1262: /*
1263: execl("/bin/tcsh", "tcsh", NULL);
1264: */
1.2.2.4 misho 1265:
1.2 misho 1266: _exit(ret);
1267: default:
1268: /* spawn Shell mode */
1269: telnet_SetCmd(Attr + 0, DO, TELOPT_TTYPE);
1270: telnet_SetCmd(Attr + 1, WILL, TELOPT_ECHO);
1271: telnet_Set_SubOpt(Attr + 2, TELOPT_LFLOW, LFLOW_OFF, NULL, 0);
1272: telnet_Set_SubOpt(Attr + 3, TELOPT_LFLOW, LFLOW_RESTART_XON, NULL, 0);
1273: telnet_SetCmd(Attr + 4, DO, TELOPT_LINEMODE);
1274: if ((ret = telnetSend(sock, Attr, 5, NULL, 0, 0)) == -1) {
1275: cli_Errno = telnet_GetErrno();
1276: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
1277: return -1;
1278: } else
1279: flg = 0;
1280:
1281: while (42) {
1282: FD_ZERO(&fds);
1283: FD_SET(sock, &fds);
1284: FD_SET(pty, &fds);
1285: if ((ret = select(FD_SETSIZE, &fds, NULL, NULL, &tv)) < 1) {
1286: if (!ret)
1287: cli_SetErr(ETIMEDOUT, "Client session timeout ...");
1288:
1289: break;
1290: }
1291:
1292: r = FD_ISSET(sock, &fds) ? sock : pty;
1293: s = FD_ISSET(sock, &fds) ? pty : sock;
1294:
1295: if ((ret = telnetRecv(r, &a, &alen, buf, BUFSIZ)) < 0) {
1296: if (a)
1297: free(a);
1298:
1299: if (-2 == ret)
1300: continue;
1301: // EOF
1302: if (-3 == ret)
1303: shutdown(r, SHUT_RD);
1304: else {
1305: cli_Errno = telnet_GetErrno();
1306: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
1307: }
1308: break;
1309: }
1310: attrlen = 0;
1311: if (1 == flg && alen) {
1312: telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_SGA);
1313: telnet_SetCmd(&Attr[attrlen++], DO, TELOPT_ECHO);
1314: }
1315: if (2 == flg && alen) {
1316: telnet_SetCmd(&Attr[attrlen++], WILL, TELOPT_ECHO);
1317: telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW,
1318: LFLOW_OFF, NULL, 0);
1319: telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW,
1320: LFLOW_RESTART_XON, NULL, 0);
1321: telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_LINEMODE);
1322: }
1323: if (a)
1324: free(a);
1325:
1326: if ((ret = telnetSend(s, Attr, pty == s ? 0 : attrlen, buf, ret, 0)) == -1) {
1327: cli_Errno = telnet_GetErrno();
1328: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
1329: break;
1330: } else
1331: flg++;
1332: }
1333:
1334: close(pty);
1335: }
1336:
1337: return ret;
1338: }
1339:
1340: /*
1.2.2.4 misho 1341: * cliLoop() CLI main loop
1342: * @buffer = CLI buffer
1343: * @csHistFile = History file name
1344: * return: RETCODE_ERR error, RETCODE_OK ok
1.1 misho 1345: */
1.2.2.4 misho 1346: int
1347: cliLoop(linebuffer_t * __restrict buffer, const char *csHistFile)
1.1 misho 1348: {
1349: char *line, *s, *t, **app, *items[MAX_PROMPT_ITEMS];
1350: register int i;
1.2.2.4 misho 1351: int ret = RETCODE_OK;
1352: struct tagCommand *cmd;
1.1 misho 1353:
1354: /* --- main body of CLI --- */
1.2.2.4 misho 1355:
1356: if (cli_loadHistory(buffer, csHistFile) == RETCODE_ERR)
1357: return RETCODE_ERR;
1.1 misho 1358:
1359: do {
1.2.2.4 misho 1360: line = cliReadLine(buffer);
1.2.2.5 misho 1361: if (!line) {
1362: printfNL(buffer, 0);
1.1 misho 1363: break;
1.2.2.5 misho 1364: } else
1.2.2.4 misho 1365: cli_addHistory(buffer, NULL);
1.1 misho 1366: // clear whitespaces
1367: for (s = line; isspace(*s); s++);
1368: if (*s) {
1369: for (t = s + strlen(s) - 1; t > s && isspace(*t); t--);
1370: *++t = 0;
1371: }
1372:
1373: if (*s) {
1374: memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
1375: for (app = items; app < items + MAX_PROMPT_ITEMS - 1 && (*app = strsep(&s, " \t"));
1376: *app ? app++ : app);
1377:
1378: // exec_cmd ...
1.2.2.4 misho 1379: i = 0;
1380: SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next) {
1381: if (*items[0] && !strncmp(cmd->cmd_name, items[0], strlen(items[0])))
1.1 misho 1382: break;
1.2.2.4 misho 1383: else
1384: i++;
1385: }
1.2.2.5 misho 1386:
1.1 misho 1387: if (!cmd) {
1.2.2.5 misho 1388: cli_Printf(buffer, "\nCommand '%s' not found!\n", items[0]);
1.1 misho 1389: ret = -1;
1390: } else
1.2.2.4 misho 1391: ret = cmd->cmd_func(buffer, i, items);
1.1 misho 1392: }
1393:
1.2.2.4 misho 1394: cli_freeLine(buffer);
1395: cli_resetHistory(buffer);
1.1 misho 1396: free(line);
1397: } while (ret < 1);
1398:
1.2.2.4 misho 1399: cli_saveHistory(buffer, csHistFile, HISTORY_LINES);
1.1 misho 1400: return ret;
1401: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>