This code is supplied AS IS. no warrantee either expressed or implied
is provided. This code may be freeley modified and modified as long as my
origional authorship is acknowledged.
Tim Graves
Sun Microsystems
*/
/* a set of routines for transfering data between the Psion and the Sun machines
where possible I have provided a sensible wrapper for the low level function
This program should be started BEFORE the suncom program on the psion */
#include <stdio.h>
#include "psion.h"
#include "psmain.h"
#include "psfilt.h"
#define MAXSEND 200
/*#define DEBUG 1*/
/*#define PDEBUG 1*/
static char * vsn = "@(#) psmain.c 3.24@(#)" ;
int pscs() ;
int sunsum() ;
int cmlist(), cmspeed(), cmmkdir(), cmtmode(), cmget(), cmput(), cmsetp(), cmdiscon() ;
#ifdef PDEBUG
int cmdebug() ;
#endif
int cmtrans(), cmtransreset(), cmfilechksum() ;
int cmhelp(), cmecho(), cmignore(), cmsystem(), cmrun() ;
int cmgetenv(), cmdumpv(), cmsetv(), cmunsetv(), cmifusetv();
int cmrm(), cmcs() ;
int cmforeach(), cmfilter(),cmfilterprint() ;
int cmexclude(), cmexclprint(), cmrlist(), cmbackup(), cminfo(), cmsetwriteflag() ;
int cmlcd(), cmrcd(), cmlpwd(), cmrpwd(), cmftransinfo(), cmftransreset();
int cmproclist(), cmprocprot(), cmprockill(), cmprocshut() ;
char * findvar() ;
int running ;
int level ;
int linecmd ;
int dovsnchk ;
int debugargs = FALSE ;
int debugrun = FALSE ;
int runtype, finish ;
int debugcall = FALSE ;
int logfile = FALSE ;
char * lfname ;
extern int debuglink ;
extern int debugpath ;
extern int debugbackup ;
extern int filechksum ;
extern char psfname[] ;
/* the following count good and bad blocks transmitted / recieved in pslib */
extern int transgood, transbad, recgood, recbad ;
/* the following count the file block level good / bad blocks counted in pslib */
extern int ftransgood, ftransbad, frecgood, frecbad ;
/* command parsing structures, the command name (primary key), the number
of arguments (secondary key) and the function to call which will be
passed two parameters, an int (argc) and the value array (char * argv[]), then the usage text followed by the help text */
struct cmdstruct cmds[] = {
{"get", 2, 1, cmget, "path [sun filename]",
"gets a file from the psion to the sun, optionaly using a different filename\n filename only can contain wildcards in which case multiple files are got,\nno sun filename is applicable in this case"},
{"put", 2, 1, cmput, "path [sun filename]",
"Puts a file to the psion from the sun, optionaly using a different filename"},
{"lcd", 1, 1, cmlcd, "path",
"Changes the current working directory on the sun to <path>. Is behaves\nin roughly the same manner as cd in the shells"},
{"rcd", 1, 1, cmrcd, "path",
"Changes the current working directory on the psion (Initialy set to M:)\nto <path> similar to the cd command in ftp"},
{"lpwd", 0, 0, cmlpwd,"",
"Prints the current working directory on the Sun ala shell pwd commands"},
{"rpwd", 0, 0, cmrpwd, "",
"Printe the current working directory on the psion"},
{"sum", 2, 1, cmcs, "path [sun|psion]",
"Computes a checksum on the path given either on the sun or the psion (default)\n"} ,
{"filesum", 1, 0, cmfilechksum, "[on|off]",
"Turns on checksums at the binary transfer level, adds saftey at\nthe cost of speed\nIf no argunents prints the current status"} ,
"Reads the command file pscmd and executes the instructions in it, a new level of\nvariables is created and variables manipulated in side this new level will not affect\nvariables from lower levels (Like to the shells). Any arguments to run will be saved in a\nsequence of variables arg0 (the command name) arg1 (first arg) arg2 (second arg) etc. Any \nexisting variables will be copied to the new level"},
{"source", 1, 1, cmrun, "pscmd_filename",
"Reads the command file and executes the instructions in it. No new variable level\nis created and any variable manipulation affects the existing level. No arg variables\n are created. It is expected that source will be used to load in configurations"},
{"which", 1, 1, cmrun, "pscmd_filename",
"Similar to the csh which command, locates the first occurence of\n pscmd_filename in the current path"},
"Executes the unix command string via the system call, only variable interpretation is\nperformed before the command is executed"},
{"#", MAXARGS, 0, cmignore, "text",
"Ignores the remainder of the line, a comment indicator, intended to be used in \npscmd files"},
{"REM", MAXARGS, 0, cmignore, "text",
"Ignores the remainder of the line, a comment indicator, intended to be used in \npscmd files"},
{"Rem", MAXARGS, 0, cmignore, "text",
"Ignores the remainder of the line, a comment indicator, intended to be used in \npscmd files"} ,
{"echo", MAXARGS, 0, cmecho, "text",
"echoes the text back, intended to be used in pscmd files"},
{"setv", 2, 1, cmsetv, "varname [varvalue]",
"Associates varvalue with varname in the variables list, replacing any previous value\nif required. If varvalue is not present the null string is used"},
"Gets the unix variable unixname from the unix environment and\noptionaly calls it a different name psionname if the variable does not\nexist use defaultvalue"},
{"printv", 0, 0, cmdumpv, "",
"Prints out the current variables list"},
{"ifusetv", 2, 2, cmifusetv, "varname value",
"If varname is already set do nothing, otherwise set varname to value"} ,
{"vars", 0, 1, cmdumpv, "Not a command, see help",
"Variables are set using setv and printv, to use a variable it must be a word\non its own enclosed in square brackets e.g. [varname], the word will be\nsubstituted for the text of the variable, e.g. echo [arg0] will print out\nthe commands name if envoked by run."},
{"specialvars1",0,0,cmdumpv,"Not a command, see help",
"Special Variables\npath\tA : seperated list of locations run will use to find its pscmd files\nrmcheck\tChecks with you that you realy want to delete the file (like rm -i)\nbackupnocheck\tStops the system asking you to exit all psion applications before\trunning the backup (usefull for scripts)\nautofilefilter\tCauses all file transfers to be checked to see if there is a conversion\n\tfilter to be run during the transfer\ndebugargs\tIf set the system will print debugging info for argument parsing\ndebuglink\tIf set the system will print debugging info for the data link\ndebugpath\tIf set the system will print out path handling debuging info"},
{"specialvars2", 0, 0, cmdumpv, "Not a command see help",
"debugrun\tIf set the system will print debugging info about run\ndebugcall (level) If set the system will printout (very verbose) subroutine call debuging info\ndebugbackup\tIf set the system will print backup debugging calls\nverbose\tIf set the system will display transfer statistics\ndolower\tIf set maps all psion paths for get and put to lower case\nchksumwarn\tIf set this computes checksums on the psion and sun files \nand produces a warning if these differ after a get / put\nchksumcorrect\tIf set this will attempt to correct on discovering a \nchecksum error between the sun / psion after a get / put"},
{"specialvars3", 0, 0, cmdumpv, "Not a command see help",
"backupnodo\tIf set the backup and restore systems do not actialy get / put files\nbut instead print out what would happen (usefull for backup)\nbackupask\tIf set asks before backingup each file, usefull for\ninteractive backupsrestoreask\tIf set asks before restoring each file (usefull for\ninteractive restores"},
{"help", 1, 0, cmhelp, "[cmdname]",
"Prints out the help message for cmdname or the list of available commands if there is\nno cmdname"},
{"usage", 1, 0, cmhelp, "[cmdname]",
"Prints out the usage text for cmdname or the list of available commands if there is\nno cmdname"},
"Sets up a filter in the given directionto run pscmd on all files with\nsuffix suffix the pscmd file should exist before the filter is called\nrestore filters are called to restore the filt to its state before a put"},
"Starts / stops psion debugging to the [psion_filename].\nIf [psion_filename] is not given it uses M:\\debug.txt,\n[psion_filename] is truncated before the logging information is written each time"},
#endif
{"transinfo", 0, 0, cmtrans, "",
"Prints information about the number of good and bad\nblocks transmited and recieved"},
{"transreset", 0, 0, cmtransreset, "",
"Resets the good and bad block counts for transmision and recieve"},
{"ftransinfo", 0, 0, cmftransinfo, "",
"Prints information about the number of good and bad\nblocks transmited and recieved for the file checksums"},
{"ftransreset", 0, 0, cmftransreset, "",
"Resets the good and bad block counts for transmision and recieve\n for the file checksums"},
"Lists processes found matching process_pattern on the psion.\nprocess_pattern defaults to * (all). If filename is given the output\nwill be written to filename. In this case process_pattern MUST\nbe specified"},
{"procprotect", 1, 0, cmprocprot, "[on|off]",
"Turns on / off process kill protection for system processes and suncom\non the psion, if no argument is enables protection. TURNONG PROTECTION OFF IS DEFINATLEY NOT ADVISED"},
{"prockill", 1, 1, cmprockill, "process_pattern",
"Kills processes matching process_pattern on the psion. unless process\nkill protection is turned off (procprotect off) system processes and\nsuncom will not be killed"},
{"shutdown", 1, 1, cmprocshut, "process_pattern",
"Sends a shutdown message to the processes matching process_pattern on the psion\nNot all processes can handle this (E.g. suncom and OPL processes) though\nall the builtin applications can"},
{"pause", 0, 0, cmdiscon, "",
"Exit the sun end of the comms link without effecting the psion\nNOTE you should only use this in shell scripts as the psion will detect\na period of inactivity and powerdown, currently the software cannot cope with this !"},
{"quit", 0, 0, cmdiscon, "",
"Instruct the psion end of the link to exit then exit the sun end"}
} ;
main (argc, argv, environ)
int argc ;
char * argv[] ;
char * environ[] ;
{
int restart ;
int talk ;
char devname[100] ;
if (debugcall >= 1)
fprintf(stderr, "CALL: Main\n") ;
/* init any argv dependent variables to their default state */
restart = FALSE ;
talk = FALSE ;
devname[0] ='\0' ;
dovsnchk = TRUE ;
finish = QUIT ;
runtype = FALSE ;
logfile = FALSE ;
/* init the variable handler code */
initvars() ;
/* handle any command line switches */
/* we must have at least one value in argv and it must start with
a - to have any command line switches NOTE due to this restriction
no psion command interpreter command may start with - though they
may also have flags as the routine below will break on the first
arg it finds that does not start with a - */
/* remove the command name */
argv ++ ;
argc -- ;
while (argc > 0)
{
/* break out of the loop if required */
if(argv[0][0] != '-')
break ;
/* -var variable, value set up the variables */
if (strcmp (argv[0], "-var") == 0 )
{
/* use the next argument as the variable and the following
one as the value unless the next argument starts with a
- in which case just set the variable*/
if (argc < 2)
{
/* no variable name */
useage() ;
}
if (argc == 2)
{
/* variable name but no value and at end of the args */
cmsetv(2,argv) ;
argc -= 2;
argv += 2;
continue ;
}
if (argv[2][0] == '-')
{
cmsetv(2,argv) ;
argc -= 2 ;
argv += 2 ;
continue ;
}
else
{
cmsetv (3,argv) ;
argc -= 3 ;
argv -= 3;
continue ;
}
}
/* -log [fname], log the comms sequence to [fname] if [fname] is
not present use DEFAULTLOG */
if (strcmp(argv[0], "-log") == 0)
{
logfile = TRUE ;
if (argc == 1) /* no [fname] as we are at ther end of
the arg list */
{
lfname = DEFAULTLOG ;
argc -- ;
argv ++ ;
}
else
if (argv[1][0] == '-') /* if no [fname] as next arg is a flag */
{
lfname = DEFAULTLOG ;
argc -- ;
argv ++ ;
}
else
{
lfname = argv[1] ;
argc -= 2 ;
argv += 2 ;
}
if (freopen (lfname, "w", stderr) == NULL)
{
printf("ERROR - opening log file %s\n") ;
exit (1) ;
}
printf("Logging to %s\n", lfname) ;
debugcall = 5 ;
continue ;
}
/* -r initiate the coms link with a running suncom program
on the psion, we do this by calling psinit with a true falue,
if we want a cold start call psinit with a FALSE parameter */
if (strcmp(argv[0], "-r") == 0)
{
restart = TRUE ;
argc -- ;
argv ++ ;
continue ;
}
/* -t - give cmdline parameters dump */
if (strcmp(argv[0], "-t") == 0)
{
talk = TRUE ;
argc -- ;
argv ++ ;
continue ;
}
/* -q on exiting (has effect in batch only) quit (default) */
if (strcmp(argv[0], "-q") == 0)
{
finish = QUIT ;
argc -- ;
argv ++ ;
continue ;
}
/* -p on exiting (has effect in batch only) pause instead of quit */
if (strcmp(argv[0], "-p") == 0)
{
finish = PAUSE ;
argc -- ;
argv ++ ;
continue ;
}
/* -b batch mode, dont be verbose etc */
if (strcmp(argv[0], "-b") == 0)
{
runtype = BATCH ;
argc -- ;
argv ++ ;
continue ;
}
/* -i interactive mode, oposite of batch mode assumed if no command line commands given */
if (strcmp(argv[0], "-i") == 0)
{
runtype = INTERACTIVE ;
argc -- ;
argv ++ ;
continue ;
}
/* -d next arg contains the name of the serial device, default to /dev/ttya*/
if (strcmp(argv[0], "-d") == 0)
{
if (argc < 2)
useage() ;
strcpy(devname, argv[1]) ;
/* shift along the arguments */
argc -= 2 ;
argv += 2 ;
continue ;
}
if (strcmp(argv[0], "-nv") == 0)
{
dovsnchk = FALSE ;
argc -- ;
argv ++ ;
continue ;
}
if (strcmp(argv[0], "-v") == 0)
{
dovsnchk = TRUE ;
argc -- ;
argv ++ ;
continue ;
}
}
/* if there are any args left (argc > 0) we are running batch else interactive, only work this out is we have not had a runtype previously set */
if (runtype == FALSE) ;
if (argc > 0)
runtype = BATCH ;
else
runtype = INTERACTIVE ;
psinit(restart, devname) ;
initfilters() ;
initexclude() ;
/* we have to load this variable first otherwise the system wont find the
~/.psrc.pscmd file */
loadvar("HOME", "HOME", environ) ;
if (dovsnchk == FALSE)
{
pssetdefvsn() ;
}
if (runtype = INTERACTIVE)
printf("Suncom program version %s, psion program version, 3.24,\n (C) Tim Graves, Sun Microsystems 1994-1995\n", psversion()) ;
/* check that the psion code is atleast version 2 otherwise the system
will fail as the path specifications will differ and the tranfer of
any path information (required for virtualy anything) will fail */
printf ("transmission information good blocks %d, bad blocks %d\n", endrecgood - startrecgood, endrecbad - startrecbad) ;
}
/* if VAR_CHKSUM_WARN is in effect check is the checksums are
different on the filenames, if VAR_CHKSUM_CORRECT redo the get
we have to do this BEFORE any filtering takes place */
if ((findvar(VAR_CHKSUM_WARN) != NULL) || (findvar(VAR_CHKSUM_CORRECT) != NULL))
{
/* get the sun chksum */
if (argc == 2)
sunchksum = sunsum(psfname) ;
else
sunchksum = sunsum(argv[2]) ;
/* get the psion chksum (we can assume that the psion path
has already been set )*/
psionchksum = pscs() ;
if ((findvar(VAR_CHKSUM_WARN) != NULL) && (sunchksum != psionchksum))
printf("Warning, the psion and sun check sums disagree (sun = %d, psion = %d)\n", sunchksum, psionchksum) ;
if (((findvar(VAR_CHKSUM_CORRECT)) != NULL) && (sunchksum != psionchksum))
{
/* if VAR_BAD_CHKSUM_SAVE is in place move the bad file
so I can look at it later */
if (findvar(VAR_BAD_CHKSUM_SAVE) != NULL)
{
char cmd[2000] ;
char newname[1000] ;
/* create the new file name */
if (argc == 2)
strcpy(newname, psfname) ;
else
strcpy(newname, argv[2]) ;
sprintf(cmd, "mv %s ", newname) ;
strcat (newname, "XXXXXX") ;
mktemp(newname) ;
strcat(cmd, newname) ;
if (findvar(VAR_VERBOSE) != NULL)
printf("Saving incorrect version using :%s:\n", cmd) ;
system(cmd) ;
} /* if we do not save the filer unlink the old version */
else
{
/* remove the local file */
if (argc == 2)
unlink(psfname) ;
else
unlink(argv[2]) ;
}
/* if VAR_CHKSUM_CORRECT redo the get, we must disable
file filtering though otherwise nasty things could
happen. we do this by moving up a variable level,
this enables us to unset the VAR_FILEFILT variable
with impunity */
if (findvar(VAR_VERBOSE) != NULL)
printf("A Checksum difference has been detected, regetting the file\n") ;
/* go up a variable stack level */
/* this is realy starting to get somewhat nasty
having to to this but it appears to work */
upvarlevel() ;
/* remove VAR_FILEFILT */
delvar(VAR_FILEFILT) ;
/* build a command list */
strcpy(getcmd, "get ") ;
strcat(getcmd, argv[1]) ;
if (argc == 3)
{
strcat(getcmd, " ") ;
strcat(getcmd, argv[2]) ;
}
/* redo the get command, if this also fails we are
OK as the code is all safe to call recursivly as we
do things at a higher variable level */
cmdintr(getcmd) ;
/* drop down the variable level, this resets the
variables to the previous state and restores
VAR_FILE_FILT if it was set */
downvarlevel() ;
}
}
/* is file filtering enabled ? */
if (findvar(VAR_FILEFILT) != NULL)
{
if (argc == 2)
{
/* we are dealing with a direct get from the same file, psfname is already setup*/
filefilt(INFILTER,psfname) ;
}
else
{
/* the file was grabbed into argv[2] */
filefilt(INFILTER,argv[2]) ;
}
}
return(OK) ;
}
getfilefiles(fname)
char * fname ;
{
/* scan each of the filenames and then get it */
FILE *fd ;
char psionname[300] ;
char pspath[255] ;
char cmdname[300] ;
if (debugcall >= 1)
{
fprintf(stderr, "CALL: getfilefiles from %s\n",fname) ;
}
if ((fd = fopen(fname, "r")) == NULL)
{
printf("Wildcard get error on opening names file\n") ;
return(BAD) ;
}
while (fgets(psionname, 300, fd) != NULL)
{
/* if required remove the trailing \n from the string */
if (psionname[strlen(psionname)] == '\n')
psionname[strlen(psionname) -1] == '\0' ;
/* create the get command */
strcpy (cmdname, "get ") ;
strcat (cmdname, pspath) ;
cmdintr(cmdname) ;
}
}
cmput(argc, argv)
int argc ;
char * argv[] ;
{
time_t timestart, timeend ;
int timediff ;
int res ;
int sunchksum, psionchksum ;
char putcmd [255] ;
int starttransgood, starttransbad ;
int endtransgood, endtransbad ;
if (debugcall >= 1)
{
fprintf(stderr, "CALL: cmput\n") ;
dodebugargs(argc, argv) ;
}
/* map the path to lower case if desired */
if (findvar(VAR_DOLOWERPATH) != NULL)
lowerpath(argv[1]) ;
/* send the path, do this here so that the next call to psgetfname will have the correct value installed and we can use it for filt output filtering */
pssetpath(argv[1]) ;
/* is file filtering enabled ? */
if (findvar(VAR_FILEFILT) != NULL)
{
if (argc == 2)
{
/* we are dealing with a direct put from the same file, we need to setup psfname */
psgetfname() ;
filefilt(OUTFILTER,psfname) ;
}
else
{
/* the file is being sent from argv[2] */
filefilt(OUTFILTER,argv[2]) ;
}
}
if (argc-1 == 1)
{
if (findvar(VAR_VERBOSE) != NULL)
printf("putting one file %s\n", argv[1]) ;
starttransgood = transgood ;
starttransbad = transbad ;
time(×tart) ;
res = pssendfile("") ;
endtransgood = transgood ;
endtransbad = transbad ;
}
else
{
if (findvar(VAR_VERBOSE) != NULL)
printf("putting %s from %s\n", argv[1], argv[2]) ;
starttransgood = transgood ;
starttransbad = transbad ;
time(×tart) ;
res = pssendfile(argv[2]) ;
endtransgood = transgood ;
endtransbad = transbad ;
}
time(&timeend) ;
/* if res != OK skip the next bit, we cant leave the function in case there is a restore filter */