/*
**	$RCSfile: StartSM.c,v $
**	$Filename: StartSM.c $
**	$Revision: 0.6 $
**	$Date: 1995/11/04 14:11:26 $
**
**	sysmon.library startup command StartSM (version 0.7) 
**	
**	(C) Copyright 1995 by Etienne Vogt
*/

#include <exec/alerts.h>
#include <exec/memory.h>
#include <exec/execbase.h>
#include <dos/dos.h>
#include <dos/dostags.h>
#include <workbench/startup.h>
#define __USE_SYSBASE
#include <proto/exec.h>
#include <proto/dos.h>
#include "sysmon.h"
#include "sysmon_protos.h"
#include "sysmon_pragmas.h"
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

struct ExecBase *SysBase;
struct DosLibrary *DOSBase;
struct SysmonBase *SysmonBase;
static struct WBStartup *wbmsg;
static struct RDArgs *myrda;

static UBYTE version[] = "$VER: StartSM 0.7 (19.11.95)";
static UBYTE template[] = "CONF=CONFIGFILE";
static UBYTE configfile[] = "S:Sysmon.config";
static UBYTE syslogfile[] = "S:Sysmon.log";
static UBYTE syslogwindow[] = "CON:20/50/600/80/SysLog/AUTO/CLOSE/WAIT";
static ULONG filepri = LOG_DEBUG;
static ULONG windowpri = LOG_WARN;
static ULONG consolepri = LOG_EMERG;
static ULONG numbuffers = 5;
static ULONG stampperiod = 60;	/* 1 hour default period	*/
static int idleled = FALSE;
static STRPTR logfile,logwindow;

#define	OPT_CONFIG	0
#define OPTMAX		1

/* Definitions for config file parser	*/

#define P_IGNORE    0
#define P_STRING    1
#define P_BOOL	    2
#define P_INT	    3

#define	OK		0
#define	ERR_OPEN	1
#define ERR_UNKNPREF	2
#define ERR_NOMEM	3

static STRPTR errmsg[] = {
	"OK",
	"Unable to Open",
	"Unknown Keyword",
	"Out of memory",
};

typedef struct
{	STRPTR	name;			/* Configuration item name	*/
	APTR	pflag;			/* Pointer to variable	*/
	UWORD	nbmin_char;		/* Required characters in item name	*/
	UWORD	type;			/* Parameter type	*/
} Pref;

Pref Prefs[] = {
	{"LOGFILE",		&logfile,	4,	P_STRING},
	{"LOGWINDOW",		&logwindow,	4,	P_STRING},
	{"FILEPRI",		&filepri,	5,	P_INT},
	{"WINPRI",		&windowpri,	4,	P_INT},
	{"CONPRI",		&consolepri,	4,	P_INT},
	{"LOGBUFFERS",		&numbuffers,	4,	P_INT},
	{"STAMPPERIOD",		&stampperiod,	6,	P_INT},
	{"IDLELED",		&idleled,	4,	P_BOOL},
	{"#",			NULL,		1,	P_IGNORE},
	{";",			NULL,		1,	P_IGNORE},
};

#define NB_PREFS (sizeof(Prefs)/sizeof(Pref))

ULONG __saveds main(void);
static void cleanexit(ULONG rc);
static void KPrintf(STRPTR fmt, ...);
static BOOL SysLog(ULONG priority, STRPTR format, ...);
static int ReadConfig(STRPTR file);
static char *strtokg(char *s1, char *s2);
static int InitPrefLine(char *line, Pref *pref_array, int nb_prefs);

ULONG __saveds main(void)	/* No startup code */
{
  struct Process *myproc;
  LONG opts[OPTMAX];
  int error;

  SysBase = *(struct ExecBase **)4;
  DOSBase = NULL;
  SysmonBase = NULL;
  wbmsg = NULL;
  myrda = NULL;

  myproc = (struct Process *)FindTask(NULL);
  if ((DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",36)) == NULL)
  { Alert(AT_Recovery|AG_OpenLib|AO_DOSLib);
    return 100;
  }

  if (!(myproc->pr_CLI))		/* If started from WB, exit cleanly */
  { WaitPort(&(myproc->pr_MsgPort));
    wbmsg = (struct WBStartup *)GetMsg(&(myproc->pr_MsgPort));
    cleanexit(20);
  }
  else
  { if ((SysmonBase = (struct SysmonBase *)OpenLibrary("sysmon.library",0)) == NULL)
    { Printf("StartSM : Couldn't open sysmon.library\n");
      cleanexit(20);
    }
    memset((char *)opts, 0, sizeof(opts));
    if ((myrda = ReadArgs(template, opts, NULL)) == NULL)
    { PrintFault(IoErr(),NULL);
      cleanexit(20);
    }
    if (opts[OPT_CONFIG] == 0) opts[OPT_CONFIG] = (LONG)configfile;

    Forbid();
    if (SysmonBase->sb_SyslogPort)
    { Permit();
      Printf("StartSM : The %s process is already running.\n", SysmonBase->sb_ServerName);
      cleanexit(10);
    }
    Permit();
    if ((logfile = AllocVec(strlen(syslogfile)+1,MEMF_PUBLIC)) == NULL)
    { Printf("StartSM : No memory for File name buffer\n");
      cleanexit(20);
    }
    strcpy(logfile, syslogfile);
    if ((logwindow = AllocVec(strlen(syslogwindow)+1,MEMF_PUBLIC)) == NULL)
    { Printf("StartSM : No memory for Window name buffer\n");
      FreeVec(logfile);
      cleanexit(20);
    }
    strcpy(logwindow, syslogwindow);

    if (error = ReadConfig((STRPTR)opts[OPT_CONFIG]))
    { Printf("StartSM : Error reading configuration file (%s).\n", errmsg[error]);
      cleanexit(20);
    }

    if (idleled) SysmonBase->sb_Flags |= SBFF_IDLELED;
    SysmonBase->sb_SyslogFile = logfile;
    SysmonBase->sb_SyslogWindow = logwindow;
    SysmonBase->sb_FilePri = filepri;
    SysmonBase->sb_WindowPri = windowpri;
    SysmonBase->sb_ConsolePri = consolepri;
    SysmonBase->sb_NumLogBuffers = numbuffers;
    SysmonBase->sb_StampPeriod = stampperiod * 60;
    if (CreateNewProcTags(NP_Entry,	SysmonBase->sb_ServerEntry,
			  NP_StackSize,	4000,
			  NP_Name,	SysmonBase->sb_ServerName,
			  NP_Priority,	3,
			  NP_WindowPtr,	-1,
			  TAG_DONE	 ) == NULL)
    { Printf("StartSM : Could not start %s process.\n", SysmonBase->sb_ServerName);
      FreeVec(logfile);
      FreeVec(logwindow);
      cleanexit(20);
    }
    if ((error = SysmonBase->sb_LastGuru) != -1)
    { SysLog(LOG_WARN | LOG_NOWIN, "StartSM : System rebooted by Alert !\nGuru Meditation #%08lx.%08lx\n",
		error, SysBase->LastAlert[1]);
    }
    smSleep(20);
  }
  cleanexit(0);
}

static void cleanexit(ULONG rc)
{
  if (myrda) FreeArgs(myrda);
  if (SysmonBase) CloseLibrary((struct Library *)SysmonBase);
  if (DOSBase) CloseLibrary((struct Library *)DOSBase);
  if (wbmsg)
  { Forbid();
    ReplyMsg((struct Message *)wbmsg);
  }
  Exit(rc);
}

static void KPrintf(STRPTR fmt, ...)
{ smVKPrintf(fmt, &fmt + 1);
}

static BOOL SysLog(ULONG priority, STRPTR format, ...)
{ return smVSysLog(priority, format, &format + 1);
}

#define	MAX_T_LINE	80

static int ReadConfig(STRPTR file)
{ char line[MAX_T_LINE+1];
  BPTR f_in;
  int error;

  if ((f_in = Open(file, MODE_OLDFILE)) == NULL) return ERR_OPEN;	
  while (FGets(f_in, (STRPTR)line, MAX_T_LINE))
  { if (error = InitPrefLine(line, Prefs, NB_PREFS)) return error;
  }
  Close(f_in);
  return OK;
}

static char *strtokg(char *s1, char *s2)
{ char *begin, *end;
  static char *save = "";

  begin = s1 ? s1 : save;
  if (begin == NULL) return NULL;
  begin += strspn(begin, s2);
  if (*begin == '\0')
  { save = "";
    return NULL;
  }
  else
  { if (*begin == '\"')
    { begin++;
      end = strchr(begin, '\"');
    }
    else
      end = strpbrk(begin, s2);
    if (end && *end) *end++ = '\0';
  }
  save = end;

  return begin;
}

static int InitPrefLine(char *line, Pref *pref_array, int nb_prefs)
{ char *p, *parm, **pflag;
  char *seps = " =\t\r";
  int i, l;

  if (p = strchr(line, '\n')) *p = '\0';
  if ((p = strtok(line, seps)) == NULL) return OK;

  for (i=0; i < nb_prefs; i++)
  { l = strlen(p);
    if (l < pref_array[i].nbmin_char) continue;
    if (strnicmp(p, pref_array[i].name, l) == 0) break;
  }

  if (i == nb_prefs) return ERR_UNKNPREF;

  if ((parm = strtok(NULL, seps)) == NULL) return OK; /* no value */

  if (pref_array[i].type ==  P_IGNORE) return OK;

  if (pref_array[i].type == P_BOOL)
  { *parm = toupper((int)*parm);
    if (*parm == 'N' || *parm == 'F') *(int *)pref_array[i].pflag = 0;
    if (*parm == 'Y' || *parm == 'O' || *parm == 'T') *(int *)pref_array[i].pflag = 1;
  }
  else if (pref_array[i].type == P_STRING)
  { pflag = (char **)pref_array[i].pflag;
    if (*pflag) FreeVec(*pflag);		/* Free default string buffer	*/
    *pflag = AllocVec(strlen(parm)+1, MEMF_PUBLIC);
    if (*pflag) strcpy(*pflag, parm);
    else return ERR_NOMEM;
  }
  else if (pref_array[i].type == P_INT)
  { *(int *)pref_array[i].pflag = atoi(parm);
  }

  return OK;
}
