2011-03-30 12:46:40 +00:00
|
|
|
#include <u.h>
|
|
|
|
#include <libc.h>
|
|
|
|
#include <bio.h>
|
|
|
|
#include <auth.h>
|
|
|
|
#include <libsec.h>
|
|
|
|
|
|
|
|
#include "../ip/telnet.h"
|
|
|
|
|
|
|
|
/* console state (for consctl) */
|
|
|
|
typedef struct Consstate Consstate;
|
|
|
|
struct Consstate{
|
|
|
|
int raw;
|
|
|
|
int hold;
|
|
|
|
};
|
|
|
|
Consstate *cons;
|
|
|
|
|
|
|
|
int notefd; /* for sending notes to the child */
|
|
|
|
int noproto; /* true if we shouldn't be using the telnet protocol */
|
|
|
|
int trusted; /* true if we need not authenticate - current user
|
|
|
|
is ok */
|
|
|
|
int nonone = 1; /* don't allow none logins */
|
|
|
|
int noworldonly; /* only noworld accounts */
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
Maxpath= 256,
|
|
|
|
Maxuser= 64,
|
|
|
|
Maxvar= 32,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* input and output buffers for network connection */
|
|
|
|
Biobuf netib;
|
|
|
|
Biobuf childib;
|
|
|
|
char remotesys[Maxpath]; /* name of remote system */
|
|
|
|
|
|
|
|
int alnum(int);
|
|
|
|
int conssim(void);
|
|
|
|
int fromchild(char*, int);
|
|
|
|
int fromnet(char*, int);
|
|
|
|
int termchange(Biobuf*, int);
|
|
|
|
int termsub(Biobuf*, uchar*, int);
|
|
|
|
int xlocchange(Biobuf*, int);
|
|
|
|
int xlocsub(Biobuf*, uchar*, int);
|
|
|
|
int challuser(char*);
|
|
|
|
int noworldlogin(char*);
|
|
|
|
void* share(ulong);
|
|
|
|
int doauth(char*);
|
|
|
|
|
|
|
|
#define TELNETLOG "telnet"
|
|
|
|
|
|
|
|
void
|
|
|
|
logit(char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list arg;
|
|
|
|
char buf[8192];
|
|
|
|
|
|
|
|
va_start(arg, fmt);
|
|
|
|
vseprint(buf, buf + sizeof(buf) / sizeof(*buf), fmt, arg);
|
|
|
|
va_end(arg);
|
|
|
|
syslog(0, TELNETLOG, "(%s) %s", remotesys, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
getremote(char *dir)
|
|
|
|
{
|
|
|
|
int fd, n;
|
|
|
|
char remfile[Maxpath];
|
|
|
|
|
|
|
|
sprint(remfile, "%s/remote", dir);
|
|
|
|
fd = open(remfile, OREAD);
|
|
|
|
if(fd < 0)
|
|
|
|
strcpy(remotesys, "unknown2");
|
|
|
|
n = read(fd, remotesys, sizeof(remotesys)-1);
|
|
|
|
if(n>0)
|
|
|
|
remotesys[n-1] = 0;
|
|
|
|
else
|
|
|
|
strcpy(remotesys, remfile);
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
char buf[1024];
|
|
|
|
int fd;
|
|
|
|
char user[Maxuser];
|
|
|
|
int tries = 0;
|
|
|
|
int childpid;
|
|
|
|
int n, eofs;
|
|
|
|
|
|
|
|
memset(user, 0, sizeof(user));
|
|
|
|
ARGBEGIN {
|
|
|
|
case 'n':
|
|
|
|
opt[Echo].local = 1;
|
|
|
|
noproto = 1;
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
noproto = 1;
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
nonone = 0;
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
trusted = 1;
|
|
|
|
strncpy(user, getuser(), sizeof(user)-1);
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
strncpy(user, ARGF(), sizeof(user)-1);
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
debug = 1;
|
|
|
|
break;
|
|
|
|
case 'N':
|
|
|
|
noworldonly = 1;
|
|
|
|
break;
|
|
|
|
} ARGEND
|
|
|
|
|
|
|
|
if(argc)
|
|
|
|
getremote(argv[argc-1]);
|
|
|
|
else
|
|
|
|
strcpy(remotesys, "unknown");
|
|
|
|
|
|
|
|
/* options we need routines for */
|
|
|
|
opt[Term].change = termchange;
|
|
|
|
opt[Term].sub = termsub;
|
|
|
|
opt[Xloc].sub = xlocsub;
|
|
|
|
|
|
|
|
/* setup default telnet options */
|
|
|
|
if(!noproto){
|
|
|
|
send3(1, Iac, Will, opt[Echo].code);
|
|
|
|
send3(1, Iac, Do, opt[Term].code);
|
|
|
|
send3(1, Iac, Do, opt[Xloc].code);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* shared data for console state */
|
|
|
|
cons = share(sizeof(Consstate));
|
|
|
|
if(cons == 0)
|
|
|
|
fatal("shared memory", 0, 0);
|
|
|
|
|
|
|
|
/* authenticate and create new name space */
|
|
|
|
Binit(&netib, 0, OREAD);
|
|
|
|
if (!trusted){
|
|
|
|
while(doauth(user) < 0)
|
|
|
|
if(++tries == 5){
|
|
|
|
logit("failed as %s: %r", user);
|
|
|
|
print("authentication failure:%r\r\n");
|
|
|
|
exits("authentication");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
logit("logged in as %s", user);
|
|
|
|
putenv("service", "con");
|
|
|
|
|
|
|
|
/* simulate /dev/consctl and /dev/cons using pipes */
|
|
|
|
fd = conssim();
|
|
|
|
if(fd < 0)
|
|
|
|
fatal("simulating", 0, 0);
|
|
|
|
Binit(&childib, fd, OREAD);
|
|
|
|
|
|
|
|
/* start a shell in a different process group */
|
|
|
|
switch(childpid = rfork(RFPROC|RFNAMEG|RFFDG|RFNOTEG)){
|
|
|
|
case -1:
|
|
|
|
fatal("fork", 0, 0);
|
|
|
|
case 0:
|
|
|
|
close(fd);
|
|
|
|
fd = open("/dev/cons", OREAD);
|
|
|
|
dup(fd, 0);
|
|
|
|
close(fd);
|
|
|
|
fd = open("/dev/cons", OWRITE);
|
|
|
|
dup(fd, 1);
|
|
|
|
dup(fd, 2);
|
|
|
|
close(fd);
|
|
|
|
segdetach(cons);
|
|
|
|
execl("/bin/rc", "rc", "-il", nil);
|
|
|
|
fatal("/bin/rc", 0, 0);
|
|
|
|
default:
|
|
|
|
sprint(buf, "/proc/%d/notepg", childpid);
|
|
|
|
notefd = open(buf, OWRITE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* two processes to shuttle bytes twixt children and network */
|
|
|
|
switch(fork()){
|
|
|
|
case -1:
|
|
|
|
fatal("fork", 0, 0);
|
|
|
|
case 0:
|
|
|
|
eofs = 0;
|
|
|
|
for(;;){
|
|
|
|
n = fromchild(buf, sizeof(buf));
|
|
|
|
if(n <= 0){
|
|
|
|
if(eofs++ > 2)
|
|
|
|
break;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
eofs = 0;
|
|
|
|
if(write(1, buf, n) != n)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
while((n = fromnet(buf, sizeof(buf))) >= 0)
|
|
|
|
if(write(fd, buf, n) != n)
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* kill off all server processes */
|
|
|
|
sprint(buf, "/proc/%d/notepg", getpid());
|
|
|
|
fd = open(buf, OWRITE);
|
|
|
|
write(fd, "die", 3);
|
|
|
|
exits(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
prompt(char *p, char *b, int n, int raw)
|
|
|
|
{
|
|
|
|
char *e;
|
|
|
|
int i;
|
|
|
|
int echo;
|
|
|
|
|
|
|
|
echo = opt[Echo].local;
|
|
|
|
if(raw)
|
|
|
|
opt[Echo].local = 0;
|
|
|
|
print("%s: ", p);
|
|
|
|
for(e = b+n; b < e;){
|
|
|
|
i = fromnet(b, e-b);
|
|
|
|
if(i <= 0)
|
|
|
|
exits("fromnet: hungup");
|
|
|
|
b += i;
|
|
|
|
if(*(b-1) == '\n' || *(b-1) == '\r'){
|
|
|
|
*(b-1) = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(raw)
|
|
|
|
opt[Echo].local = echo;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* challenge user
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
challuser(char *user)
|
|
|
|
{
|
|
|
|
char nchall[64];
|
|
|
|
char response[64];
|
|
|
|
Chalstate *ch;
|
|
|
|
AuthInfo *ai;
|
|
|
|
|
|
|
|
if(strcmp(user, "none") == 0){
|
|
|
|
if(nonone)
|
|
|
|
return -1;
|
|
|
|
newns("none", nil);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if((ch = auth_challenge("proto=p9cr role=server user=%q", user)) == nil)
|
|
|
|
return -1;
|
|
|
|
snprint(nchall, sizeof nchall, "challenge: %s\r\nresponse", ch->chal);
|
|
|
|
prompt(nchall, response, sizeof response, 0);
|
|
|
|
ch->resp = response;
|
|
|
|
ch->nresp = strlen(response);
|
|
|
|
ai = auth_response(ch);
|
|
|
|
auth_freechal(ch);
|
|
|
|
if(ai == nil){
|
|
|
|
rerrstr(response, sizeof response);
|
|
|
|
print("!%s\n", response);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if(auth_chuid(ai, nil) < 0)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* use the in the clear apop password to change user id
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
noworldlogin(char *user)
|
|
|
|
{
|
|
|
|
char password[256];
|
|
|
|
|
|
|
|
prompt("password", password, sizeof(password), 1);
|
|
|
|
if(login(user, password, "/lib/namespace.noworld") < 0)
|
|
|
|
return -1;
|
|
|
|
rfork(RFNOMNT); /* sandbox */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
doauth(char *user)
|
|
|
|
{
|
|
|
|
if(*user == 0)
|
|
|
|
prompt("user", user, Maxuser, 0);
|
|
|
|
if(noworld(user))
|
|
|
|
return noworldlogin(user);
|
|
|
|
if(noworldonly)
|
|
|
|
return -1;
|
|
|
|
return challuser(user);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Process some input from the child, add protocol if needed. If
|
|
|
|
* the input buffer goes empty, return.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
fromchild(char *bp, int len)
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
char *start;
|
|
|
|
|
|
|
|
for(start = bp; bp-start < len-1; ){
|
|
|
|
c = Bgetc(&childib);
|
|
|
|
if(c < 0){
|
|
|
|
if(bp == start)
|
|
|
|
return -1;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(cons->raw == 0 && c == '\n')
|
|
|
|
*bp++ = '\r';
|
|
|
|
*bp++ = c;
|
|
|
|
if(Bbuffered(&childib) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return bp-start;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read from the network up to a '\n' or some other break.
|
|
|
|
*
|
|
|
|
* If in binary mode, buffer characters but don't
|
|
|
|
*
|
|
|
|
* The following characters are special:
|
|
|
|
* '\r\n's and '\r's get turned into '\n's.
|
|
|
|
* ^H erases the last character buffered.
|
|
|
|
* ^U kills the whole line buffered.
|
|
|
|
* ^W erases the last word
|
|
|
|
* ^D causes a 0-length line to be returned.
|
|
|
|
* Intr causes an "interrupt" note to be sent to the children.
|
|
|
|
*/
|
|
|
|
#define ECHO(c) { *ebp++ = (c); }
|
|
|
|
int
|
|
|
|
fromnet(char *bp, int len)
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
char echobuf[1024];
|
|
|
|
char *ebp;
|
|
|
|
char *start;
|
|
|
|
static int crnl;
|
|
|
|
static int doeof;
|
|
|
|
|
|
|
|
|
|
|
|
/* simulate an EOF as a 0 length input */
|
|
|
|
if(doeof){
|
|
|
|
doeof = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(ebp = echobuf,start = bp; bp-start < len && ebp-echobuf < sizeof(echobuf); ){
|
|
|
|
c = Bgetc(&netib);
|
|
|
|
if(c < 0){
|
|
|
|
if(bp == start)
|
|
|
|
return -1;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* telnet protocol only */
|
|
|
|
if(!noproto){
|
|
|
|
/* protocol messages */
|
|
|
|
switch(c){
|
|
|
|
case Iac:
|
|
|
|
crnl = 0;
|
|
|
|
c = Bgetc(&netib);
|
|
|
|
if(c == Iac)
|
|
|
|
break;
|
|
|
|
control(&netib, c);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* \r\n or \n\r become \n */
|
|
|
|
if(c == '\r' || c == '\n'){
|
|
|
|
if(crnl && crnl != c){
|
|
|
|
crnl = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(cons->raw == 0 && opt[Echo].local){
|
|
|
|
ECHO('\r');
|
|
|
|
ECHO('\n');
|
|
|
|
}
|
|
|
|
crnl = c;
|
|
|
|
if(cons->raw == 0)
|
|
|
|
*bp++ = '\n';
|
|
|
|
else
|
|
|
|
*bp++ = c;
|
|
|
|
break;
|
|
|
|
} else
|
|
|
|
crnl = 0;
|
|
|
|
|
|
|
|
/* raw processing (each character terminates */
|
|
|
|
if(cons->raw){
|
|
|
|
*bp++ = c;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* in binary mode, there are no control characters */
|
|
|
|
if(opt[Binary].local){
|
|
|
|
if(opt[Echo].local)
|
|
|
|
ECHO(c);
|
|
|
|
*bp++ = c;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* cooked processing */
|
|
|
|
switch(c){
|
|
|
|
case 0x00:
|
|
|
|
if(noproto) /* telnet ignores nulls */
|
|
|
|
*bp++ = c;
|
|
|
|
continue;
|
|
|
|
case 0x04:
|
|
|
|
if(bp != start)
|
|
|
|
doeof = 1;
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
case 0x08: /* ^H */
|
|
|
|
if(start < bp)
|
|
|
|
bp--;
|
|
|
|
if(opt[Echo].local)
|
|
|
|
ECHO(c);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x15: /* ^U */
|
|
|
|
bp = start;
|
|
|
|
if(opt[Echo].local){
|
|
|
|
ECHO('^');
|
|
|
|
ECHO('U');
|
|
|
|
ECHO('\r');
|
|
|
|
ECHO('\n');
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x17: /* ^W */
|
|
|
|
if (opt[Echo].local) {
|
|
|
|
while (--bp >= start && !alnum(*bp))
|
|
|
|
ECHO('\b');
|
|
|
|
while (bp >= start && alnum(*bp)) {
|
|
|
|
ECHO('\b');
|
|
|
|
bp--;
|
|
|
|
}
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x7f: /* Del */
|
|
|
|
write(notefd, "interrupt", 9);
|
|
|
|
bp = start;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if(opt[Echo].local)
|
|
|
|
ECHO(c);
|
|
|
|
*bp++ = c;
|
|
|
|
}
|
|
|
|
if(ebp != echobuf)
|
|
|
|
write(1, echobuf, ebp-echobuf);
|
|
|
|
ebp = echobuf;
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
if(ebp != echobuf)
|
|
|
|
write(1, echobuf, ebp-echobuf);
|
|
|
|
return bp - start;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
termchange(Biobuf *bp, int cmd)
|
|
|
|
{
|
|
|
|
char buf[8];
|
|
|
|
char *p = buf;
|
|
|
|
|
|
|
|
if(cmd != Will)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* ask other side to send term type info */
|
|
|
|
*p++ = Iac;
|
|
|
|
*p++ = Sb;
|
|
|
|
*p++ = opt[Term].code;
|
|
|
|
*p++ = 1;
|
|
|
|
*p++ = Iac;
|
|
|
|
*p++ = Se;
|
|
|
|
return iwrite(Bfildes(bp), buf, p-buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
termsub(Biobuf *bp, uchar *sub, int n)
|
|
|
|
{
|
|
|
|
char term[Maxvar];
|
|
|
|
|
|
|
|
USED(bp);
|
|
|
|
if(n-- < 1 || sub[0] != 0)
|
|
|
|
return 0;
|
|
|
|
if(n >= sizeof term)
|
|
|
|
n = sizeof term;
|
|
|
|
strncpy(term, (char*)sub, n);
|
|
|
|
putenv("TERM", term);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
xlocchange(Biobuf *bp, int cmd)
|
|
|
|
{
|
|
|
|
char buf[8];
|
|
|
|
char *p = buf;
|
|
|
|
|
|
|
|
if(cmd != Will)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* ask other side to send x display info */
|
|
|
|
*p++ = Iac;
|
|
|
|
*p++ = Sb;
|
|
|
|
*p++ = opt[Xloc].code;
|
|
|
|
*p++ = 1;
|
|
|
|
*p++ = Iac;
|
|
|
|
*p++ = Se;
|
|
|
|
return iwrite(Bfildes(bp), buf, p-buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
xlocsub(Biobuf *bp, uchar *sub, int n)
|
|
|
|
{
|
|
|
|
char xloc[Maxvar];
|
|
|
|
|
|
|
|
USED(bp);
|
|
|
|
if(n-- < 1 || sub[0] != 0)
|
|
|
|
return 0;
|
|
|
|
if(n >= sizeof xloc)
|
|
|
|
n = sizeof xloc;
|
|
|
|
strncpy(xloc, (char*)sub, n);
|
|
|
|
putenv("DISPLAY", xloc);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2014-09-14 19:20:13 +00:00
|
|
|
* create a shared segment.
|
2011-03-30 12:46:40 +00:00
|
|
|
*/
|
|
|
|
void*
|
|
|
|
share(ulong len)
|
|
|
|
{
|
2014-09-14 19:20:13 +00:00
|
|
|
void *v;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2014-09-14 19:20:13 +00:00
|
|
|
v = segattach(0, "shared", 0, len);
|
|
|
|
if(v == (void*)-1)
|
|
|
|
return nil;
|
|
|
|
return v;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bind a pipe onto consctl and keep reading it to
|
|
|
|
* get changes to console state.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
conssim(void)
|
|
|
|
{
|
|
|
|
int i, n;
|
|
|
|
int fd;
|
|
|
|
int tries;
|
|
|
|
char buf[128];
|
|
|
|
char *field[10];
|
|
|
|
|
|
|
|
/* a pipe to simulate the /dev/cons */
|
2012-08-04 12:52:29 +00:00
|
|
|
if(bind("#|", "/mnt/cons", MREPL) < 0)
|
2011-03-30 12:46:40 +00:00
|
|
|
fatal("/dev/cons1", 0, 0);
|
2012-08-04 12:52:29 +00:00
|
|
|
if(bind("/mnt/cons/data1", "/dev/cons", MREPL) < 0)
|
2011-03-30 12:46:40 +00:00
|
|
|
fatal("/dev/cons2", 0, 0);
|
|
|
|
|
|
|
|
/* a pipe to simulate consctl */
|
2012-08-04 12:52:29 +00:00
|
|
|
if(bind("#|", "/mnt/consctl", MBEFORE) < 0
|
|
|
|
|| bind("/mnt/consctl/data1", "/dev/consctl", MREPL) < 0)
|
2011-03-30 12:46:40 +00:00
|
|
|
fatal("/dev/consctl", 0, 0);
|
|
|
|
|
|
|
|
/* a process to read /dev/consctl and set the state in cons */
|
|
|
|
switch(fork()){
|
|
|
|
case -1:
|
|
|
|
fatal("forking", 0, 0);
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
default:
|
2012-08-04 12:52:29 +00:00
|
|
|
return open("/mnt/cons/data", ORDWR);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for(tries = 0; tries < 100; tries++){
|
|
|
|
cons->raw = 0;
|
|
|
|
cons->hold = 0;
|
2012-08-04 12:52:29 +00:00
|
|
|
fd = open("/mnt/consctl/data", OREAD);
|
2011-03-30 12:46:40 +00:00
|
|
|
if(fd < 0)
|
|
|
|
continue;
|
|
|
|
tries = 0;
|
|
|
|
for(;;){
|
|
|
|
n = read(fd, buf, sizeof(buf)-1);
|
|
|
|
if(n <= 0)
|
|
|
|
break;
|
|
|
|
buf[n] = 0;
|
|
|
|
n = getfields(buf, field, 10, 1, " ");
|
|
|
|
for(i = 0; i < n; i++){
|
|
|
|
if(strcmp(field[i], "rawon") == 0) {
|
|
|
|
if(debug) fprint(2, "raw = 1\n");
|
|
|
|
cons->raw = 1;
|
|
|
|
} else if(strcmp(field[i], "rawoff") == 0) {
|
|
|
|
if(debug) fprint(2, "raw = 0\n");
|
|
|
|
cons->raw = 0;
|
|
|
|
} else if(strcmp(field[i], "holdon") == 0) {
|
|
|
|
cons->hold = 1;
|
|
|
|
if(debug) fprint(2, "raw = 1\n");
|
|
|
|
} else if(strcmp(field[i], "holdoff") == 0) {
|
|
|
|
cons->hold = 0;
|
|
|
|
if(debug) fprint(2, "raw = 0\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
exits(0);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
alnum(int c)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Hard to get absolutely right. Use what we know about ASCII
|
|
|
|
* and assume anything above the Latin control characters is
|
|
|
|
* potentially an alphanumeric.
|
|
|
|
*/
|
|
|
|
if(c <= ' ')
|
|
|
|
return 0;
|
|
|
|
if(0x7F<=c && c<=0xA0)
|
|
|
|
return 0;
|
|
|
|
if(strchr("!\"#$%&'()*+,-./:;<=>?@`[\\]^{|}~", c))
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|