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
26 * $FreeBSD: src/usr.sbin/ppp/prompt.c,v 1.20.2.5 2003/04/05 10:51:39 ume Exp $
27 * $DragonFly: src/usr.sbin/ppp/prompt.c,v 1.2 2003/06/17 04:30:01 dillon Exp $
30 #include <sys/param.h>
31 #include <netinet/in.h>
32 #include <netinet/in_systm.h>
33 #include <netinet/ip.h>
34 #include <sys/socket.h>
42 #include <sys/fcntl.h>
51 #include "descriptor.h"
56 #include "throughput.h"
57 #include "slcompress.h"
84 prompt_Display(struct prompt
*p
)
86 /* XXX: See Index2Nam() - should we only figure this out once ? */
87 static char shostname
[MAXHOSTNAMELEN
];
88 const char *pconnect
, *pauth
;
90 if (p
->TermMode
|| !p
->needprompt
)
98 fprintf(p
->Term
, "\n");
100 if (p
->auth
== LOCAL_AUTH
)
105 if (p
->bundle
->ncp
.ipcp
.fsm
.state
== ST_OPENED
)
108 else if (!Enabled(p
->bundle
, OPT_IPCP
) &&
109 p
->bundle
->ncp
.ipv6cp
.fsm
.state
== ST_OPENED
)
112 else if (bundle_Phase(p
->bundle
) == PHASE_NETWORK
)
114 else if (bundle_Phase(p
->bundle
) == PHASE_AUTHENTICATE
)
119 if (*shostname
== '\0') {
122 if (gethostname(shostname
, sizeof shostname
) || *shostname
== '\0')
123 strcpy(shostname
, "localhost");
124 else if ((dot
= strchr(shostname
, '.')))
128 fprintf(p
->Term
, "%s%s%s> ", pconnect
, pauth
, shostname
);
133 prompt_UpdateSet(struct fdescriptor
*d
, fd_set
*r
, fd_set
*w
, fd_set
*e
, int *n
)
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
, const fd_set
*fdset
)
185 struct prompt
*p
= descriptor2prompt(d
);
189 char linebuff
[LINE_LEN
];
191 if (p
->TermMode
== NULL
) {
192 n
= read(p
->fd_in
, linebuff
, sizeof linebuff
- 1);
194 if (linebuff
[n
-1] == '\n')
195 linebuff
[--n
] = '\0';
198 p
->nonewline
= 1; /* Maybe command_Decode does a prompt */
201 if ((op
= log_PromptContext
) == NULL
)
202 log_PromptContext
= p
;
203 if (!command_Decode(bundle
, linebuff
, n
, p
, p
->src
.from
))
204 prompt_Printf(p
, "Syntax error\n");
205 log_PromptContext
= op
;
208 log_Printf(LogPHASE
, "%s: Client connection closed.\n", p
->src
.from
);
211 prompt_Destroy(p
, 0);
216 switch (p
->TermMode
->state
) {
217 case DATALINK_CLOSED
:
218 prompt_Printf(p
, "Link lost, terminal mode.\n");
219 prompt_TtyCommandMode(p
);
228 prompt_Printf(p
, "\nPacket mode detected.\n");
229 prompt_TtyCommandMode(p
);
231 /* We'll get a prompt because of our status change */
235 /* Wait 'till we're in a state we care about */
240 * We are in terminal mode, decode special sequences
242 n
= read(p
->fd_in
, &ch
, 1);
243 log_Printf(LogDEBUG
, "Got %d bytes (reading from the terminal)\n", n
);
246 switch (p
->readtilde
) {
251 if (physical_Write(p
->TermMode
->physical
, &ch
, n
) < 0) {
252 log_Printf(LogWARN
, "error writing to modem: %s\n", strerror(errno
));
253 prompt_TtyCommandMode(p
);
262 datalink_Up(p
->TermMode
, 0, 1);
263 prompt_Printf(p
, "\nPacket mode.\n");
264 prompt_TtyCommandMode(p
);
267 prompt_TtyCommandMode(p
);
284 arg
.cx
= p
->TermMode
;
291 if (physical_Write(p
->TermMode
->physical
, &ch
, n
) < 0) {
292 log_Printf(LogWARN
, "error writing to modem: %s\n", strerror(errno
));
293 prompt_TtyCommandMode(p
);
304 prompt_Write(struct fdescriptor
*d
, struct bundle
*bundle
, const fd_set
*fdset
)
306 /* We never want to write here ! */
307 log_Printf(LogALERT
, "prompt_Write: Internal error: Bad call !\n");
312 prompt_Create(struct server
*s
, struct bundle
*bundle
, int fd
)
314 struct prompt
*p
= (struct prompt
*)malloc(sizeof(struct prompt
));
317 p
->desc
.type
= PROMPT_DESCRIPTOR
;
318 p
->desc
.UpdateSet
= prompt_UpdateSet
;
319 p
->desc
.IsSet
= prompt_IsSet
;
320 p
->desc
.Read
= prompt_Read
;
321 p
->desc
.Write
= prompt_Write
;
323 if (fd
== PROMPT_STD
) {
324 char *tty
= ttyname(STDIN_FILENO
);
330 p
->fd_in
= STDIN_FILENO
;
331 p
->fd_out
= STDOUT_FILENO
;
334 p
->auth
= LOCAL_AUTH
;
335 p
->src
.type
= "Controller";
336 strncpy(p
->src
.from
, tty
, sizeof p
->src
.from
- 1);
337 p
->src
.from
[sizeof p
->src
.from
- 1] = '\0';
338 tcgetattr(p
->fd_in
, &p
->oldtio
); /* Save original tty mode */
340 p
->fd_in
= p
->fd_out
= fd
;
341 p
->Term
= fdopen(fd
, "a+");
343 p
->auth
= *s
->cfg
.passwd
? LOCAL_NO_AUTH
: LOCAL_AUTH
;
344 p
->src
.type
= "unknown";
352 log_RegisterPrompt(p
);
359 prompt_Destroy(struct prompt
*p
, int verbose
)
362 if (p
->Term
!= stdout
) {
365 if (p
->fd_out
!= p
->fd_in
)
368 log_Printf(LogPHASE
, "%s: Client connection dropped.\n", p
->src
.from
);
370 prompt_TtyOldMode(p
);
372 log_UnRegisterPrompt(p
);
378 prompt_Printf(struct prompt
*p
, const char *fmt
,...)
380 if (p
&& p
->active
) {
384 prompt_vPrintf(p
, fmt
, ap
);
390 prompt_vPrintf(struct prompt
*p
, const char *fmt
, va_list ap
)
392 if (p
&& p
->active
) {
397 /* Stuff '\r' in front of '\n' 'cos we're in raw mode */
398 int len
= strlen(fmt
);
400 if (len
&& len
< sizeof nfmt
- 1 && fmt
[len
-1] == '\n' &&
401 (len
== 1 || fmt
[len
-2] != '\r')) {
403 strcpy(nfmt
+ len
- 1, "\r\n");
409 vfprintf(p
->Term
, pfmt
, ap
);
416 prompt_TtyInit(struct prompt
*p
)
418 int stat
, fd
= p
? p
->fd_in
: STDIN_FILENO
;
419 struct termios newtio
;
421 stat
= fcntl(fd
, F_GETFL
, 0);
424 fcntl(fd
, F_SETFL
, stat
);
430 tcgetattr(fd
, &newtio
);
432 newtio
.c_lflag
&= ~(ECHO
| ISIG
| ICANON
);
434 newtio
.c_oflag
&= ~OPOST
;
436 newtio
.c_cc
[VINTR
] = _POSIX_VDISABLE
;
437 newtio
.c_cc
[VMIN
] = 1;
438 newtio
.c_cc
[VTIME
] = 0;
439 newtio
.c_cflag
|= CS8
;
440 tcsetattr(fd
, TCSANOW
, &newtio
);
446 * Set tty into command mode. We allow canonical input and echo processing.
449 prompt_TtyCommandMode(struct prompt
*p
)
451 struct termios newtio
;
454 tcgetattr(p
->fd_in
, &newtio
);
455 newtio
.c_lflag
|= (ECHO
| ISIG
| ICANON
);
456 newtio
.c_iflag
= p
->oldtio
.c_iflag
;
457 newtio
.c_oflag
|= OPOST
;
458 tcsetattr(p
->fd_in
, TCSADRAIN
, &newtio
);
460 stat
= fcntl(p
->fd_in
, F_GETFL
, 0);
463 fcntl(p
->fd_in
, F_SETFL
, stat
);
470 * Set tty into terminal mode which is used while we invoke term command.
473 prompt_TtyTermMode(struct prompt
*p
, struct datalink
*dl
)
477 if (p
->Term
== stdout
)
478 tcsetattr(p
->fd_in
, TCSADRAIN
, &p
->comtio
);
480 stat
= fcntl(p
->fd_in
, F_GETFL
, 0);
483 fcntl(p
->fd_in
, F_SETFL
, stat
);
489 prompt_TtyOldMode(struct prompt
*p
)
493 stat
= fcntl(p
->fd_in
, F_GETFL
, 0);
496 fcntl(p
->fd_in
, F_SETFL
, stat
);
499 if (p
->Term
== stdout
)
500 tcsetattr(p
->fd_in
, TCSADRAIN
, &p
->oldtio
);
504 prompt_pgrp(struct prompt
*p
)
506 return tcgetpgrp(p
->fd_in
);
510 PasswdCommand(struct cmdargs
const *arg
)
515 log_Printf(LogWARN
, "passwd: Cannot specify without a prompt\n");
519 if (arg
->prompt
->owner
== NULL
) {
520 log_Printf(LogWARN
, "passwd: Not required\n");
524 if (arg
->argc
== arg
->argn
)
526 else if (arg
->argc
> arg
->argn
+1)
529 pass
= arg
->argv
[arg
->argn
];
531 if (!strcmp(arg
->prompt
->owner
->cfg
.passwd
, pass
))
532 arg
->prompt
->auth
= LOCAL_AUTH
;
534 arg
->prompt
->auth
= LOCAL_NO_AUTH
;
539 static struct pppTimer bgtimer
;
542 prompt_TimedContinue(void *v
)
544 prompt_Continue((struct prompt
*)v
);
548 prompt_Continue(struct prompt
*p
)
550 timer_Stop(&bgtimer
);
551 if (getpgrp() == prompt_pgrp(p
)) {
552 prompt_TtyCommandMode(p
);
555 log_ActivatePrompt(p
);
556 } else if (!p
->owner
) {
557 bgtimer
.func
= prompt_TimedContinue
;
558 bgtimer
.name
= "prompt bg";
559 bgtimer
.load
= SECTICKS
;
561 timer_Start(&bgtimer
);
566 prompt_Suspend(struct prompt
*p
)
568 if (getpgrp() == prompt_pgrp(p
)) {
569 prompt_TtyOldMode(p
);
570 log_DeactivatePrompt(p
);