2 * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/param.h>
30 #include <netinet/in.h>
31 #include <netinet/in_systm.h>
32 #include <netinet/ip.h>
33 #include <sys/socket.h>
41 #include <sys/fcntl.h>
50 #include "descriptor.h"
55 #include "throughput.h"
56 #include "slcompress.h"
83 prompt_Display(struct prompt
*p
)
85 /* XXX: See Index2Nam() - should we only figure this out once ? */
86 static char shostname
[MAXHOSTNAMELEN
];
87 const char *pconnect
, *pauth
;
89 if (p
->TermMode
|| !p
->needprompt
)
97 fprintf(p
->Term
, "\n");
99 if (p
->auth
== LOCAL_AUTH
)
104 if (p
->bundle
->ncp
.ipcp
.fsm
.state
== ST_OPENED
)
107 else if (!Enabled(p
->bundle
, OPT_IPCP
) &&
108 p
->bundle
->ncp
.ipv6cp
.fsm
.state
== ST_OPENED
)
111 else if (bundle_Phase(p
->bundle
) == PHASE_NETWORK
)
113 else if (bundle_Phase(p
->bundle
) == PHASE_AUTHENTICATE
)
118 if (*shostname
== '\0') {
121 if (gethostname(shostname
, sizeof shostname
) || *shostname
== '\0')
122 strcpy(shostname
, "localhost");
123 else if ((dot
= strchr(shostname
, '.')))
127 fprintf(p
->Term
, "%s%s%s> ", pconnect
, pauth
, shostname
);
132 prompt_UpdateSet(struct fdescriptor
*d
, fd_set
*r
, fd_set
*w __unused
,
135 struct prompt
*p
= descriptor2prompt(d
);
146 log_Printf(LogTIMER
, "prompt %s: fdset(r) %d\n", p
->src
.from
, p
->fd_in
);
151 log_Printf(LogTIMER
, "prompt %s: fdset(e) %d\n", p
->src
.from
, p
->fd_in
);
154 if (sets
&& *n
< p
->fd_in
+ 1)
164 prompt_IsSet(struct fdescriptor
*d
, const fd_set
*fdset
)
166 struct prompt
*p
= descriptor2prompt(d
);
167 return p
->fd_in
>= 0 && FD_ISSET(p
->fd_in
, fdset
);
172 prompt_ShowHelp(struct prompt
*p
)
174 prompt_Printf(p
, "The following commands are available:\n");
175 prompt_Printf(p
, " ~p\tEnter Packet mode\n");
176 prompt_Printf(p
, " ~t\tShow timers\n");
177 prompt_Printf(p
, " ~m\tShow memory map\n");
178 prompt_Printf(p
, " ~.\tTerminate program\n");
179 prompt_Printf(p
, " ~?\tThis help\n");
183 prompt_Read(struct fdescriptor
*d
, struct bundle
*bundle
,
184 const fd_set
*fdset __unused
)
186 struct prompt
*p
= descriptor2prompt(d
);
190 char linebuff
[LINE_LEN
];
192 if (p
->TermMode
== NULL
) {
193 n
= read(p
->fd_in
, linebuff
, sizeof linebuff
- 1);
195 if (linebuff
[n
-1] == '\n')
196 linebuff
[--n
] = '\0';
199 p
->nonewline
= 1; /* Maybe command_Decode does a prompt */
202 if ((op
= log_PromptContext
) == NULL
)
203 log_PromptContext
= p
;
204 if (!command_Decode(bundle
, linebuff
, n
, p
, p
->src
.from
))
205 prompt_Printf(p
, "Syntax error\n");
206 log_PromptContext
= op
;
209 log_Printf(LogPHASE
, "%s: Client connection closed.\n", p
->src
.from
);
212 prompt_Destroy(p
, 0);
217 switch (p
->TermMode
->state
) {
218 case DATALINK_CLOSED
:
219 prompt_Printf(p
, "Link lost, terminal mode.\n");
220 prompt_TtyCommandMode(p
);
229 prompt_Printf(p
, "\nPacket mode detected.\n");
230 prompt_TtyCommandMode(p
);
232 /* We'll get a prompt because of our status change */
236 /* Wait 'till we're in a state we care about */
241 * We are in terminal mode, decode special sequences
243 n
= read(p
->fd_in
, &ch
, 1);
244 log_Printf(LogDEBUG
, "Got %d bytes (reading from the terminal)\n", n
);
247 switch (p
->readtilde
) {
252 if (physical_Write(p
->TermMode
->physical
, &ch
, n
) < 0) {
253 log_Printf(LogWARN
, "error writing to modem: %s\n", strerror(errno
));
254 prompt_TtyCommandMode(p
);
263 datalink_Up(p
->TermMode
, 0, 1);
264 prompt_Printf(p
, "\nPacket mode.\n");
265 prompt_TtyCommandMode(p
);
268 prompt_TtyCommandMode(p
);
285 arg
.cx
= p
->TermMode
;
292 if (physical_Write(p
->TermMode
->physical
, &ch
, n
) < 0) {
293 log_Printf(LogWARN
, "error writing to modem: %s\n", strerror(errno
));
294 prompt_TtyCommandMode(p
);
305 prompt_Write(struct fdescriptor
*d __unused
, struct bundle
*bundle __unused
,
306 const fd_set
*fdset __unused
)
308 /* We never want to write here ! */
309 log_Printf(LogALERT
, "prompt_Write: Internal error: Bad call !\n");
314 prompt_Create(struct server
*s
, struct bundle
*bundle
, int fd
)
316 struct prompt
*p
= (struct prompt
*)malloc(sizeof(struct prompt
));
319 p
->desc
.type
= PROMPT_DESCRIPTOR
;
320 p
->desc
.UpdateSet
= prompt_UpdateSet
;
321 p
->desc
.IsSet
= prompt_IsSet
;
322 p
->desc
.Read
= prompt_Read
;
323 p
->desc
.Write
= prompt_Write
;
325 if (fd
== PROMPT_STD
) {
326 char *tty
= ttyname(STDIN_FILENO
);
332 p
->fd_in
= STDIN_FILENO
;
333 p
->fd_out
= STDOUT_FILENO
;
336 p
->auth
= LOCAL_AUTH
;
337 p
->src
.type
= "Controller";
338 strncpy(p
->src
.from
, tty
, sizeof p
->src
.from
- 1);
339 p
->src
.from
[sizeof p
->src
.from
- 1] = '\0';
340 tcgetattr(p
->fd_in
, &p
->oldtio
); /* Save original tty mode */
342 p
->fd_in
= p
->fd_out
= fd
;
343 p
->Term
= fdopen(fd
, "a+");
345 p
->auth
= *s
->cfg
.passwd
? LOCAL_NO_AUTH
: LOCAL_AUTH
;
346 p
->src
.type
= "unknown";
354 log_RegisterPrompt(p
);
361 prompt_Destroy(struct prompt
*p
, int verbose
)
364 if (p
->Term
!= stdout
) {
367 if (p
->fd_out
!= p
->fd_in
)
370 log_Printf(LogPHASE
, "%s: Client connection dropped.\n", p
->src
.from
);
372 prompt_TtyOldMode(p
);
374 log_UnRegisterPrompt(p
);
380 prompt_Printf(struct prompt
*p
, const char *fmt
,...)
382 if (p
&& p
->active
) {
386 prompt_vPrintf(p
, fmt
, ap
);
392 prompt_vPrintf(struct prompt
*p
, const char *fmt
, va_list ap
)
394 if (p
&& p
->active
) {
399 /* Stuff '\r' in front of '\n' 'cos we're in raw mode */
400 size_t len
= strlen(fmt
);
402 if (len
&& len
< sizeof nfmt
- 1 && fmt
[len
-1] == '\n' &&
403 (len
== 1 || fmt
[len
-2] != '\r')) {
405 strcpy(nfmt
+ len
- 1, "\r\n");
411 vfprintf(p
->Term
, pfmt
, ap
);
418 prompt_TtyInit(struct prompt
*p
)
420 int stat
, fd
= p
? p
->fd_in
: STDIN_FILENO
;
421 struct termios newtio
;
423 stat
= fcntl(fd
, F_GETFL
, 0);
426 fcntl(fd
, F_SETFL
, stat
);
432 tcgetattr(fd
, &newtio
);
434 newtio
.c_lflag
&= ~(ECHO
| ISIG
| ICANON
);
436 newtio
.c_oflag
&= ~OPOST
;
438 newtio
.c_cc
[VINTR
] = _POSIX_VDISABLE
;
439 newtio
.c_cc
[VMIN
] = 1;
440 newtio
.c_cc
[VTIME
] = 0;
441 newtio
.c_cflag
|= CS8
;
442 tcsetattr(fd
, TCSANOW
, &newtio
);
448 * Set tty into command mode. We allow canonical input and echo processing.
451 prompt_TtyCommandMode(struct prompt
*p
)
453 struct termios newtio
;
456 tcgetattr(p
->fd_in
, &newtio
);
457 newtio
.c_lflag
|= (ECHO
| ISIG
| ICANON
);
458 newtio
.c_iflag
= p
->oldtio
.c_iflag
;
459 newtio
.c_oflag
|= OPOST
;
460 tcsetattr(p
->fd_in
, TCSADRAIN
, &newtio
);
462 stat
= fcntl(p
->fd_in
, F_GETFL
, 0);
465 fcntl(p
->fd_in
, F_SETFL
, stat
);
472 * Set tty into terminal mode which is used while we invoke term command.
475 prompt_TtyTermMode(struct prompt
*p
, struct datalink
*dl
)
479 if (p
->Term
== stdout
)
480 tcsetattr(p
->fd_in
, TCSADRAIN
, &p
->comtio
);
482 stat
= fcntl(p
->fd_in
, F_GETFL
, 0);
485 fcntl(p
->fd_in
, F_SETFL
, stat
);
491 prompt_TtyOldMode(struct prompt
*p
)
495 stat
= fcntl(p
->fd_in
, F_GETFL
, 0);
498 fcntl(p
->fd_in
, F_SETFL
, stat
);
501 if (p
->Term
== stdout
)
502 tcsetattr(p
->fd_in
, TCSADRAIN
, &p
->oldtio
);
506 prompt_pgrp(struct prompt
*p
)
508 return tcgetpgrp(p
->fd_in
);
512 PasswdCommand(struct cmdargs
const *arg
)
517 log_Printf(LogWARN
, "passwd: Cannot specify without a prompt\n");
521 if (arg
->prompt
->owner
== NULL
) {
522 log_Printf(LogWARN
, "passwd: Not required\n");
526 if (arg
->argc
== arg
->argn
)
528 else if (arg
->argc
> arg
->argn
+1)
531 pass
= arg
->argv
[arg
->argn
];
533 if (!strcmp(arg
->prompt
->owner
->cfg
.passwd
, pass
))
534 arg
->prompt
->auth
= LOCAL_AUTH
;
536 arg
->prompt
->auth
= LOCAL_NO_AUTH
;
541 static struct pppTimer bgtimer
;
544 prompt_TimedContinue(void *v
)
546 prompt_Continue((struct prompt
*)v
);
550 prompt_Continue(struct prompt
*p
)
552 timer_Stop(&bgtimer
);
553 if (getpgrp() == prompt_pgrp(p
)) {
554 prompt_TtyCommandMode(p
);
557 log_ActivatePrompt(p
);
558 } else if (!p
->owner
) {
559 bgtimer
.func
= prompt_TimedContinue
;
560 bgtimer
.name
= "prompt bg";
561 bgtimer
.load
= SECTICKS
;
563 timer_Start(&bgtimer
);
568 prompt_Suspend(struct prompt
*p
)
570 if (getpgrp() == prompt_pgrp(p
)) {
571 prompt_TtyOldMode(p
);
572 log_DeactivatePrompt(p
);