home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
pub
/
uniflex
/
ufksup.c
< prev
next >
Wrap
C/C++ Source or Header
|
2020-01-01
|
15KB
|
487 lines
/*
Uniflex Kermit's support task.
This privileged task accounts for the following functions:
1. Set the baudrate of any terminal with that possibility.
2. Get the number of free blocks from the current device.
3. Set the specified date on a specified file.
4. Set the default directory (to keep track with the caller).
5. Send a break to the specified device.
This program reads stdin (normally a pipe) to get the function.
Current functions are:
1. 'b' - set the baudrate on the specified device
2. 'd' - set the specified date on the specified file
3. 'f' - get number of free blocks on the specified device
4. 's' - set the default directory
5. 'w' - send 'break' to the specified device
6. 'e' - exit the support task
*/
#asm
info UniFLEX Kermit's support task
info Author: Jur van der Burg
info Nettelhorst 56
info 2402 LS Alphen aan den Rijn
info The Netherlands
info Version: V 1.2
#endasm
#define PROTOCOL_VERSION 2
#include <stdio.h>
#include <stat.h>
#include <modes.h>
#include <signal.h>
#include <sys/dir.h>
#include <setjmp.h>
#define chtim touch /* other name in my library */
#define TRUE 1
#define FALSE 0
#define IN 0
#define OUT 1
#define BAUD 0
#define BREAK 1
#define ERROR (-1)
#define TIMBYTE 0x2b
main()
{
char command,
mask,
errmsg[128],
device[30],
file[128];
int status,
len,
owner,
perms;
unsigned int baudrate;
struct stat buf;
long get_freedisk(),
free_blks,
date;
fstat(0,&buf); /* check standard input */
if (buf.st_nlink != 0) /* input must come from a pipe */
exit(0); /* bye bye, leave him in confusion */
signal(SIGTERM,SIG_IGN); /* Ignore this signals */
signal(SIGHUP,SIG_IGN);
signal(SIGQUIT,SIG_IGN);
signal(SIGINT,SIG_IGN);
command = PROTOCOL_VERSION;
write(OUT,&command,1); /* Send acknowledge to parent */
while (TRUE) /* Keep looking for commands */
{
if (read(IN,&command,1) <= 0) /* Get command byte */
exit(1); /* Read error */
switch(command)
{
case 'b': /* Set device baudrate */
read(IN,&len,2); /* Get device name length */
read(IN,device,len); /* Get device name */
read(IN,&baudrate,2); /* Get the baudrate */
read(IN,&mask,1); /* Get the mask */
status = set_dev(device,baudrate,mask,errmsg,BAUD); /* Set */
write(OUT,&status,2); /* Return status */
if (status)
send_error(errmsg); /* Send error message */
break;
case 'w': /* Send break to device */
read(IN,&len,2); /* Get device name length */
read(IN,device,len); /* Get device name */
status = set_dev(device,0,0,errmsg,BREAK); /* Send it */
write(OUT,&status,2); /* Return status */
if (status)
send_error(errmsg); /* Send error message */
break;
case 'd':
read(IN,&len,2); /* Get file name length */
read(IN,file,len); /* Get file name */
read(IN,&date,4); /* Get the date */
status = set_date(file,date,errmsg); /* Set it */
write(OUT,&status,2); /* Return status */
if (status)
send_error(errmsg); /* Send error message */
break;
case 'f':
read(IN,&len,2); /* Get device name length */
read(IN,device,len); /* Get device name */
free_blks = get_freedisk(device,errmsg);/* Get # of blocks */
write(OUT,&free_blks,4); /* Send to parent */
if (free_blks == (long) ERROR)
send_error(errmsg); /* Send error message */
break;
case 's':
read(IN,&len,2); /* Get directory name length */
read(IN,device,len); /* Get directory name */
status = set_dir(device,errmsg); /* Set it */
write(OUT,&status,2); /* Return status */
if (status)
send_error(errmsg); /* Send error message */
break;
case 'e':
exit(0); /* bye bye */
default:
break; /* Ignore unknown command */
}
}
}
send_error(msg)
char *msg;
{
int length;
length = strlen(msg) + 1; /* Must send terminator as well */
write(OUT,&length,2); /* Send length */
write(OUT,msg,length); /* Send message */
}
/*
Routine to set the baudrate of a port, or to send a break to it.
The user must either be the owner or have read and write
access to the selected device. A check will be made if the
system consists of new hardware. In the case of old hardware
the baudrate is not under program control.
*/
#define P_TTY 0x5c /* Pointer to tty structure */
#define P_NTTY 0x5008 /* Pointer to number of tty's */
int valid_speed[] = { /* Table containing valid speed's */
75,0xff,
150,0xee,
300,0xdd,
600,0xcc,
1200,0xbb,
2400,0xaa,
4800,0x99,
9600,0x88,
0
};
struct ttydef { /* Internal UniFLEX tty structure definition */
char *rawq,
*canq,
*outq;
unsigned int devadr;
char flags,
delay,
major,
minor,
delcnt,
col,
kill,
erase,
speed,
type,
state,
xstate };
#define ISOPEN 0x04 /* Current state */
jmp_buf env;
set_dev(dev,speed,mask,errmsg,what)
char *dev;
unsigned int speed;
char *errmsg;
char mask,
what;
{
int *fp,
*fp1,
*p,
i,
timeout();
char found,
speed_val,
n_tty;
unsigned int c,
np;
struct stat buf;
struct ttydef tt_dsc;
struct ttydef *sp;
if (stat(dev,&buf)) /* Get device parameters */
return(prterr("Invalid device specified",errmsg));
if ((buf.st_mode & S_IFMT) != S_IFCHR) /* Check for a character device */
return(prterr("Not a character device",errmsg));
buf.st_mode &= S_IPRM; /* Mask type bits */
if (!((buf.st_mode & S_IOREAD) && /* Check for read and write */
(buf.st_mode & S_IOWRITE))) /* access for others */
if (buf.st_uid != getuid()) /* No access, check if he owns */
/* the device */
return(prterr("Don't own device",errmsg));
if (what == BAUD)
{
found = FALSE;
p = valid_speed;
while (*p)
{
if (speed == *p++) /* Compare against table */
{
speed_val = *p; /* Got it ! */
found = TRUE;
break;
}
p++; /* Point to next entry */
}
if (!found)
return(prterr("Invalid speed specified",errmsg));
if (mask)
speed_val &= 0x77; /* Mask RTS and DCD */
}
/*
The following piece of code ensures that a device address will
be available in the internal data structures for the specified
device. This is simply done by opening the device. In case it's
not ready (modem for example) a timeout has been setup to allow
the program to continue.
*/
signal(SIGALRM,timeout); /* Catch the timeout trap */
alarm(1); /* One second timeout */
if (!setjmp(env)) /* If for the first time */
fp = open(dev,2); /* Open the port */
alarm(0); /* Reset timer */
close(fp);
if ((fp = open("/dev/smem",2)) == ERROR) /* Must open this one */
return(prterr("Error opening '/dev/smem'",errmsg));
readat(fp,P_NTTY,&np,2); /* Get pointer to number of tty's */
readat(fp,np,&n_tty,1); /* Get number of tty's */
readat(fp,P_TTY,&sp,2); /* Get pointer to TTY structure */
found = FALSE;
for (i = 0; i < n_tty; i++)
{
readat(fp,sp++,&tt_dsc,sizeof(struct ttydef));/* Read total structure */
if (tt_dsc.devadr == 0) /* Skip on zero device address */
continue;
if ((tt_dsc.major == ((int)(buf.st_size >> 16) & 0xff)) &&
(tt_dsc.minor == ((int)buf.st_size & 0xff))) /* Chk maj + min id */
{
readat(fp,tt_dsc.devadr + 2,&c,2); /* Get speed register */
if ((c == 0xffff) || (what == BREAK)) /* Should read as 'ffff' */
found = TRUE;
else
return(prterr("Baudrate not programmable",errmsg));
break;
}
}
if (found)
{
setuid(0); /* Make sure we've got the priv's */
if (what == BAUD)
writeat(fp,tt_dsc.devadr + 2,&speed_val,1); /* Update speed */
else if (what == BREAK)
poke_tty(fp,&tt_dsc,--sp);
}
else
return(prterr("Unable to set baudrate",errmsg));
close(fp);
return(NULL);
}
poke_tty(fp,tt_dsc,sp)
int *fp;
struct ttydef *tt_dsc,
*sp;
{
char break_val,
org_value,
new_speed;
org_value = (tt_dsc->speed & ~0x1c) | 0x81; /* Current characteristics */
if (!(tt_dsc->state & ISOPEN)) /* RTS high if port closed */
org_value |= 0x40;
break_val = org_value | 0x60; /* Add 'break' bits */
new_speed = tt_dsc->speed | 0x60;
writeat(fp,&sp->speed,&new_speed,1); /* break will not be terminated */
writeat(fp,tt_dsc->devadr,&break_val,1); /* if new char is received */
short_delay(fp,3); /* 300 Ms delay */
writeat(fp,&sp->speed,&tt_dsc->speed,1);
writeat(fp,tt_dsc->devadr,&org_value,1);
}
readat(fp,address,value,count)
int *fp;
unsigned int address;
char *value;
int count;
{
lseek(fp, (unsigned long)address, 0);
read (fp, value, count);
}
writeat(fp,address,value,count)
int *fp;
unsigned int address;
char *value;
int count;
{
lseek(fp, (unsigned long)address, 0);
write(fp, value, count);
}
short_delay(fp,time)
int *fp, time;
{
int i;
char n,
m;
n = m = -1;
for (i = 0; i < time + 1; i++)
{
while (n == m)
{
lseek(fp, (long)TIMBYTE, 0); /* Position to time byute */
read(fp,&m,1); /* Read current value */
}
n = m;
}
}
timeout()
{
longjmp(env,TRUE); /* Return after timeout */
}
prterr(str,errstr)
char *str,
*errstr;
{
sprintf(errstr,"%s",str);
return(ERROR);
}
/*
This routine returns the number of free blocks on the specified device
or directory. The real device is found by searching for it in the '/dev'
directory, and comparing the major and minor id of the device with the
device number of the specified directory. If the device name is found,
a 'sync' is done to be sure that the information on the disk is current.
Then the SIR is read and the number of free blocks is retrieved from that.
*/
long get_freedisk(indev,errstr)
char *indev,
*errstr;
{
struct stat statbuf;
struct direct dirptr;
int device,
status,
fpt;
unsigned int mode;
char found,
filename[20];
long freeblks,
get_disk();
fpt = ERROR;
found = FALSE; /* Loop end indicator */
strcpy(filename,"/dev/");
if (!stat(indev,&statbuf)) /* Get stat of specified directory */
{
device = statbuf.st_dev; /* Save device major and minor */
mode = statbuf.st_mode & S_IFMT; /* mask for file type */
if (mode == S_IFCHR) /* Character device not allowed */
return(prterr("Invalid device or file specified",errstr));
else if (mode == S_IFBLK) /* already a block device ? */
{
strcpy(filename,indev); /* supply device name */
found = TRUE;
}
if ((fpt = open("/dev",0)) != ERROR)
while (!found) /* Until we're done... */
{
status = read(fpt,&dirptr,sizeof(struct direct)); /* Get entry */
if ((status == ERROR) || (status == NULL))/* Quit on err or EOF */
break;
if (dirptr.d_ino) /* If not deleted */
{
strcpy(&filename[5],dirptr.d_name);
if (stat(filename,&statbuf)) /* Get status */
break;
else
{
statbuf.st_mode &= S_IFMT; /* Mask file type bits */
if ((statbuf.st_mode == S_IFBLK) && /* block type device */
(statbuf.st_size == device)) /* Maj. and Min. match ? */
found = TRUE; /* Yes, return name */
}
}
}
}
else
return(prterr("Invalid device or file specified",errstr));
if (fpt != ERROR)
close(fpt); /* We're done with it */
if (found)
if ((freeblks = get_disk(filename)) != ERROR) /* Get the data */
return(freeblks);
return(prterr("Disk read error",errstr));
}
long get_disk(name)
char *name;
{
int dpt;
unsigned char freeb[3];
long size;
size = ERROR; /* assume error */
if ((dpt = open(name,0)) == ERROR) /* Open the block device */
return(ERROR);
sync(); /* Make sure count is up to date */
if (lseek(dpt,(long) 512 + 21, 0) != ERROR) /* Position in SIR */
if (read(dpt,freeb,3) != ERROR) /* Get the three bytes */
l3tol(&size,freeb,1); /* Convert to long int */
close(dpt);
return (size);
}
set_date(filename,filedate,errmsg)
char *filename,
*errmsg;
long filedate;
{
if (chtim(filename,filedate) == ERROR) /* change the date */
return(prterr("Error setting file date",errmsg));
else
return(NULL);
}
set_dir(directory,errmsg)
char *directory,
*errmsg;
{
if (chdir(directory) == ERROR)
return(prterr("Error setting directory",errmsg));
else
return NULL;
}