/* log4fix.c (c)Copyright Sequiter Software Inc., 1988-1996. All rights reserved. */ /* Fixes corrupt server .LOG files */ /**************************************************************************** **:: Preprocessor Directives ****************************************************************************/ #include "d4all.h" #ifndef S4UTILS #error - Must compile with S4UTILS defined #endif #include "u4trans.h" #ifndef S4WINDOWS #ifndef S4UNIX #ifdef __TURBOC__ #pragma hdrstop #endif extern unsigned _stklen = 10000; #endif #endif #ifdef S4DLL_BUILD extern FILE *stdout, *stderr ; extern unsigned int messageType ; HWND hWndStatus ; /* status window handle */ #endif #ifndef S4UTIL_CONCURRENCY #define UTIL4LOG 0 #else #define UTIL4CONFIG 0 #endif #define UTIL4FORCE 1 /**************************************************************************** **:: Global scope types and variables ****************************************************************************/ static UTIL4FLAG u4flags[] = { #ifndef S4UTIL_CONCURRENCY { "Log", 0, 1, 1, 1, 1, 0, 0, 0, "{-log }\r\n" }, #else { "Config", 0, 1, 1, -1, 0, 0, 0, 0, "{-config []}\r\n" }, #endif { "Force", 0, 1, 1, 1, 1, 0, 0, 0, "[-force {OFF | ON}]\r\n" }, }; static int u4flagsNum = 2; static FIELD4INFO openFields[] = { { "CLIENTID", 'N', 11, 0 }, { "CLIENTDTID", 'N', 11, 0 }, { "SERVERDTID", 'N', 11, 0 }, { "PHYSNAME", 'C', LEN4PATH, 0 }, { "RECORDWID", 'N', 11, 0 }, { "NUMFIELDS", 'N', 6, 0 }, { 0,0,0,0 }, }; static TAG4INFO openTags[] = { { "CLID", "STR(CLIENTID,11,0)+STR(SERVERDTID,11,0)", ".NOT.DELETED()", r4unique, 0 }, { 0,0,0,0,0 }, }; static FIELD4INFO tranFields[] = { { "TRANID", 'N', 11, 0 }, { 0,0,0,0 }, } ; static TAG4INFO tranTags[] = { { "TRANID", "STR(TRANID,11,0)", ".NOT.DELETED()", r4unique, 0 }, { 0,0,0,0,0 }, } ; #ifndef S4WINDOWS char *statusStringBlank = " "; char *statusStringMessg = "Processing log file: "; char *statusStringBckSp = "\r"; char *statusStringFormt = "%3d.%02d%%%%"; #ifdef S4UNIX char statusStringSpace[10] ; #else char *statusStringSpace = "100.00 "; #endif #else extern char *statusStringBlank ; extern char *statusStringMessg ; extern char *statusStringBckSp ; extern char *statusStringFormt ; extern char *statusStringSpace ; #endif /*::************************************************************************/ /**************************************************************************** **:: Function: findIncompleteTran ** ***************************************************************************** ** ** Function: findIncompleteTran() ** ****************************************************************************/ short findIncompleteTran(CODE4 *c4, DATA4 *openDbf, DATA4 *tranDbf) { short rc, intPart, decPart; TRAN4 *t4=0; FIELD4 *openClientId=0, *openClientDataId=0, *openServerDataId=0, *openPhysName=0, *tranTranId=0, *tranClientId=0; FIELD4 *openRecordWidth=0, *openNumFields=0; char client[23], *outMess[3]; char *data=0; long logFileLen; TRAN4ENTRY_LEN len; #ifdef S4DATA_ALIGN long templong; short tempshort; #endif rc = file4refresh(&c4->transFile.file); if (rc != 0) return(rc); logFileLen = file4len(&c4->transFile.file); if (logFileLen < 0) return((short)logFileLen); t4 = &c4->c4trans.trans; openClientId = d4field(openDbf, "CLIENTID"); openClientDataId = d4field(openDbf, "CLIENTDTID"); openServerDataId = d4field(openDbf, "SERVERDTID"); openPhysName = d4field(openDbf, "PHYSNAME"); openRecordWidth = d4field(openDbf, "RECORDWID"); openNumFields = d4field(openDbf, "NUMFIELDS"); d4tagSelect(openDbf, d4tag(openDbf, "CLID")); tranTranId = d4field(tranDbf, "TRANID"); d4tagSelect(tranDbf, d4tag(tranDbf, "TRANID")); #ifndef S4WINDOWS outMess[0] = statusStringBlank; util4out(c4, stderr, outMess, 1); #endif for (rc = tran4top(t4); ; rc = tran4skip(t4, TRAN4FORWARDS)) { if (rc != 0) break; intPart = (short)((unsigned long)c4->c4trans.trans.pos*50/logFileLen); decPart = (short)((unsigned long)c4->c4trans.trans.pos*5000/logFileLen%100); #ifndef S4WINDOWS sprintf(statusStringSpace, statusStringFormt, intPart, decPart); outMess[0] = statusStringBckSp; outMess[1] = statusStringMessg; outMess[2] = statusStringSpace; util4out(c4, stderr, outMess, 3); #else sendStatusMessage( hWndStatus, intPart ) ; #endif switch (tran4type(t4)) { case TRAN4BACKEDUP: case TRAN4WRITE: case TRAN4APPEND: case TRAN4PACK: case TRAN4ZAP: case TRAN4VOID: break; case TRAN4SHUTDOWN: rc = d4pack(openDbf); if (rc != 0) break; if (d4recCount(openDbf) > 0) { outMess[0] = "\r\n\r\nLog file corrupt! User(s) initialized at shutdown, continuing.\r\n\r\n"; #ifndef S4WINDOWS outMess[1] = statusStringBlank; util4out(c4, stdout, outMess, 2); #else util4out(c4, stdout, outMess, 1); #endif rc = d4zap(openDbf, 1L, d4recCount(openDbf)); if (rc != 0) break; } rc = d4pack(tranDbf); if (rc != 0) break; if (d4recCount(tranDbf) > 0) { outMess[0] = "\r\n\r\nLog file corrupt! Transaction(s) active at shutdown, continuing.\r\n\r\n"; #ifndef S4WINDOWS outMess[1] = statusStringBlank; util4out(c4, stdout, outMess, 2); #else util4out(c4, stdout, outMess, 1) ; #endif rc = d4zap(tranDbf, 1L, d4recCount(tranDbf)); if (rc != 0) break; } if (tran4serverDataId(&c4->c4trans.trans) > TRAN4VERSION_NUM) { outMess[0] = "\r\n\r\nLog file error! File is a newer version than this utility can handle!\r\n\r\n"; util4out(c4, stdout, outMess, 1); rc = -1; } break; case TRAN4INIT: rc = d4appendStart(openDbf, 0); if (rc != 0) break; d4blank(openDbf); f4assignLong(openClientId, tran4clientId(t4)); rc = d4append(openDbf); if (rc == r4unique) { outMess[0] = "\r\n\r\nLog file error! User already initialized.\r\n\r\n"; util4out(c4, stdout, outMess, 1); } break; case TRAN4INIT_UNDO: util4rightJ(ltoa(tran4clientId(t4), client, 10), 12); rc = d4seek(openDbf, client); if (rc == 0 && f4long(openClientDataId) != 0) rc = r4after; if (rc != 0) { if (rc == r4after || rc == r4eof) { outMess[0] = "\r\n\r\nLog file error! User uninitialized that is not initialized.\r\n\r\n"; util4out(c4, stdout, outMess, 1); rc = -1; } break; } d4delete(openDbf); rc = d4seek(openDbf, client); if (rc == 0) { outMess[0] = "\r\n\r\nLog file error! User uninitialized with DBF's still open.\r\n\r\n"; util4out(c4, stdout, outMess, 1); rc = -1; break; } if (rc == r4after || rc == r4eof) rc = 0; break; case TRAN4OPEN: case TRAN4OPEN_TEMP: data = (char *)tran4getData(t4, 0L); if (data == 0) { rc = -1; break; } util4rightJ(ltoa(tran4clientId(t4), client, 10), 12); rc = d4seek(openDbf, client); if (rc != 0) { if (rc == r4after || rc == r4eof) { outMess[0] = "\r\n\r\nLog file error! DBF opened by user that is not initialized.\r\n\r\n"; util4out(c4, stdout, outMess, 1); rc = -1; } break; } rc = d4appendStart(openDbf, 0); if (rc != 0) break; f4assignLong(openClientDataId, tran4clientDataId(t4)); f4assignLong(openServerDataId, tran4serverDataId(t4)); f4assignN(openPhysName, data+2, *(short *)data); #ifdef S4DATA_ALIGN memcpy(&templong, (data+2+*(short *)data), sizeof(long) ); f4assignLong(openRecordWidth, templong); memcpy(&tempshort, (data+6+*(short *)data), sizeof(short) ); f4assignInt(openNumFields, tempshort); #else f4assignLong(openRecordWidth, *(long *)(data+2+ *(short *)data)); f4assignInt(openNumFields, *(short *)(data+6+ *(short *)data)); #endif rc = d4append(openDbf); if (rc == r4unique) { outMess[0] = "\r\n\r\nLog file error! DBF identifier already used.\r\n\r\n"; util4out(c4, stdout, outMess, 1); } break; case TRAN4CLOSE: util4rightJ(ltoa(tran4clientId(t4), client, 10), 12); util4rightJ(ltoa(tran4serverDataId(t4), client+11, 10), 12); rc = d4seek(openDbf, client); if (rc != 0) { if (rc == r4after || rc == r4eof) { outMess[0] = "\r\n\r\nLog file error! DBF closed that is not open.\r\n\r\n"; util4out(c4, stdout, outMess, 1); rc = -1; } break; } d4delete(openDbf); break; case TRAN4START: util4rightJ(ltoa(tran4clientId(t4), client, 10), 12); rc = d4seek(openDbf, client); if (rc != 0) { if (rc == r4after || rc == r4eof) { outMess[0] = "\r\n\r\nLog file error! Transaction started by user that is not initialized.\r\n\r\n"; util4out(c4, stdout, outMess, 1); rc = -1; } break; } rc = d4appendStart(tranDbf, 0); if (rc != 0) break; d4blank(tranDbf); f4assignLong(tranTranId, tran4id(t4)); rc = d4append(tranDbf); if (rc == r4unique) { outMess[0] = "\r\n\r\nLog file error! Transaction ID already started.\r\n\r\n"; util4out(c4, stdout, outMess, 1); } break ; case TRAN4COMPLETE: case TRAN4ROLLBACK: util4rightJ(ltoa(tran4id(t4), client, 10), 12); rc = d4seek(tranDbf, client); if (rc != 0) { if (rc == r4after || rc == r4eof) { if (tran4type(t4) == TRAN4COMPLETE) outMess[0] = "\r\n\r\nLog file error! Transaction completed that was not started.\r\n\r\n"; else outMess[0] = "\r\n\r\nLog file error! Transaction rolledback that was not started.\r\n\r\n"; util4out(c4, stdout, outMess, 1); rc = -1; } break; } d4delete(tranDbf); break; default: outMess[0] = "\r\n\r\nLog file error! Unknown log entry type.\r\n\r\n"; util4out(c4, stdout, outMess, 1); rc = -1; } if (rc != 0) break; if (t4->pos+sizeof(LOG4HEADER)+sizeof(TRAN4ENTRY_LEN) > logFileLen) { rc = r4eof; break; } rc = file4readAll(&c4->transFile.file, t4->pos+sizeof(LOG4HEADER), &len, sizeof(TRAN4ENTRY_LEN)); if (rc == 0 && (long)(t4->pos+sizeof(LOG4HEADER)+len) > logFileLen) { rc = r4eof; break; } if (rc != 0) break; } if (rc == r4eof) if (t4->pos+sizeof(LOG4HEADER) != logFileLen) rc = file4lenSet(&c4->transFile.file, t4->pos+sizeof(LOG4HEADER)); else rc = 0; return rc; } /**************************************************************************** **:: Function: checkDbfHeader ** ***************************************************************************** ** ** Function: checkDbfHeader() ** ****************************************************************************/ short checkDbfHeader(CODE4 *c4, char *fileName) { short rc, rc2; FILE4 file; DATA4HEADER_FULL fullHeader; S4LONG lengthRecords; c4trimN(fileName, strlen(fileName)+1); rc = file4open(&file, c4, fileName, 1); if (rc != 0) if (rc != r4noOpen) return(rc); else return(0); rc = file4readAll(&file, 0L, &fullHeader, sizeof(fullHeader)); if (rc < 0) { file4close(&file); return(rc); } #ifdef S4BYTE_SWAP fullHeader.numRecs = x4reverseLong( (void *)&fullHeader.numRecs ) ; fullHeader.headerLen = x4reverseShort( (void *)&fullHeader.headerLen ) ; fullHeader.recordLen = x4reverseShort( (void *)&fullHeader.recordLen ) ; #endif lengthRecords = (file4len(&file) - fullHeader.headerLen) / fullHeader.recordLen; if (fullHeader.numRecs != lengthRecords) rc = file4write(&file, 4L, &lengthRecords, sizeof(S4LONG)); rc2 = file4close(&file); if (rc != 0) rc2 = rc; return(rc2); } /**************************************************************************** **:: Function: fixIncompleteTran ** ***************************************************************************** ** ** Function: fixIncompleteTran() ** ****************************************************************************/ short fixIncompleteTran(CODE4 *c4, DATA4 *openDbf, DATA4 *tranDbf, short force) { short rc, rc2, rc3, i, curNumFields, consistency, intPart, decPart; unsigned smallerSize; TRAN4 *t4=0; DATA4 **userDbfs=0, *curDbf=0; char *outMess[8], *data=0, client[23]; char ltoaTemp[12]; char ltoaTemp2[12]; unsigned long offsetMemo, offset; long curRecWidth; long logFileLen; rc = file4refresh(&c4->transFile.file); if (rc != 0) return(rc); logFileLen = file4len(&c4->transFile.file); if (logFileLen < 0) return((short)logFileLen); t4 = &c4->c4trans.trans; rc = d4pack(openDbf); if (rc != 0) return(rc); if (d4recCount(openDbf) > 0) { userDbfs = (DATA4 **)u4allocFree(c4, d4recCount(openDbf)*4); if (userDbfs == 0) return(-1); } c4->errOpen = 0; for (rc = d4top(openDbf); rc == 0; rc = d4skip(openDbf,1L)) { if (f4long(d4field(openDbf, "SERVERDTID")) == 0) { userDbfs[d4recNo(openDbf)-1L] = 0; continue; } rc = checkDbfHeader(c4, f4str(d4field(openDbf, "PHYSNAME"))); if (rc != 0) { outMess[0] = "\r\n\r\nError! Can not fix record count for "; outMess[1] = f4str(d4field(openDbf, "PHYSNAME")); outMess[2] = "\r\n\r\n"; util4out(c4, stdout, outMess, 3); curDbf = 0; c4->errorCode = 0; } else curDbf = d4open(c4, f4str(d4field(openDbf, "PHYSNAME"))); if (curDbf && ((unsigned)f4long(d4field(openDbf, "RECORDWID")) != d4recWidth(curDbf) || f4int(d4field(openDbf, "NUMFIELDS")) != d4numFields(curDbf))) { rc = d4close(curDbf); if (rc != 0) c4->errorCode = 0; else c4->errorCode = r4noOpen; curDbf = 0; } if (curDbf != 0) { rc = d4reindex(curDbf); if (rc != 0) { d4close(curDbf); curDbf = 0; c4->errorCode = 0; } } if (curDbf == 0) if (c4->errorCode == r4noOpen) { outMess[0] = "\r\n\r\n"; outMess[1] = f4str(d4field(openDbf, "PHYSNAME")); c4trimN(outMess[1], strlen(outMess[1])+1); outMess[2] = "\r\neither not found or structure does not match log file entry, skipping.\r\n\r\n"; #ifndef S4WINDOWS outMess[3] = statusStringBlank; util4out(c4, stdout, outMess, 4); #else util4out(c4, stdout, outMess, 3); #endif } else { for (rc = d4skip(openDbf, -1L); rc == 0; rc = d4skip(openDbf, -1L)) if (userDbfs[d4recNo(openDbf)-1L] != 0) d4close(userDbfs[d4recNo(openDbf)-1L]); u4free(userDbfs); return(-1); } userDbfs[d4recNo(openDbf)-1L] = curDbf; } c4->errOpen = 1; for (rc = tran4bottom(t4); ; rc = tran4skip(t4, TRAN4BACKWARDS)) { if (rc != 0) break; consistency = 1; intPart = (short)((unsigned long)(logFileLen-c4->c4trans.trans.pos)*50/logFileLen+50); decPart = (short)((unsigned long)(logFileLen-c4->c4trans.trans.pos)*5000/logFileLen%100); #ifndef S4WINDOWS sprintf(statusStringSpace, statusStringFormt, intPart, decPart); outMess[0] = statusStringBckSp; outMess[1] = statusStringMessg; outMess[2] = statusStringSpace; util4out(c4, stderr, outMess, 3); #else sendStatusMessage( hWndStatus, intPart ) ; #endif switch (tran4type(t4)) { case TRAN4SHUTDOWN: case TRAN4BACKEDUP: case TRAN4INIT: case TRAN4INIT_UNDO: case TRAN4OPEN: case TRAN4OPEN_TEMP: case TRAN4CLOSE: case TRAN4START: case TRAN4COMPLETE: case TRAN4ROLLBACK: case TRAN4PACK: case TRAN4ZAP: case TRAN4VOID: break; case TRAN4WRITE: util4rightJ(ltoa(tran4id(t4), client, 10), 12); rc = d4seek(tranDbf, client); if (rc != 0) { if (rc == r4after || rc == r4eof) rc = 0; break; } util4rightJ(ltoa(tran4clientId(t4), client, 10), 12); util4rightJ(ltoa(tran4serverDataId(t4), client+11, 10), 12); rc = d4seek(openDbf, client); if (rc != 0) { if (rc == r4after || rc == r4eof) { outMess[0] = "\r\n\r\nLog file error! Write to DBF that is not open.\r\n\r\n"; util4out(c4, stdout, outMess, 1); rc = -1; } break; } curDbf = userDbfs[d4recNo(openDbf)-1L]; if (curDbf == 0) break; data = (char *)tran4getData(t4, 0L); if (data == 0) { rc = -1; break; } c4->errGo = 0; rc = d4go(curDbf, *(long *)data); c4->errGo = 1; if (rc != 0) { if (rc == r4entry) { outMess[0] = "\r\n\r\n"; outMess[1] = f4str(d4field(openDbf, "PHYSNAME")); c4trimN(outMess[1], strlen(outMess[1])+1); outMess[2] = " consistency error!\r\nIn transaction #"; outMess[3] = ltoa(tran4id(t4), ltoaTemp, 10); outMess[4] = ", write to DBF record #"; outMess[5] = ltoa(*(long *)data, ltoaTemp2, 10); outMess[6] = " that does not exist, skipping.\r\n\r\n"; outMess[7] = statusStringBlank; util4out(c4, stdout, outMess, 8); rc = 0; } break; } curRecWidth = f4long(d4field(openDbf, "RECORDWID")); curNumFields = f4int(d4field(openDbf, "NUMFIELDS")); if (*(data+4+curRecWidth) == '*') { if (!d4deleted(curDbf)) consistency = 0; } else if (d4deleted(curDbf)) consistency = 0; offset = 5 + curRecWidth; offsetMemo = 4 + 2*curRecWidth; for (i=1; i <= d4numFields(curDbf) && consistency == 1; i++) { if (f4type(d4fieldJ(curDbf, i)) == 'M') { offsetMemo += 4 + *(unsigned long *)(data+offsetMemo); smallerSize = f4memoLen(d4fieldJ(curDbf, i)) < *(unsigned *)(data+offsetMemo) ? f4memoLen(d4fieldJ(curDbf, i)) : *(unsigned *)(data+offsetMemo); if (strncmp(f4memoPtr(d4fieldJ(curDbf, i)), data+offsetMemo+4, smallerSize) != 0) consistency = 0; offsetMemo += 4 + *(unsigned long *)(data+offsetMemo); offset += 10; } else { if (strncmp(f4ptr(d4fieldJ(curDbf, i)), data+offset, f4len(d4fieldJ(curDbf, i))) != 0) consistency = 0; offset += f4len(d4fieldJ(curDbf, i)); } } if (consistency == 0 && force == 0) break; if (*(data+4) == '*') d4delete(curDbf); else d4recall(curDbf); offset = 5; offsetMemo = 4 + 2*curRecWidth; for (i=1; i <= d4numFields(curDbf); i++) { if (f4type(d4fieldJ(curDbf, i)) == 'M') { if (*(unsigned long *)(data+offsetMemo) != 0) { f4memoAssignN(d4fieldJ(curDbf, i), data+offsetMemo+4, *(unsigned *)(data+offsetMemo)); offsetMemo += 4 + *(unsigned long *)(data+offsetMemo); } else { offsetMemo += 4 + *(unsigned long *)(data+offsetMemo); if (*(unsigned long *)(data+offsetMemo) != 0) f4memoAssignN(d4fieldJ(curDbf, i), 0, 0); } offsetMemo += 4 + *(unsigned long *)(data+offsetMemo); offset += 10; } else { f4assignN(d4fieldJ(curDbf, i), data+offset, f4len(d4fieldJ(curDbf, i))); offset += f4len(d4fieldJ(curDbf, i)); } } break; case TRAN4APPEND: util4rightJ(ltoa(tran4id(t4), client, 10), 12); rc = d4seek(tranDbf, client); if (rc != 0) { if (rc == r4after || rc == r4eof) rc = 0; break; } util4rightJ(ltoa(tran4clientId(t4), client, 10), 12); util4rightJ(ltoa(tran4serverDataId(t4), client+11, 10), 12); rc = d4seek(openDbf, client); if (rc != 0) { if (rc == r4after || rc == r4eof) { outMess[0] = "\r\n\r\nLog file error! Append to DBF that is not open.\r\n\r\n"; util4out(c4, stdout, outMess, 1); rc = -1; } break; } curDbf = userDbfs[d4recNo(openDbf)-1L]; if (curDbf == 0) break; data = (char *)tran4getData(t4, 0L); if (data == 0) { rc = -1; break; } if (*(long *)data != d4recCount(curDbf)) { outMess[0] ="\r\n\r\n"; outMess[1] = f4str(d4field(openDbf, "PHYSNAME")); c4trimN(outMess[1], strlen(outMess[1])+1); outMess[2] = " consistency error!\r\nIn transaction #"; outMess[3] = ltoa(tran4id(t4), ltoaTemp, 10); outMess[4] = ", appended DBF record #"; outMess[5] = ltoa(*(long *)data, ltoaTemp2, 10); outMess[6] = " is no longer the last record, skipping.\r\n\r\n"; outMess[7] = statusStringBlank; util4out(c4, stdout, outMess, 8); rc = 0; break; } c4->errGo = 0; rc = d4go(curDbf, *(long *)data); c4->errGo = 1; if (rc != 0) break; curRecWidth = f4long(d4field(openDbf, "RECORDWID")); curNumFields = f4int(d4field(openDbf, "NUMFIELDS")); if (*(data+4) == '*') { if (!d4deleted(curDbf)) consistency = 0; } else if (d4deleted(curDbf)) consistency = 0; offset = 5; offsetMemo = 4 + curRecWidth; for (i=1; i <= d4numFields(curDbf) && consistency == 1; i++) { if (f4type(d4fieldJ(curDbf, i)) == 'M') { smallerSize = f4memoLen(d4fieldJ(curDbf, i)) < *(unsigned *)(data+offsetMemo) ? f4memoLen(d4fieldJ(curDbf, i)) : *(unsigned *)(data+offsetMemo); if (strncmp(f4memoPtr(d4fieldJ(curDbf, i)), data+offsetMemo+4, smallerSize) != 0) consistency = 0; offsetMemo += 4 + *(unsigned long *)(data+offsetMemo); offset += 10; } else { if (strncmp(f4ptr(d4fieldJ(curDbf, i)), data+offset, f4len(d4fieldJ(curDbf, i))) != 0) consistency = 0; offset += f4len(d4fieldJ(curDbf, i)); } } if (consistency == 0 && force == 0) break; code4unlockAutoSet(c4, 0); rc = d4unappend(curDbf); code4unlockAutoSet(c4, 1); break; default: outMess[0] = "\r\n\r\nLog file error! Unknown log entry type.\r\n\r\n"; util4out(c4, stdout, outMess, 1); rc = -1; } if (consistency == 0) { outMess[0] ="\r\n\r\n"; outMess[1] = f4str(d4field(openDbf, "PHYSNAME")); c4trimN(outMess[1], strlen(outMess[1])+1); outMess[2] = " consistency error!\r\nIn transaction #"; outMess[3] = ltoa(tran4id(t4), ltoaTemp, 10); outMess[4] = ", DBF record #"; outMess[5] = ltoa(*(long *)data, ltoaTemp2, 10); if (force == 0) outMess[6] = " does not match log file entry, skipping.\r\n"; else outMess[6] = " does not match log file entry, restore forced anyways.\r\n\r\n"; outMess[7] = statusStringBlank; util4out(c4, stdout, outMess, 8); } if ( rc != 0 ) break ; } if (rc == r4bof) { rc = 0; #ifndef S4WINDOWS outMess[0] = statusStringBckSp; outMess[1] = statusStringMessg; sprintf(statusStringSpace, statusStringFormt, 100, 0); outMess[2] = statusStringSpace; util4out(c4, stderr, outMess, 3); #endif } #ifndef S4WINDOWS outMess[0] = "\r\n"; util4out(c4, stderr, outMess, 1); util4out(c4, stdout, outMess, 1); #endif rc2 = rc; rc3 = 0; if (rc == 0) { for (rc=d4top(tranDbf); rc == 0; rc = d4skip(tranDbf, 1L)) { rc = tran4set(t4, r4off, f4long(d4field(tranDbf, "TRANID")), 0, TRAN4ROLLBACK, 0, 0, 0); if (rc < 0) { rc2 = rc; continue; } rc = tran4lowAppend(t4, 0); if (rc < 0) rc2 = rc; } if (rc != r4eof) rc2 = rc; } for (rc=d4bottom(openDbf); rc == 0; rc = d4skip(openDbf, -1L)) { if (rc2 == 0) { if (f4long(d4field(openDbf, "SERVERDTID")) == 0) { if (rc3 == 0) rc = tran4set(t4, r4off, 0, f4long(d4field(openDbf, "CLIENTID")), TRAN4INIT_UNDO, 0, 0, 0); } else rc = tran4set(t4, r4off, 0, f4long(d4field(openDbf, "CLIENTID")), TRAN4CLOSE, 0, f4long(d4field(openDbf, "CLIENTDTID")), f4long(d4field(openDbf, "SERVERDTID"))); if (rc < 0) { rc3 = rc; continue; } rc = tran4lowAppend(t4, 0); if (rc < 0) rc3 = rc; } if (userDbfs[d4recNo(openDbf)-1L] != 0) rc2 = rc2 || d4close(userDbfs[d4recNo(openDbf)-1L]); } if (rc == r4bof || rc == r4eof) rc = 0; if (!rc && !rc2 && !rc3) { tran4set(t4, r4off, 0, 0, TRAN4SHUTDOWN, 0, 0, TRAN4VERSION_NUM); tran4lowAppend(t4, 0); } return(rc || rc2 || rc3); } /**************************************************************************** **:: Function: getLogFileName ** ***************************************************************************** ** ** Function: getLogFileName() ** ****************************************************************************/ int getLogFileName(CODE4 *c4, UTIL4FLAG *u4flag, char **logFileName) { #ifdef S4UTIL_CONCURRENCY int rc; DATA4 *configDbf=0; char *outMess[1]; if (u4flags[UTIL4CONFIG].ptr != 0) configDbf = d4open(c4, u4flags[UTIL4CONFIG].ptr[0]); else configDbf = d4open(c4, "S4SERVER"); if (configDbf == 0) return(-1); rc = d4top(configDbf); if (rc == 0) { *logFileName = u4allocFree(c4, f4len(d4field(configDbf, "LOGNAME"))+1); if (*logFileName == 0) rc = -1; } if (rc == 0) { strcpy(*logFileName, f4str(d4field(configDbf, "LOGNAME"))); c4trimN(*logFileName, f4len(d4field(configDbf, "LOGNAME"))+1); if (**logFileName == 0) { rc = -1; outMess[0] = "Config Dbf error! Logging is disabled.\r\n\r\n"; util4out(c4, stdout, outMess, 1); } } rc = rc || d4close(configDbf); return(rc); #else *logFileName = u4flags[UTIL4LOG].ptr[0] ; return 0 ; #endif } /**************************************************************************** **:: Function: main ** ***************************************************************************** ** ** Function: main() ** ****************************************************************************/ #ifdef S4DLL_BUILD int S4FUNCTION mainLog4Fix(int argc, char *argv[], int hWnd ) #else int main(int argc, char *argv[]) #endif { CODE4 c4; DATA4 *openDbf=0, *tranDbf=0; char *logFileName=0, *outMess[2]; int rc=0, goodAlready=0; short force; #ifdef S4WINDOWS hWndStatus = hWnd ; messageType = MB_ICONSTOP ; #endif #ifndef S4DLL_BUILD #ifdef _WINDOWS _wabout("LOG4FIX.EXE\r\n(c)Copyright Sequiter Software Inc., 1988-1996"); #endif #endif code4init(&c4); c4.lockAttempts = WAIT4EVER; c4.accessMode = OPEN4DENY_RW; #ifdef N4OTHER c4.autoOpen = 0; #endif #ifndef S4WINDOWS outMess[0] = "\r\n"; util4out(&c4, stderr, outMess, 1); #endif if (argc < 2) rc = -1; if (rc == 0) rc = util4parseCommandLine(&c4, u4flags, u4flagsNum, argv, argc); force = util4checkOnOffCommandLine(&c4, u4flags, UTIL4FORCE, 0); if (force == -1) rc = -1; #ifdef S4UTIL_CONCURRENCY if (rc == 0 && u4flags[UTIL4CONFIG].found == 0) { outMess[0] = "Command line error! Must specify -config switch.\r\n\r\n"; #else if (rc == 0 && u4flags[UTIL4LOG].found == 0) { outMess[0] = "Command line error! Must specify -log switch.\r\n\r\n"; #endif util4out(&c4, stdout, outMess, 1); rc = -1; } if (rc != 0) { util4printCommandLine(&c4, u4flags, u4flagsNum, argv[0]); util4flagsFree(u4flags, u4flagsNum); code4initUndo(&c4); #ifdef S4WINDOWS sendCloseMessage( hWndStatus ) ; #endif return(rc); } rc = getLogFileName(&c4, u4flags, &logFileName); if (rc == 0) { rc = code4logOpen( &c4, logFileName, "" ) ; code4tranStatusSet(&c4, r4off); } if (rc == 0 && sizeof(LOG4HEADER)+sizeof(TRAN4ENTRY_LEN) > file4len(&c4.transFile.file)) { rc = file4lenSet(&c4.transFile.file, 0L); outMess[0] = "Log file error! Log file is empty.\r\n\r\n"; util4out(&c4, stdout, outMess, 1); rc = -1; } if (rc == 0) { openDbf = d4createTemp(&c4, openFields, openTags); tranDbf = d4createTemp(&c4, tranFields, tranTags); if (openDbf == 0 || tranDbf == 0) rc = -1; } c4.lockAttempts = 1; if (rc == 0) { rc = code4tranLockTransactions(&c4.c4trans, TRAN4LOCK_FIX); if (rc == r4locked) { outMess[0] = "Concurrency error! Another copy of this utility is running!\r\n\r\n"; util4out(&c4, stdout, outMess, 1); } } if (rc == 0) { rc = code4tranLockTransactions(&c4.c4trans, TRAN4LOCK_BACKUP); if (rc == r4locked) { outMess[0] = "Concurrency error! Backup utility is running!\r\n\r\n"; util4out(&c4, stdout, outMess, 1); } } if (rc == 0) { rc = code4tranLockTransactions(&c4.c4trans, TRAN4LOCK_SERVER); if (rc == r4locked) { outMess[0] = "Concurrency error! The server is running!\r\n\r\n"; util4out(&c4, stdout, outMess, 1); } } c4.lockAttempts = WAIT4EVER; if (rc == 0) { rc = tran4top(&c4.c4trans.trans); if (rc == 0) if (tran4type(&c4.c4trans.trans) != TRAN4SHUTDOWN || tran4serverDataId(&c4.c4trans.trans) > TRAN4VERSION_NUM) { outMess[0] = "Log file error! File is either a backup file or a newer version than this utility can handle!\r\n\r\n"; util4out(&c4, stdout, outMess, 1); rc = -1; } } if (rc == 0) rc = findIncompleteTran(&c4, openDbf, tranDbf); if (rc == 0) { rc = tran4bottom(&c4.c4trans.trans); if (rc == 0) if (tran4type(&c4.c4trans.trans) == TRAN4SHUTDOWN) { #ifndef S4WINDOWS outMess[0] = "\r\n"; util4out(&c4, stderr, outMess, 1); util4out(&c4, stdout, outMess, 1); #endif outMess[0] = "Log file already in correct condition!\r\n\r\n"; util4out(&c4, stdout, outMess, 1); } else rc = fixIncompleteTran(&c4, openDbf, tranDbf, force); } if (rc != 0) outMess[0] = "Error! Utility did not successfully finish!\r\n"; else { #ifdef S4WINDOWS messageType = MB_ICONEXCLAMATION ; sendStatusMessage( hWndStatus, 100 ) ; #endif outMess[0] = "Utility successfully finished!\r\n"; } util4out(&c4, stdout, outMess, 1); code4transInitUndo(&c4.c4trans); if (tranDbf) rc = rc || d4close(tranDbf); if (openDbf) rc = rc || d4close(openDbf); #ifdef S4UTIL_CONCURRENCY if (logFileName) u4free(logFileName); #endif util4flagsFree(u4flags, u4flagsNum); code4initUndo(&c4); #ifdef S4WINDOWS sendCloseMessage( hWndStatus ) ; #endif return(rc); }