ic35link/src/ic35mgr.c

992 lines
28 KiB
C

/************************************************************************
* Copyright (C) 2001 Thomas Schulz *
* */
static char rcsid[] =
"$Id: ic35mgr.c,v 1.20 2001/11/20 23:08:35 thosch Exp $"; /*
* *
* IC35 manager *
* *
*************************************************************************
* *
* ??? is "fixme" mark: sections of code needing fixes *
* *
* conditional compile on NO_LOGSIM: if #defined, logging of the *
* IC35 communications as well as simulated communication are NOT *
* supported, default WITH logging and com-simulation support. *
* *
* for usage run ic35mgr -h or see function usage() below. *
* *
************************************************************************/
#include <stdio.h> /* printf(), .. */
#include <stdlib.h> /* malloc(), free() */
#include <string.h> /* memcpy(), strcpy() ..*/
#include <ctype.h> /* islower(), .. */
#include <getopt.h> /* getopt(), optarg, .. */
#include <time.h> /* struct tm, time() .. */
#include <utime.h> /* struct utimbuf, .. */
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include "util.h" /* FALSE, .. */
#include "comio.h" /* COM_SIMINIT(), .. */
#include "mgrtrans.h" /* IC35mgr transactions */
NOTUSED(rcsid)
extern char * pkgvers; /* these are all */
extern char * pkgdate; /* in versinfo.c, which is */
extern char * bldinfo; /* auto-generated by Makefile */
/* ==================================== */
/* IC35 manager commands */
/* ==================================== */
/* report IC35 status
* ------------------
*/
static int
ic35mgrstat( char * devname, char * statfname )
{
int mmcnum;
int rval;
char label[11+1];
if ( (rval = mconnect( devname, statfname )) != OK )
return rval;
for ( mmcnum = 1; mmcnum <= 2; ++mmcnum ) {
if ( (rval = mmc_status( mmcnum )) < 0 )
break;
if ( rval != 0 ) {
if ( (rval = mmc_label( mmcnum, label )) < 0 )
break;
message( "MMCard%d found, label: \"%s\"", mmcnum, label );
} else {
message( "MMCard%d not present", mmcnum );
}
}
mdisconnect();
return rval;
}
/* backup IC35 database to file
* ----------------------------
*/
static int
ic35backup( char * devname, char * fname )
{
int rval;
if ( (rval = mconnect( devname, NULL )) != OK )
return rval;
rval = readdatabase( fname );
mdisconnect();
return rval;
}
/* restore IC35 database from file
* -------------------------------
*/
static int
ic35restore( char * devname, char * fname )
{
int rval;
if ( (rval = mconnect( devname, NULL )) != OK )
return rval;
rval = writedatabase( fname );
mdisconnect();
return rval;
}
/* list IC35 MMCard(s) directories
* -------------------------------
* list looks like:
* MMCardn "Label"
* size filetimestamp attr filepath
* nnnnnnnnnn yyyy-mm-dd hh:mm:ss xxx MMCard1\subdir\filename.ext
*/
static int
mmcdirlist( char * dirpath )
{
MMCDIR * dirp;
MMCDIRENT * dirent;
size_t pfxlen;
char * subdir;
char attrtext[4+1];
int rval, rc;
if ( (dirp = mmc_opendir( dirpath )) == NULL )
return ERR;
pfxlen = strlen( dirpath ) + 1;
rval = OK;
while ( (dirent = mmc_readdir( dirp )) != NULL ) {
switch ( dirent->attr ) {
case MMCattrDirectory: strcpy( attrtext, "dir" ); break;
case MMCattrArchive: strcpy( attrtext, "arc" ); break;
default: sprintf( attrtext, "0x%02X", dirent->attr & 0xFF );
}
printf( "%10ld %s %4s %s\\%s\n",
dirent->size, mmctstampstr( dirent->tstamp ),
attrtext, dirpath, dirent->name );
fflush( stdout );
if ( dirent->attr & MMCattrDirectory
&& strcmp( dirent->name, ".." ) != 0
&& (subdir = malloc( pfxlen + strlen(dirent->name) + 1 )) != NULL ) {
sprintf( subdir, "%s\\%s", dirpath, dirent->name );
rc = mmcdirlist( subdir );
if ( rval == OK ) rval = rc;
free( subdir );
}
}
rc = mmc_closedir( dirp );
if ( rval == OK ) rval = rc;
return rval; /* errcode of first failure or success OK */
}
static int
ic35mmcdir( char * devname )
{
int mmcnum;
int rval;
char label[11+1];
char dirpath[7+1];
if ( (rval = mconnect( devname, NULL )) != OK )
return rval;
for ( mmcnum = 1; mmcnum <= 2; ++mmcnum ) {
if ( (rval = mmc_status( mmcnum )) < 0 )
break;
if ( rval == 0 ) {
message( "MMCard%d not present", mmcnum );
continue;
}
if ( (rval = mmc_label( 1, label )) < 0 )
break;
printf( "MMCard%d \"%s\"\n", mmcnum, label );
fflush( stdout );
sprintf( dirpath, "MMCard%d", mmcnum );
if ( (rval = mmcdirlist( dirpath )) < 0 )
break;
}
mdisconnect();
return rval;
}
/* ==================================== */
/* IC35 MMCard file commands */
/* ==================================== */
#define MINBLKSZ 1 /* min.blocksize */
#define MAXBLKSZ 16350 /* max.blocksize (found by experiments) */
#define ERR_mmcpfx -1
#define ERR_mmcnum -2
#define ERR_mmcslash -3
#define ERR_mmcbadpath -4
static char * MMCard = "MMCard";
static int blocksize; /* read/write buffer size mmcget/mmcput */
/* check,convert MMCard path to IC35 format & get MMCard number
* ------------------------------------------------------
* the ic35path will be checked (slash means / or \):
* - prefix must be "MMCard" in lowercase or uppercase or mixed
* - MMCard number after prefix must be '1' or '2'
* - slash after MMCard number (unless the path ends there)
* - no adjacent slashes
* - at most one dot between slashes
* - max. 8 characters after slash until dot or slash or end
* - max. 3 characters after dot until slash or end
* the ic35path will be translated to match IC35 requirements:
* translate '/' to '\' dir separators and lowercase to upper.
* the translation is done in place, i.e. the argument string
* is modified.
* returns:
* -1 ERR, missing "MMCard" prefix
* -2 ERR, bad MMCard number (not 1,2)
* -3 ERR, missing slash/backslash after "MMCard[12]"
* -4 ERR, bad path component (too long, >1 dot, adjacent slashes)
*
* parameter mode: if 1 create directories
*/
static int
_ic35mmcpath( char * ic35path , int mode)
{
MMCDIR * mdirp;
int mmcnum;
char * ptr;
char * pdot;
char * pslash;
/* check/set "MMCard" prefix in ic35fpath */
if ( strncasecmp( ic35path, MMCard, strlen(MMCard) ) != 0
|| ! isdigit( ic35path[strlen(MMCard)] ) )
return ERR_mmcpfx; /* error: missing MMCard prefix */
memcpy( ic35path, MMCard, strlen(MMCard) );
/* check MMCard number and slash/backslash after prefix */
ptr = ic35path + strlen(MMCard);
if ( *ptr != '1' && *ptr != '2' )
return ERR_mmcnum; /* error: bad MMCard number */
mmcnum = *ptr - '0';
++ptr;
if ( *ptr == 0 ) return mmcnum; /* allow just MMCard<n> */
if ( *ptr == '/' ) *ptr = '\\';
if ( *ptr != '\\' )
return ERR_mmcslash; /* error: miss slash/backslash */
/* check path components for 8+3, too many dots, etc. */
pslash = ptr++; pdot = NULL;
do {
switch ( *ptr ) {
case '/':
case '\\':
if (mode == 1) {
/* create directory if it does not yet exist */
*ptr = 0;
if ((mdirp = mmc_opendir(ic35path)) == NULL)
mdirp = mmc_createdir(ic35path);
mmc_closedir(mdirp);
}
*ptr = '\\';
/* fall through */
case '\0':
if ( ptr - (pslash+1) == 0 ) {
if (*ptr == 0) *pslash = 0; /* remove trailing slash */
else return ERR_mmcbadpath; /* error: adjacent slashes */
}
if ( (pdot != NULL && ptr - (pdot+1) > 3)
|| (pdot == NULL && ptr - (pslash+1) > 8) )
return ERR_mmcbadpath; /* error: too long since slash */
pslash = ptr; pdot = NULL;
break;
case '.':
if ( pdot != NULL )
return ERR_mmcbadpath; /* error: too many dots */
if ( ptr - (pslash+1) > 8 )
return ERR_mmcbadpath; /* error: too long before dot */
pdot = ptr;
break;
}
} while ( *ptr++ );
/* convert ic35path '/' to '\\', lowercase to uppercase */
for ( ptr = ic35path+strlen(MMCard); *ptr; ++ptr ) {
if ( islower( *ptr ) )
*ptr = (char)toupper( *ptr );
}
return mmcnum;
}
/* output MMCard path error message
* --------------------------------
*/
static void
_mmcpatherror( int errnum, char * ic35path )
{
switch ( errnum ) {
case ERR_mmcpfx:
error( "missing \"%s\" prefix in IC35 filepath: %s", MMCard, ic35path );
break;
case ERR_mmcnum:
error( "bad MMCard number in IC35 filepath: %s", ic35path );
break;
case ERR_mmcslash:
error( "missing \\ or / in IC35 filepath: %s", ic35path );
break;
case ERR_mmcbadpath:
default:
error( "bad path component in IC35 filepath: %s", ic35path );
break;
}
}
/* get filename from IC35 MMCard path
* ----------------------------------
* derive local filename from base filename in ic35path, i.e. leading
* directory components removed, and translate to lowercase.
* the buffer for the local filename is strdup()'d and shall be freed
* by caller.
*/
static char *
_dupic35fname( char * ic35path, int mode)
{
char * ptr;
char * fname;
/* create copy */
if ( (fname = strdup( ic35path )) == NULL )
return NULL;
/* convert to unix filename, creating dirs on the way */
ptr = fname;
while (*ptr) {
if (*ptr == '\\' || *ptr == '/') {
if ( mode == 1 ) {
/* create subdir */
*ptr = 0;
if (mkdir(fname, 0700) < 0
&& errno != EEXIST ) {
perror(fname);
}
}
*ptr++ = '/';
} else {
*ptr++ = tolower( *ptr );
}
}
return fname;
}
static void progress( int mode, char* ipath, char *upath, ulong curr, ulong total)
{
fprintf( stderr, "\r%s %s %s %s %ld",
mode? "read": "write", ipath,
mode? "->" : "<-", upath, (curr+511)/1024);
if (total) fprintf( stderr, "/%ldk, %ld%% ", (total+511)/1024,
curr*100/total);
else fprintf( stderr, "k ");
}
/* read file from IC35 MMCard
* --------------------------
* the ic35path will be translated to match IC35 requirements:
* translate '/' to '\' dir separators and lowercase to upper.
* on absent local filename (NULL or empty string) derive it from
* base filename in ic35path, i.e. leading directory components
* removed, translated to lowercase.
* e.g. mmcard1/Ic35\App\Reversi.APP will be translated
* to MMCard1\IC35\APP\REVERSI.APP and local file reversi.app
* the local file's timestamp will be set to the IC35 file's.
* (but IC35 seems to errorneously set the IC35 file's timestamp
* to the time of read, although the IC35 file is not modified!?)
*
*/
static int
mmcget( char * ic35path, char * a_fname )
{
int rbuffsize = 5 * 1024;
char * fname;
MMCFILE * mmcfp;
MMCDIRENT * mmcfstat;
FILE * fp;
struct utimbuf ftime;
uchar * buff;
size_t blen;
int rlen;
ulong frlen;
int rval = OK;
ulong size;
if ( MINBLKSZ <= blocksize && blocksize <= MAXBLKSZ )
rbuffsize = blocksize;
else if ( blocksize != 0 )
error( "bad buffer size %d, using default %d", blocksize, rbuffsize );
/* create fname from basename(ic35path) if absent */
if ( a_fname && *a_fname ) {
fname = a_fname;
} else
if ( (fname = _dupic35fname( ic35path, 1 )) == NULL ) {
error( "no memory for local filename from %s", ic35path );
return ERR;
}
if ( (mmcfp = mmc_openfile( ic35path, MMCopenexist )) != NULL ) {
if ( (mmcfstat = mmc_statfile( mmcfp )) != NULL ) {
size = mmcfstat->size;
if ( (buff = malloc( blen = rbuffsize )) != NULL ) {
if ( (fp = fopen( fname, "w" )) != NULL ) {
rval = OK;
frlen = 0;
progress( 1, ic35path, fname, frlen, size );
while ( (rlen = mmc_readfile( mmcfp, buff, blen )) > 0 ) {
frlen += rlen;
progress( 1, ic35path, fname, frlen, size );
if ( fwrite( buff, 1, rlen, fp ) != rlen ) {
error( "write error %s: %s (%d)",
fname, strerror(errno), errno );
rval = ERR;
break;
}
}
fclose( fp );
if ( rlen == 0 && rval == OK ) {
ftime.actime = time( NULL );
ftime.modtime = mmctstampunixtime( mmcfstat->tstamp );
utime( fname, &ftime ); /* set file modtime from IC35 */
fprintf( stderr, "\n" );
} else /* mmc_readfile() or fwrite() failed */
rval = ERR;
} else /* (fp = fopen()) == NULL */
error( "cannot open %s: %s (%d)",
fname, strerror(errno), errno );
free( buff );
} else /* (buff = malloc()) == NULL */
error( "no memory for read buffer (%d)", rbuffsize );
} else /* mmc_statfile() failed */
rval = ERR;
mmc_closefile( mmcfp );
} else /* mmc_openfile() failed */
rval = ERR;
if ( fname != a_fname )
free( fname );
return rval;
}
static int
ic35mmcget( char * devname, char * ic35path, char * a_fname )
{
int mmcnum;
int rval;
/* check ic35path, check/set "MMCard" prefix and */
/* convert '/' to '\\', lowercase to uppercase */
if ( (mmcnum = _ic35mmcpath( ic35path, 0 )) < 0 ) {
_mmcpatherror( mmcnum, ic35path );
return ERR;
}
/* connect to IC35 in SyncStation via serial device */
if ( (rval = mconnect( devname, NULL )) != OK )
return rval;
/* get MMCard status (else other MMCard ops would fail) */
if ( (rval = mmc_status( mmcnum )) <= 0 ) {
if ( rval == 0 )
message( "MMCard%d not present", mmcnum );
mdisconnect();
return ERR;
}
/* read file from IC35 MMCard */
rval = mmcget( ic35path, a_fname);
/* cleanup and disconnect from IC35 */
mdisconnect();
return rval;
}
/* get complete tree from IC35 MMCard(s)
* -------------------------------
* dirpath = subdir from which to start
*
*
*
*/
static int
mmcgettree( char * dirpath )
{
MMCDIR * dirp;
MMCDIRENT * dirent;
size_t pfxlen;
char * subdir;
char * ic35path;
int rval, rc;
if ( (dirp = mmc_opendir( dirpath )) == NULL )
return ERR;
pfxlen = strlen( dirpath ) + 1;
rval = OK;
while ( (dirent = mmc_readdir( dirp )) != NULL ) {
switch ( dirent->attr ) {
case MMCattrDirectory:
if (strcmp(dirent->name, ".." ) != 0
&& (subdir = malloc( pfxlen + strlen(dirent->name) + 1 )) != NULL ) {
sprintf(subdir, "%s\\%s", dirpath, dirent->name );
rc = mmcgettree(subdir);
if ( rval == OK ) rval = rc;
free(subdir);
}
break;
case MMCattrArchive:
ic35path = malloc(pfxlen + strlen(dirent->name) + 1 );
sprintf(ic35path, "%s\\%s", dirpath, dirent->name);
mmcget(ic35path, NULL);
free(ic35path);
break;
default:
}
}
rc = mmc_closedir( dirp );
if ( rval == OK ) rval = rc;
return rval; /* errcode of first failure or success OK */
}
static int
ic35mmcgettree( char * devname, char * ic35path)
{
int mmcnum;
int rval;
char dirpath[7+1];
if (ic35path) {
/* check ic35path, check/set "MMCard" prefix and */
/* convert '/' to '\\', lowercase to uppercase */
if ( (mmcnum = _ic35mmcpath( ic35path, 0 )) < 0 ) {
_mmcpatherror( mmcnum, ic35path );
return ERR;
}
if ( (rval = mconnect( devname, NULL )) != OK )
return rval;
if ( (rval = mmc_status( mmcnum )) == 0 ) {
message( "MMCard%d not present", mmcnum );
rval = ERR;
} else if (rval > 0)
rval = mmcgettree( ic35path );
}
else {
if ( (rval = mconnect( devname, NULL )) != OK )
return rval;
for ( mmcnum = 1; mmcnum <= 2; ++mmcnum ) {
if ( (rval = mmc_status( mmcnum )) < 0 )
break;
if ( rval == 0 ) {
message( "MMCard%d not present", mmcnum );
continue;
}
sprintf( dirpath, "MMCard%d", mmcnum );
if ( (rval = mmcgettree( dirpath )) < 0 )
break;
}
}
mdisconnect();
return rval;
}
/* write file to IC35 MMCard
* -------------------------
* see ic35mmcget() comment about ic35path conversions and deriving
* fname from it if a_fname is NULL or empty.
*/
static int
mmcput(char * ic35path, char * a_fname )
{
int wbuffsize = 2 * 1024;
MMCFILE * mmcfp;
FILE * fp;
uchar * buff;
size_t blen;
char * fname;
int rlen;
ulong fwlen;
ulong size;
int rval = OK;
struct stat statbuf;
if ( MINBLKSZ <= blocksize && blocksize <= MAXBLKSZ )
wbuffsize = blocksize;
else if ( blocksize != 0 )
error( "bad buffer size %d, using default %d", blocksize, wbuffsize );
/* create fname from basename(ic35path) if absent */
if ( a_fname && *a_fname ) {
fname = a_fname;
} else
if ( (fname = _dupic35fname( ic35path, 0 )) == NULL ) {
error( "no memory for local filename from %s", ic35path );
return ERR;
}
/* write file to IC35 MMCard */
if ( (mmcfp = mmc_openfile( ic35path, MMCcreatrunc )) != NULL ) {
if ( (buff = malloc( blen = wbuffsize )) != NULL ) {
if ( (fp = fopen( fname, "r" )) != NULL ) {
rval = OK;
fwlen = 0;
stat(fname, &statbuf);
size = statbuf.st_size;
progress( 0, ic35path, fname, fwlen, size );
while ( (rlen = fread( buff, 1, blen, fp )) > 0 ) {
if ( mmc_writefile( mmcfp, buff, rlen ) != rlen ) {
rval = ERR;
break;
}
fwlen += rlen;
progress( 0, ic35path, fname, fwlen, size );
}
if ( rlen <= 0 && feof( fp ) && rval == OK ) {
fprintf( stderr, "\n" );
} else { /* fread() or mmc_writefile() failed */
if ( rval != ERR )
error( "read error %s: %s (%d)",
fname, strerror(errno), errno );
rval = ERR;
}
fclose( fp );
} else /* (fp = fopen()) == NULL */
error( "cannot open %s: %s (%d)",
fname, strerror(errno), errno );
free( buff );
} else /* (buff = malloc()) == NULL */
error( "no memory for write buffer (%d)", wbuffsize );
mmc_closefile( mmcfp );
} else /* mmc_openfile() failed */
rval = ERR;
if ( fname != a_fname )
free( fname );
return rval;
}
static int
ic35mmcput( char * devname, char * ic35path, char * a_fname )
{
int mmcnum;
int rval;
/* check ic35path, check/set "MMCard" prefix and */
/* convert '/' to '\\', lowercase to uppercase */
if ( (mmcnum = _ic35mmcpath( ic35path, 0 )) < 0 ) {
_mmcpatherror( mmcnum, ic35path );
return ERR;
}
/* connect to IC35 in SyncStation via serial device */
if ( (rval = mconnect( devname, NULL )) != OK )
return rval;
/* get MMCard status (else other MMCard ops would fail) */
if ( (rval = mmc_status( mmcnum )) <= 0 ) {
if ( rval == 0 )
message( "MMCard%d not present", mmcnum );
mdisconnect();
return ERR;
}
rval = mmcput(ic35path, a_fname );
/* cleanup and disconnect from IC35 */
mdisconnect();
return rval;
}
/* put complete tree to IC35 MMCard(s)
* -------------------------------
* dirpath = subdir from which to start
*
*
*
*/
static int
mmcputtree( char * dirpath )
{
DIR * dirp;
struct dirent * dirent;
size_t pfxlen;
char * path;
int rval, rc;
int mmcnum;
struct stat statbuf;
if ( (dirp = opendir( dirpath )) == NULL )
return ERR;
pfxlen = strlen( dirpath ) + 1;
rval = OK;
while ( (dirent = readdir( dirp )) != NULL ) {
if (strcmp(dirent->d_name, ".." ) == 0) continue;
if (strcmp(dirent->d_name, "." ) == 0) continue;
path = malloc(pfxlen + strlen(dirent->d_name) + 1 );
if (path == NULL) {
rval = ERR;
break;
}
sprintf(path, "%s/%s", dirpath, dirent->d_name);
if (stat(path, &statbuf) == -1) {
rval = ERR;
break;
}
if (S_ISDIR(statbuf.st_mode)) {
rval = mmcputtree(path);
} else if (S_ISREG(statbuf.st_mode)) {
/* convert to IC35 name */
if ( (mmcnum = _ic35mmcpath( path, 1)) < 0 ) {
_mmcpatherror( mmcnum, path );
return ERR;
}
mmcput(path, NULL);
}
free(path);
}
rc = closedir( dirp );
if ( rval == OK ) rval = rc;
return rval; /* errcode of first failure or success OK */
}
static int
ic35mmcputtree( char * devname, char * ic35path)
{
int mmcnum;
int rval;
char * tmp;
/* check ic35path, check/set "MMCard" prefix and */
/* convert '/' to '\\', lowercase to uppercase */
tmp = strdup(ic35path);
mmcnum = _ic35mmcpath( tmp, 0 );
free(tmp);
if ( mmcnum < 0 ) {
_mmcpatherror( mmcnum, tmp );
return ERR;
}
if ( (rval = mconnect( devname, NULL )) != OK )
return rval;
if ( (rval = mmc_status( mmcnum )) == 0 ) {
message( "MMCard%d not present", mmcnum );
rval = ERR;
} else if (rval > 0)
rval = mmcputtree( ic35path );
mdisconnect();
return rval;
}
/* delete file on IC35 MMCard
* -------------------------
*/
static int
ic35mmcdel( char * devname, char * ic35path )
{
int mmcnum;
int rval;
/* check ic35path, check/set "MMCard" prefix and */
/* convert '/' to '\\', lowercase to uppercase */
if ( (mmcnum = _ic35mmcpath( ic35path, 0 )) < 0 ) {
_mmcpatherror( mmcnum, ic35path );
return ERR;
}
/* connect to IC35 in SyncStation via serial device */
if ( (rval = mconnect( devname, NULL )) != OK )
return rval;
/* get MMCard status (else delete MMCard file fails) */
if ( (rval = mmc_status( mmcnum )) > 0 ) {
message( "delete %s", ic35path );
rval = mmc_delfile( ic35path ); /* delete IC35 MMCard file */
} else if ( rval == 0 ) {
message( "MMCard%d not present", mmcnum );
rval = ERR;
}
/* disconnect from IC35 */
mdisconnect();
return rval;
}
/* -------------------- M A I N - program ----------------------------- */
static void
versinfo( void )
{
printf( "IC35manager for GNU/Linux %s (%s)\n", pkgvers, pkgdate );
printf( "%s\n", bldinfo );
printf(
"Copyright (C) 2001 Thomas Schulz\n"
"This is free software; see the GNU General Public Licence version 2 in\n"
"the file named COPYING for copying conditions. There is NO warranty.\n"
);
}
static void
usage( void )
{
static char * usetext[] = {
"usage: ic35mgr [option..] command [argument..]",
"commands and arguments are:",
" status [FILE] report IC35 status (and write to FILE)",
" backup FILE backup IC35 database to FILE",
" restore FILE restore IC35 database from FILE",
" mmcdir list contents of IC35 MMCard(s)",
" mmcdel IC35PATH delete MMCard file IC35PATH",
" mmcget IC35PATH [FILE] read FILE from IC35PATH on IC35 MMCard",
" mmcgettree [IC35PATH] read file tree starting at IC35PATH on IC35 MMCard",
" mmcput IC35PATH [FILE] write FILE to IC35PATH on IC35 MMCard",
" mmcputtree IC35PATH write file tree starting at IC35PATH to IC35 MMCard",
" IC35PATH e.g. MMCard1/ic35/app/reversi.app will be",
" converted to MMCard1\\IC35\\APP\\REVERSI.APP on IC35",
" filename FILE is taken from IC35PATH if absent",
"options in short and long form are:",
" -d DEV --device=DEV serial device with IC35 connected, default /dev/ic35",
" -b SIZE --blocksize=SIZE block size for mmcget / mmcput, default 5120 / 2048",
" -n NINC --nice=NINC lower process priority for restore,mmcput, default 2",
#ifndef NO_LOGSIM
" -l FILE --logfile=FILE log communications to FILE, default no logging",
" -s FILE --simfile=FILE simulate communication with IC35 using FILE",
" (create simulation FILE from logfile with 'ic35log')",
#endif
" -V --version show version information and exit",
" -h --help show this help and exit",
NULL
};
char ** lptr;
for ( lptr = usetext; *lptr != NULL; ++lptr )
printf( "%s\n", *lptr );
}
int
main( int argc, char *argv[] )
{
static struct option const long_opts[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{ "device", required_argument, NULL, 'd' },
{ "blocksize", required_argument, NULL, 'b' },
{ "nice", required_argument, NULL, 'n' },
#ifndef NO_LOGSIM
{ "logfile", required_argument, NULL, 'l' },
{ "simfile", required_argument, NULL, 's' },
#endif
{ NULL, 0, NULL, 0 }
};
char * devname = "/dev/ic35";
char * nicearg = "2";
char * command = NULL;
#ifndef NO_LOGSIM
char * logfname = NULL;
char * simfname = NULL;
#endif
int rval;
/*
* parse command line
*/
for ( ; ; ) {
switch ( getopt_long( argc, argv,
#ifndef NO_LOGSIM
"l:s:"
#endif
"d:b:hV", long_opts, NULL ) ) {
default: /* invalid option */
fprintf( stderr, "use 'ic35mgr --help' for more information\n" );
return 1;
case 'h': /* show Help and exit */
usage();
return 0;
case 'V': /* show Version and exit */
versinfo();
return 0;
case 'd': /* serial Device where IC35 */
devname = optarg;
continue;
case 'b': /* buffer size for mmcget,put */
blocksize = atoi( optarg );
continue;
case 'n': /* nice processs priority */
nicearg = optarg;
continue;
#ifndef NO_LOGSIM
case 'l': /* communication logfile */
logfname = optarg;
continue;
case 's': /* simulate: no communication */
simfname = optarg;
continue;
#endif /*NO_LOGSIM*/
case -1: /* end of options */
break;
}
break;
}
if ( argc < optind+1 ) {
fatal( "missing command\n"
"use 'ic35mgr --help' for more information" );
return 1;
}
if ( atoi( nicearg ) == 0 && !isdigit(*nicearg) ) {
fatal( "non-integer nice argument: %s", nicearg );
return 1;
}
com_waitnice( atoi( nicearg ) );
/*
* initial info to logfile: date,time, version, command line
* if 'logfname' is NULL or empty, nothing will be logged.
*/
LOG_INIT(( logfname, "ic35mgr", 0 ));
LOG_PROGINFO(( "ic35mgr", pkgvers, pkgdate, bldinfo ));
LOG_ARGSINFO(( argc, argv ));
/*
* setup simulated communication if requested
*/
COM_SIMINIT(( simfname ));
/*
* process command
*/
command = argv[optind]; /* note command */
argv += optind, argc -= optind; /* skip options */
rval = 1;
if ( strcmp( command, "status" ) == 0 ) {
if ( argc <= 2 )
rval = ic35mgrstat( devname, argc > 1 ? argv[1] /*???*/
: "/tmp/ic35.stat" );
else
error( "too many arguments" );
} else if ( strcmp( command, "backup" ) == 0 ) {
if ( argc == 2 )
rval = ic35backup( devname, argv[1] );
else
error( argc < 2 ? "missing backup file"
: "too many arguments" );
} else if ( strcmp( command, "restore" ) == 0 ) {
if ( argc == 2 )
rval = ic35restore( devname, argv[1] );
else
error( argc < 2 ? "missing restore file"
: "too many arguments" );
} else if ( strcmp( command, "mmcdir" ) == 0 ) {
if ( argc == 1 )
rval = ic35mmcdir( devname ) == OK ? 0 : 1;
else
error( "too many arguments" );
} else if ( strcmp( command, "mmcdel" ) == 0 ) {
if ( argc == 2 )
rval = ic35mmcdel( devname, argv[1] ) == OK ? 0 : 1;
else
error( argc < 2 ? "missing ic35path"
: "too many arguments" );
} else if ( strcmp( command, "mmcget" ) == 0 ) {
if ( argc == 2 || argc == 3 )
rval = ic35mmcget( devname, argv[1], argc == 3 ? argv[2] : NULL );
else
error( argc < 2 ? "missing ic35path"
: "too many arguments" );
} else if ( strcmp( command, "mmcgettree" ) == 0 ) {
if ( argc == 1 || argc == 2 )
rval = ic35mmcgettree( devname, argc == 2 ? argv[1] : NULL );
else
error( "too many arguments" );
} else if ( strcmp( command, "mmcput" ) == 0 ) {
if ( argc == 2 || argc == 3 )
rval = ic35mmcput( devname, argv[1], argc == 3 ? argv[2] : NULL );
else
error( argc < 2 ? "missing ic35path,file"
: "too many arguments" );
} else if ( strcmp( command, "mmcputtree" ) == 0 ) {
if ( argc == 2 )
rval = ic35mmcputtree( devname, argv[1]);
else
error( argc < 2 ? "missing ic35path,file"
: "too many arguments" );
} else {
error( "unsupported command: %s", command );
rval = 1;
}
if ( rval != OK )
rval = 1;
LOG_CLOSE(());
return rval;
}