/* PureAdmin
* Copyright (C) 2003 Isak Savo
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* Wrapper functions for FAM (File Alteration Monitor). Used to monitor changes in files and directories.
*
* Copyright (C) 2003-2004 Isak Savo
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <gtk/gtk.h>
#include <errno.h>
#include "globals.h"
#include "famwrap.h"
#ifdef HAVE_LIBFAM
#include <fam.h>
#include "globals.h"
#include "helper.h"
FAMConnection *famconn = NULL;
FAMRequest *req = NULL;
gint input_id = 0;
GIOChannel *iochannel = NULL;
void (*event_cb_func)(void) = NULL;
char *fam_event_names[] =
{
"",
"FAMChanged", "FAMDeleted", "FAMStartExecuting",
"FAMStopExecuting", "FAMCreated", "FAMMoved",
"FAMAcknowledge", "FAMExists", "FAMEndExist"
};
static gboolean fam_event_handler (GIOChannel *src, GIOCondition cond, gpointer data);
/* Only for internal use, connects to local FAM-service */
static
gboolean connect_to_fam ()
{
#ifdef HAVE_LIBFAM
famconn = g_new0 (FAMConnection, 1);
pur_log_dbg ("Opening FAM connection...");
if (FAMOpen (famconn) != 0)
{
g_free (famconn);
famconn = NULL;
pur_log_wrn ("Unable to connect to FAM!");
return FALSE;
}
return TRUE;
#else /* HAVE_LIBFAM */
pur_log_dbg ("Can't connect to FAM: not supported!");
return FALSE;
#endif /* HAVE_LIBFAM */
}
/*** Public Functions ***/
/* fam_add_watch: Adds a watch to a file and calls a function when a change is noticed.
*
* Args:
* fname - The name of the file that should be watched.
* func - A pointer to the function that should be called. Function should be of type "void function (void)"
* Returns:
* TRUE if watch was added, else FALSE.
*/
gboolean fam_set_watch (const gchar *fname, void (*func))
{
pur_log_dbg ("Adding watch: %s", fname);
if (!fname || g_file_test (fname, G_FILE_TEST_EXISTS) == FALSE)
return FALSE;
/* Connect to FAM if not done before */
if (famconn == NULL)
{
if (!connect_to_fam ())
return FALSE;
iochannel = g_io_channel_unix_new (FAMCONNECTION_GETFD(famconn));
if (!iochannel)
{
pur_log_err ("Unable to create iochannel");
return FALSE;
}
input_id = g_io_add_watch (iochannel, G_IO_IN | G_IO_HUP,
(GIOFunc) fam_event_handler, NULL);
pur_log_dbg ("GIOChannel Input watch added, id=%d, fd=%d", input_id,
FAMCONNECTION_GETFD(famconn));
g_io_channel_unref (iochannel); /* Remove our reference (add_watch() has one already) */
}
/* First time allocation */
if (!req)
req = g_new0 (FAMRequest, 1);
if (FAMMonitorFile (famconn, fname, req, NULL) == -1)
{
g_free (req);
req = NULL;
pur_log_err ("FAMMonitorFile: %s", g_strerror (errno));
return FALSE;
}
event_cb_func = func;
return TRUE;
}
/* fam_suspend_watch: Suspends (temporary disables) a watch
*
* Returns:
* TRUE if suspension was successful, otherwise FALSE.
*/
gboolean fam_suspend_watch (void)
{
int res;
if (!famconn || !req)
return FALSE;
res = FAMSuspendMonitor(famconn, req);
if (res != 0)
return FALSE; /* Error while suspending */
return TRUE;
}
/* fam_resume_watch: Resumes a previously suspended watch
*
* Returns:
* TRUE if the resume was successful, otherwise FALSE.
*/
gboolean fam_resume_watch (void)
{
int res;
if (!famconn || !req)
return FALSE;
res = FAMResumeMonitor(famconn, req);
if (res != 0)
return FALSE; /* Error while resuming */
return TRUE;
}
/* fam_delete_watch: Cancels a watch. No more notifixations will be recieved for that file!
*
* Returns:
* TRUE if the deletion was successful, otherwise FALSE.
*/
gboolean fam_delete_watch (void)
{
int res;
if (!famconn || !req)
return FALSE;
/* g_print ("Removing watch: %s\n", fname); */
res = FAMCancelMonitor (famconn, req);
if (res != 0)
return FALSE; /* Error while canceling */
g_free (req);
req = NULL;
return TRUE;
}
/* fam_terminate: Removes all watches and terminates connection to local FAM service.
*
* Returns:
* TRUE if all went well, otherwise FALSE.
*/
gboolean fam_terminate (void)
{
gboolean ret = TRUE;
if (!famconn)
return TRUE; /* We consider termination a success if a connection was never established... */
g_source_remove (input_id);
input_id = 0;
FAMClose (famconn);
g_free (famconn);
famconn = NULL;
return ret;
}
/* fam_event_handler: Internal function, handles events and calls the
* appropiate function depending on the filename */
static gboolean fam_event_handler (GIOChannel *src, GIOCondition cond, gpointer data)
{
FAMEvent ev;
while (FAMPending(famconn))
{
if (FAMNextEvent(famconn, &ev) != 1)
{
/* Nuts! An error! Shut down & clean up. */
pur_log_err ("Error while receiving FAM-event! This shouldn't happen");
fam_terminate ();
return FALSE;
}
switch (ev.code)
{
case FAMExists:
case FAMChanged:
/* Only call functions when file has changed or first time
watch is enabled */
pur_log_dbg ("File %s changed, calling handler", ev.filename);
if (event_cb_func)
event_cb_func();
break;
case FAMDeleted:
fam_delete_watch ();
pur_log_dbg ("Removing watch [%s] (file deleted)\n", ev.filename);
break;
default:
break;
}
}
return TRUE;
}
#else /* HAVE_LIBFAM */
gboolean fam_add_watch (const gchar *fname, void (*func))
{
return FALSE;
}
gboolean fam_suspend_watch (void)
{
return FALSE;
}
gboolean fam_resume_watch (void)
{
return FALSE;
}
gboolean fam_delete_watch (void)
{
return TRUE;
}
gboolean fam_terminate (void)
{
return TRUE;
}
#endif /* HAVE_LIBFAM */
syntax highlighted by Code2HTML, v. 0.9.1