From 2c40f06f0df60a4a9c5f45225c1f7ebf23d60f95 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Thu, 8 Apr 2004 06:38:46 +0000 Subject: [PATCH] Daemon logging to a database. --- ODBC-dblog.diff | 784 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 784 insertions(+) create mode 100644 ODBC-dblog.diff diff --git a/ODBC-dblog.diff b/ODBC-dblog.diff new file mode 100644 index 0000000..ea3ee43 --- /dev/null +++ b/ODBC-dblog.diff @@ -0,0 +1,784 @@ +Add support for logging daemon messages to an SQL database. + +After applying this patch you'll need to run autoconf and autoheader to +generate updated versions of "configure" and "config.h.in". + +You'll need to run configure with the --with-ODBC option in order for the +extended features to be active. + +Patch provided by Steve Sether. + +(Tweaked by Wayne Davison for rsync-style purposes but not compiled, so if the +dblog.c file has a compile problem, it's probably my fault...) + + +--- README-ODBC 2004-02-13 17:08:33.000000000 -0800 ++++ README-ODBC 2004-04-07 22:42:28.000000000 -0700 +@@ -0,0 +1,80 @@ ++This patch adds the following options: ++ ++"database logging" ++If set to True, rsync will attempt to connect to ++the specified datasource and write to the named tables. ++Defaults to False. ++ ++ ++"database datasource" ++Specifies the name of the ODBC data source to use. ++ ++"database username" ++The username to use when connecting to the database. ++ ++"database password" ++The password to use when connecting to the database. ++ ++"transfer table name" ++The name of the transfer table to log to. ++This table contains individual filenames, file sizes, bytes transferred, checksum bytes transferred, operation (send or receive), and a timestamp. ++ ++"session table name" ++The name of the session table to log to. ++This table contains the username, module name, module path, ip address, process ID, and a timestamp. ++ ++"exit table name" ++The name of the exit table to log to. ++This table contains the total bytes read, total bytes written, total size ++of all files, error code, line the error occured at, file the error occured at ++and the text of the error. (most of which will be blank if the program exited normally). ++ ++ ++"unique id method" ++Different databases use different methods to get a unique identifier. ++Some databases support sequence objects, and use various forms of the ++nextval command to retrieve a unique identifier from it. Other databases ++support an autonumber field, and support different methds of retrieving ++the ID used in the last insert. Valid values for this option are: ++ ++ nextval-postgres ++ uses the syntax of nextval for PostgreSQL databases ++ ++ nextval-oracle ++ uses the syntax of nextval for Oracle databases ++ ++ nextval-db2 ++ uses the syntax of nextval for DB2 databases ++ ++ last_insert_id ++ uses the last_insert_id() command for the MySQL databases ++ ++ @@IDENTITY ++ uses the @@IDENTITY command for Sybase databases ++ ++ custom ++ Define your own method to get a unique identifier. See the ++ "custom unique id select", and the "get custom id before select" ++ parameters. ++ ++ ++"sequence name" ++If your database supports sequences, list the name of the sequence to use ++for the session unique identifier. ++ ++"custom unique id select" ++Only used if you specify the custom method in "unique id method". This ++is a SQL statement to be executed to get a unique ID. This SQL ++statement must return one column with the unique ID to use for ++the session ID. Should be used in concert with the "get custom ++id before select" parameter. ++ ++"get custom id before insert" ++This parameter is ignored unless the "unique id method" is set to custom. ++If set to true, the "custom unique id select" statement will ++be executed BEFORE the session row is inserted into the database. ++(as is done when a sequence is used for unique IDs). ++If False the statement will be executed after the session ++row is inserted (as is done when the session ID is automatically generates ++unique IDs). ++Defaults to True. +--- Makefile.in 10 Feb 2004 17:06:11 -0000 1.98 ++++ Makefile.in 8 Apr 2004 05:56:31 -0000 +@@ -32,7 +32,7 @@ + zlib/inflate.o zlib/inftrees.o zlib/infutil.o zlib/trees.o \ + zlib/zutil.o zlib/adler32.o + OBJS1=rsync.o generator.o receiver.o cleanup.o sender.o exclude.o util.o \ +- main.o checksum.o match.o syscall.o log.o backup.o ++ main.o checksum.o match.o syscall.o log.o backup.o @EXTRA_OBJECT@ + OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o \ + fileio.o batch.o clientname.o + OBJS3=progress.o pipe.o +--- cleanup.c 27 Jan 2004 08:14:33 -0000 1.21 ++++ cleanup.c 8 Apr 2004 05:56:31 -0000 +@@ -138,7 +138,12 @@ + code = RERR_VANISHED; + } + +- if (code) log_exit(code, file, line); ++ if (code) { ++ log_exit(code, file, line); ++#ifdef HAVE_LIBODBC ++ db_log_exit(code,file,line); ++#endif ++ } + + if (verbose > 2) + rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): about to call exit(%d)\n", +--- clientserver.c 27 Mar 2004 09:44:01 -0000 1.118 ++++ clientserver.c 8 Apr 2004 05:56:31 -0000 +@@ -316,6 +316,9 @@ + exclude_path_prefix = NULL; + + log_init(); ++#ifdef HAVE_LIBODBC ++ db_log_open(); ++#endif + + if (use_chroot) { + /* +@@ -434,6 +437,9 @@ + rprintf(FINFO,"rsync %s %s from %s@%s (%s)\n", + am_sender?"on":"to", + request, auth_user, host, addr); ++#ifdef HAVE_LIBODBC ++ db_log_session(); ++#endif + } else { + rprintf(FINFO,"rsync %s %s from %s (%s)\n", + am_sender?"on":"to", +--- configure.in 24 Mar 2004 21:59:07 -0000 1.188 ++++ configure.in 8 Apr 2004 05:56:31 -0000 +@@ -94,6 +94,8 @@ + [ --with-rsync-path=PATH set default --rsync-path to PATH (default: rsync)], + [ RSYNC_PATH="$with_rsync_path" ], + [ RSYNC_PATH="rsync" ]) ++AC_ARG_WITH(ODBC, ++ [ --with-ODBC compile in support for ODBC database logging]) + + AC_DEFINE_UNQUOTED(RSYNC_PATH, "$RSYNC_PATH", [location of rsync on remote machine]) + +@@ -459,6 +461,14 @@ + if test x"$with_included_popt" != x"yes" + then + AC_CHECK_LIB(popt, poptGetContext, , [with_included_popt=yes]) ++fi ++ ++if test x"$with_ODBC" = x"yes" ++then ++ AC_CHECK_HEADERS(sql.h sqlext.h sqltypes.h) ++ AC_CHECK_LIB(odbc,SQLExecDirect) ++ EXTRA_OBJECT="$EXTRA_OBJECT dblog.o" ++ AC_SUBST(EXTRA_OBJECT) + fi + + AC_MSG_CHECKING([whether to use included libpopt]) +--- dblog.c 2004-02-13 17:08:33.000000000 -0800 ++++ dblog.c 2004-04-07 23:18:56.000000000 -0700 +@@ -0,0 +1,352 @@ ++/* ++ * ODBC Database logging functions ++ * ++ * Written by Steve Sether, April 2004 ++ * steve@vellmont.com ++ */ ++ ++#include "rsync.h" ++ ++#ifdef HAVE_SQL_H ++#include ++#else ++#ifdef HAVE_ODBC_SQL_H ++#include ++#endif ++#endif ++ ++#ifdef HAVE_SQLEXT_H ++#include ++#else ++#ifdef HAVE_ODBC_SQLEXT_H ++#include ++#endif ++#endif ++ ++#ifdef HAVE_SQLTYPES_H ++#include ++#else ++#ifdef HAVE_ODBC_SQLTYPES_H ++#include ++#endif ++#endif ++ ++SQLHENV db_environ_handle; /* Handle ODBC environment */ ++long result; /* result of functions */ ++SQLHDBC db_handle= NULL; /* database connection handle */ ++SQLHSTMT sql_statement_handle; /* SQL statement handle */ ++extern int am_sender; ++extern char *auth_user; ++extern int module_id; ++ ++char sql_status[10]; /* Status SQL */ ++SQLINTEGER V_OD_err, V_OD_rowanz, V_OD_id; ++SQLSMALLINT V_OD_mlen, V_OD_colanz; ++char V_OD_msg[200], V_OD_buffer[200]; ++SQLINTEGER session_id; ++ ++ ++/* This function simply removes invalid characters from the SQL statement ++ * to prevent SQL injection attacks. */ ++char *sanitizeSql(const char *input) ++{ ++ char *out, *ptr; ++ const char *c; ++ ++ if (strlen(input) > ((~(unsigned int)0)>>1)-3) ++ return 0; ++ if (!(out = ptr = new_array(char, strlen(input) * 2 + 1))) ++ return 0; ++ ++ for (c = input; *c; c++) { ++ switch (*c) { ++ case '\'': ++ *ptr++ = '\''; ++ *ptr++ = '\''; ++ break; ++ case '\b': ++ *ptr++ = '\\'; ++ *ptr++ = 'b'; ++ break; ++ case '\n': ++ *ptr++ = '\\'; ++ *ptr++ = 'n'; ++ break; ++ case '\r': ++ *ptr++ = '\\'; ++ *ptr++ = 'r'; ++ break; ++ case '\t': ++ *ptr++ = '\\'; ++ *ptr++ = 't'; ++ break; ++ default: ++ *ptr++ = *c; ++ break; ++ } ++ } ++ *ptr = '\0'; ++ return out; ++} ++ ++void db_log_open(void) ++{ ++ if (lp_database_logging(module_id)) { ++ if (db_handle == NULL) { ++ /* get ODBC environment handle */ ++ result = SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&db_environ_handle); ++ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) { ++ rprintf(FERROR, "Error: couldn't get database environment handle\n"); ++ return; ++ } ++ ++ /* Setting database enviroment */ ++ result = SQLSetEnvAttr(db_environ_handle, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); ++ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) { ++ rprintf(FERROR, "Error: couldn't set database environment.\n"); ++ SQLFreeHandle(SQL_HANDLE_ENV, db_environ_handle); ++ db_environ_handle = NULL; ++ return; ++ } ++ ++ /* Get a database handle */ ++ result = SQLAllocHandle(SQL_HANDLE_DBC, db_environ_handle, &db_handle); ++ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) { ++ rprintf(FERROR, "Error: couldn't allocate database handle\n"); ++ SQLFreeHandle(SQL_HANDLE_ENV, db_environ_handle); ++ db_environ_handle = NULL; ++ return; ++ } ++ ++ /* Set connection attributes */ ++ SQLSetConnectAttr(db_handle, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)5, 0); ++ ++ /* Connect to the database. */ ++ result = SQLConnect(db_handle, (SQLCHAR*) lp_database_datasource(module_id), SQL_NTS, ++ (SQLCHAR*) lp_database_username(module_id), SQL_NTS, ++ (SQLCHAR*) lp_database_password(module_id), SQL_NTS); ++ ++ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) { ++ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, ++ sql_status, &V_OD_err,V_OD_msg,100,&V_OD_mlen); ++ rprintf(FERROR,"Error Connecting to Database %s\n",V_OD_msg); ++ SQLFreeHandle(SQL_HANDLE_DBC,db_handle); ++ db_handle = NULL; ++ SQLFreeHandle(SQL_HANDLE_ENV, db_environ_handle); ++ db_environ_handle = NULL; ++ return; ++ } ++ rprintf(FLOG,"Connected to database!\n"); ++ ++ /* get SQL statement handle */ ++ result = SQLAllocHandle(SQL_HANDLE_STMT, db_handle, &sql_statement_handle); ++ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) { ++ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen); ++ rprintf(FERROR,"Error in allocating SQL statement handle %s\n",V_OD_msg); ++ SQLDisconnect(db_handle); ++ SQLFreeHandle(SQL_HANDLE_DBC,db_handle); ++ db_handle = NULL; ++ SQLFreeHandle(SQL_HANDLE_ENV, db_environ_handle); ++ db_environ_handle = NULL; ++ return; ++ } ++ } else { ++ rprintf(FERROR,"Already connected to database\n"); ++ } ++ } ++} ++ ++void db_log_close() ++{ ++ if (lp_database_logging(module_id)) { ++ if (sql_statement_handle != NULL) { ++ /* free the statement handle first */ ++ SQLFreeHandle(SQL_HANDLE_STMT,sql_statement_handle); ++ sql_statement_handle = NULL; ++ } else { ++ rprintf(FERROR,"No sql statement handle to close\n"); ++ } ++ if (db_handle != NULL) { ++ /* disconnect, and free the database handle. */ ++ SQLDisconnect(db_handle); ++ SQLFreeHandle(SQL_HANDLE_DBC,db_handle); ++ db_handle = NULL; ++ } else { ++ rprintf(FERROR,"Database already closed"); ++ } ++ if (db_environ_handle != NULL) { ++ /* free the environment handle */ ++ SQLFreeHandle(SQL_HANDLE_ENV, db_environ_handle); ++ db_environ_handle = NULL; ++ } else { ++ rprintf(FERROR,"No environment handle to close"); ++ } ++ } ++} ++ ++static long get_unique_session_id() ++{ ++ long unique; ++ char strSqlStatement[1024]; ++ ++ if (db_handle != NULL) { ++ /* choose the appropriate select statement based upon which DBMS we're using. ++ * different datbases use different methods to get a unique ID. Some use a counter ++ * object (sequence), others use an auto increment datatype and have a method ++ * to get the last ID inserted using this connection. */ ++ if (strcmp(lp_unique_id_method(module_id),"nextval-postgresql") == 0) { ++ snprintf(strSqlStatement,sizeof(strSqlStatement),"SELECT NEXTVAL('%s');",lp_sequence_name(module_id)); ++ } else if (strcmp(lp_unique_id_method(module_id),"nextval-oracle") == 0) { ++ snprintf(strSqlStatement,sizeof(strSqlStatement),"SELECT %s.NEXTVAL FROM dual;",lp_sequence_name(module_id)); ++ } else if (strcmp(lp_unique_id_method(module_id),"nextval-db2") == 0) { ++ snprintf(strSqlStatement,sizeof(strSqlStatement),"VALUES NEXTVAL FOR %s;",lp_sequence_name(module_id)); ++ } else if (strcmp(lp_unique_id_method(module_id),"last_insert_id") == 0) { /* MySql */ ++ snprintf(strSqlStatement,sizeof(strSqlStatement),"SELECT LAST_INSERT_ID()"); ++ } else if (strcmp(lp_unique_id_method(module_id),"@@IDENTITY") == 0) { /* Sybase */ ++ snprintf(strSqlStatement,sizeof(strSqlStatement),"SELECT @@IDENTITY"); ++ } else if (strcmp(lp_unique_id_method(module_id),"custom") == 0){ /* Users custom statement */ ++ snprintf(strSqlStatement,sizeof(strSqlStatement),lp_custom_unique_id_select(module_id)); ++ } ++ ++ /* bind the 1st column to unique */ ++ SQLBindCol(sql_statement_handle,1,SQL_C_LONG,&unique,150,&V_OD_err); ++ /* execute the SQL statement */ ++ result = SQLExecDirect(sql_statement_handle,strSqlStatement,SQL_NTS); ++ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) { ++ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen); ++ rprintf(FERROR,"Error at get_sequence: Error in Select! %s %s\n",strSqlStatement,V_OD_msg); ++ } else { ++ result = SQLFetch(sql_statement_handle); ++ if (result != SQL_NO_DATA && unique != 0) { ++ rprintf(FINFO,"Got unique sequence! %ld\n",unique); ++ } else { ++ rprintf(FERROR,"Error at get_sequence: Didn't get unique session ID\n"); ++ } ++ /* Close the cursor so the statement can be re-used */ ++ result = SQLFreeStmt(sql_statement_handle,SQL_CLOSE); ++ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) { ++ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen); ++ rprintf(FERROR,"Error at get_sequence: Error in closing SQL statement handle %s\n",V_OD_msg); ++ return unique; ++ } ++ return unique; ++ } ++ } ++ rprintf(FERROR,"Error at get_sequence: Not connected to database\n"); ++ return -1; ++} ++ ++ ++void db_log_session() ++{ ++ char strSqlStatement[1024]; ++ int gotSessionID = 0; ++ if (lp_database_logging(module_id)) { ++ /* if we're using a sequence via the nextval command to get a unique ID, we need to get it before ++ * we do the insert. We also get the unique ID now if custom, and get_custom_id_before_insert is set. */ ++ if (strcmp(lp_unique_id_method(module_id),"nextval-postgresql") == 0 ++ || strcmp(lp_unique_id_method(module_id),"nextval-oracle") == 0 ++ || strcmp(lp_unique_id_method(module_id),"nextval-db2") == 0 ++ || (strcmp(lp_unique_id_method(module_id),"custom") == 0 ++ && lp_get_custom_id_before_insert(module_id))) { ++ session_id = get_unique_session_id(); ++ gotSessionID = 1; ++ snprintf(strSqlStatement,sizeof(strSqlStatement),"INSERT INTO %s (id, date, ip_address, username, module_name, module_path, process_id) VALUES ('%ld', '%s', '%s', '%s','%s','%s','%d');",lp_session_table_name(module_id),session_id,timestring(time(NULL)),client_addr(0),auth_user,lp_name(module_id),lp_path(module_id),getpid()); ++ } else { ++ /* Otherwise the ID gets created automatically, and we get the ID it used after the insert. */ ++ snprintf(strSqlStatement,sizeof(strSqlStatement),"INSERT INTO %s (date, ip_address, username, module_name, module_path, process_id) VALUES ('%s', '%s', '%s', '%s','%s','%d');",lp_session_table_name(module_id),timestring(time(NULL)),client_addr(0),auth_user,lp_name(module_id),lp_path(module_id),getpid()); ++ } ++ ++ /* Insert the new session into the database */ ++ result = SQLExecDirect(sql_statement_handle,strSqlStatement,SQL_NTS); ++ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) { ++ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen); ++ rprintf(FERROR,"Error at db_log_session: Error in Insert %s %s\n",strSqlStatement,V_OD_msg); ++ } ++ ++ /* close the cursor so the statement handle can be re-used. */ ++ result = SQLFreeStmt(sql_statement_handle,SQL_CLOSE); ++ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) { ++ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen); ++ rprintf(FERROR,"Error in resetting SQL statement handle %s\n",V_OD_msg); ++ } ++ /* get the session ID for databases that give the unique ID after an insert */ ++ if (gotSessionID == 0) { ++ session_id = get_unique_session_id(); ++ } ++ } ++ else { ++ rprintf(FERROR,"Error at db_log_session: Not connected to database!\n"); ++ } ++} ++ ++void db_log_transfer(struct file_struct *file,struct stats *initial_stats,char *operation) ++{ ++ extern struct stats stats; ++ char strSqlStatement[1024]; ++ char strFilePath[255]; ++ char strFileName[255]; ++ char strFileSize[255]; ++ int64 intBytesTransferred; ++ int64 intCheckSumBytes; ++ ++ if (lp_database_logging(module_id)) { ++ if (db_handle != NULL) { ++ snprintf(strFileName,sizeof(strFileName), "%s",f_name(file)); ++ snprintf(strFilePath, sizeof(strFilePath), "%s", file->basedir?file->basedir:""); ++ snprintf(strFileSize,sizeof(strFileSize),"%.0f", (double)file->length); ++ if (am_sender) { ++ intBytesTransferred = stats.total_written - initial_stats->total_written; ++ } else { ++ intBytesTransferred = stats.total_read - initial_stats->total_read; ++ } ++ ++ if (!am_sender) { ++ intCheckSumBytes = stats.total_written - initial_stats->total_written; ++ } else { ++ intCheckSumBytes = stats.total_read - initial_stats->total_read; ++ } ++ ++ snprintf(strSqlStatement,sizeof(strSqlStatement),"INSERT INTO %s (session_id,date,file_path, file_name, file_size, bytes_transferred, checksum_bytes_transferred, operation) VALUES ('%ld','%s','%s','%s','%s','%Ld','%Ld','%s');",lp_transfer_table_name(module_id),session_id,timestring(time(NULL)),sanitizeSql(strFilePath),sanitizeSql(strFileName),strFileSize,intBytesTransferred,intCheckSumBytes,operation); ++ result = SQLExecDirect(sql_statement_handle,strSqlStatement,SQL_NTS); ++ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) { ++ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen); ++ rprintf(FERROR,"Error at db_log_transfer: Error in Insert %s %s\n",strSqlStatement,V_OD_msg); ++ if (result == SQL_INVALID_HANDLE) ++ rprintf(FERROR,"INVALID HANDLE\n"); ++ } ++ } else { ++ rprintf(FERROR,"Error at db_log_transfer: Not connected to database!\n"); ++ } ++ } ++} ++ ++ ++void db_log_exit(int code, const char *file, int line) ++{ ++ char strSqlStatement[2048]; ++ const char *error_text; ++ extern struct stats stats; ++ if (db_handle != NULL) { ++ if (lp_database_logging(module_id)) { ++ if (code != 0) { ++ error_text = rerr_name(code); ++ if (!error_text) { ++ error_text = "unexplained error"; ++ } ++ } else { ++ error_text = ""; ++ } ++ snprintf(strSqlStatement,sizeof(strSqlStatement),"INSERT INTO %s (session_id, date, total_bytes_written,total_bytes_read,total_size,error_text,error_code,error_file,error_line) VALUES ('%ld','%s','%Ld','%Ld','%Ld','%s','%d','%s','%d');",lp_exit_table_name(module_id),session_id,timestring(time(NULL)),stats.total_written,stats.total_read,stats.total_size,error_text,code,file,line); ++ ++ result = SQLExecDirect(sql_statement_handle,strSqlStatement,SQL_NTS); ++ ++ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) { ++ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen); ++ rprintf(FERROR,"Error at db_log_exit: Error in Insert %s %s\n",strSqlStatement,V_OD_msg); ++ } ++ } ++ } else { ++ rprintf(FERROR,"Error at db_log_exit: Not connected to database!\n"); ++ } ++} +--- dblog-tables-mysql.sql 2004-02-13 17:08:33.000000000 -0800 ++++ dblog-tables-mysql.sql 2004-04-07 23:00:13.000000000 -0700 +@@ -0,0 +1,43 @@ ++drop table transfer; ++drop table exit; ++drop table session; ++ ++CREATE TABLE session ( ++ id int auto_increment NOT NULL, ++ date timestamp NOT NULL, ++ ip_address varchar(15) NOT NULL, ++ username varchar(20) NOT NULL, ++ module_name varchar(20) NOT NULL, ++ module_path varchar(255) NOT NULL, ++ process_id int NOT NULL, ++ Primary Key (id) ++); ++ ++CREATE TABLE transfer ( ++ id int auto_increment NOT NULL, ++ session_id int NOT NULL, ++ date timestamp NOT NULL, ++ file_path varchar(255) NOT NULL, ++ file_name varchar(255) NOT NULL, ++ file_size bigint NOT NULL, ++ bytes_transferred bigint NOT NULL, ++ checksum_bytes_transferred bigint NOT NULL, ++ operation varchar(20), ++ Primary Key (id), ++ foreign key (session_id) references session (id) ++); ++ ++CREATE TABLE exit ( ++ id int auto_increment NOT NULL, ++ session_id int NOT NULL, ++ date timestamp NOT NULL, ++ total_bytes_written bigint NOT NULL, ++ total_bytes_read bigint NOT NULL, ++ total_size bigint NOT NULL, ++ error_text varchar(128) NOT NULL, ++ error_code int NOT NULL, ++ error_file varchar(64) NOT NULL, ++ error_line int NOT NULL, ++ Primary Key (id), ++ foreign key (session_id) references session (id) ++); +--- dblog-tables-postgresql.sql 2004-02-13 17:08:33.000000000 -0800 ++++ dblog-tables-postgresql.sql 2004-04-07 22:59:55.000000000 -0700 +@@ -0,0 +1,45 @@ ++drop table transfer; ++drop table exit; ++drop table session; ++drop sequence session_id_seq; ++create sequence session_id_seq; ++ ++CREATE TABLE "session" ( ++ "id" int NOT NULL, ++ "date" timestamp NOT NULL default now(), ++ "ip_address" varchar(15) NOT NULL, ++ "username" varchar(20) NOT NULL, ++ "module_name" varchar(20) NOT NULL, ++ "module_path" varchar(255) NOT NULL, ++ "process_id" int NOT NULL, ++ Primary Key (id) ++); ++ ++CREATE TABLE "transfer" ( ++ "id" serial NOT NULL, ++ "session_id" int NOT NULL, ++ "date" timestamp NOT NULL default now(), ++ "file_path" varchar(512) NOT NULL, ++ "file_name" varchar(512) NOT NULL, ++ "file_size" bigint NOT NULL, ++ "bytes_transferred" bigint NOT NULL, ++ "checksum_bytes_transferred" bigint NOT NULL, ++ "operation" varchar(20), ++ Primary Key (id), ++ foreign key (session_id) references session (id) ++); ++ ++CREATE TABLE "exit" ( ++ "id" serial NOT NULL, ++ "session_id" int NOT NULL, ++ "date" timestamp NOT NULL default now(), ++ "total_bytes_written" bigint NOT NULL, ++ "total_bytes_read" bigint NOT NULL, ++ "total_size" bigint NOT NULL, ++ "error_text" varchar(128) NOT NULL, ++ "error_code" int NOT NULL, ++ "error_file" varchar(64) NOT NULL, ++ "error_line" int NOT NULL, ++ Primary Key (id), ++ foreign key (session_id) references session (id) ++); +--- loadparm.c 4 Feb 2004 07:31:29 -0000 1.50 ++++ loadparm.c 8 Apr 2004 06:31:18 -0000 +@@ -122,6 +122,17 @@ + BOOL list; + BOOL use_chroot; + BOOL transfer_logging; ++ BOOL database_logging; ++ char *database_datasource; ++ char *database_username; ++ char *database_password; ++ char *transfer_table_name; ++ char *exit_table_name; ++ char *session_table_name; ++ char *sequence_name; ++ char *unique_id_method; ++ char *custom_unique_id_select; ++ BOOL get_custom_id_before_insert; + BOOL ignore_errors; + char *uid; + char *gid; +@@ -154,6 +165,17 @@ + True, /* list */ + True, /* use chroot */ + False, /* transfer logging */ ++ False, /* Database Logging */ ++ NULL, /* Database datasource */ ++ NULL, /* Database username */ ++ NULL, /* Database password */ ++ NULL, /* Transfer table name */ ++ NULL, /* Exit table name */ ++ NULL, /* Session table name */ ++ NULL, /* sequence name */ ++ NULL, /* unique method */ ++ NULL, /* custom unique id select*/ ++ True, /* get custom id before insert */ + False, /* ignore errors */ + "nobody",/* uid */ + +@@ -292,6 +314,17 @@ + {"include", P_STRING, P_LOCAL, &sDefault.include, NULL, 0}, + {"include from", P_STRING, P_LOCAL, &sDefault.include_from,NULL, 0}, + {"transfer logging", P_BOOL, P_LOCAL, &sDefault.transfer_logging,NULL,0}, ++ {"database logging", P_BOOL, P_LOCAL, &sDefault.database_logging,NULL,0}, ++ {"database datasource",P_STRING,P_LOCAL, &sDefault.database_datasource,NULL,0}, ++ {"database username",P_STRING, P_LOCAL, &sDefault.database_username,NULL,0}, ++ {"database password",P_STRING, P_LOCAL, &sDefault.database_password,NULL,0}, ++ {"transfer table name",P_STRING,P_LOCAL, &sDefault.transfer_table_name,NULL,0}, ++ {"exit table name", P_STRING, P_LOCAL, &sDefault.exit_table_name,NULL,0}, ++ {"session table name",P_STRING, P_LOCAL, &sDefault.session_table_name,NULL,0}, ++ {"sequence name", P_STRING, P_LOCAL, &sDefault.sequence_name,NULL,0}, ++ {"unique id method", P_STRING, P_LOCAL, &sDefault.unique_id_method,NULL,0}, ++ {"custom unique id select",P_STRING,P_LOCAL,&sDefault.custom_unique_id_select,NULL,0}, ++ {"get custom id before insert",P_BOOL,P_LOCAL,&sDefault.get_custom_id_before_insert,NULL,0}, + {"ignore errors", P_BOOL, P_LOCAL, &sDefault.ignore_errors,NULL,0}, + {"log format", P_STRING, P_LOCAL, &sDefault.log_format, NULL, 0}, + {"refuse options", P_STRING, P_LOCAL, &sDefault.refuse_options,NULL, 0}, +@@ -359,6 +392,17 @@ + FN_LOCAL_BOOL(lp_list, list) + FN_LOCAL_BOOL(lp_use_chroot, use_chroot) + FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging) ++FN_LOCAL_BOOL(lp_database_logging, database_logging) ++FN_LOCAL_STRING(lp_database_datasource, database_datasource) ++FN_LOCAL_STRING(lp_database_username, database_username) ++FN_LOCAL_STRING(lp_database_password, database_password) ++FN_LOCAL_STRING(lp_transfer_table_name, transfer_table_name) ++FN_LOCAL_STRING(lp_exit_table_name, exit_table_name) ++FN_LOCAL_STRING(lp_session_table_name,session_table_name) ++FN_LOCAL_STRING(lp_sequence_name,sequence_name) ++FN_LOCAL_STRING(lp_unique_id_method,unique_id_method) ++FN_LOCAL_STRING(lp_custom_unique_id_select,custom_unique_id_select) ++FN_LOCAL_BOOL(lp_get_custom_id_before_insert,get_custom_id_before_insert) + FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors) + FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable) + FN_LOCAL_STRING(lp_uid, uid) +--- log.c 20 Jan 2004 05:15:14 -0000 1.71 ++++ log.c 8 Apr 2004 05:56:32 -0000 +@@ -75,7 +75,7 @@ + /* + * Map from rsync error code to name, or return NULL. + */ +-static char const *rerr_name(int code) ++char const *rerr_name(int code) + { + int i; + for (i = 0; rerr_names[i].name; i++) { +--- main.c 10 Feb 2004 03:54:47 -0000 1.192 ++++ main.c 8 Apr 2004 05:56:32 -0000 +@@ -120,6 +120,9 @@ + + if (am_daemon) { + log_exit(0, __FILE__, __LINE__); ++#ifdef HAVE_LIBODBC ++ db_log_exit(0,__FILE__,__LINE__); ++#endif + if (f == -1 || !am_sender) return; + } + +--- proto.h 27 Mar 2004 09:44:34 -0000 1.185 ++++ proto.h 8 Apr 2004 05:56:32 -0000 +@@ -51,6 +51,12 @@ + int daemon_main(void); + void setup_protocol(int f_out,int f_in); + int claim_connection(char *fname,int max_connections); ++char *sanitizeSql(const char *input) ; ++void db_log_open(void); ++void db_log_close(); ++void db_log_session(); ++void db_log_transfer(struct file_struct *file,struct stats *initial_stats,char *operation); ++void db_log_exit(int code, const char *file, int line); + void free_exclude_list(struct exclude_struct ***listp); + int check_exclude(struct exclude_struct **list, char *name, int name_is_dir); + void add_exclude(struct exclude_struct ***listp, const char *pattern, int include); +@@ -137,6 +143,17 @@ + BOOL lp_list(int ); + BOOL lp_use_chroot(int ); + BOOL lp_transfer_logging(int ); ++BOOL lp_database_logging(int ); ++char *lp_database_datasource(int ); ++char *lp_database_username(int ); ++char *lp_database_password(int ); ++char *lp_transfer_table_name(int ); ++char *lp_exit_table_name(int ); ++char *lp_session_table_name(int ); ++char *lp_sequence_name(int ); ++char *lp_unique_id_method(int ); ++char *lp_custom_unique_id_select(int ); ++BOOL lp_get_custom_id_before_insert(int ); + BOOL lp_ignore_errors(int ); + BOOL lp_ignore_nonreadable(int ); + char *lp_uid(int ); +@@ -158,6 +175,7 @@ + BOOL lp_load(char *pszFname, int globals_only); + int lp_numservices(void); + int lp_number(char *name); ++char const *rerr_name(int code); + void log_init(void); + void log_open(void); + void log_close(void); +--- receiver.c 23 Mar 2004 16:50:40 -0000 1.75 ++++ receiver.c 8 Apr 2004 05:56:32 -0000 +@@ -453,7 +453,9 @@ + recv_ok = receive_data(f_in,mapbuf,fd2,fname,file->length); + + log_recv(file, &initial_stats); +- ++#ifdef HAVE_LIBODBC ++ db_log_transfer(file, &initial_stats,"receive"); ++#endif + if (mapbuf) unmap_file(mapbuf); + if (fd1 != -1) { + close(fd1); +--- sender.c 17 Feb 2004 21:57:44 -0000 1.38 ++++ sender.c 8 Apr 2004 05:56:32 -0000 +@@ -283,6 +283,9 @@ + } else { + match_sums(f_out, s, buf, st.st_size); + log_send(file, &initial_stats); ++#ifdef HAVE_LIBODBC ++ db_log_transfer(file, &initial_stats,"send"); ++#endif + } + + if (!read_batch) { -- 2.34.1