]> git.sur5r.net Git - openocd/blob - src/server/telnet_server.c
cb79189eec11dc9d9b871535b13da70405a210e8
[openocd] / src / server / telnet_server.c
1 /***************************************************************************
2  *   Copyright (C) 2005 by Dominic Rath                                    *
3  *   Dominic.Rath@gmx.de                                                   *
4  *                                                                         *
5  *   Copyright (C) 2007-2010 Ã˜yvind Harboe                                 *
6  *   oyvind.harboe@zylin.com                                               *
7  *                                                                         *
8  *   Copyright (C) 2008 by Spencer Oliver                                  *
9  *   spen@spen-soft.co.uk                                                  *
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  *   This program is distributed in the hope that it will be useful,       *
17  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
19  *   GNU General Public License for more details.                          *
20  *                                                                         *
21  *   You should have received a copy of the GNU General Public License     *
22  *   along with this program; if not, write to the                         *
23  *   Free Software Foundation, Inc.,                                       *
24  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
25  ***************************************************************************/
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include "telnet_server.h"
32 #include <target/target_request.h>
33 #include <helper/configuration.h>
34
35 static char *telnet_port;
36
37 static char *negotiate =
38         "\xFF\xFB\x03"                  /* IAC WILL Suppress Go Ahead */
39         "\xFF\xFB\x01"                  /* IAC WILL Echo */
40         "\xFF\xFD\x03"                  /* IAC DO Suppress Go Ahead */
41         "\xFF\xFE\x01";                 /* IAC DON'T Echo */
42
43 #define CTRL(c) (c - '@')
44 #define TELNET_HISTORY  ".openocd_history"
45
46 /* The only way we can detect that the socket is closed is the first time
47  * we write to it, we will fail. Subsequent write operations will
48  * succeed. Shudder!
49  */
50 static int telnet_write(struct connection *connection, const void *data,
51         int len)
52 {
53         struct telnet_connection *t_con = connection->priv;
54         if (t_con->closed)
55                 return ERROR_SERVER_REMOTE_CLOSED;
56
57         if (connection_write(connection, data, len) == len)
58                 return ERROR_OK;
59         t_con->closed = 1;
60         return ERROR_SERVER_REMOTE_CLOSED;
61 }
62
63 static int telnet_prompt(struct connection *connection)
64 {
65         struct telnet_connection *t_con = connection->priv;
66
67         return telnet_write(connection, t_con->prompt, strlen(t_con->prompt));
68 }
69
70 static int telnet_outputline(struct connection *connection, const char *line)
71 {
72         int len;
73
74         /* process lines in buffer */
75         while (*line) {
76                 char *line_end = strchr(line, '\n');
77
78                 if (line_end)
79                         len = line_end-line;
80                 else
81                         len = strlen(line);
82
83                 telnet_write(connection, line, len);
84                 if (line_end) {
85                         telnet_write(connection, "\r\n", 2);
86                         line += len + 1;
87                 } else
88                         line += len;
89         }
90
91         return ERROR_OK;
92 }
93
94 static int telnet_output(struct command_context *cmd_ctx, const char *line)
95 {
96         struct connection *connection = cmd_ctx->output_handler_priv;
97
98         return telnet_outputline(connection, line);
99 }
100
101 static void telnet_log_callback(void *priv, const char *file, unsigned line,
102         const char *function, const char *string)
103 {
104         struct connection *connection = priv;
105         struct telnet_connection *t_con = connection->priv;
106         int i;
107
108         /* if there is no prompt, simply output the message */
109         if (t_con->line_cursor < 0) {
110                 telnet_outputline(connection, string);
111                 return;
112         }
113
114         /* clear the command line */
115         for (i = strlen(t_con->prompt) + t_con->line_size; i > 0; i -= 16)
116                 telnet_write(connection, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i > 16 ? 16 : i);
117         for (i = strlen(t_con->prompt) + t_con->line_size; i > 0; i -= 16)
118                 telnet_write(connection, "                ", i > 16 ? 16 : i);
119         for (i = strlen(t_con->prompt) + t_con->line_size; i > 0; i -= 16)
120                 telnet_write(connection, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i > 16 ? 16 : i);
121
122         /* output the message */
123         telnet_outputline(connection, string);
124
125         /* put the command line to its previous state */
126         telnet_prompt(connection);
127         telnet_write(connection, t_con->line, t_con->line_size);
128         for (i = t_con->line_size; i > t_con->line_cursor; i--)
129                 telnet_write(connection, "\b", 1);
130 }
131
132 static void telnet_load_history(struct telnet_connection *t_con)
133 {
134         FILE *histfp;
135         char buffer[TELNET_BUFFER_SIZE];
136         int i = 0;
137
138         char *history = get_home_dir(TELNET_HISTORY);
139
140         if (history == NULL) {
141                 LOG_INFO("unable to get user home directory, telnet history will be disabled");
142                 return;
143         }
144
145         histfp = fopen(history, "rb");
146
147         if (histfp) {
148
149                 while (fgets(buffer, sizeof(buffer), histfp) != NULL) {
150
151                         char *p = strchr(buffer, '\n');
152                         if (p)
153                                 *p = '\0';
154                         if (buffer[0] && i < TELNET_LINE_HISTORY_SIZE)
155                                 t_con->history[i++] = strdup(buffer);
156                 }
157
158                 t_con->next_history = i;
159                 t_con->next_history %= TELNET_LINE_HISTORY_SIZE;
160                 /* try to set to last entry - 1, that way we skip over any exit/shutdown cmds */
161                 t_con->current_history = t_con->next_history > 0 ? i - 1 : 0;
162                 fclose(histfp);
163         }
164
165         free(history);
166 }
167
168 static void telnet_save_history(struct telnet_connection *t_con)
169 {
170         FILE *histfp;
171         int i;
172         int num;
173
174         char *history = get_home_dir(TELNET_HISTORY);
175
176         if (history == NULL) {
177                 LOG_INFO("unable to get user home directory, telnet history will be disabled");
178                 return;
179         }
180
181         histfp = fopen(history, "wb");
182
183         if (histfp) {
184
185                 num = TELNET_LINE_HISTORY_SIZE;
186                 i = t_con->current_history + 1;
187                 i %= TELNET_LINE_HISTORY_SIZE;
188
189                 while (t_con->history[i] == NULL && num > 0) {
190                         i++;
191                         i %= TELNET_LINE_HISTORY_SIZE;
192                         num--;
193                 }
194
195                 if (num > 0) {
196                         for (; num > 0; num--) {
197                                 fprintf(histfp, "%s\n", t_con->history[i]);
198                                 i++;
199                                 i %= TELNET_LINE_HISTORY_SIZE;
200                         }
201                 }
202                 fclose(histfp);
203         }
204
205         free(history);
206 }
207
208 static int telnet_new_connection(struct connection *connection)
209 {
210         struct telnet_connection *telnet_connection;
211         struct telnet_service *telnet_service = connection->service->priv;
212         int i;
213
214         telnet_connection = malloc(sizeof(struct telnet_connection));
215
216         if (!telnet_connection) {
217                 LOG_ERROR("Failed to allocate telnet connection.");
218                 return ERROR_FAIL;
219         }
220
221         connection->priv = telnet_connection;
222
223         /* initialize telnet connection information */
224         telnet_connection->closed = 0;
225         telnet_connection->line_size = 0;
226         telnet_connection->line_cursor = 0;
227         telnet_connection->option_size = 0;
228         telnet_connection->prompt = strdup("> ");
229         telnet_connection->state = TELNET_STATE_DATA;
230
231         /* output goes through telnet connection */
232         command_set_output_handler(connection->cmd_ctx, telnet_output, connection);
233
234         /* negotiate telnet options */
235         telnet_write(connection, negotiate, strlen(negotiate));
236
237         /* print connection banner */
238         if (telnet_service->banner) {
239                 telnet_write(connection, telnet_service->banner, strlen(telnet_service->banner));
240                 telnet_write(connection, "\r\n", 2);
241         }
242
243         /* the prompt is always placed at the line beginning */
244         telnet_write(connection, "\r", 1);
245         telnet_prompt(connection);
246
247         /* initialize history */
248         for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++)
249                 telnet_connection->history[i] = NULL;
250         telnet_connection->next_history = 0;
251         telnet_connection->current_history = 0;
252         telnet_load_history(telnet_connection);
253
254         log_add_callback(telnet_log_callback, connection);
255
256         return ERROR_OK;
257 }
258
259 static void telnet_clear_line(struct connection *connection,
260         struct telnet_connection *t_con)
261 {
262         /* move to end of line */
263         if (t_con->line_cursor < t_con->line_size)
264                 telnet_write(connection,
265                         t_con->line + t_con->line_cursor,
266                         t_con->line_size - t_con->line_cursor);
267
268         /* backspace, overwrite with space, backspace */
269         while (t_con->line_size > 0) {
270                 telnet_write(connection, "\b \b", 3);
271                 t_con->line_size--;
272         }
273         t_con->line_cursor = 0;
274 }
275
276 static void telnet_history_go(struct connection *connection, int idx)
277 {
278         struct telnet_connection *t_con = connection->priv;
279
280         if (t_con->history[idx]) {
281                 telnet_clear_line(connection, t_con);
282                 t_con->line_size = strlen(t_con->history[idx]);
283                 t_con->line_cursor = t_con->line_size;
284                 memcpy(t_con->line, t_con->history[idx], t_con->line_size);
285                 telnet_write(connection, t_con->line, t_con->line_size);
286                 t_con->current_history = idx;
287         }
288         t_con->state = TELNET_STATE_DATA;
289 }
290
291 static void telnet_history_up(struct connection *connection)
292 {
293         struct telnet_connection *t_con = connection->priv;
294
295         int last_history = (t_con->current_history > 0) ?
296                                 t_con->current_history - 1 :
297                                 TELNET_LINE_HISTORY_SIZE-1;
298         telnet_history_go(connection, last_history);
299 }
300
301 static void telnet_history_down(struct connection *connection)
302 {
303         struct telnet_connection *t_con = connection->priv;
304
305         int next_history = (t_con->current_history + 1) % TELNET_LINE_HISTORY_SIZE;
306         telnet_history_go(connection, next_history);
307 }
308
309 static int telnet_input(struct connection *connection)
310 {
311         int bytes_read;
312         unsigned char buffer[TELNET_BUFFER_SIZE];
313         unsigned char *buf_p;
314         struct telnet_connection *t_con = connection->priv;
315         struct command_context *command_context = connection->cmd_ctx;
316
317         bytes_read = connection_read(connection, buffer, TELNET_BUFFER_SIZE);
318
319         if (bytes_read == 0)
320                 return ERROR_SERVER_REMOTE_CLOSED;
321         else if (bytes_read == -1) {
322                 LOG_ERROR("error during read: %s", strerror(errno));
323                 return ERROR_SERVER_REMOTE_CLOSED;
324         }
325
326         buf_p = buffer;
327         while (bytes_read) {
328                 switch (t_con->state) {
329                         case TELNET_STATE_DATA:
330                                 if (*buf_p == 0xff)
331                                         t_con->state = TELNET_STATE_IAC;
332                                 else {
333                                         if (isprint(*buf_p)) {  /* printable character */
334                                                 /* watch buffer size leaving one spare character for
335                                                  * string null termination */
336                                                 if (t_con->line_size == TELNET_LINE_MAX_SIZE-1) {
337                                                         /* output audible bell if buffer is full
338                                                          * "\a" does not work, at least on windows */
339                                                         telnet_write(connection, "\x07", 1);
340                                                 } else if (t_con->line_cursor == t_con->line_size) {
341                                                         telnet_write(connection, buf_p, 1);
342                                                         t_con->line[t_con->line_size++] = *buf_p;
343                                                         t_con->line_cursor++;
344                                                 } else {
345                                                         int i;
346                                                         memmove(t_con->line + t_con->line_cursor + 1,
347                                                                         t_con->line + t_con->line_cursor,
348                                                                         t_con->line_size - t_con->line_cursor);
349                                                         t_con->line[t_con->line_cursor] = *buf_p;
350                                                         t_con->line_size++;
351                                                         telnet_write(connection,
352                                                                         t_con->line + t_con->line_cursor,
353                                                                         t_con->line_size - t_con->line_cursor);
354                                                         t_con->line_cursor++;
355                                                         for (i = t_con->line_cursor; i < t_con->line_size; i++)
356                                                                 telnet_write(connection, "\b", 1);
357                                                 }
358                                         } else {        /* non-printable */
359                                                 if (*buf_p == 0x1b) {   /* escape */
360                                                         t_con->state = TELNET_STATE_ESCAPE;
361                                                         t_con->last_escape = '\x00';
362                                                 } else if ((*buf_p == 0xd) || (*buf_p == 0xa)) {        /* CR/LF */
363                                                         int retval;
364
365                                                         /* skip over combinations with CR/LF and NUL characters */
366                                                         if ((bytes_read > 1) && ((*(buf_p + 1) == 0xa) ||
367                                                                         (*(buf_p + 1) == 0xd))) {
368                                                                 buf_p++;
369                                                                 bytes_read--;
370                                                         }
371                                                         if ((bytes_read > 1) && (*(buf_p + 1) == 0)) {
372                                                                 buf_p++;
373                                                                 bytes_read--;
374                                                         }
375                                                         t_con->line[t_con->line_size] = 0;
376
377                                                         telnet_write(connection, "\r\n\x00", 3);
378
379                                                         if (strcmp(t_con->line, "history") == 0) {
380                                                                 int i;
381                                                                 for (i = 1; i < TELNET_LINE_HISTORY_SIZE; i++) {
382                                                                         /* the t_con->next_history line contains empty string
383                                                                          * (unless NULL), thus it is not printed */
384                                                                         char *history_line = t_con->history[(t_con->
385                                                                                         next_history + i) %
386                                                                                         TELNET_LINE_HISTORY_SIZE];
387                                                                         if (history_line) {
388                                                                                 telnet_write(connection, history_line,
389                                                                                                 strlen(history_line));
390                                                                                 telnet_write(connection, "\r\n\x00", 3);
391                                                                         }
392                                                                 }
393                                                                 t_con->line_size = 0;
394                                                                 t_con->line_cursor = 0;
395                                                                 continue;
396                                                         }
397
398                                                         /* save only non-blank not repeating lines in the history */
399                                                         char *prev_line = t_con->history[(t_con->current_history > 0) ?
400                                                                         t_con->current_history - 1 : TELNET_LINE_HISTORY_SIZE-1];
401                                                         if (*t_con->line && (prev_line == NULL ||
402                                                                         strcmp(t_con->line, prev_line))) {
403                                                                 /* if the history slot is already taken, free it */
404                                                                 if (t_con->history[t_con->next_history])
405                                                                         free(t_con->history[t_con->next_history]);
406
407                                                                 /* add line to history */
408                                                                 t_con->history[t_con->next_history] = strdup(t_con->line);
409
410                                                                 /* wrap history at TELNET_LINE_HISTORY_SIZE */
411                                                                 t_con->next_history = (t_con->next_history + 1) %
412                                                                                 TELNET_LINE_HISTORY_SIZE;
413
414                                                                 /* current history line starts at the new entry */
415                                                                 t_con->current_history =
416                                                                                 t_con->next_history;
417
418                                                                 if (t_con->history[t_con->current_history])
419                                                                         free(t_con->history[t_con->current_history]);
420                                                                 t_con->history[t_con->current_history] = strdup("");
421                                                         }
422
423                                                         t_con->line_size = 0;
424
425                                                         /* to suppress prompt in log callback during command execution */
426                                                         t_con->line_cursor = -1;
427
428                                                         if (strcmp(t_con->line, "shutdown") == 0)
429                                                                 telnet_save_history(t_con);
430
431                                                         retval = command_run_line(command_context, t_con->line);
432
433                                                         t_con->line_cursor = 0;
434
435                                                         if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
436                                                                 return ERROR_SERVER_REMOTE_CLOSED;
437
438                                                         /* the prompt is always * placed at the line beginning */
439                                                         telnet_write(connection, "\r", 1);
440
441                                                         retval = telnet_prompt(connection);
442                                                         if (retval == ERROR_SERVER_REMOTE_CLOSED)
443                                                                 return ERROR_SERVER_REMOTE_CLOSED;
444
445                                                 } else if ((*buf_p == 0x7f) || (*buf_p == 0x8)) {       /* delete character */
446                                                         if (t_con->line_cursor > 0) {
447                                                                 if (t_con->line_cursor != t_con->line_size) {
448                                                                         int i;
449                                                                         telnet_write(connection, "\b", 1);
450                                                                         t_con->line_cursor--;
451                                                                         t_con->line_size--;
452                                                                         memmove(t_con->line + t_con->line_cursor,
453                                                                                         t_con->line + t_con->line_cursor + 1,
454                                                                                         t_con->line_size -
455                                                                                         t_con->line_cursor);
456
457                                                                         telnet_write(connection,
458                                                                                         t_con->line + t_con->line_cursor,
459                                                                                         t_con->line_size -
460                                                                                         t_con->line_cursor);
461                                                                         telnet_write(connection, " \b", 2);
462                                                                         for (i = t_con->line_cursor; i < t_con->line_size; i++)
463                                                                                 telnet_write(connection, "\b", 1);
464                                                                 } else {
465                                                                         t_con->line_size--;
466                                                                         t_con->line_cursor--;
467                                                                         /* back space: move the 'printer' head one char
468                                                                          * back, overwrite with space, move back again */
469                                                                         telnet_write(connection, "\b \b", 3);
470                                                                 }
471                                                         }
472                                                 } else if (*buf_p == 0x15) /* clear line */
473                                                         telnet_clear_line(connection, t_con);
474                                                 else if (*buf_p == CTRL('B')) { /* cursor left */
475                                                         if (t_con->line_cursor > 0) {
476                                                                 telnet_write(connection, "\b", 1);
477                                                                 t_con->line_cursor--;
478                                                         }
479                                                         t_con->state = TELNET_STATE_DATA;
480                                                 } else if (*buf_p == CTRL('F')) {       /* cursor right */
481                                                         if (t_con->line_cursor < t_con->line_size)
482                                                                 telnet_write(connection, t_con->line + t_con->line_cursor++, 1);
483                                                         t_con->state = TELNET_STATE_DATA;
484                                                 } else if (*buf_p == CTRL('P'))         /* cursor up */
485                                                         telnet_history_up(connection);
486                                                 else if (*buf_p == CTRL('N'))           /* cursor down */
487                                                         telnet_history_down(connection);
488                                                 else
489                                                         LOG_DEBUG("unhandled nonprintable: %2.2x", *buf_p);
490                                         }
491                                 }
492                                 break;
493                         case TELNET_STATE_IAC:
494                                 switch (*buf_p) {
495                                 case 0xfe:
496                                         t_con->state = TELNET_STATE_DONT;
497                                         break;
498                                 case 0xfd:
499                                         t_con->state = TELNET_STATE_DO;
500                                         break;
501                                 case 0xfc:
502                                         t_con->state = TELNET_STATE_WONT;
503                                         break;
504                                 case 0xfb:
505                                         t_con->state = TELNET_STATE_WILL;
506                                         break;
507                                 }
508                                 break;
509                         case TELNET_STATE_SB:
510                                 break;
511                         case TELNET_STATE_SE:
512                                 break;
513                         case TELNET_STATE_WILL:
514                         case TELNET_STATE_WONT:
515                         case TELNET_STATE_DO:
516                         case TELNET_STATE_DONT:
517                                 t_con->state = TELNET_STATE_DATA;
518                                 break;
519                         case TELNET_STATE_ESCAPE:
520                                 if (t_con->last_escape == '[') {
521                                         if (*buf_p == 'D') {    /* cursor left */
522                                                 if (t_con->line_cursor > 0) {
523                                                         telnet_write(connection, "\b", 1);
524                                                         t_con->line_cursor--;
525                                                 }
526                                                 t_con->state = TELNET_STATE_DATA;
527                                         } else if (*buf_p == 'C') {     /* cursor right */
528                                                 if (t_con->line_cursor < t_con->line_size)
529                                                         telnet_write(connection,
530                                                                         t_con->line + t_con->line_cursor++, 1);
531                                                 t_con->state = TELNET_STATE_DATA;
532                                         } else if (*buf_p == 'A') {     /* cursor up */
533                                                 telnet_history_up(connection);
534                                         } else if (*buf_p == 'B') {     /* cursor down */
535                                                 telnet_history_down(connection);
536                                         } else if (*buf_p == '3')
537                                                 t_con->last_escape = *buf_p;
538                                         else
539                                                 t_con->state = TELNET_STATE_DATA;
540                                 } else if (t_con->last_escape == '3') {
541                                         /* Remove character */
542                                         if (*buf_p == '~') {
543                                                 if (t_con->line_cursor < t_con->line_size) {
544                                                         int i;
545                                                         t_con->line_size--;
546                                                         /* remove char from line buffer */
547                                                         memmove(t_con->line + t_con->line_cursor,
548                                                                         t_con->line + t_con->line_cursor + 1,
549                                                                         t_con->line_size - t_con->line_cursor);
550
551                                                         /* print remainder of buffer */
552                                                         telnet_write(connection, t_con->line + t_con->line_cursor,
553                                                                         t_con->line_size - t_con->line_cursor);
554                                                         /* overwrite last char with whitespace */
555                                                         telnet_write(connection, " \b", 2);
556
557                                                         /* move back to cursor position*/
558                                                         for (i = t_con->line_cursor; i < t_con->line_size; i++)
559                                                                 telnet_write(connection, "\b", 1);
560                                                 }
561
562                                                 t_con->state = TELNET_STATE_DATA;
563                                         } else
564                                                 t_con->state = TELNET_STATE_DATA;
565                                 } else if (t_con->last_escape == '\x00') {
566                                         if (*buf_p == '[')
567                                                 t_con->last_escape = *buf_p;
568                                         else
569                                                 t_con->state = TELNET_STATE_DATA;
570                                 } else {
571                                         LOG_ERROR("BUG: unexpected value in t_con->last_escape");
572                                         t_con->state = TELNET_STATE_DATA;
573                                 }
574
575                                 break;
576                         default:
577                                 LOG_ERROR("unknown telnet state");
578                                 exit(-1);
579                 }
580
581                 bytes_read--;
582                 buf_p++;
583         }
584
585         return ERROR_OK;
586 }
587
588 static int telnet_connection_closed(struct connection *connection)
589 {
590         struct telnet_connection *t_con = connection->priv;
591         int i;
592
593         log_remove_callback(telnet_log_callback, connection);
594
595         if (t_con->prompt) {
596                 free(t_con->prompt);
597                 t_con->prompt = NULL;
598         }
599
600         /* save telnet history */
601         telnet_save_history(t_con);
602
603         for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++) {
604                 if (t_con->history[i]) {
605                         free(t_con->history[i]);
606                         t_con->history[i] = NULL;
607                 }
608         }
609
610         /* if this connection registered a debug-message receiver delete it */
611         delete_debug_msg_receiver(connection->cmd_ctx, NULL);
612
613         if (connection->priv) {
614                 free(connection->priv);
615                 connection->priv = NULL;
616         } else
617                 LOG_ERROR("BUG: connection->priv == NULL");
618
619         return ERROR_OK;
620 }
621
622 int telnet_init(char *banner)
623 {
624         if (strcmp(telnet_port, "disabled") == 0) {
625                 LOG_INFO("telnet server disabled");
626                 return ERROR_OK;
627         }
628
629         struct telnet_service *telnet_service;
630
631         telnet_service = malloc(sizeof(struct telnet_service));
632
633         if (!telnet_service) {
634                 LOG_ERROR("Failed to allocate telnet service.");
635                 return ERROR_FAIL;
636         }
637
638         telnet_service->banner = banner;
639
640         return add_service("telnet",
641                 telnet_port,
642                 CONNECTION_LIMIT_UNLIMITED,
643                 telnet_new_connection,
644                 telnet_input,
645                 telnet_connection_closed,
646                 telnet_service);
647 }
648
649 /* daemon configuration command telnet_port */
650 COMMAND_HANDLER(handle_telnet_port_command)
651 {
652         return CALL_COMMAND_HANDLER(server_pipe_command, &telnet_port);
653 }
654
655 COMMAND_HANDLER(handle_exit_command)
656 {
657         return ERROR_COMMAND_CLOSE_CONNECTION;
658 }
659
660 static const struct command_registration telnet_command_handlers[] = {
661         {
662                 .name = "exit",
663                 .handler = handle_exit_command,
664                 .mode = COMMAND_EXEC,
665                 .usage = "",
666                 .help = "exit telnet session",
667         },
668         {
669                 .name = "telnet_port",
670                 .handler = handle_telnet_port_command,
671                 .mode = COMMAND_ANY,
672                 .help = "Specify port on which to listen "
673                         "for incoming telnet connections.  "
674                         "Read help on 'gdb_port'.",
675                 .usage = "[port_num]",
676         },
677         COMMAND_REGISTRATION_DONE
678 };
679
680 int telnet_register_commands(struct command_context *cmd_ctx)
681 {
682         telnet_port = strdup("4444");
683         return register_commands(cmd_ctx, NULL, telnet_command_handlers);
684 }