prompt.c revision 36285
136285Sbrian/*- 236285Sbrian * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> 336285Sbrian * All rights reserved. 436285Sbrian * 536285Sbrian * Redistribution and use in source and binary forms, with or without 636285Sbrian * modification, are permitted provided that the following conditions 736285Sbrian * are met: 836285Sbrian * 1. Redistributions of source code must retain the above copyright 936285Sbrian * notice, this list of conditions and the following disclaimer. 1036285Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1136285Sbrian * notice, this list of conditions and the following disclaimer in the 1236285Sbrian * documentation and/or other materials provided with the distribution. 1336285Sbrian * 1436285Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1536285Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1636285Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1736285Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1836285Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1936285Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2036285Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2136285Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2236285Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2336285Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2436285Sbrian * SUCH DAMAGE. 2536285Sbrian * 2636285Sbrian * $Id: prompt.c,v 1.1.2.30 1998/05/10 22:20:17 brian Exp $ 2736285Sbrian */ 2836285Sbrian 2936285Sbrian#include <sys/param.h> 3036285Sbrian#include <netinet/in.h> 3136285Sbrian#include <netinet/in_systm.h> 3236285Sbrian#include <netinet/ip.h> 3336285Sbrian#include <sys/un.h> 3436285Sbrian 3536285Sbrian#include <errno.h> 3636285Sbrian#include <stdarg.h> 3736285Sbrian#include <stdio.h> 3836285Sbrian#include <stdlib.h> 3936285Sbrian#include <string.h> 4036285Sbrian#include <sys/fcntl.h> 4136285Sbrian#include <termios.h> 4236285Sbrian#include <unistd.h> 4336285Sbrian 4436285Sbrian#include "defs.h" 4536285Sbrian#include "timer.h" 4636285Sbrian#include "command.h" 4736285Sbrian#include "log.h" 4836285Sbrian#include "descriptor.h" 4936285Sbrian#include "prompt.h" 5036285Sbrian#include "fsm.h" 5136285Sbrian#include "lcp.h" 5236285Sbrian#include "auth.h" 5336285Sbrian#include "iplist.h" 5436285Sbrian#include "throughput.h" 5536285Sbrian#include "slcompress.h" 5636285Sbrian#include "ipcp.h" 5736285Sbrian#include "filter.h" 5836285Sbrian#include "lqr.h" 5936285Sbrian#include "hdlc.h" 6036285Sbrian#include "async.h" 6136285Sbrian#include "mbuf.h" 6236285Sbrian#include "ccp.h" 6336285Sbrian#include "link.h" 6436285Sbrian#include "physical.h" 6536285Sbrian#include "mp.h" 6636285Sbrian#include "bundle.h" 6736285Sbrian#include "chat.h" 6836285Sbrian#include "chap.h" 6936285Sbrian#include "datalink.h" 7036285Sbrian#include "server.h" 7136285Sbrian 7236285Sbrianstatic void 7336285Sbrianprompt_Display(struct prompt *p) 7436285Sbrian{ 7536285Sbrian static char shostname[MAXHOSTNAMELEN]; 7636285Sbrian const char *pconnect, *pauth; 7736285Sbrian 7836285Sbrian if (p->TermMode || !p->needprompt) 7936285Sbrian return; 8036285Sbrian 8136285Sbrian p->needprompt = 0; 8236285Sbrian 8336285Sbrian if (p->nonewline) 8436285Sbrian p->nonewline = 0; 8536285Sbrian else 8636285Sbrian fprintf(p->Term, "\n"); 8736285Sbrian 8836285Sbrian if (p->auth == LOCAL_AUTH) 8936285Sbrian pauth = " ON "; 9036285Sbrian else 9136285Sbrian pauth = " on "; 9236285Sbrian 9336285Sbrian if (p->bundle->ncp.ipcp.fsm.state == ST_OPENED) 9436285Sbrian pconnect = "PPP"; 9536285Sbrian else if (bundle_Phase(p->bundle) == PHASE_NETWORK) 9636285Sbrian pconnect = "PPp"; 9736285Sbrian else if (bundle_Phase(p->bundle) == PHASE_AUTHENTICATE) 9836285Sbrian pconnect = "Ppp"; 9936285Sbrian else 10036285Sbrian pconnect = "ppp"; 10136285Sbrian 10236285Sbrian if (*shostname == '\0') { 10336285Sbrian char *dot; 10436285Sbrian 10536285Sbrian if (gethostname(shostname, sizeof shostname)) 10636285Sbrian strcpy(shostname, "localhost"); 10736285Sbrian else if ((dot = strchr(shostname, '.'))) 10836285Sbrian *dot = '\0'; 10936285Sbrian } 11036285Sbrian 11136285Sbrian fprintf(p->Term, "%s%s%s> ", pconnect, pauth, shostname); 11236285Sbrian fflush(p->Term); 11336285Sbrian} 11436285Sbrian 11536285Sbrianstatic int 11636285Sbrianprompt_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 11736285Sbrian{ 11836285Sbrian struct prompt *p = descriptor2prompt(d); 11936285Sbrian int sets; 12036285Sbrian 12136285Sbrian sets = 0; 12236285Sbrian 12336285Sbrian if (!p->active) 12436285Sbrian return sets; 12536285Sbrian 12636285Sbrian if (p->fd_in >= 0) { 12736285Sbrian if (r) { 12836285Sbrian FD_SET(p->fd_in, r); 12936285Sbrian log_Printf(LogTIMER, "prompt %s: fdset(r) %d\n", p->src.from, p->fd_in); 13036285Sbrian sets++; 13136285Sbrian } 13236285Sbrian if (e) { 13336285Sbrian FD_SET(p->fd_in, e); 13436285Sbrian log_Printf(LogTIMER, "prompt %s: fdset(e) %d\n", p->src.from, p->fd_in); 13536285Sbrian sets++; 13636285Sbrian } 13736285Sbrian if (sets && *n < p->fd_in + 1) 13836285Sbrian *n = p->fd_in + 1; 13936285Sbrian } 14036285Sbrian 14136285Sbrian prompt_Display(p); 14236285Sbrian 14336285Sbrian return sets; 14436285Sbrian} 14536285Sbrian 14636285Sbrianstatic int 14736285Sbrianprompt_IsSet(struct descriptor *d, const fd_set *fdset) 14836285Sbrian{ 14936285Sbrian struct prompt *p = descriptor2prompt(d); 15036285Sbrian return p->fd_in >= 0 && FD_ISSET(p->fd_in, fdset); 15136285Sbrian} 15236285Sbrian 15336285Sbrian 15436285Sbrianstatic void 15536285Sbrianprompt_ShowHelp(struct prompt *p) 15636285Sbrian{ 15736285Sbrian prompt_Printf(p, "The following commands are available:\r\n"); 15836285Sbrian prompt_Printf(p, " ~p\tEnter Packet mode\r\n"); 15936285Sbrian prompt_Printf(p, " ~-\tDecrease log level\r\n"); 16036285Sbrian prompt_Printf(p, " ~+\tIncrease log level\r\n"); 16136285Sbrian prompt_Printf(p, " ~t\tShow timers\r\n"); 16236285Sbrian prompt_Printf(p, " ~m\tShow memory map\r\n"); 16336285Sbrian prompt_Printf(p, " ~.\tTerminate program\r\n"); 16436285Sbrian prompt_Printf(p, " ~?\tThis help\r\n"); 16536285Sbrian} 16636285Sbrian 16736285Sbrianstatic void 16836285Sbrianprompt_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 16936285Sbrian{ 17036285Sbrian struct prompt *p = descriptor2prompt(d); 17136285Sbrian int n; 17236285Sbrian char ch; 17336285Sbrian static int ttystate; 17436285Sbrian char linebuff[LINE_LEN]; 17536285Sbrian 17636285Sbrian if (p->TermMode == NULL) { 17736285Sbrian n = read(p->fd_in, linebuff, sizeof linebuff - 1); 17836285Sbrian if (n > 0) { 17936285Sbrian if (linebuff[n-1] == '\n') 18036285Sbrian linebuff[--n] = '\0'; 18136285Sbrian else 18236285Sbrian linebuff[n] = '\0'; 18336285Sbrian p->nonewline = 1; /* Maybe command_Decode does a prompt */ 18436285Sbrian prompt_Required(p); 18536285Sbrian if (n) 18636285Sbrian command_Decode(bundle, linebuff, n, p, p->src.from); 18736285Sbrian } else if (n <= 0) { 18836285Sbrian log_Printf(LogPHASE, "Client connection closed.\n"); 18936285Sbrian prompt_Destroy(p, 0); 19036285Sbrian } 19136285Sbrian return; 19236285Sbrian } 19336285Sbrian 19436285Sbrian switch (p->TermMode->state) { 19536285Sbrian case DATALINK_CLOSED: 19636285Sbrian prompt_Printf(p, "Link lost, terminal mode.\n"); 19736285Sbrian prompt_TtyCommandMode(p); 19836285Sbrian p->nonewline = 0; 19936285Sbrian prompt_Required(p); 20036285Sbrian return; 20136285Sbrian 20236285Sbrian case DATALINK_READY: 20336285Sbrian break; 20436285Sbrian 20536285Sbrian case DATALINK_OPEN: 20636285Sbrian prompt_Printf(p, "\nPacket mode detected.\n"); 20736285Sbrian prompt_TtyCommandMode(p); 20836285Sbrian p->nonewline = 0; 20936285Sbrian /* We'll get a prompt because of our status change */ 21036285Sbrian /* Fall through */ 21136285Sbrian 21236285Sbrian default: 21336285Sbrian /* Wait 'till we're in a state we care about */ 21436285Sbrian return; 21536285Sbrian } 21636285Sbrian 21736285Sbrian /* 21836285Sbrian * We are in terminal mode, decode special sequences 21936285Sbrian */ 22036285Sbrian n = read(p->fd_in, &ch, 1); 22136285Sbrian log_Printf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n); 22236285Sbrian 22336285Sbrian if (n > 0) { 22436285Sbrian switch (ttystate) { 22536285Sbrian case 0: 22636285Sbrian if (ch == '~') 22736285Sbrian ttystate++; 22836285Sbrian else 22936285Sbrian if (physical_Write(p->TermMode->physical, &ch, n) < 0) { 23036285Sbrian log_Printf(LogERROR, "error writing to modem: %s\n", strerror(errno)); 23136285Sbrian prompt_TtyCommandMode(p); 23236285Sbrian } 23336285Sbrian break; 23436285Sbrian case 1: 23536285Sbrian switch (ch) { 23636285Sbrian case '?': 23736285Sbrian prompt_ShowHelp(p); 23836285Sbrian break; 23936285Sbrian case 'p': 24036285Sbrian datalink_Up(p->TermMode, 0, 1); 24136285Sbrian prompt_Printf(p, "\nPacket mode.\n"); 24236285Sbrian prompt_TtyCommandMode(p); 24336285Sbrian break; 24436285Sbrian case '.': 24536285Sbrian prompt_TtyCommandMode(p); 24636285Sbrian p->nonewline = 0; 24736285Sbrian prompt_Required(p); 24836285Sbrian break; 24936285Sbrian case 't': 25036285Sbrian timer_Show(0, p); 25136285Sbrian break; 25236285Sbrian case 'm': 25336285Sbrian mbuf_Show(NULL); 25436285Sbrian break; 25536285Sbrian default: 25636285Sbrian if (physical_Write(p->TermMode->physical, &ch, n) < 0) { 25736285Sbrian log_Printf(LogERROR, "error writing to modem: %s\n", strerror(errno)); 25836285Sbrian prompt_TtyCommandMode(p); 25936285Sbrian } 26036285Sbrian break; 26136285Sbrian } 26236285Sbrian ttystate = 0; 26336285Sbrian break; 26436285Sbrian } 26536285Sbrian } 26636285Sbrian} 26736285Sbrian 26836285Sbrianstatic void 26936285Sbrianprompt_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 27036285Sbrian{ 27136285Sbrian /* We never want to write here ! */ 27236285Sbrian log_Printf(LogERROR, "prompt_Write: Internal error: Bad call !\n"); 27336285Sbrian} 27436285Sbrian 27536285Sbrianstruct prompt * 27636285Sbrianprompt_Create(struct server *s, struct bundle *bundle, int fd) 27736285Sbrian{ 27836285Sbrian struct prompt *p = (struct prompt *)malloc(sizeof(struct prompt)); 27936285Sbrian 28036285Sbrian if (p != NULL) { 28136285Sbrian p->desc.type = PROMPT_DESCRIPTOR; 28236285Sbrian p->desc.next = NULL; 28336285Sbrian p->desc.UpdateSet = prompt_UpdateSet; 28436285Sbrian p->desc.IsSet = prompt_IsSet; 28536285Sbrian p->desc.Read = prompt_Read; 28636285Sbrian p->desc.Write = prompt_Write; 28736285Sbrian 28836285Sbrian if (fd == PROMPT_STD) { 28936285Sbrian p->fd_in = STDIN_FILENO; 29036285Sbrian p->fd_out = STDOUT_FILENO; 29136285Sbrian p->Term = stdout; 29236285Sbrian p->owner = NULL; 29336285Sbrian p->auth = LOCAL_AUTH; 29436285Sbrian p->src.type = "Controller"; 29536285Sbrian strncpy(p->src.from, ttyname(p->fd_out), sizeof p->src.from - 1); 29636285Sbrian p->src.from[sizeof p->src.from - 1] = '\0'; 29736285Sbrian tcgetattr(p->fd_in, &p->oldtio); /* Save original tty mode */ 29836285Sbrian } else { 29936285Sbrian p->fd_in = p->fd_out = fd; 30036285Sbrian p->Term = fdopen(fd, "a+"); 30136285Sbrian p->owner = s; 30236285Sbrian p->auth = *s->passwd ? LOCAL_NO_AUTH : LOCAL_AUTH; 30336285Sbrian p->src.type = "unknown"; 30436285Sbrian *p->src.from = '\0'; 30536285Sbrian } 30636285Sbrian p->TermMode = NULL; 30736285Sbrian p->nonewline = 1; 30836285Sbrian p->needprompt = 1; 30936285Sbrian p->active = 1; 31036285Sbrian p->bundle = bundle; 31136285Sbrian if (p->bundle) 31236285Sbrian bundle_RegisterDescriptor(p->bundle, &p->desc); 31336285Sbrian log_RegisterPrompt(p); 31436285Sbrian log_DiscardAllLocal(&p->logmask); 31536285Sbrian } 31636285Sbrian 31736285Sbrian return p; 31836285Sbrian} 31936285Sbrian 32036285Sbrianvoid 32136285Sbrianprompt_Destroy(struct prompt *p, int verbose) 32236285Sbrian{ 32336285Sbrian if (p->Term != stdout) { 32436285Sbrian fclose(p->Term); 32536285Sbrian close(p->fd_in); 32636285Sbrian if (p->fd_out != p->fd_in) 32736285Sbrian close(p->fd_out); 32836285Sbrian if (verbose) 32936285Sbrian log_Printf(LogPHASE, "Client connection dropped.\n"); 33036285Sbrian } else 33136285Sbrian prompt_TtyOldMode(p); 33236285Sbrian 33336285Sbrian log_UnRegisterPrompt(p); 33436285Sbrian bundle_UnRegisterDescriptor(p->bundle, &p->desc); 33536285Sbrian free(p); 33636285Sbrian} 33736285Sbrian 33836285Sbrianvoid 33936285Sbrianprompt_Printf(struct prompt *p, const char *fmt,...) 34036285Sbrian{ 34136285Sbrian if (p && p->active) { 34236285Sbrian va_list ap; 34336285Sbrian va_start(ap, fmt); 34436285Sbrian vfprintf(p->Term, fmt, ap); 34536285Sbrian fflush(p->Term); 34636285Sbrian va_end(ap); 34736285Sbrian p->nonewline = 1; 34836285Sbrian } 34936285Sbrian} 35036285Sbrian 35136285Sbrianvoid 35236285Sbrianprompt_vPrintf(struct prompt *p, const char *fmt, va_list ap) 35336285Sbrian{ 35436285Sbrian if (p && p->active) { 35536285Sbrian vfprintf(p->Term, fmt, ap); 35636285Sbrian fflush(p->Term); 35736285Sbrian p->nonewline = 1; 35836285Sbrian } 35936285Sbrian} 36036285Sbrian 36136285Sbrianvoid 36236285Sbrianprompt_TtyInit(struct prompt *p) 36336285Sbrian{ 36436285Sbrian int stat, fd = p ? p->fd_in : STDIN_FILENO; 36536285Sbrian struct termios newtio; 36636285Sbrian 36736285Sbrian stat = fcntl(fd, F_GETFL, 0); 36836285Sbrian if (stat > 0) { 36936285Sbrian stat |= O_NONBLOCK; 37036285Sbrian fcntl(fd, F_SETFL, stat); 37136285Sbrian } 37236285Sbrian 37336285Sbrian if (p) 37436285Sbrian newtio = p->oldtio; 37536285Sbrian else 37636285Sbrian tcgetattr(fd, &newtio); 37736285Sbrian 37836285Sbrian newtio.c_lflag &= ~(ECHO | ISIG | ICANON); 37936285Sbrian newtio.c_iflag = 0; 38036285Sbrian newtio.c_oflag &= ~OPOST; 38136285Sbrian newtio.c_cc[VEOF] = _POSIX_VDISABLE; 38236285Sbrian if (!p) 38336285Sbrian newtio.c_cc[VINTR] = _POSIX_VDISABLE; 38436285Sbrian newtio.c_cc[VMIN] = 1; 38536285Sbrian newtio.c_cc[VTIME] = 0; 38636285Sbrian newtio.c_cflag |= CS8; 38736285Sbrian tcsetattr(fd, TCSANOW, &newtio); 38836285Sbrian if (p) 38936285Sbrian p->comtio = newtio; 39036285Sbrian} 39136285Sbrian 39236285Sbrian/* 39336285Sbrian * Set tty into command mode. We allow canonical input and echo processing. 39436285Sbrian */ 39536285Sbrianvoid 39636285Sbrianprompt_TtyCommandMode(struct prompt *p) 39736285Sbrian{ 39836285Sbrian struct termios newtio; 39936285Sbrian int stat; 40036285Sbrian 40136285Sbrian tcgetattr(p->fd_in, &newtio); 40236285Sbrian newtio.c_lflag |= (ECHO | ISIG | ICANON); 40336285Sbrian newtio.c_iflag = p->oldtio.c_iflag; 40436285Sbrian newtio.c_oflag |= OPOST; 40536285Sbrian tcsetattr(p->fd_in, TCSADRAIN, &newtio); 40636285Sbrian 40736285Sbrian stat = fcntl(p->fd_in, F_GETFL, 0); 40836285Sbrian if (stat > 0) { 40936285Sbrian stat |= O_NONBLOCK; 41036285Sbrian fcntl(p->fd_in, F_SETFL, stat); 41136285Sbrian } 41236285Sbrian 41336285Sbrian p->TermMode = NULL; 41436285Sbrian} 41536285Sbrian 41636285Sbrian/* 41736285Sbrian * Set tty into terminal mode which is used while we invoke term command. 41836285Sbrian */ 41936285Sbrianvoid 42036285Sbrianprompt_TtyTermMode(struct prompt *p, struct datalink *dl) 42136285Sbrian{ 42236285Sbrian int stat; 42336285Sbrian 42436285Sbrian prompt_Printf(p, "Entering terminal mode on %s.\n", dl->name); 42536285Sbrian prompt_Printf(p, "Type `~?' for help.\n"); 42636285Sbrian 42736285Sbrian if (p->Term == stdout) 42836285Sbrian tcsetattr(p->fd_in, TCSADRAIN, &p->comtio); 42936285Sbrian 43036285Sbrian stat = fcntl(p->fd_in, F_GETFL, 0); 43136285Sbrian if (stat > 0) { 43236285Sbrian stat &= ~O_NONBLOCK; 43336285Sbrian fcntl(p->fd_in, F_SETFL, stat); 43436285Sbrian } 43536285Sbrian p->TermMode = dl; 43636285Sbrian} 43736285Sbrian 43836285Sbrianvoid 43936285Sbrianprompt_TtyOldMode(struct prompt *p) 44036285Sbrian{ 44136285Sbrian int stat; 44236285Sbrian 44336285Sbrian stat = fcntl(p->fd_in, F_GETFL, 0); 44436285Sbrian if (stat > 0) { 44536285Sbrian stat &= ~O_NONBLOCK; 44636285Sbrian fcntl(p->fd_in, F_SETFL, stat); 44736285Sbrian } 44836285Sbrian 44936285Sbrian if (p->Term == stdout) 45036285Sbrian tcsetattr(p->fd_in, TCSADRAIN, &p->oldtio); 45136285Sbrian} 45236285Sbrian 45336285Sbrianpid_t 45436285Sbrianprompt_pgrp(struct prompt *p) 45536285Sbrian{ 45636285Sbrian return tcgetpgrp(p->fd_in); 45736285Sbrian} 45836285Sbrian 45936285Sbrianint 46036285SbrianPasswdCommand(struct cmdargs const *arg) 46136285Sbrian{ 46236285Sbrian const char *pass; 46336285Sbrian 46436285Sbrian if (!arg->prompt) { 46536285Sbrian log_Printf(LogWARN, "passwd: Cannot specify without a prompt\n"); 46636285Sbrian return 0; 46736285Sbrian } 46836285Sbrian 46936285Sbrian if (arg->prompt->owner == NULL) { 47036285Sbrian log_Printf(LogWARN, "passwd: Not required\n"); 47136285Sbrian return 0; 47236285Sbrian } 47336285Sbrian 47436285Sbrian if (arg->argc == arg->argn) 47536285Sbrian pass = ""; 47636285Sbrian else if (arg->argc > arg->argn+1) 47736285Sbrian return -1; 47836285Sbrian else 47936285Sbrian pass = arg->argv[arg->argn]; 48036285Sbrian 48136285Sbrian if (!strcmp(arg->prompt->owner->passwd, pass)) 48236285Sbrian arg->prompt->auth = LOCAL_AUTH; 48336285Sbrian else 48436285Sbrian arg->prompt->auth = LOCAL_NO_AUTH; 48536285Sbrian 48636285Sbrian return 0; 48736285Sbrian} 48836285Sbrian 48936285Sbrianstatic struct pppTimer bgtimer; 49036285Sbrian 49136285Sbrianstatic void 49236285Sbrianprompt_TimedContinue(void *v) 49336285Sbrian{ 49436285Sbrian prompt_Continue((struct prompt *)v); 49536285Sbrian} 49636285Sbrian 49736285Sbrianvoid 49836285Sbrianprompt_Continue(struct prompt *p) 49936285Sbrian{ 50036285Sbrian timer_Stop(&bgtimer); 50136285Sbrian if (getpgrp() == prompt_pgrp(p)) { 50236285Sbrian prompt_TtyCommandMode(p); 50336285Sbrian p->nonewline = 1; 50436285Sbrian prompt_Required(p); 50536285Sbrian p->active = 1; 50636285Sbrian } else if (!p->owner) { 50736285Sbrian bgtimer.func = prompt_TimedContinue; 50836285Sbrian bgtimer.name = "prompt bg"; 50936285Sbrian bgtimer.load = SECTICKS; 51036285Sbrian bgtimer.arg = p; 51136285Sbrian timer_Start(&bgtimer); 51236285Sbrian } 51336285Sbrian} 51436285Sbrian 51536285Sbrianvoid 51636285Sbrianprompt_Suspend(struct prompt *p) 51736285Sbrian{ 51836285Sbrian if (getpgrp() == prompt_pgrp(p)) { 51936285Sbrian prompt_TtyOldMode(p); 52036285Sbrian p->active = 0; 52136285Sbrian } 52236285Sbrian} 523