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