Archived
1
0
Fork 0

throwing away the client and let database functionality always be built.

The debug output used in client/stdout.c should coexist with the database. via __DEBUG__ macro.
This commit is contained in:
Henrik Hautakoski 2010-10-22 16:46:58 +02:00
parent cfb5e85699
commit 2d247fd827
3 changed files with 190 additions and 321 deletions

View file

@ -3,9 +3,9 @@
# #
CC = gcc CC = gcc
CFLAGS = -O2 -Werror CFLAGS = -O2 -Werror `mysql_config --cflags`
LD = $(CC) LD = $(CC)
LDFLAGS = LDFLAGS = -L/usr/lib/mysql -lmysqlclient
FINDOBJ = find . -name "*.o" -type f -printf "%P\n" FINDOBJ = find . -name "*.o" -type f -printf "%P\n"
@ -28,16 +28,6 @@ endif
obj = obj =
ifeq ($(DEBUG), 2)
obj += src/client/stdout.o
else
CFLAGS += `mysql_config --cflags`
LDFLAGS += -L/usr/lib/mysql -lmysqlclient
obj += src/ini/iniparser.o
obj += src/ini/dictionary.o
obj += src/client/mysql.o
endif
obj += src/rbtree.o obj += src/rbtree.o
obj += src/path.o obj += src/path.o
obj += src/strbuf.o obj += src/strbuf.o
@ -49,6 +39,10 @@ obj += src/event.o
obj += src/fscrawl.o obj += src/fscrawl.o
obj += src/queue.o obj += src/queue.o
obj += src/ini/iniparser.o
obj += src/ini/dictionary.o
obj += src/archived.o
.PHONY : all clean cleaner .PHONY : all clean cleaner
all : $(PROGRAM) all : $(PROGRAM)

View file

@ -1,11 +1,14 @@
/* client/mysql.c /* archived.c
* *
* (C) Copyright 2010 Fredric Nilsson <fredric@fiktivkod.org> * Copyright (C) 2010 Fredric Nilsson <fredric@fiktivkod.org>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdio.h> #include <stdio.h>
@ -16,14 +19,13 @@
#include <mysql/mysql.h> #include <mysql/mysql.h>
#include "../notify.h" #include "notify.h"
#include "../event.h" #include "xalloc.h"
#include "../xalloc.h" #include "ini/iniparser.h"
#include "../ini/iniparser.h" #include "util.h"
#include "../util.h" #include "debug.h"
#include "../debug.h"
typedef struct { struct config {
char *host; char *host;
int port; int port;
char *username; char *username;
@ -34,104 +36,11 @@ typedef struct {
unsigned long thread; unsigned long thread;
MYSQL* connection; MYSQL* connection;
my_bool reconnect; my_bool reconnect;
};
} database; static struct config db = { NULL, 3306, NULL, NULL, NULL, NULL, 0, NULL, 0 };
static database db;
static dictionary *config = NULL; static dictionary *config = NULL;
/*
* Converts error codes to string
*/
static const char* client_error(int error) {
switch (error) {
case 1:
return "Missing 'host' in configuration";
case 2:
return "Missing 'username' in configuration";
case 3:
return "Missing 'password' in configuration";
case 4:
return "Missing 'database' in configuration";
case 5:
return "Missing 'table' in configuration";
case 6:
return mysql_error(db.connection);
case 7:
return "Error while creating table";
case 8:
return "Lost connection to database. Could not reconnect";
case 9:
return "Missing configuration";
}
return "Unkown error";
}
/*
* Close database connection
*/
static int client_exit() {
/* Close database connection */
mysql_close(db.connection);
/* Another leak fix */
mysql_library_end();
return 0;
}
/* Only way to exit the application properly
when in main loop is by signal */
static void clean_exit(int excode) {
time_t t = time(NULL);
notify_exit();
/* Clean mysql */
int status = client_exit();
if (0 != status) {
const char *str = client_error(status);
fprintf(stderr,"%s", str);
}
/* Clean config */
iniparser_freedict(config);
printf("\nprocess exit at: %s", ctime(&t));
exit(excode);
}
/* Signal handler */
static void sighandl(int sig) {
switch(sig) {
/* normal exit signals */
case SIGTERM :
case SIGKILL :
case SIGQUIT :
case SIGINT :
clean_exit(EXIT_SUCCESS);
/* segmentation violation, let user now */
case SIGSEGV :
fprintf(stderr, "SEGFAULT: o no he didn't\n");
clean_exit(EXIT_FAILURE);
case SIGUSR1 :
case SIGUSR2 :
printf("notify stat:\n");
notify_stat();
/* don't know why, but everything goes bananas if we keep executing */
clean_exit(EXIT_SUCCESS);
}
}
/* /*
* Database setup * Database setup
*/ */
@ -154,9 +63,9 @@ static int database_setup() {
/* Build query /* Build query
Notice: -1 for "%s" in stmt_create and \0 */ Notice: -1 for "%s" in stmt_create and \0 */
char *stmt = (char *) xmalloc(strlen(stmt_create) + strlen(db.table) - 1); char *stmt = xmalloc(strlen(stmt_create) + strlen(db.table) - 1);
if (stmt == NULL || sprintf(stmt, stmt_create, db.table) < 0)
return 7; sprintf(stmt, stmt_create, db.table);
/* Run mysql query */ /* Run mysql query */
ret = mysql_query(db.connection, stmt); ret = mysql_query(db.connection, stmt);
@ -168,7 +77,7 @@ static int database_setup() {
} }
/* Build new query */ /* Build new query */
stmt = (char *) xrealloc(stmt, strlen(stmt_trunc) + strlen(db.table) - 1); stmt = xrealloc(stmt, strlen(stmt_trunc) + strlen(db.table) - 1);
if (sprintf(stmt, stmt_trunc, db.table) < 0) if (sprintf(stmt, stmt_trunc, db.table) < 0)
return 8; return 8;
@ -181,46 +90,13 @@ static int database_setup() {
return 6; return 6;
} }
return 0; return 0;
} }
/* /*
* Initialize database connection and connect to database * Initialize database connection and connect to database
*/ */
static int client_init() { static int init_db() {
/* Load database information from ini config */
db.host = iniparser_getstring(config, "mysql:host", NULL);
db.port = iniparser_getint(config, "mysql:port", 3306);
db.username = iniparser_getstring(config, "mysql:username", NULL);
db.password = iniparser_getstring(config, "mysql:password", NULL);
db.database = iniparser_getstring(config, "mysql:database", NULL);
db.table = iniparser_getstring(config, "mysql:table", NULL);
/* Return exit code for missconfiguration */
if (NULL == db.host)
return 1;
if (NULL == db.username)
return 2;
if (NULL == db.password)
return 3;
if (NULL == db.database)
return 4;
if (NULL == db.table)
return 5;
/* Enable reconnection */
if (1 == iniparser_getboolean(config, "mysql:reconnect", 1)) {
db.reconnect = 1;
} else {
db.reconnect = 0;
}
/* Init. database connection */ /* Init. database connection */
db.connection = mysql_init(NULL); db.connection = mysql_init(NULL);
@ -229,44 +105,148 @@ static int client_init() {
mysql_options(db.connection, MYSQL_OPT_RECONNECT, &db.reconnect); mysql_options(db.connection, MYSQL_OPT_RECONNECT, &db.reconnect);
/* Connect to database */ /* Connect to database */
if (!mysql_real_connect(db.connection, db.host, db.username, db.password, db.database, db.port, NULL, 0)) if (!mysql_real_connect(db.connection, db.host, db.username, db.password, db.database, db.port, NULL, 0)) {
return 6; fprintf(stderr, "mysql: Could not connect to database (%s)\n", mysql_error(db.connection));
return -1;
}
/* Save mysql thread id */ /* Save mysql thread id */
db.thread = mysql_thread_id(db.connection); db.thread = mysql_thread_id(db.connection);
#ifdef DB_DEBUG
fprintf(stderr, "output_init(): %li\n", db.thread);
#endif
/* Setup database */ /* Setup database */
return database_setup(); return database_setup();
} }
static int load_dbconf(const char *file) {
int status = 0;
if (config)
return -1;
if (file_exists(file)) {
config = iniparser_load(file);
if (NULL == config) {
fprintf(stderr, "Could not load configuration file '%s'\n", file);
return -1;
}
} else {
fprintf(stderr, "Configuration file '%s' don't exist\n", file);
return -1;
}
db.host = iniparser_getstring(config, "mysql:host", NULL);
db.port = iniparser_getint(config, "mysql:port", 3306);
db.username = iniparser_getstring(config, "mysql:username", NULL);
db.password = iniparser_getstring(config, "mysql:password", NULL);
db.database = iniparser_getstring(config, "mysql:database", NULL);
db.table = iniparser_getstring(config, "mysql:table", NULL);
db.reconnect = iniparser_getboolean(config, "mysql:reconnect", 1);
if (NULL == db.host) {
fprintf(stderr, "Missing 'host' in configuration\n");
status = -1;
}
if (NULL == db.username) {
fprintf(stderr, "Missing 'username' in configuration\n");
status = -1;
}
if (NULL == db.password) {
fprintf(stderr, "Missing 'password' in configuration\n");
status = -1;
}
if (NULL == db.database) {
fprintf(stderr, "Missing 'database' in configuration\n");
status = -1;
}
if (NULL == db.table) {
fprintf(stderr, "Missing 'table' in configuration\n");
status = -1;
}
return status;
}
/*
* Close database connection
*/
static int mysql_exit() {
/* Close database connection */
mysql_close(db.connection);
/* memory leak fix */
mysql_library_end();
return 0;
}
/* Only way to exit the application properly
when in main loop is by signal */
static void clean_exit(int excode) {
time_t t = time(NULL);
notify_exit();
/* Clean mysql */
mysql_exit();
if (config)
iniparser_freedict(config);
printf("\nprocess exit at: %s", ctime(&t));
exit(excode);
}
/* Signal handler */
static void sighandl(int sig) {
switch(sig) {
/* normal exit signals */
case SIGTERM :
case SIGKILL :
case SIGINT :
clean_exit(EXIT_SUCCESS);
/* segmentation violation, let user now */
case SIGSEGV :
fprintf(stderr, "SEGFAULT: o no he didn't\n");
clean_exit(EXIT_FAILURE);
case SIGUSR1 :
case SIGUSR2 :
printf("notify stat:\n");
notify_stat();
/* don't know why, but everything goes bananas if we keep executing */
clean_exit(EXIT_SUCCESS);
}
}
/* /*
* Process events * Process events
*/ */
static int client_process(notify_event *event) { static int process(notify_event *event) {
int ret = 0, dir = 0; int ret = 0, dir = 0;
char *stmt; char *stmt;
dprint("%s: (%c) %s%s\n", notify_event_typetostr(event),
event->dir ? 'D' : 'F', event->path, event->filename);
/* Skip if event is unknown */ /* Skip if event is unknown */
if (NOTIFY_UNKNOWN == event->type) if (NOTIFY_UNKNOWN == event->type)
return 0; return 0;
if (mysql_ping(db.connection) != 0) {
fprintf(stderr, "mysql: Lost connection to database. Could not reconnect\n");
return -1;
}
/* Insert new row in database */ /* Insert new row in database */
if (NOTIFY_CREATE == event->type) { if (NOTIFY_CREATE == event->type) {
char stmt_insert[] = "INSERT INTO `%s` (`Path`, `Base`, `Type`, `Status`, `Date`) VALUES('%s','%s','%i','0', NOW())"; char stmt_insert[] = "INSERT INTO `%s` (`Path`, `Base`, `Type`, `Status`, `Date`) VALUES('%s','%s','%i','0', NOW())";
if(mysql_ping(db.connection) != 0) { stmt = xmalloc(strlen(stmt_insert) + strlen(db.table) + strlen(event->path)*2 + strlen(event->filename)*2 - 6);
return 8;
}
stmt = (char *)xmalloc(sizeof(char) * (strlen(stmt_insert) + strlen(db.table) + strlen(event->path)*2 + strlen(event->filename)*2 - 6));
/* Escape paths */ /* Escape paths */
char *escaped_path = xmalloc(strlen(event->path) * 2 + 1); char *escaped_path = xmalloc(strlen(event->path) * 2 + 1);
@ -275,15 +255,9 @@ static int client_process(notify_event *event) {
mysql_real_escape_string(db.connection, escaped_path, event->path, strlen(event->path)); mysql_real_escape_string(db.connection, escaped_path, event->path, strlen(event->path));
mysql_real_escape_string(db.connection, escaped_filename, event->filename, strlen(event->filename)); mysql_real_escape_string(db.connection, escaped_filename, event->filename, strlen(event->filename));
/* dir :D */
if (event->dir == 1) {
dir = 1;
}
/* Create mysql query */ /* Create mysql query */
sprintf(stmt, stmt_insert, db.table, escaped_path, escaped_filename, dir); sprintf(stmt, stmt_insert, db.table, escaped_path, escaped_filename, event->dir == 1);
/* Run mysql query */
ret = mysql_real_query(db.connection, stmt, strlen(stmt)); ret = mysql_real_query(db.connection, stmt, strlen(stmt));
/* Clean up */ /* Clean up */
@ -296,10 +270,6 @@ static int client_process(notify_event *event) {
char stmt_delete[] = "DELETE FROM `%s` WHERE `Path` LIKE '%s%s%%' OR (`Path` = '%s' AND `Base` = '%s')"; char stmt_delete[] = "DELETE FROM `%s` WHERE `Path` LIKE '%s%s%%' OR (`Path` = '%s' AND `Base` = '%s')";
if(mysql_ping(db.connection) != 0) {
return 8;
}
/* Escape paths */ /* Escape paths */
char *escaped_path = xmalloc(strlen(event->path) * 2 + 1); char *escaped_path = xmalloc(strlen(event->path) * 2 + 1);
char *escaped_filename = xmalloc(strlen(event->filename) * 2 + 1); char *escaped_filename = xmalloc(strlen(event->filename) * 2 + 1);
@ -312,39 +282,35 @@ static int client_process(notify_event *event) {
/* Create mysql query */ /* Create mysql query */
sprintf(stmt, stmt_delete, db.table, escaped_path, escaped_filename, escaped_path, escaped_filename); sprintf(stmt, stmt_delete, db.table, escaped_path, escaped_filename, escaped_path, escaped_filename);
/* Run mysql query */
ret = mysql_query(db.connection, stmt); ret = mysql_query(db.connection, stmt);
/* Clean up */ /* Clean up */
xfree(stmt); xfree(stmt);
xfree(escaped_path); xfree(escaped_path);
xfree(escaped_filename); xfree(escaped_filename);
}
/* Make sure query was successfull */
if(ret != 0) {
return 6;
} }
#ifdef __DEBUG__ #ifdef __DEBUG__
/* Make sure query was successfull */
if(db.thread != mysql_thread_id(db.connection)) { if (ret != 0) {
fprintf(stderr, "Connection was lost. Reconnected. Old_Thread: %li, New_Thread: %li\n", db.thread, mysql_thread_id(db.connection)); fprintf(stderr, "mysql: can't execute query\n");
return -1;
} }
if (db.thread != mysql_thread_id(db.connection)) {
fprintf(stderr, "mysql: Connection was lost. Reconnected."
"Old_Thread: %li, New_Thread: %li\n", db.thread, mysql_thread_id(db.connection));
}
#endif #endif
return 0; return 0;
} }
/* /*
* The main loop - read events from notify API * The main loop - read events from notify API
*/ */
static void main_loop() { static void main_loop() {
int status;
notify_event *event; notify_event *event;
for(;;) { for(;;) {
@ -354,9 +320,7 @@ static void main_loop() {
if (event == NULL) if (event == NULL)
continue; continue;
status = client_process(event); process(event);
if (status)
fprintf(stderr,"%s", client_error(status));
notify_event_del(event); notify_event_del(event);
} }
@ -366,23 +330,38 @@ int main(int argc, char **argv) {
/* Return value */ /* Return value */
int ret; int ret;
char *configfile = "config.ini", *rootdir;
/* Validate arguments */ /* Validate arguments */
if (argc != 2) { if (argc > 3 && !strcmp(argv[1], "-c")) {
configfile = argv[2];
printf("Usage: %s <Root Directory>\n" rootdir = argv[3];
"Root Directory - Path to indexroot. All subdirectories will be indexed.\n", argv[0]); } else if (argc > 1 && strcmp(argv[1], "-c")) {
rootdir = argv[1];
} else {
fprintf(stderr, "Usage: archived [-c <config>] <Root Directory>\n"
"config - path to the configuration file\n"
"Root Directory - Path to indexroot. All subdirectories will be indexed.\n");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
/* Load configuration */ /* Load configuration */
if (file_exists("config.ini")) { if (load_dbconf(configfile) < 0)
config = iniparser_load("config.ini"); return EXIT_FAILURE;
if (NULL == config) {
fprintf(stderr, "Could not load configuration"); ret = init_db();
if (ret == -1)
return EXIT_FAILURE;
ret = notify_init();
if (ret == -1)
return EXIT_FAILURE;
ret = notify_add_watch(rootdir);
if (ret == -1) {
fprintf(stderr, "Invalid path: %s\n", rootdir);
return EXIT_FAILURE; return EXIT_FAILURE;
}
} }
/* Setup signal handlers */ /* Setup signal handlers */
@ -393,23 +372,7 @@ int main(int argc, char **argv) {
signal(SIGUSR1, sighandl); signal(SIGUSR1, sighandl);
signal(SIGUSR2, sighandl); signal(SIGUSR2, sighandl);
ret = client_init();
if (ret) {
fprintf(stderr, "%s", client_error(ret));
return EXIT_FAILURE;
}
ret = notify_init();
if (ret == -1)
return EXIT_FAILURE;
ret = notify_add_watch(argv[1]);
if (ret == -1) {
fprintf(stderr, "Invalid path: %s\n", argv[1]);
return EXIT_FAILURE;
}
main_loop(); main_loop();
return (EXIT_SUCCESS); return EXIT_SUCCESS;
} }

View file

@ -1,88 +0,0 @@
/*
* Debugging client
*
* Copyright (C) 2010 Henrik Hautakoski <henrik@fiktivkod.org>
*
* 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 3 of the License, or
* (at your option) any later version.
*/
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "../notify.h"
static void p_exit_time() {
time_t t = time(NULL);
printf("\nprocess exit at: %s", ctime(&t));
}
static void sighandler(int sig) {
p_exit_time();
if (sig == SIGSEGV) {
fprintf(stderr, "Segmentation fault\n");
abort();
}
notify_exit();
exit(EXIT_SUCCESS);
}
static void pevent(notify_event *ev) {
const char *strtype = notify_event_typetostr(ev);
char slash = ev->dir ? '/' : '\0';
printf("%s : %s%s%c\n", strtype, ev->path, ev->filename, slash);
}
static void mainloop() {
notify_event *event;
for(;;) {
event = notify_read();
if (event == NULL)
continue;
pevent(event);
notify_event_del(event);
}
}
int main(int argc, char **argv) {
int rc;
if (argc < 2) {
fprintf(stderr, "usage: %s <dir>\n", argv[0]);
return EXIT_FAILURE;
}
signal(SIGINT, sighandler);
signal(SIGTERM, sighandler);
signal(SIGQUIT, sighandler);
signal(SIGSEGV, sighandler);
rc = notify_init();
if (rc < 0)
return EXIT_FAILURE;
rc = notify_add_watch(argv[1]);
if (rc < 0) {
fprintf(stderr, "Invalid path: %s\n", argv[1]);
return EXIT_FAILURE;
}
mainloop();
return EXIT_SUCCESS;
}