diff --git a/Makefile b/Makefile index 8982382..938ba97 100644 --- a/Makefile +++ b/Makefile @@ -9,8 +9,7 @@ LDFLAGS = -L/usr/lib/mysql -lmysqlclient FINDOBJ = find . -name "*.o" -type f -printf "%P\n" -BUILD := build -PROGRAM := $(BUILD)/archived +PROGRAM := archived include Makefile.local.mk @@ -31,6 +30,8 @@ obj = obj += lib/ini/iniparser.o obj += lib/ini/dictionary.o +obj += src/database/mysql.o + obj += src/rbtree.o obj += src/path.o obj += src/strbuf.o @@ -49,7 +50,6 @@ obj += src/archived.o all : $(PROGRAM) $(PROGRAM) : $(obj) - @mkdir -p $(BUILD) $(QUIET_LD)$(LD) $(LDFLAGS) $^ -o $@ clean : @@ -58,7 +58,7 @@ clean : done cleaner : clean - $(RM) -r $(BUILD) + $(RM) $(PROGRAM) %.o : %.c $(QUIET_CC)$(CC) $(CFLAGS) -c $< -o $@ diff --git a/src/archived.c b/src/archived.c index 73b2d38..78f722f 100644 --- a/src/archived.c +++ b/src/archived.c @@ -17,167 +17,27 @@ #include #include -#include #include #include "notify.h" -#include "xalloc.h" +#include "database.h" #include "util.h" #include "debug.h" -struct config { - char *host; - int port; - char *username; - char *password; - char *database; - char *table; - - unsigned long thread; - MYSQL* connection; - my_bool reconnect; -}; - -static struct config db = { NULL, 3306, NULL, NULL, NULL, NULL, 0, NULL, 0 }; static dictionary *config = NULL; -/* - * Database setup - */ -static int database_setup() { +static int load_config(const char *file) { - int ret; - - /* Sql statements */ - char stmt_create[] = "CREATE TABLE IF NOT EXISTS `%s` (" - "`Path` varchar(512) default NULL, " - "`Base` varchar(512) default NULL, " - "`Type` tinyint(1) default NULL, " - "`Status` tinyint(1) default NULL, " - "`Date` datetime default NULL, " - "KEY `idx_path` (`Path`(333)), " - "KEY `idx_base` (`Base`(333)) " - ") ENGINE=MyISAM DEFAULT CHARSET=utf8 "; - - char stmt_trunc[] = "TRUNCATE TABLE `%s`"; - - /* Build query - Notice: -1 for "%s" in stmt_create and \0 */ - char *stmt = xmalloc(strlen(stmt_create) + strlen(db.table) - 1); - - sprintf(stmt, stmt_create, db.table); - - /* Run mysql query */ - ret = mysql_query(db.connection, stmt); - - /* Make sure query was successfull */ - if (ret != 0) { - free(stmt); - return 6; - } - - /* Build new query */ - stmt = xrealloc(stmt, strlen(stmt_trunc) + strlen(db.table) - 1); - if (sprintf(stmt, stmt_trunc, db.table) < 0) - return 8; - - /* Run mysql query */ - ret = mysql_query(db.connection, stmt); - - /* Make sure query was successfull */ - if (ret != 0) { - free(stmt); - return 6; - } - - return 0; -} - -/* - * Initialize database connection and connect to database - */ -static int init_db() { - - /* Init. database connection */ - db.connection = mysql_init(NULL); - - /* Set mysql options */ - mysql_options(db.connection, MYSQL_OPT_RECONNECT, &db.reconnect); - - /* Connect to database */ - if (!mysql_real_connect(db.connection, db.host, db.username, db.password, db.database, db.port, NULL, 0)) { - fprintf(stderr, "mysql: Could not connect to database (%s)\n", mysql_error(db.connection)); - return -1; - } - - /* Save mysql thread id */ - db.thread = mysql_thread_id(db.connection); - - /* Setup database */ - return database_setup(); -} - -static int load_dbconf(const char *file) { - - int status = 0; - - if (config) - return -1; + iniparser_freedict(config); if (file_exists(file)) { config = iniparser_load(file); - if (NULL == config) { - fprintf(stderr, "Could not load configuration file '%s'\n", file); + if (NULL == config) 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; } @@ -189,11 +49,9 @@ static void clean_exit(int excode) { notify_exit(); - /* Clean mysql */ - mysql_exit(); + database_close(); - if (config) - iniparser_freedict(config); + iniparser_freedict(config); printf("\nprocess exit at: %s", ctime(&t)); exit(excode); @@ -221,91 +79,6 @@ static void sighandl(int sig) { } } -/* - * Process events - */ -static int process(notify_event *event) { - - int ret = 0, dir = 0; - 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 */ - if (NOTIFY_UNKNOWN == event->type) - 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 */ - if (NOTIFY_CREATE == event->type) { - - char stmt_insert[] = "INSERT INTO `%s` (`Path`, `Base`, `Type`, `Status`, `Date`) VALUES('%s','%s','%i','0', NOW())"; - - stmt = xmalloc(strlen(stmt_insert) + strlen(db.table) + strlen(event->path)*2 + strlen(event->filename)*2 - 6); - - /* Escape paths */ - char *escaped_path = xmalloc(strlen(event->path) * 2 + 1); - char *escaped_filename = xmalloc(strlen(event->filename) * 2 + 1); - - 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)); - - /* Create mysql query */ - sprintf(stmt, stmt_insert, db.table, escaped_path, escaped_filename, event->dir == 1); - - ret = mysql_real_query(db.connection, stmt, strlen(stmt)); - - /* Clean up */ - xfree(stmt); - xfree(escaped_path); - xfree(escaped_filename); - - /* Delete row in database */ - } else if (NOTIFY_DELETE == event->type) { - - char stmt_delete[] = "DELETE FROM `%s` WHERE `Path` LIKE '%s%s%%' OR (`Path` = '%s' AND `Base` = '%s')"; - - /* Escape paths */ - char *escaped_path = xmalloc(strlen(event->path) * 2 + 1); - char *escaped_filename = xmalloc(strlen(event->filename) * 2 + 1); - - 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)); - - stmt = xmalloc(strlen(stmt_delete) + strlen(db.table) + strlen(escaped_path)*2 + strlen(escaped_filename)*2 + 1); - - /* Create mysql query */ - sprintf(stmt, stmt_delete, db.table, escaped_path, escaped_filename, escaped_path, escaped_filename); - - ret = mysql_query(db.connection, stmt); - - /* Clean up */ - xfree(stmt); - xfree(escaped_path); - xfree(escaped_filename); - } - -#ifdef __DEBUG__ - /* Make sure query was successfull */ - if (ret != 0) { - 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 - - return 0; -} - /* * The main loop - read events from notify API */ @@ -320,7 +93,13 @@ static void main_loop() { if (event == NULL) continue; - process(event); + dprint("%s: (%c) %s%s\n", notify_event_typetostr(event), + event->dir ? 'D' : 'F', event->path, event->filename); + + if (event->type == NOTIFY_CREATE) + database_insert(event->path, event->filename, event->dir); + else if (event->type == NOTIFY_DELETE) + database_delete(event->path, event->filename); notify_event_del(event); } @@ -346,11 +125,10 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } - /* Load configuration */ - if (load_dbconf(configfile) < 0) + if (load_config(configfile) < 0) return EXIT_FAILURE; - ret = init_db(); + ret = database_init(config); if (ret == -1) return EXIT_FAILURE; diff --git a/src/database.h b/src/database.h new file mode 100644 index 0000000..061dc34 --- /dev/null +++ b/src/database.h @@ -0,0 +1,24 @@ +/* database.h - database driver API + * + * Copyright (C) 2010 Fredric Nilsson + * + * 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. + */ + +#ifndef __DATABASE_H +#define __DATABASE_H + +#include + +int database_init(dictionary *conf); + +int database_insert(const char *path, const char *filename, const int isdir); + +int database_delete(const char *path, const char *filename); + +int database_close(); + +#endif /* __DATABASE_H */ diff --git a/src/database/mysql.c b/src/database/mysql.c new file mode 100644 index 0000000..2169c5e --- /dev/null +++ b/src/database/mysql.c @@ -0,0 +1,220 @@ +/* database/mysql.c - mysql implementation + * + * Copyright (C) 2010 Fredric Nilsson + * + * 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 +#include +#include "../database.h" +#include "../xalloc.h" + +static struct { + char *host; + int port; + char *username; + char *password; + char *database; + char *table; + + unsigned long thread; + MYSQL* connection; + my_bool reconnect; +} db = { NULL, 3306, NULL, NULL, NULL, NULL, 0, NULL, 0 }; + +/* Helper for escaping strings in mysql queries. */ +static char* escape(const char *str) { + + size_t len = strlen(str); + char *esc = xmalloc(len * 2 + 1); + + mysql_real_escape_string(db.connection, esc, str, len); + + return esc; +} + +static int load_dbconf(dictionary *conf) { + + int status = 0; + + db.host = iniparser_getstring(conf, "mysql:host", NULL); + db.port = iniparser_getint(conf, "mysql:port", 3306); + db.username = iniparser_getstring(conf, "mysql:username", NULL); + db.password = iniparser_getstring(conf, "mysql:password", NULL); + db.database = iniparser_getstring(conf, "mysql:database", NULL); + db.table = iniparser_getstring(conf, "mysql:table", NULL); + db.reconnect = iniparser_getboolean(conf, "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; +} + +static int database_setup() { + + int ret; + + /* Sql statements */ + char stmt_create[] = "CREATE TABLE IF NOT EXISTS `%s` (" + "`Path` varchar(512) default NULL, " + "`Base` varchar(512) default NULL, " + "`Type` tinyint(1) default NULL, " + "`Status` tinyint(1) default NULL, " + "`Date` datetime default NULL, " + "KEY `idx_path` (`Path`(333)), " + "KEY `idx_base` (`Base`(333)) " + ") ENGINE=MyISAM DEFAULT CHARSET=utf8 "; + + char stmt_trunc[] = "TRUNCATE TABLE `%s`"; + + /* Build query + Notice: -1 for "%s" in stmt_create and \0 */ + char *stmt = xmalloc(strlen(stmt_create) + strlen(db.table) - 1); + + sprintf(stmt, stmt_create, db.table); + + /* Run mysql query */ + ret = mysql_query(db.connection, stmt); + + /* Make sure query was successfull */ + if (ret != 0) { + free(stmt); + return 6; + } + + /* Build new query */ + stmt = xrealloc(stmt, strlen(stmt_trunc) + strlen(db.table) - 1); + if (sprintf(stmt, stmt_trunc, db.table) < 0) + return 8; + + /* Run mysql query */ + ret = mysql_query(db.connection, stmt); + + /* Make sure query was successfull */ + if (ret != 0) { + free(stmt); + return 6; + } + + return 0; +} + +/* + * Initialize database connection and connect to database + */ +int database_init(dictionary *conf) { + + if (load_dbconf(conf) < 0) + return -1; + + /* Init. database connection */ + db.connection = mysql_init(NULL); + + /* Set mysql options */ + mysql_options(db.connection, MYSQL_OPT_RECONNECT, &db.reconnect); + + /* Connect to database */ + if (!mysql_real_connect(db.connection, db.host, db.username, db.password, db.database, db.port, NULL, 0)) { + fprintf(stderr, "mysql: Could not connect to database (%s)\n", mysql_error(db.connection)); + return -1; + } + + /* Save mysql thread id */ + db.thread = mysql_thread_id(db.connection); + + /* Setup database */ + return database_setup(); +} + +int database_insert(const char *path, const char *filename, const int isdir) { + + int ret; + char stmt_insert[] = "INSERT INTO `%s` (`Path`, `Base`, `Type`, `Status`, `Date`) VALUES('%s','%s','%i','0', NOW())"; + char *stmt, *escaped_path, *escaped_filename; + + if (mysql_ping(db.connection) != 0) { + fprintf(stderr, "mysql: Lost connection to database. Could not reconnect\n"); + return -1; + } + + /* Escape the strings */ + escaped_path = escape(path); + escaped_filename = escape(filename); + + stmt = xmalloc(strlen(stmt_insert) + strlen(db.table) + strlen(escaped_path) + strlen(escaped_filename) - 6); + + /* Create mysql query */ + sprintf(stmt, stmt_insert, db.table, escaped_path, escaped_filename, isdir != 0); + + ret = mysql_query(db.connection, stmt); + + xfree(stmt); + xfree(escaped_path); + xfree(escaped_filename); + + if (ret != 0) { + fprintf(stderr, "mysql: %s\n", mysql_error(db.connection)); + return -1; + } + return 0; +} + +int database_delete(const char *path, const char *filename) { + + int ret; + char stmt_delete[] = "DELETE FROM `%s` WHERE `Path` LIKE '%s%s%%' OR (`Path` = '%s' AND `Base` = '%s')"; + char *stmt; + + /* Escape paths */ + char *escaped_path = escape(path); + char *escaped_filename = escape(filename); + + stmt = xmalloc(strlen(stmt_delete) + strlen(db.table) + strlen(escaped_path)*2 + strlen(escaped_filename)*2 + 1); + + /* Create mysql query */ + sprintf(stmt, stmt_delete, db.table, escaped_path, escaped_filename, escaped_path, escaped_filename); + + ret = mysql_query(db.connection, stmt); + + xfree(stmt); + xfree(escaped_path); + xfree(escaped_filename); + + if (ret != 0) { + fprintf(stderr, "mysql: %s\n", mysql_error(db.connection)); + return -1; + } + return 0; +} + +int database_close() { + + mysql_close(db.connection); + + /* memory leak fix */ + mysql_library_end(); + + return 0; +}