Got rid of patch fuzz.
[rsync/rsync-patches.git] / ODBC-dblog.diff
CommitLineData
2c40f06f
WD
1Add support for logging daemon messages to an SQL database.
2
8a529471 3After applying this patch, run these commands for a successful build:
2c40f06f 4
8a529471
WD
5 autoconf
6 autoheader
7 ./configure --with-ODBC
8 make proto
9 make
2c40f06f 10
8a529471 11Steve Sether writes:
2c40f06f 12
8a529471 13This patch adds the following options:
2c40f06f 14
8a529471
WD
15"database logging"
16 If set to True, rsync will attempt to connect to
17 the specified datasource and write to the named tables.
18 Defaults to False.
2c40f06f 19
8a529471
WD
20"database datasource"
21 Specifies the name of the ODBC data source to use.
22
23"database username"
24 The username to use when connecting to the database.
25
26"database password"
27 The password to use when connecting to the database.
28
29"transfer table name"
30 The name of the transfer table to log to. This table contains individual
31 filenames, file sizes, bytes transferred, checksum bytes transferred,
32 operation (send or receive), and a timestamp.
33
34"session table name"
35 The name of the session table to log to. This table contains the username,
36 module name, module path, ip address, process ID, and a timestamp.
37
38"exit table name"
39
40 The name of the exit table to log to. This table contains the total bytes
41 read, total bytes written, total size of all files, error code, line the
42 error occured at, file the error occured at and the text of the error.
43 (most of which will be blank if the program exited normally).
44
45"unique id method"
46 Different databases use different methods to get a unique identifier.
47 Some databases support sequence objects, and use various forms of the
48 nextval command to retrieve a unique identifier from it. Other databases
49 support an autonumber field, and support different methds of retrieving
50 the ID used in the last insert. Valid values for this option are:
51
52 nextval-postgres
53 uses the syntax of nextval for PostgreSQL databases
54
55 nextval-oracle
56 uses the syntax of nextval for Oracle databases
57
58 nextval-db2
59 uses the syntax of nextval for DB2 databases
60
61 last_insert_id
62 uses the last_insert_id() command for the MySQL databases
63
64 @@IDENTITY
65 uses the @@IDENTITY command for Sybase databases
66
67 custom
68 Define your own method to get a unique identifier. See the
69 "custom unique id select", and the "get custom id before select"
70 parameters.
71
72"sequence name"
73 If your database supports sequences, list the name of the sequence to use
74 for the session unique identifier.
75
76"custom unique id select"
77 Only used if you specify the custom method in "unique id method". This is
78 a SQL statement to be executed to get a unique ID. This SQL statement must
79 return one column with the unique ID to use for the session ID. Should be
80 used in concert with the "get custom id before select" parameter.
81
82"get custom id before insert"
83 This parameter is ignored unless the "unique id method" is set to custom.
84 If set to true, the "custom unique id select" statement will be executed
85 BEFORE the session row is inserted into the database. (as is done when a
86 sequence is used for unique IDs). If False the statement will be executed
87 after the session row is inserted (as is done when the session ID is
88 automatically generates unique IDs). Defaults to True.
89
90
ac23c334 91--- orig/Makefile.in 2004-11-03 11:56:03
13bed3dd 92+++ Makefile.in 2004-07-03 20:22:18
103bcb1d
WD
93@@ -32,7 +32,7 @@ ZLIBOBJ=zlib/deflate.o zlib/infblock.o z
94 zlib/inflate.o zlib/inftrees.o zlib/infutil.o zlib/trees.o \
95 zlib/zutil.o zlib/adler32.o
96 OBJS1=rsync.o generator.o receiver.o cleanup.o sender.o exclude.o util.o \
97- main.o checksum.o match.o syscall.o log.o backup.o
98+ main.o checksum.o match.o syscall.o log.o backup.o @EXTRA_OBJECT@
99 OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o \
100 fileio.o batch.o clientname.o
101 OBJS3=progress.o pipe.o
ac23c334 102--- orig/cleanup.c 2005-01-10 09:46:11
13bed3dd 103+++ cleanup.c 2004-07-03 20:22:18
ac23c334 104@@ -143,8 +143,12 @@ void _exit_cleanup(int code, const char
2c40f06f
WD
105 code = RERR_VANISHED;
106 }
107
13bed3dd 108- if (code)
2c40f06f 109+ if (code) {
13bed3dd 110 log_exit(code, file, line);
2c40f06f
WD
111+#ifdef HAVE_LIBODBC
112+ db_log_exit(code,file,line);
113+#endif
114+ }
115
8a529471
WD
116 if (verbose > 2) {
117 rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): about to call exit(%d)\n",
ac23c334 118--- orig/clientserver.c 2005-01-25 00:53:58
13bed3dd 119+++ clientserver.c 2004-07-03 20:22:18
ac23c334
WD
120@@ -341,6 +341,9 @@ static int rsync_module(int f_in, int f_
121 XFLG_WORD_SPLIT | XFLG_ABS_PATH | XFLG_DEF_EXCLUDE);
2c40f06f
WD
122
123 log_init();
124+#ifdef HAVE_LIBODBC
125+ db_log_open();
126+#endif
127
128 if (use_chroot) {
129 /*
ac23c334 130@@ -459,6 +462,9 @@ static int rsync_module(int f_in, int f_
545864f1
WD
131 rprintf(FLOG, "rsync %s %s from %s@%s (%s)\n",
132 am_sender ? "on" : "to",
2c40f06f
WD
133 request, auth_user, host, addr);
134+#ifdef HAVE_LIBODBC
135+ db_log_session();
136+#endif
137 } else {
545864f1
WD
138 rprintf(FLOG, "rsync %s %s from %s (%s)\n",
139 am_sender ? "on" : "to",
ac23c334 140--- orig/configure.in 2005-01-10 00:21:12
13bed3dd 141+++ configure.in 2004-07-03 20:22:18
b0aa8860 142@@ -94,6 +94,8 @@ AC_ARG_WITH(rsync-path,
2c40f06f
WD
143 [ --with-rsync-path=PATH set default --rsync-path to PATH (default: rsync)],
144 [ RSYNC_PATH="$with_rsync_path" ],
145 [ RSYNC_PATH="rsync" ])
146+AC_ARG_WITH(ODBC,
147+ [ --with-ODBC compile in support for ODBC database logging])
148
149 AC_DEFINE_UNQUOTED(RSYNC_PATH, "$RSYNC_PATH", [location of rsync on remote machine])
150
ac23c334 151@@ -500,6 +502,14 @@ then
2c40f06f 152 AC_CHECK_LIB(popt, poptGetContext, , [with_included_popt=yes])
545864f1
WD
153 fi
154
2c40f06f
WD
155+if test x"$with_ODBC" = x"yes"
156+then
157+ AC_CHECK_HEADERS(sql.h sqlext.h sqltypes.h)
158+ AC_CHECK_LIB(odbc,SQLExecDirect)
159+ EXTRA_OBJECT="$EXTRA_OBJECT dblog.o"
160+ AC_SUBST(EXTRA_OBJECT)
545864f1
WD
161+fi
162+
2c40f06f 163 AC_MSG_CHECKING([whether to use included libpopt])
545864f1
WD
164 if test x"$with_included_popt" = x"yes"
165 then
13bed3dd
WD
166--- orig/dblog-tables-mysql.sql 2004-07-02 21:35:58
167+++ dblog-tables-mysql.sql 2004-07-02 21:35:58
103bcb1d
WD
168@@ -0,0 +1,43 @@
169+drop table transfer;
170+drop table exit;
171+drop table session;
172+
173+CREATE TABLE session (
174+ id int auto_increment NOT NULL,
175+ date timestamp NOT NULL,
176+ ip_address varchar(15) NOT NULL,
177+ username varchar(20) NOT NULL,
178+ module_name varchar(20) NOT NULL,
179+ module_path varchar(255) NOT NULL,
180+ process_id int NOT NULL,
181+ Primary Key (id)
182+);
183+
184+CREATE TABLE transfer (
185+ id int auto_increment NOT NULL,
186+ session_id int NOT NULL,
187+ date timestamp NOT NULL,
188+ file_path varchar(255) NOT NULL,
189+ file_name varchar(255) NOT NULL,
190+ file_size bigint NOT NULL,
191+ bytes_transferred bigint NOT NULL,
192+ checksum_bytes_transferred bigint NOT NULL,
193+ operation varchar(20),
194+ Primary Key (id),
195+ foreign key (session_id) references session (id)
196+);
197+
198+CREATE TABLE exit (
199+ id int auto_increment NOT NULL,
200+ session_id int NOT NULL,
201+ date timestamp NOT NULL,
202+ total_bytes_written bigint NOT NULL,
203+ total_bytes_read bigint NOT NULL,
204+ total_size bigint NOT NULL,
205+ error_text varchar(128) NOT NULL,
206+ error_code int NOT NULL,
207+ error_file varchar(64) NOT NULL,
208+ error_line int NOT NULL,
209+ Primary Key (id),
210+ foreign key (session_id) references session (id)
211+);
13bed3dd
WD
212--- orig/dblog-tables-postgresql.sql 2004-07-02 21:35:58
213+++ dblog-tables-postgresql.sql 2004-07-02 21:35:58
103bcb1d
WD
214@@ -0,0 +1,45 @@
215+drop table transfer;
216+drop table exit;
217+drop table session;
218+drop sequence session_id_seq;
219+create sequence session_id_seq;
220+
221+CREATE TABLE "session" (
222+ "id" int NOT NULL,
223+ "date" timestamp NOT NULL default now(),
224+ "ip_address" varchar(15) NOT NULL,
225+ "username" varchar(20) NOT NULL,
226+ "module_name" varchar(20) NOT NULL,
227+ "module_path" varchar(255) NOT NULL,
228+ "process_id" int NOT NULL,
229+ Primary Key (id)
230+);
231+
232+CREATE TABLE "transfer" (
233+ "id" serial NOT NULL,
234+ "session_id" int NOT NULL,
235+ "date" timestamp NOT NULL default now(),
236+ "file_path" varchar(512) NOT NULL,
237+ "file_name" varchar(512) NOT NULL,
238+ "file_size" bigint NOT NULL,
239+ "bytes_transferred" bigint NOT NULL,
240+ "checksum_bytes_transferred" bigint NOT NULL,
241+ "operation" varchar(20),
242+ Primary Key (id),
243+ foreign key (session_id) references session (id)
244+);
245+
246+CREATE TABLE "exit" (
247+ "id" serial NOT NULL,
248+ "session_id" int NOT NULL,
249+ "date" timestamp NOT NULL default now(),
250+ "total_bytes_written" bigint NOT NULL,
251+ "total_bytes_read" bigint NOT NULL,
252+ "total_size" bigint NOT NULL,
253+ "error_text" varchar(128) NOT NULL,
254+ "error_code" int NOT NULL,
255+ "error_file" varchar(64) NOT NULL,
256+ "error_line" int NOT NULL,
257+ Primary Key (id),
258+ foreign key (session_id) references session (id)
259+);
13bed3dd
WD
260--- orig/dblog.c 2004-07-02 21:35:58
261+++ dblog.c 2004-07-02 21:35:58
2c40f06f
WD
262@@ -0,0 +1,352 @@
263+/*
264+ * ODBC Database logging functions
265+ *
266+ * Written by Steve Sether, April 2004
267+ * steve@vellmont.com
268+ */
269+
270+#include "rsync.h"
271+
272+#ifdef HAVE_SQL_H
273+#include <sql.h>
274+#else
275+#ifdef HAVE_ODBC_SQL_H
276+#include <odbc/sql.h>
277+#endif
278+#endif
279+
280+#ifdef HAVE_SQLEXT_H
281+#include <sqlext.h>
282+#else
283+#ifdef HAVE_ODBC_SQLEXT_H
284+#include <odbc/sqlext.h>
285+#endif
286+#endif
287+
288+#ifdef HAVE_SQLTYPES_H
289+#include <sqltypes.h>
290+#else
291+#ifdef HAVE_ODBC_SQLTYPES_H
292+#include <odbc/sqltypes.h>
293+#endif
294+#endif
295+
296+SQLHENV db_environ_handle; /* Handle ODBC environment */
297+long result; /* result of functions */
298+SQLHDBC db_handle= NULL; /* database connection handle */
299+SQLHSTMT sql_statement_handle; /* SQL statement handle */
300+extern int am_sender;
301+extern char *auth_user;
302+extern int module_id;
303+
304+char sql_status[10]; /* Status SQL */
305+SQLINTEGER V_OD_err, V_OD_rowanz, V_OD_id;
306+SQLSMALLINT V_OD_mlen, V_OD_colanz;
307+char V_OD_msg[200], V_OD_buffer[200];
308+SQLINTEGER session_id;
309+
310+
311+/* This function simply removes invalid characters from the SQL statement
312+ * to prevent SQL injection attacks. */
313+char *sanitizeSql(const char *input)
314+{
315+ char *out, *ptr;
316+ const char *c;
317+
318+ if (strlen(input) > ((~(unsigned int)0)>>1)-3)
319+ return 0;
320+ if (!(out = ptr = new_array(char, strlen(input) * 2 + 1)))
321+ return 0;
322+
323+ for (c = input; *c; c++) {
324+ switch (*c) {
325+ case '\'':
326+ *ptr++ = '\'';
327+ *ptr++ = '\'';
328+ break;
329+ case '\b':
330+ *ptr++ = '\\';
331+ *ptr++ = 'b';
332+ break;
333+ case '\n':
334+ *ptr++ = '\\';
335+ *ptr++ = 'n';
336+ break;
337+ case '\r':
338+ *ptr++ = '\\';
339+ *ptr++ = 'r';
340+ break;
341+ case '\t':
342+ *ptr++ = '\\';
343+ *ptr++ = 't';
344+ break;
345+ default:
346+ *ptr++ = *c;
347+ break;
348+ }
349+ }
350+ *ptr = '\0';
351+ return out;
352+}
353+
354+void db_log_open(void)
355+{
356+ if (lp_database_logging(module_id)) {
357+ if (db_handle == NULL) {
358+ /* get ODBC environment handle */
359+ result = SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&db_environ_handle);
360+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
361+ rprintf(FERROR, "Error: couldn't get database environment handle\n");
362+ return;
363+ }
364+
365+ /* Setting database enviroment */
366+ result = SQLSetEnvAttr(db_environ_handle, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
367+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
368+ rprintf(FERROR, "Error: couldn't set database environment.\n");
369+ SQLFreeHandle(SQL_HANDLE_ENV, db_environ_handle);
370+ db_environ_handle = NULL;
371+ return;
372+ }
373+
374+ /* Get a database handle */
375+ result = SQLAllocHandle(SQL_HANDLE_DBC, db_environ_handle, &db_handle);
376+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
377+ rprintf(FERROR, "Error: couldn't allocate database handle\n");
378+ SQLFreeHandle(SQL_HANDLE_ENV, db_environ_handle);
379+ db_environ_handle = NULL;
380+ return;
381+ }
382+
383+ /* Set connection attributes */
384+ SQLSetConnectAttr(db_handle, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)5, 0);
385+
386+ /* Connect to the database. */
387+ result = SQLConnect(db_handle, (SQLCHAR*) lp_database_datasource(module_id), SQL_NTS,
388+ (SQLCHAR*) lp_database_username(module_id), SQL_NTS,
389+ (SQLCHAR*) lp_database_password(module_id), SQL_NTS);
390+
391+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
392+ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1,
393+ sql_status, &V_OD_err,V_OD_msg,100,&V_OD_mlen);
394+ rprintf(FERROR,"Error Connecting to Database %s\n",V_OD_msg);
395+ SQLFreeHandle(SQL_HANDLE_DBC,db_handle);
396+ db_handle = NULL;
397+ SQLFreeHandle(SQL_HANDLE_ENV, db_environ_handle);
398+ db_environ_handle = NULL;
399+ return;
400+ }
401+ rprintf(FLOG,"Connected to database!\n");
402+
403+ /* get SQL statement handle */
404+ result = SQLAllocHandle(SQL_HANDLE_STMT, db_handle, &sql_statement_handle);
405+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
406+ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen);
407+ rprintf(FERROR,"Error in allocating SQL statement handle %s\n",V_OD_msg);
408+ SQLDisconnect(db_handle);
409+ SQLFreeHandle(SQL_HANDLE_DBC,db_handle);
410+ db_handle = NULL;
411+ SQLFreeHandle(SQL_HANDLE_ENV, db_environ_handle);
412+ db_environ_handle = NULL;
413+ return;
414+ }
415+ } else {
416+ rprintf(FERROR,"Already connected to database\n");
417+ }
418+ }
419+}
420+
421+void db_log_close()
422+{
423+ if (lp_database_logging(module_id)) {
424+ if (sql_statement_handle != NULL) {
425+ /* free the statement handle first */
426+ SQLFreeHandle(SQL_HANDLE_STMT,sql_statement_handle);
427+ sql_statement_handle = NULL;
428+ } else {
429+ rprintf(FERROR,"No sql statement handle to close\n");
430+ }
431+ if (db_handle != NULL) {
432+ /* disconnect, and free the database handle. */
433+ SQLDisconnect(db_handle);
434+ SQLFreeHandle(SQL_HANDLE_DBC,db_handle);
435+ db_handle = NULL;
436+ } else {
437+ rprintf(FERROR,"Database already closed");
438+ }
439+ if (db_environ_handle != NULL) {
440+ /* free the environment handle */
441+ SQLFreeHandle(SQL_HANDLE_ENV, db_environ_handle);
442+ db_environ_handle = NULL;
443+ } else {
444+ rprintf(FERROR,"No environment handle to close");
445+ }
446+ }
447+}
448+
449+static long get_unique_session_id()
450+{
451+ long unique;
452+ char strSqlStatement[1024];
453+
454+ if (db_handle != NULL) {
455+ /* choose the appropriate select statement based upon which DBMS we're using.
456+ * different datbases use different methods to get a unique ID. Some use a counter
457+ * object (sequence), others use an auto increment datatype and have a method
458+ * to get the last ID inserted using this connection. */
459+ if (strcmp(lp_unique_id_method(module_id),"nextval-postgresql") == 0) {
460+ snprintf(strSqlStatement,sizeof(strSqlStatement),"SELECT NEXTVAL('%s');",lp_sequence_name(module_id));
461+ } else if (strcmp(lp_unique_id_method(module_id),"nextval-oracle") == 0) {
462+ snprintf(strSqlStatement,sizeof(strSqlStatement),"SELECT %s.NEXTVAL FROM dual;",lp_sequence_name(module_id));
463+ } else if (strcmp(lp_unique_id_method(module_id),"nextval-db2") == 0) {
464+ snprintf(strSqlStatement,sizeof(strSqlStatement),"VALUES NEXTVAL FOR %s;",lp_sequence_name(module_id));
465+ } else if (strcmp(lp_unique_id_method(module_id),"last_insert_id") == 0) { /* MySql */
466+ snprintf(strSqlStatement,sizeof(strSqlStatement),"SELECT LAST_INSERT_ID()");
467+ } else if (strcmp(lp_unique_id_method(module_id),"@@IDENTITY") == 0) { /* Sybase */
468+ snprintf(strSqlStatement,sizeof(strSqlStatement),"SELECT @@IDENTITY");
469+ } else if (strcmp(lp_unique_id_method(module_id),"custom") == 0){ /* Users custom statement */
470+ snprintf(strSqlStatement,sizeof(strSqlStatement),lp_custom_unique_id_select(module_id));
471+ }
472+
473+ /* bind the 1st column to unique */
474+ SQLBindCol(sql_statement_handle,1,SQL_C_LONG,&unique,150,&V_OD_err);
475+ /* execute the SQL statement */
476+ result = SQLExecDirect(sql_statement_handle,strSqlStatement,SQL_NTS);
477+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
478+ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen);
479+ rprintf(FERROR,"Error at get_sequence: Error in Select! %s %s\n",strSqlStatement,V_OD_msg);
480+ } else {
481+ result = SQLFetch(sql_statement_handle);
482+ if (result != SQL_NO_DATA && unique != 0) {
483+ rprintf(FINFO,"Got unique sequence! %ld\n",unique);
484+ } else {
485+ rprintf(FERROR,"Error at get_sequence: Didn't get unique session ID\n");
486+ }
487+ /* Close the cursor so the statement can be re-used */
488+ result = SQLFreeStmt(sql_statement_handle,SQL_CLOSE);
489+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
490+ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen);
491+ rprintf(FERROR,"Error at get_sequence: Error in closing SQL statement handle %s\n",V_OD_msg);
492+ return unique;
493+ }
494+ return unique;
495+ }
496+ }
497+ rprintf(FERROR,"Error at get_sequence: Not connected to database\n");
498+ return -1;
499+}
500+
501+
502+void db_log_session()
503+{
504+ char strSqlStatement[1024];
505+ int gotSessionID = 0;
506+ if (lp_database_logging(module_id)) {
507+ /* if we're using a sequence via the nextval command to get a unique ID, we need to get it before
508+ * we do the insert. We also get the unique ID now if custom, and get_custom_id_before_insert is set. */
509+ if (strcmp(lp_unique_id_method(module_id),"nextval-postgresql") == 0
510+ || strcmp(lp_unique_id_method(module_id),"nextval-oracle") == 0
511+ || strcmp(lp_unique_id_method(module_id),"nextval-db2") == 0
512+ || (strcmp(lp_unique_id_method(module_id),"custom") == 0
513+ && lp_get_custom_id_before_insert(module_id))) {
514+ session_id = get_unique_session_id();
515+ gotSessionID = 1;
516+ 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());
517+ } else {
518+ /* Otherwise the ID gets created automatically, and we get the ID it used after the insert. */
519+ 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());
520+ }
521+
522+ /* Insert the new session into the database */
523+ result = SQLExecDirect(sql_statement_handle,strSqlStatement,SQL_NTS);
524+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
525+ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen);
526+ rprintf(FERROR,"Error at db_log_session: Error in Insert %s %s\n",strSqlStatement,V_OD_msg);
527+ }
528+
529+ /* close the cursor so the statement handle can be re-used. */
530+ result = SQLFreeStmt(sql_statement_handle,SQL_CLOSE);
531+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
532+ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen);
533+ rprintf(FERROR,"Error in resetting SQL statement handle %s\n",V_OD_msg);
534+ }
535+ /* get the session ID for databases that give the unique ID after an insert */
536+ if (gotSessionID == 0) {
537+ session_id = get_unique_session_id();
538+ }
539+ }
540+ else {
541+ rprintf(FERROR,"Error at db_log_session: Not connected to database!\n");
542+ }
543+}
544+
545+void db_log_transfer(struct file_struct *file,struct stats *initial_stats,char *operation)
546+{
547+ extern struct stats stats;
548+ char strSqlStatement[1024];
549+ char strFilePath[255];
550+ char strFileName[255];
551+ char strFileSize[255];
552+ int64 intBytesTransferred;
553+ int64 intCheckSumBytes;
554+
555+ if (lp_database_logging(module_id)) {
556+ if (db_handle != NULL) {
557+ snprintf(strFileName,sizeof(strFileName), "%s",f_name(file));
558+ snprintf(strFilePath, sizeof(strFilePath), "%s", file->basedir?file->basedir:"");
559+ snprintf(strFileSize,sizeof(strFileSize),"%.0f", (double)file->length);
560+ if (am_sender) {
561+ intBytesTransferred = stats.total_written - initial_stats->total_written;
562+ } else {
563+ intBytesTransferred = stats.total_read - initial_stats->total_read;
564+ }
565+
566+ if (!am_sender) {
567+ intCheckSumBytes = stats.total_written - initial_stats->total_written;
568+ } else {
569+ intCheckSumBytes = stats.total_read - initial_stats->total_read;
570+ }
571+
572+ 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);
573+ result = SQLExecDirect(sql_statement_handle,strSqlStatement,SQL_NTS);
574+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
575+ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen);
576+ rprintf(FERROR,"Error at db_log_transfer: Error in Insert %s %s\n",strSqlStatement,V_OD_msg);
577+ if (result == SQL_INVALID_HANDLE)
578+ rprintf(FERROR,"INVALID HANDLE\n");
579+ }
580+ } else {
581+ rprintf(FERROR,"Error at db_log_transfer: Not connected to database!\n");
582+ }
583+ }
584+}
585+
586+
587+void db_log_exit(int code, const char *file, int line)
588+{
589+ char strSqlStatement[2048];
590+ const char *error_text;
591+ extern struct stats stats;
592+ if (db_handle != NULL) {
593+ if (lp_database_logging(module_id)) {
594+ if (code != 0) {
595+ error_text = rerr_name(code);
596+ if (!error_text) {
597+ error_text = "unexplained error";
598+ }
599+ } else {
600+ error_text = "";
601+ }
602+ 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);
603+
604+ result = SQLExecDirect(sql_statement_handle,strSqlStatement,SQL_NTS);
605+
606+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
607+ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen);
608+ rprintf(FERROR,"Error at db_log_exit: Error in Insert %s %s\n",strSqlStatement,V_OD_msg);
609+ }
610+ }
611+ } else {
612+ rprintf(FERROR,"Error at db_log_exit: Not connected to database!\n");
613+ }
614+}
ac23c334 615--- orig/loadparm.c 2005-01-25 00:53:58
13bed3dd 616+++ loadparm.c 2004-07-03 20:22:18
ac23c334 617@@ -125,6 +125,17 @@ typedef struct
2c40f06f
WD
618 BOOL list;
619 BOOL use_chroot;
620 BOOL transfer_logging;
621+ BOOL database_logging;
622+ char *database_datasource;
623+ char *database_username;
624+ char *database_password;
625+ char *transfer_table_name;
626+ char *exit_table_name;
627+ char *session_table_name;
628+ char *sequence_name;
629+ char *unique_id_method;
630+ char *custom_unique_id_select;
631+ BOOL get_custom_id_before_insert;
632 BOOL ignore_errors;
633 char *uid;
634 char *gid;
ac23c334 635@@ -159,6 +170,17 @@ static service sDefault =
2c40f06f
WD
636 True, /* list */
637 True, /* use chroot */
638 False, /* transfer logging */
639+ False, /* Database Logging */
640+ NULL, /* Database datasource */
641+ NULL, /* Database username */
642+ NULL, /* Database password */
643+ NULL, /* Transfer table name */
644+ NULL, /* Exit table name */
645+ NULL, /* Session table name */
646+ NULL, /* sequence name */
647+ NULL, /* unique method */
648+ NULL, /* custom unique id select*/
649+ True, /* get custom id before insert */
650 False, /* ignore errors */
651 "nobody",/* uid */
652
ac23c334 653@@ -302,6 +324,17 @@ static struct parm_struct parm_table[] =
2c40f06f
WD
654 {"include", P_STRING, P_LOCAL, &sDefault.include, NULL, 0},
655 {"include from", P_STRING, P_LOCAL, &sDefault.include_from,NULL, 0},
656 {"transfer logging", P_BOOL, P_LOCAL, &sDefault.transfer_logging,NULL,0},
657+ {"database logging", P_BOOL, P_LOCAL, &sDefault.database_logging,NULL,0},
658+ {"database datasource",P_STRING,P_LOCAL, &sDefault.database_datasource,NULL,0},
659+ {"database username",P_STRING, P_LOCAL, &sDefault.database_username,NULL,0},
660+ {"database password",P_STRING, P_LOCAL, &sDefault.database_password,NULL,0},
661+ {"transfer table name",P_STRING,P_LOCAL, &sDefault.transfer_table_name,NULL,0},
662+ {"exit table name", P_STRING, P_LOCAL, &sDefault.exit_table_name,NULL,0},
663+ {"session table name",P_STRING, P_LOCAL, &sDefault.session_table_name,NULL,0},
664+ {"sequence name", P_STRING, P_LOCAL, &sDefault.sequence_name,NULL,0},
665+ {"unique id method", P_STRING, P_LOCAL, &sDefault.unique_id_method,NULL,0},
666+ {"custom unique id select",P_STRING,P_LOCAL,&sDefault.custom_unique_id_select,NULL,0},
667+ {"get custom id before insert",P_BOOL,P_LOCAL,&sDefault.get_custom_id_before_insert,NULL,0},
668 {"ignore errors", P_BOOL, P_LOCAL, &sDefault.ignore_errors,NULL,0},
669 {"log format", P_STRING, P_LOCAL, &sDefault.log_format, NULL, 0},
670 {"refuse options", P_STRING, P_LOCAL, &sDefault.refuse_options,NULL, 0},
ac23c334 671@@ -372,6 +405,17 @@ FN_LOCAL_BOOL(lp_write_only, write_only)
2c40f06f
WD
672 FN_LOCAL_BOOL(lp_list, list)
673 FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
674 FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging)
675+FN_LOCAL_BOOL(lp_database_logging, database_logging)
676+FN_LOCAL_STRING(lp_database_datasource, database_datasource)
677+FN_LOCAL_STRING(lp_database_username, database_username)
678+FN_LOCAL_STRING(lp_database_password, database_password)
679+FN_LOCAL_STRING(lp_transfer_table_name, transfer_table_name)
680+FN_LOCAL_STRING(lp_exit_table_name, exit_table_name)
681+FN_LOCAL_STRING(lp_session_table_name,session_table_name)
682+FN_LOCAL_STRING(lp_sequence_name,sequence_name)
683+FN_LOCAL_STRING(lp_unique_id_method,unique_id_method)
684+FN_LOCAL_STRING(lp_custom_unique_id_select,custom_unique_id_select)
685+FN_LOCAL_BOOL(lp_get_custom_id_before_insert,get_custom_id_before_insert)
686 FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors)
687 FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable)
688 FN_LOCAL_STRING(lp_uid, uid)
a6587818 689--- orig/log.c 2004-09-07 19:54:51
13bed3dd 690+++ log.c 2004-07-03 20:22:18
b0aa8860 691@@ -75,7 +75,7 @@ struct {
2c40f06f
WD
692 /*
693 * Map from rsync error code to name, or return NULL.
694 */
695-static char const *rerr_name(int code)
696+char const *rerr_name(int code)
697 {
698 int i;
699 for (i = 0; rerr_names[i].name; i++) {
ac23c334 700--- orig/main.c 2005-01-24 01:43:10
13bed3dd 701+++ main.c 2004-07-03 20:22:18
ac23c334 702@@ -139,6 +139,9 @@ static void report(int f)
2c40f06f
WD
703
704 if (am_daemon) {
705 log_exit(0, __FILE__, __LINE__);
706+#ifdef HAVE_LIBODBC
707+ db_log_exit(0,__FILE__,__LINE__);
708+#endif
7628f156
WD
709 if (f == -1 || !am_sender)
710 return;
2c40f06f 711 }
ac23c334 712--- orig/receiver.c 2005-01-24 01:43:10
dc3ae351 713+++ receiver.c 2004-07-20 21:47:47
ac23c334 714@@ -490,6 +490,9 @@ int recv_files(int f_in, struct file_lis
dc3ae351 715 fname, fd2, file->length);
2c40f06f
WD
716
717 log_recv(file, &initial_stats);
2c40f06f 718+#ifdef HAVE_LIBODBC
13bed3dd 719+ db_log_transfer(file, &initial_stats, "receive");
2c40f06f 720+#endif
dc3ae351 721
13bed3dd 722 if (fd1 != -1)
dc3ae351 723 close(fd1);
ac23c334 724--- orig/sender.c 2005-01-25 00:00:31
9be39c35 725+++ sender.c 2004-07-15 02:37:48
ac23c334 726@@ -231,6 +231,9 @@ void send_files(struct file_list *flist,
9be39c35
WD
727
728 match_sums(f_out, s, mbuf, st.st_size);
729 log_send(file, &initial_stats);
2c40f06f 730+#ifdef HAVE_LIBODBC
9be39c35 731+ db_log_transfer(file, &initial_stats,"send");
2c40f06f 732+#endif
2c40f06f 733
9be39c35
WD
734 if (mbuf) {
735 j = unmap_file(mbuf);