402 lines
11 KiB
C
402 lines
11 KiB
C
/*--------------------------------------------------------------------------
|
|
|
|
Handling of status files
|
|
|
|
|
|
Mark Koennecke, November 1996
|
|
|
|
Updated in order to prevent status floods
|
|
Mark Koennecke, July 2004
|
|
|
|
Reworked restore to keep parameters from uninitialized devices
|
|
Mark Koennecke, November 2007
|
|
|
|
Copyright:
|
|
|
|
Labor fuer Neutronenstreuung
|
|
Paul Scherrer Institut
|
|
CH-5423 Villigen-PSI
|
|
|
|
|
|
The authors hereby grant permission to use, copy, modify, distribute,
|
|
and license this software and its documentation for any purpose, provided
|
|
that existing copyright notices are retained in all copies and that this
|
|
notice is included verbatim in any distributions. No written agreement,
|
|
license, or royalty fee is required for any of the authorized uses.
|
|
Modifications to this software may be copyrighted by their authors
|
|
and need not follow the licensing terms described here, provided that
|
|
the new terms are clearly indicated on the first page of each file where
|
|
they apply.
|
|
|
|
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
|
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
|
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
|
|
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
|
|
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
|
MODIFICATIONS.
|
|
-----------------------------------------------------------------------------*/
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <time.h>
|
|
#include "fortify.h"
|
|
#include <string.h>
|
|
#include "sics.h"
|
|
#include "statusfile.h"
|
|
#include "lld_str.h"
|
|
#include "lld.h"
|
|
#include "exebuf.h"
|
|
|
|
#define CLEAN_LOCKED 1
|
|
#define CLEAN_MISSING 2
|
|
|
|
static int parameterChange = 0;
|
|
/*-----------------------------------------------------------------------*/
|
|
int StatusFileTask(void *data)
|
|
{
|
|
char *pFile = NULL;
|
|
|
|
if (!hasRestored())
|
|
return 1;
|
|
if (parameterChange) {
|
|
parameterChange = 0;
|
|
|
|
assert(pServ->pSics);
|
|
pFile = IFindOption(pSICSOptions, "statusfile");
|
|
if (pFile) {
|
|
WriteSicsStatus(pServ->pSics, pFile, 0);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
static int motorSave = 0;
|
|
/*-----------------------------------------------------------------------*/
|
|
int BackupStatus(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
int iRet;
|
|
char pBueffel[512];
|
|
char *pFile = NULL;
|
|
|
|
assert(pSics);
|
|
assert(pCon);
|
|
|
|
if (argc < 2) {
|
|
pFile = IFindOption(pSICSOptions, "statusfile");
|
|
if (pFile) {
|
|
iRet = WriteSicsStatus(pSics, pFile, motorSave);
|
|
} else {
|
|
SCWrite(pCon, "ERROR: No filename given for backup, Aborted.",
|
|
eError);
|
|
return 0;
|
|
}
|
|
} else {
|
|
if (strcmp(argv[1], "motorSave") == 0) {
|
|
if (motorSave == 1)
|
|
motorSave = 0;
|
|
else
|
|
motorSave = 1;
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "New Value of motorSave= %d\n", motorSave);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
} else {
|
|
iRet = WriteSicsStatus(pSics, argv[1], motorSave);
|
|
}
|
|
}
|
|
|
|
if (!iRet) {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: could not open file %s\n", argv[1]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
static int restoreOccurred = 0;
|
|
int hasRestored()
|
|
{
|
|
return restoreOccurred;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
typedef struct {
|
|
pObjectDescriptor pDes;
|
|
int errList;
|
|
} RestoreObj, *pRestoreObj;
|
|
/*---------------------------------------------------------------------------*/
|
|
static void killRestore(void *data)
|
|
{
|
|
pRestoreObj self = (pRestoreObj) data;
|
|
if (self == NULL) {
|
|
return;
|
|
}
|
|
if (self->errList >= 0) {
|
|
LLDdeleteBlob(self->errList);
|
|
}
|
|
if (self->pDes != NULL) {
|
|
DeleteDescriptor(self->pDes);
|
|
}
|
|
free(self);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int SaveRestore(void *obj, char *name, FILE * fd)
|
|
{
|
|
int status;
|
|
char buffer[1024];
|
|
|
|
pRestoreObj self = (pRestoreObj) obj;
|
|
if (self == NULL) {
|
|
return 0;
|
|
}
|
|
fprintf(fd,
|
|
"\n#--- BEGIN (commands producing errors on last restore)\n");
|
|
status = LLDnodePtr2First(self->errList);
|
|
while (status == 1) {
|
|
LLDstringData(self->errList, buffer);
|
|
fprintf(fd, "%s", buffer);
|
|
status = LLDnodePtr2Next(self->errList);
|
|
}
|
|
fprintf(fd, "#--- END (commands producing errors on last restore)\n\n");
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
int InstallBckRestore(SConnection * pCon, SicsInterp * pSics)
|
|
{
|
|
pRestoreObj pNew = NULL;
|
|
|
|
pNew = malloc(sizeof(RestoreObj));
|
|
if (pNew == NULL) {
|
|
SCWrite(pCon,
|
|
"ERROR: no memory to create restore object! This is SERIOUS!!!",
|
|
eError);
|
|
return 0;
|
|
}
|
|
pNew->pDes = CreateDescriptor("BckRestore");
|
|
pNew->errList = LLDstringCreate();
|
|
if (pNew->pDes == NULL || pNew->errList < 0) {
|
|
SCWrite(pCon,
|
|
"ERROR: no memory to create restore object! This is SERIOUS!!!",
|
|
eError);
|
|
return 0;
|
|
}
|
|
pNew->pDes->SaveStatus = SaveRestore;
|
|
AddCommand(pSics, "Backup", BackupStatus, NULL, NULL);
|
|
AddCommand(pSics, "Restore", RestoreStatus, killRestore, pNew);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static int listRestoreErr(pRestoreObj self, SConnection * pCon)
|
|
{
|
|
char buffer[1024];
|
|
int status;
|
|
pDynString data = NULL;
|
|
|
|
data = CreateDynString(256,256);
|
|
if(data == NULL){
|
|
SCWrite(pCon,"ERROR: out of memory listing errors",eError);
|
|
return 0;
|
|
}
|
|
status = LLDnodePtr2First(self->errList);
|
|
while (status == 1) {
|
|
LLDstringData(self->errList, buffer);
|
|
DynStringConcatLine(data,buffer);
|
|
status = LLDnodePtr2Next(self->errList);
|
|
}
|
|
SCWrite(pCon, GetCharArray(data), eValue);
|
|
DeleteDynString(data);
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static int cleanRestoreErr(pRestoreObj self, SConnection * pCon, int hard)
|
|
{
|
|
char command[1024];
|
|
char message[1024];
|
|
char *errMsg = NULL;
|
|
int status;
|
|
int newErrList;
|
|
pDynString data = NULL;
|
|
pStringDict dict;
|
|
int count_in = 0;
|
|
int count_ex = 0;
|
|
|
|
if (!self->errList)
|
|
return 1;
|
|
|
|
data = CreateDynString(256,256);
|
|
if (data == NULL) {
|
|
SCWrite(pCon,"ERROR: out of memory cleaning errors",eError);
|
|
return 0;
|
|
}
|
|
dict = CreateStringDict();
|
|
if (dict == NULL) {
|
|
SCWrite(pCon,"ERROR: out of memory cleaning errors",eError);
|
|
DeleteDynString(data);
|
|
return 0;
|
|
}
|
|
/* create new list */
|
|
newErrList = LLDstringCreate();
|
|
if (newErrList < 0) {
|
|
SCWrite(pCon,"ERROR: out of blobs cleaning errors",eError);
|
|
DeleteDynString(data);
|
|
DeleteStringDict(dict);
|
|
return 0;
|
|
}
|
|
status = LLDnodePtr2First(self->errList);
|
|
while (status == 1) {
|
|
LLDstringData(self->errList, command);
|
|
status = LLDnodePtr2Next(self->errList);
|
|
if (status != 1) {
|
|
/* Error */
|
|
errMsg = "ERROR: unpaired error cleaning errors";
|
|
break;
|
|
}
|
|
LLDstringData(self->errList, message);
|
|
if (command[0] == '#' || message[0] != '#') {
|
|
/* Error */
|
|
errMsg = "ERROR: sequence error cleaning errors";
|
|
break;
|
|
}
|
|
DynStringClear(data);
|
|
DynStringConcat(data, command);
|
|
DynStringConcat(data, message);
|
|
status = LLDnodePtr2Next(self->errList);
|
|
++count_in;
|
|
/* Skip duplicate messages */
|
|
if (StringDictExists(dict, GetCharArray(data)))
|
|
continue;
|
|
/* Skip "configured locked!" messages */
|
|
if (hard == CLEAN_LOCKED &&
|
|
strstr(message, "#ERR: ERROR: variable ") &&
|
|
strstr(message, " is configured locked!"))
|
|
continue;
|
|
/* Skip "not found" messages */
|
|
if (hard == CLEAN_MISSING &&
|
|
strstr(message, "#ERR: Object ") &&
|
|
strstr(message, "not found"))
|
|
continue;
|
|
/* add to dictionary and new list */
|
|
StringDictAddPair(dict, GetCharArray(data), "");
|
|
LLDstringAppend(newErrList, command);
|
|
LLDstringAppend(newErrList, message);
|
|
++count_ex;
|
|
}
|
|
if (errMsg) {
|
|
SCWrite(pCon, errMsg, eError);
|
|
LLDdeleteString(newErrList);
|
|
} else {
|
|
/* swap lists */
|
|
LLDdeleteString(self->errList);
|
|
self->errList = newErrList;
|
|
SCPrintf(pCon, eLog, "CleanErr: %d pairs in, %d pairs out", count_in, count_ex);
|
|
}
|
|
DeleteDynString(data);
|
|
DeleteStringDict(dict);
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
int RestoreStatus(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
char pBueffel[512];
|
|
int iRights;
|
|
int iRet;
|
|
char *pFile = NULL;
|
|
writeFunc oldWrite;
|
|
pExeBuf buffi = NULL;
|
|
pRestoreObj self = (pRestoreObj) pData;
|
|
|
|
assert(pSics);
|
|
assert(pCon);
|
|
assert(self != NULL);
|
|
|
|
if (argc < 2) {
|
|
pFile = IFindOption(pSICSOptions, "statusfile");
|
|
if (pFile) {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "%s", pFile);
|
|
} else {
|
|
SCWrite(pCon, "ERROR: No filename given for backup, Aborted.",
|
|
eError);
|
|
return 0;
|
|
}
|
|
} else {
|
|
if (strcasecmp(argv[1], "listerr") == 0) {
|
|
return listRestoreErr(self, pCon);
|
|
} else if (strcasecmp(argv[1], "cleanerr") == 0) {
|
|
if (argc > 2 && strcasecmp(argv[2], "locked") == 0)
|
|
return cleanRestoreErr(self, pCon, CLEAN_LOCKED);
|
|
else if (argc > 2 && strcasecmp(argv[2], "missing") == 0)
|
|
return cleanRestoreErr(self, pCon, CLEAN_MISSING);
|
|
else
|
|
return cleanRestoreErr(self, pCon, 0);
|
|
} else if (strcasecmp(argv[1], "killerr") == 0) {
|
|
if (self->errList >= 0) {
|
|
LLDdeleteBlob(self->errList);
|
|
}
|
|
self->errList = LLDstringCreate();
|
|
StatusFileDirty();
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "%s", argv[1]);
|
|
}
|
|
}
|
|
|
|
buffi = exeBufCreate("restore");
|
|
if (buffi == NULL) {
|
|
SCWrite(pCon, "ERROR: failed to allocate buffer for restore", eError);
|
|
return 0;
|
|
}
|
|
iRet = exeBufLoad(buffi, pBueffel);
|
|
if (iRet != 1) {
|
|
exeBufDelete(buffi);
|
|
SCWrite(pCon, "ERROR: failed open status file", eError);
|
|
return 0;
|
|
}
|
|
LLDdeleteBlob(self->errList);
|
|
self->errList = LLDstringCreate();
|
|
iRights = SCGetRights(pCon);
|
|
SCSetRights(pCon,usInternal);
|
|
oldWrite = SCGetWriteFunc(pCon);
|
|
SCSetWriteFunc(pCon, SCNotWrite);
|
|
iRet = exeBufProcessErrList(buffi, pSics, pCon, self->errList);
|
|
restoreOccurred = 1;
|
|
SCSetWriteFunc(pCon, oldWrite);
|
|
SCSetRights(pCon,iRights);
|
|
exeBufDelete(buffi);
|
|
/*
|
|
if we do not override parameterChange here, the backup file
|
|
would be overwritten after each restore... Not the right thing
|
|
to do!
|
|
*/
|
|
parameterChange = 0;
|
|
SCSendOK(pCon);
|
|
return iRet;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
void StatusFileDirty(void)
|
|
{
|
|
parameterChange = 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
void StatusFileInit(void)
|
|
{
|
|
TaskRegisterN(pServ->pTasker, "statusfile", StatusFileTask, NULL, NULL, NULL, TASK_PRIO_HIGH);
|
|
}
|