📄 tfs.c
字号:
* and a power hit occurred. Refer to notes in tfsadd() for details.
* There are a few cases to be covered here...
* 1. there is no stale file; so there is nothing to do.
* 2. there is a stale file, but no other file with the same name...
* In this case, the stale file must be copied to another file (with the
* TFS_NSTALE flag set) and the stale file is deleted.
* 3. there is stale file and another file with the same name...
* In this case, the stale file is simply deleted because the other file
* with the same name is newer.
*/
static void
tfsstalecheck(void)
{
int err;
ulong flags;
TDEV *tdp;
TFILE *tfp, *tfpa;
char buf[16];
tfpa = (TFILE *)0;
for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
tfp = (TFILE *)tdp->start;
tfpa = (TFILE *)0;
while(validtfshdr(tfp)) {
if (TFS_FILEEXISTS(tfp)) {
if (tfpa) {
if (!strcmp(TFS_NAME(tfp),TFS_NAME(tfpa))) {
_tfsunlink(TFS_NAME(tfpa));
return;
}
}
else if (TFS_STALE(tfp)) {
tfpa = tfp;
}
}
tfp = nextfp(tfp,tdp);
}
if (tfpa)
break;
}
if (tfpa) {
char name[TFSNAMESIZE+1];
strcpy(name,TFS_NAME(tfpa));
printf("TFS stale fixup (%s)...\n",name);
if (pollConsole("ok?")) {
printf("aborted\n");
return;
}
flags = TFS_FLAGS(tfpa) | TFS_NSTALE;
err = tfsadd(TFS_NAME(tfpa),TFS_INFO(tfpa),tfsflagsbtoa(flags,buf),
(char *)(TFS_BASE(tfpa)),TFS_SIZE(tfpa));
/* If rewrite was successful, then remove the stale one;
* else, leave it there and report the error.
*/
if (err == TFS_OKAY) {
_tfsunlink(TFS_NAME(tfpa));
}
else {
printf("TFS stalecheck(%s) error: %s\n",name,tfserrmsg(err));
}
}
}
/* tfsdevtblinit():
* Transfer the information in tfsdevtbl (in tfsdev.h) to tfsDeviceTbl[].
* In most cases, this will be a simple copy. If the device flag is set
* to indicate that the initalization is dynamic, then use the flash
* ops to retrieve the information from the specified bank.
*
* For dynamic configuration, the "start" member of the tfsdev structure
* must be set in tfsdev.h and the "devinfo & TFS_DEVINFO_BANKMASK" area
* must contain the number of the last flash bank that is to be part of
* the TFS device. Typically this value is the same bank number as the
* starting bank, but it could span across multiple contiguous banks
* if the hardware is set up that way.
*
* To support the use of top-boot devices, plus the TFS requirement that
* the SPARE sector be at-least as large as any other sector in the device,
* this code will automatically step down the sector list until it finds
* the first large sector below all the small ones usually at the top of
* a top-boot device. The call to lastlargesector() takes care of this.
*
* NOTE:
* This dynamic configuration assumes that the end of the TFS space is
* just below the beginning of the spare space.
*
*/
void
tfsdevtblinit(void)
{
int i, startsector, endsector, bank;
TDEV *tDp, *tdp;
for(i=0;i<TFSDEVTOT;i++) {
if (alt_tfsdevtbl[i].prefix != (char *)0xffffffff)
tdp = &alt_tfsdevtbl[i];
else
tdp = &tfsdevtbl[i];
tDp = &tfsDeviceTbl[i];
*tDp = *tdp;
if (i == TFSDEVTOT-1)
break;
if (tdp->devinfo & TFS_DEVINFO_DYNAMIC) {
bank = tDp->devinfo & TFS_DEVINFO_BANKMASK;
/* The spare sector may not be the last sector in the device...
* device. Especially if the device is TopBoot type.
*/
if (lastlargesector(bank,&endsector,
(int *)&tDp->sparesize,(uchar **)&tDp->spare) == -1)
break;
tDp->end = tDp->spare - 1;
if (addrtosector((uchar *)tDp->start,&startsector,0,0) == -1)
break;
tDp->sectorcount = endsector - startsector;
}
}
}
/* tfsstartup():
* Called at system startup to get things properly initialized.
*/
void
tfsstartup()
{
static int beenhere;
TDEV *tdp;
tfsdevtblinit();
tfsclear((TDEV *)0);
/* No need to walk through the entire TFS init if it has already
* been done...
*/
if (beenhere)
return;
/* Step through the table looking for RAM-based TFS devices.
* If the AUTOINIT flag is set, then initialize that device.
*/
for(tdp = tfsDeviceTbl;tdp->prefix != 0;tdp++) {
if (((tdp->devinfo & TFS_DEVTYPE_MASK) == TFS_DEVTYPE_NVRAM) &&
(tdp->devinfo & TFS_DEVINFO_AUTOINIT)) {
_tfsinit(tdp);
}
}
tfsfixup(3,0);
tfsstalecheck();
beenhere = 1;
}
/* tfsexec: Treat the file as machine code that is COFF or ELF. */
static int
tfsexec(TFILE *fp,int verbose)
{
int err, (*entry)();
long address;
err = tfsloadebin(fp,verbose,&address,0,0);
if (err != TFS_OKAY)
return(err);
entry = (int(*)())address;
entry(); /* Call entrypoint (may not return). */
return(TFS_OKAY);
}
/* struct tfsran:
Used by tfsrunboot only. No need to put this in tfs.h.
*/
struct tfsran {
char name[TFSNAMESIZE+1];
};
/* tfsrunboot():
* This function is called at monitor startup. It scans the list of
* files built by tfsreorder() and executes each file in the list that has
* the BRUN flag set. As each file is run its name is added to the
* ranlist[] table.
*
* After each file is run, there is a check made to see if the flash has
* been modified. If yes, then tfsreorder() is run again and we start
* over at the top of the list of files organized by tfsreorder(). As
* we step through the tfsAlist[] array, if the file has a BRUN flag set
* but it is already in the ranlist[] table, it is not run again.
*
* This scheme allows a file in the initial list of BRUN files to modify
* the file list without confusing the list of files that are to be run.
* Files (even new BRUN files) can be added to the list by some other BRUN
* file, and these new files will be run.
*/
int
tfsrunboot(void)
{
static struct tfsran *ranlist;
char *argv[2];
int rancnt, aidx, ridx, err, fmodcnt;
/* The argv[] array is used by tfsrun(); argv[0] is name of file to be
* executed, argv[1] must be nulled to indicate no command line args
* passed to the BRUN file/script.
*/
argv[1] = (char *)0;
/* Keep a local copy of tfsFmodCount so that we can determine if flash
* was modified by one of the BRUN files executed.
*/
fmodcnt = tfsFmodCount;
/* Create list of file pointers (tfsAlist[]) in alphabetical order
* based on name...
*/
if ((err = tfsreorder()) < 0) {
printf("tfsrunboot() reorder1: %s\n",tfserrmsg(err));
return(-1);
}
/* Clear the ranlist pointer. This pointer is the base address of a
* list of file names that have been run.
*/
rancnt = 0;
ranlist = (struct tfsran *)0;
restartloop:
for (aidx=0;tfsAlist[aidx];aidx++) {
char fname[TFSNAMESIZE+1];
int alreadyran;
TFILE *fp;
struct tfsran *rp;
fp = tfsAlist[aidx];
strcpy(fname,TFS_NAME(fp));
/* If the file has no BRUN flag set, just continue. If a BRUN flag
* is set, then see if the file has already been run. If yes, then
* just continue; else run the file.
*/
alreadyran = 0;
if (fp->flags & (TFS_BRUN | TFS_QRYBRUN)) {
for(ridx=0;ridx<rancnt;ridx++) {
if (!strcmp(ranlist[ridx].name,fname)) {
alreadyran = 1;
break;
}
}
}
else
continue; /* No BRUN flag set. */
if (alreadyran) { /* BRUN flag set, but file has already */
continue; /* been run. */
}
err = TFS_OKAY;
argv[0] = fname;
/* At this point we know the file is a BRUN type, so just see if
* the query should precede the run...
*/
if (fp->flags & TFS_QRYBRUN) {
int pollval;
char query[TFSNAMESIZE+8];
sprintf(query,"%s?",fname);
pollval = pollConsole(query);
#ifdef TFS_AUTOBOOT_CANCEL_CHAR
if (pollval == (int)TFS_AUTOBOOT_CANCEL_CHAR)
continue;
#else
if (pollval)
continue;
#endif
}
/* Increase the size of the ranlist[] table and add the file that
* is about to be run to that list...
*/
rancnt++;
rp = (struct tfsran*)realloc((char *)ranlist,
rancnt*sizeof(struct tfsran));
if (!rp) {
if (ranlist)
free((char *)ranlist);
printf("tfsrunboot() runlist realloc failure\n");
return(-1);
}
ranlist = rp;
strcpy(ranlist[rancnt-1].name,fname);
/* Run the executable...
*/
if (fp->flags & TFS_BRUN) {
err = tfsrun_abortableautoboot(argv,0);
}
else {
err = tfsrun(argv,0);
}
if (err != TFS_OKAY)
printf("%s: %s\n",fname,tfserrmsg(err));
/* If flash has been modified, then we must re-run tfsreorder() and
* start over...
*/
if (fmodcnt != tfsFmodCount) {
if ((err = tfsreorder()) < 0) {
printf("tfsrunboot() reorder2: %s\n",tfserrmsg(err));
return(err);
}
fmodcnt = tfsFmodCount;
goto restartloop;
}
}
if (ranlist)
free((char *)ranlist);
return(rancnt);
}
/* tfsreorder():
* Populate the tfsAlist[] array with the list of currently active file
* pointers, but put in alphabetical (lexicographical using strcmp()) order
* based on the filename.
* Note that after each file addition/deletion, this must be re-run.
*/
int
tfsreorder(void)
{
TFILE *fp;
TDEV *tdp;
int i, j, tot;
/* Determine how many valid files exist, and create tfsAlist array:
*/
tot = 0;
for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
fp = (TFILE *)tdp->start;
while(validtfshdr(fp)) {
if (TFS_FILEEXISTS(fp))
tot++;
fp = nextfp(fp,tdp);
}
}
/* If tfsAlist already exists, and is already big enough, then
* don't do any allocation; otherwise, create the array with one extra
* slot for a NULL pointer used elsewhere as an end-of-list indicator.
*/
if (tot > tfsAlistSize) {
tfsAlist = (TFILE **)realloc((char *)tfsAlist,
(tot+1) * sizeof(TFILE **));
if (!tfsAlist) {
tfsAlistSize = 0;
return(TFSERR_MEMFAIL);
}
tfsAlistSize = tot;
}
/* Clear the entire table (plus the extra one at the end):
*/
for(i=0;i<=tot;i++)
tfsAlist[i] = (TFILE *)0;
/* Populate tfsAlist[] with a pointer to each active file
* in flash as they exist in memory...
*/
i = 0;
for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
fp = (TFILE *)tdp->start;
while(validtfshdr(fp)) {
if (TFS_FILEEXISTS(fp)) {
tfsAlist[i++] = fp;
}
fp = nextfp(fp,tdp);
}
}
/* Now run a bubble sort on that list based on the lexicographical
* ordering returned by strcmp...
*/
for(i=1;i<tot;++i) {
for(j=tot-1;j>=i;--j) {
if (strcmp(TFS_NAME(tfsAlist[j-1]),TFS_NAME(tfsAlist[j])) > 0) {
fp = tfsAlist[j-1];
tfsAlist[j-1] = tfsAlist[j];
tfsAlist[j] = fp;
}
}
}
return(tot);
}
/* tfsheadroom():
* Based on the current offset into the file specified by the incoming
* descriptor, return the gap between the current offset and the end
* of the file.
*/
static long
tfsheadroom(int fd)
{
struct tfsdat *tdat;
if ((fd < 0) || (fd >= TFS_MAXOPEN))
return(TFSERR_BADARG);
tdat = &tfsSlots[fd];
if (tdat->flagmode & TFS_RDONLY)
return(tdat->hdr.filsize - tdat->offset);
else
return(tdat->hwp - tdat->offset);
}
/* tfstell():
* Return the offset into the file that is specified by the incoming
* descriptor.
* MONLIB NOTICE: this function is accessible through monlib.c.
*/
long
tfstell(int fd)
{
if ((fd < 0) || (fd >= TFS_MAXOPEN))
return(TFSERR_BADARG);
return(tfsSlots[fd].offset);
}
/* tfscompare():
* Compare the content of the file specified by tfp with the content pointed
* to by the remaining arguments. If identical, return 0; else return -1.
*/
static int
tfscompare(TFILE *tfp,char *name, char *info, char *flags, uchar *src, int size)
{
ulong bflags;
/* Compare size, name, info field, flags and data:
*/
/* Size...
*/
if (TFS_SIZE(tfp) != size)
return(-1);
/* Name...
*/
if (strcmp(name,TFS_NAME(tfp)))
return(-1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -