/*
 * daemon.c --
 *	Routines to control POSTGRES system daemons.
 */
#include <stdio.h>
#include <sys/param.h>
#include "tmp/postgres.h"
#include "utils/log.h"

#include "daemon.h"
#include "suputils.h"

RcsId("$Header: RCS/daemon.c,v 1.5 90/08/17 08:55:16 cimarron Exp $");

#define	VACUUM_DAEMON	"vacuumd"

/*
 *	DBNameFormVacuumDaemonProcessIdFileName
 *
 *	Put the appropriate path name into "target".
 */
static void
DBNameFormVacuumDaemonProcessIdFileName(dbname, target)
	char	*dbname, *target;
{
	char		*home;
	extern char	*GetDataHome();

	Assert(PointerIsValid(dbname));
	Assert(PointerIsValid(target));
	Assert(PointerIsValid(home = GetDataHome()));
	(void) sprintf(target, "%s/data/base/%s/%s.vacuum\0",
		       home, dbname, dbname);
}


/*
 *	DBNameRegisterVacuumDaemon
 *
 *	Registers a vacuum daemon for database "dbname".
 *
 * XXX	This just writes a the pid into a file.
 */
void
DBNameRegisterVacuumDaemon(dbname, processId)
	char	*dbname;
	int	processId;
{
	char		buffer[MAXPGPATH];
	FILE 		*file;
	static char	funcname[] = "DBNameRegisterVacuumDaemon";
	
	Assert(PointerIsValid(dbname));
	Assert(processId > 2);	/* XXX UNIX pid 0, 1, and 2 are special */

	DBNameFormVacuumDaemonProcessIdFileName(dbname, buffer);
	IFDEBUG(printf("%s: opening file: %s...\n", funcname, buffer));
	IFDEBUG(FlushOutput());
	if ((file = fopen(buffer, "w")) == (FILE *) NULL) {
		perror("open");
		PathRemoveRecursively(buffer);
		return;
	}
	fprintf(file, "%d", processId);
	fclose(file);
}

/*
 *	DBNameStartVacuumDaemon
 *
 *	Forks and execs a vacuum daemon onto database "dbname".
 */
void
DBNameStartVacuumDaemon(dbname)
	char	*dbname;
{
	register	i;
	short		vpid;     
	char		buffer[MAXPGPATH];
	FILE 		*file;
	static char	funcname[] = "DBNameStartVacuumDaemon";
	
	Assert(PointerIsValid(dbname));

	DBNameFormVacuumDaemonProcessIdFileName(dbname, buffer);
	IFDEBUG(printf("%s: opening file: %s...\n", funcname, buffer));
	IFDEBUG(FlushOutput());
	if ((file = fopen(buffer, "w")) == (FILE *) NULL) {
		perror("open");
		PathRemoveRecursively(buffer);
		return;
	}
	vpid = fork();
	if (vpid < 0) {
		elog(NOTICE, "%s: unable to fork vacuum daemon!\n", funcname);
		return;
	}
	if (vpid == 0) { 
		for (i = 3; i < NOFILE; ++i)
			close(i);
		sprintf(buffer, "%s/bin/%s\0", GetDataHome(), VACUUM_DAEMON);
		elog(NOTICE, "%s: %d: executing %s ...",
		     funcname, getpid(), buffer);
		FlushOutput();
		FlushErrors();
		execl(buffer, buffer, dbname, 0);
		elog(NOTICE, "%s: %d: executing %s ...",
		     funcname, getpid(), VACUUM_DAEMON);
		FlushOutput();
		FlushErrors();
		execl(VACUUM_DAEMON, VACUUM_DAEMON, dbname, 0);
		perror("execl vacuum daemon");
		exitpg(1);
	} else {
		fprintf(file, "%d", vpid);
		fclose(file);
	}
}


/*
 *	DBNameStopVacuumDaemon
 *
 *	Kills the vacuum daemon running on database "dbname".
 *
 *	The call to DBNameCleanupVacuumDaemon is usually redundant, but
 *	if the vacuum daemon dies without a chance to clean up itself,
 *	this allows you to clean up after it.
 */
void
DBNameStopVacuumDaemon(dbname)
	char	*dbname;
{
	short		vpid;
	static char	funcname[] = "DBNameStopVacuumDaemon";

	Assert(PointerIsValid(dbname));

	vpid = DBNameGetVacuumDaemonProcessId(dbname);
	if (vpid <= 0) {
		elog(NOTICE, "%s: no vacuumd running on %s -- no kill",
		     funcname, dbname);
		return;
	}
	elog(NOTICE, "%s: %s kill of vacuumd (pid %d) on %s",
	     funcname,
	     (kill(vpid, SIGKILLDAEMON1) < 0) ? "failed" : "successful",
	     vpid, dbname);
	FlushOutput();
	FlushErrors();
	DBNameCleanupVacuumDaemon(dbname);
}


/*
 *	DBNameCleanupVacuumDaemon
 *
 *	Clean up after a killed vacuum daemon.
 */
void
DBNameCleanupVacuumDaemon(dbname)
	char	*dbname;
{
	char		buffer[MAXPGPATH];

	Assert(PointerIsValid(dbname));

	DBNameFormVacuumDaemonProcessIdFileName(dbname, buffer);
	PathRemoveRecursively(buffer);
}


/*
 *	DBNameGetVacuumDaemonProcessId
 *
 *	Uses the awful mechanism of checking if the file
 * 		PIDFILE_PATH/<dbname>.vacuum
 *	is present to determine the presence of a vacuumd.  The only
 *	information in the file is the process id for the vacuum which 
 *	is extracted and returned.
 */
short
DBNameGetVacuumDaemonProcessId(dbname)
	char	*dbname;
{
	short		pid;
	FILE		*file;
	char		buffer[MAXPGPATH];

	Assert(PointerIsValid(dbname));

	DBNameFormVacuumDaemonProcessIdFileName(dbname, buffer);
	if ((file = fopen(buffer, "r")) != (FILE *) NULL) {
		fscanf(file, "%hd", &pid);
		fclose(file);
		return(pid);
	}
	return(0);
}
