Added the --prepare-source option that will regenerate generated
[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
a9eff38d 7 ./configure --enable-ODBC
8a529471
WD
8 make proto
9 make
2c40f06f 10
a9eff38d 11See the file "instructions" (after applying this patch) for more info.
8a529471 12
93ca4d27 13--- orig/Makefile.in 2006-01-14 08:14:29
a9eff38d 14+++ Makefile.in 2005-09-23 15:59:02
1680e814
WD
15@@ -31,7 +31,7 @@ LIBOBJ=lib/wildmatch.o lib/compat.o lib/
16 ZLIBOBJ=zlib/deflate.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o \
17 zlib/trees.o zlib/zutil.o zlib/adler32.o zlib/compress.o zlib/crc32.o
103bcb1d
WD
18 OBJS1=rsync.o generator.o receiver.o cleanup.o sender.o exclude.o util.o \
19- main.o checksum.o match.o syscall.o log.o backup.o
20+ main.o checksum.o match.o syscall.o log.o backup.o @EXTRA_OBJECT@
21 OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o \
6849cd84 22 fileio.o batch.o clientname.o chmod.o
103bcb1d 23 OBJS3=progress.o pipe.o
93ca4d27 24--- orig/cleanup.c 2006-01-14 08:14:29
a9eff38d
WD
25+++ cleanup.c 2005-09-23 15:59:19
26@@ -23,6 +23,7 @@
637ba3ff 27
a9eff38d
WD
28 extern int io_error;
29 extern int keep_partial;
30+extern int am_generator;
31 extern int log_got_error;
32 extern char *partial_dir;
33
34@@ -144,8 +145,13 @@ void _exit_cleanup(int code, const char
36bbf3d1 35 code = RERR_PARTIAL;
2c40f06f
WD
36 }
37
13bed3dd 38- if (code)
2c40f06f 39+ if (code) {
13bed3dd 40 log_exit(code, file, line);
637ba3ff 41+#ifdef HAVE_LIBODBC
2c40f06f 42+ db_log_exit(code,file,line);
a9eff38d 43+ db_log_close();
2c40f06f
WD
44+#endif
45+ }
46
8a529471
WD
47 if (verbose > 2) {
48 rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): about to call exit(%d)\n",
93ca4d27 49--- orig/clientserver.c 2006-01-14 08:14:29
a9eff38d 50+++ clientserver.c 2005-09-23 15:59:36
93ca4d27 51@@ -387,6 +387,9 @@ static int rsync_module(int f_in, int f_
6849cd84 52 XFLG_ABS_IF_SLASH | XFLG_OLD_PREFIXES);
2c40f06f
WD
53
54 log_init();
637ba3ff 55+#ifdef HAVE_LIBODBC
2c40f06f
WD
56+ db_log_open();
57+#endif
58
ff55cce0 59 #ifdef HAVE_PUTENV
6849cd84 60 if (*lp_prexfer_exec(i) || *lp_postxfer_exec(i)) {
93ca4d27 61@@ -624,6 +627,9 @@ static int rsync_module(int f_in, int f_
545864f1
WD
62 rprintf(FLOG, "rsync %s %s from %s@%s (%s)\n",
63 am_sender ? "on" : "to",
2c40f06f 64 request, auth_user, host, addr);
637ba3ff 65+#ifdef HAVE_LIBODBC
2c40f06f
WD
66+ db_log_session();
67+#endif
68 } else {
545864f1
WD
69 rprintf(FLOG, "rsync %s %s from %s (%s)\n",
70 am_sender ? "on" : "to",
bd68c3c2 71--- orig/configure.in 2006-01-15 14:52:33
a9eff38d 72+++ configure.in 2005-09-24 18:38:47
bd68c3c2 73@@ -552,6 +552,12 @@ if test x"$with_included_popt" != x"yes"
2c40f06f 74 AC_CHECK_LIB(popt, poptGetContext, , [with_included_popt=yes])
545864f1
WD
75 fi
76
a9eff38d
WD
77+AC_ARG_ENABLE(ODBC, AC_HELP_STRING([--enable-ODBC], [compile in support for ODBC database logging]),
78+ [ AC_CHECK_HEADERS(sql.h sqlext.h sqltypes.h)
2c40f06f
WD
79+ AC_CHECK_LIB(odbc,SQLExecDirect)
80+ EXTRA_OBJECT="$EXTRA_OBJECT dblog.o"
a9eff38d 81+ AC_SUBST(EXTRA_OBJECT) ])
545864f1 82+
2c40f06f 83 AC_MSG_CHECKING([whether to use included libpopt])
93ca4d27
WD
84 if test x"$with_included_popt" = x"yes"; then
85 AC_MSG_RESULT($srcdir/popt)
a9eff38d
WD
86--- orig/db_log_error-list.txt 2005-09-23 15:58:32
87+++ db_log_error-list.txt 2005-09-23 15:58:32
88@@ -0,0 +1,35 @@
89+error type description
90+0 not an error.
91+1 authentication
92+2 file/dir deletion failed
93+3 connection closed
94+4 read error
95+5 multiplexing overflow
96+6 unexpected tag
97+7 over long v-string received
98+8 invalid block length
99+9 invalid checksum length
100+10 invalid remainder length
101+11 failed to write error
102+12 attempting to send over-long vstring
103+13 temporary filename too long
104+14 lseek failed
105+15 write failed
106+16 rename failed
107+17 rsync hack failed
108+18 "invalid basis_dir index
109+19 fstat failed
110+20 is a directory
111+21 open file failed
112+22 mkstemp failed
113+23 close failed
114+24 failed verification
115+25 IO error, skipping deletion.
116+26 directory creation failed
117+27 ignoring unsafe symbolic link
118+28 symbolic link failed
119+29 mknod failed
120+30 failed to stat
121+31 unlink
122+32 failed to open file/directory
123+33 open?
124--- orig/dblog-tables-mysql.sql 2005-09-23 16:08:39
125+++ dblog-tables-mysql.sql 2005-09-23 16:08:39
126@@ -0,0 +1,64 @@
103bcb1d
WD
127+drop table transfer;
128+drop table exit;
129+drop table session;
130+
131+CREATE TABLE session (
132+ id int auto_increment NOT NULL,
133+ date timestamp NOT NULL,
134+ ip_address varchar(15) NOT NULL,
135+ username varchar(20) NOT NULL,
136+ module_name varchar(20) NOT NULL,
137+ module_path varchar(255) NOT NULL,
138+ process_id int NOT NULL,
139+ Primary Key (id)
140+);
141+
142+CREATE TABLE transfer (
143+ id int auto_increment NOT NULL,
144+ session_id int NOT NULL,
145+ date timestamp NOT NULL,
103bcb1d
WD
146+ file_name varchar(255) NOT NULL,
147+ file_size bigint NOT NULL,
148+ bytes_transferred bigint NOT NULL,
149+ checksum_bytes_transferred bigint NOT NULL,
150+ operation varchar(20),
151+ Primary Key (id),
152+ foreign key (session_id) references session (id)
153+);
154+
155+CREATE TABLE exit (
156+ id int auto_increment NOT NULL,
157+ session_id int NOT NULL,
158+ date timestamp NOT NULL,
159+ total_bytes_written bigint NOT NULL,
160+ total_bytes_read bigint NOT NULL,
161+ total_size bigint NOT NULL,
162+ error_text varchar(128) NOT NULL,
163+ error_code int NOT NULL,
164+ error_file varchar(64) NOT NULL,
165+ error_line int NOT NULL,
637ba3ff 166+ process_id int NOT NULL,
103bcb1d
WD
167+ Primary Key (id),
168+ foreign key (session_id) references session (id)
169+);
a9eff38d
WD
170+
171+CREATE TABLE error (
172+ id int auto_increment NOT NULL,
173+ session_id int NOT NULL,
174+ date timestamp NOT NULL,
175+ logcode bigint NOT NULL,
176+ error_number bigint NOT NULL,
177+ error_text varchar(512),
178+ PrimaryKey (id),
179+ foreign key (session_id) references session (id)
180+);
181+
182+CREATE TABLE delete (
183+ id serial NOT NULL,
184+ session_id int NOT NULL,
185+ date timestamp NOT NULL,
186+ path varchar(512) NOT NULL,
187+ mode int NOT NULL,
188+ PrimaryKey (id),
189+ foreign key (session_id) references session (id)
190+);
191--- orig/dblog-tables-postgresql.sql 2005-09-23 16:00:34
192+++ dblog-tables-postgresql.sql 2005-09-23 16:00:34
193@@ -0,0 +1,67 @@
103bcb1d
WD
194+drop table transfer;
195+drop table exit;
196+drop table session;
197+drop sequence session_id_seq;
198+create sequence session_id_seq;
199+
200+CREATE TABLE "session" (
201+ "id" int NOT NULL,
202+ "date" timestamp NOT NULL default now(),
203+ "ip_address" varchar(15) NOT NULL,
204+ "username" varchar(20) NOT NULL,
205+ "module_name" varchar(20) NOT NULL,
206+ "module_path" varchar(255) NOT NULL,
207+ "process_id" int NOT NULL,
208+ Primary Key (id)
209+);
210+
211+CREATE TABLE "transfer" (
212+ "id" serial NOT NULL,
213+ "session_id" int NOT NULL,
214+ "date" timestamp NOT NULL default now(),
103bcb1d
WD
215+ "file_name" varchar(512) NOT NULL,
216+ "file_size" bigint NOT NULL,
217+ "bytes_transferred" bigint NOT NULL,
218+ "checksum_bytes_transferred" bigint NOT NULL,
219+ "operation" varchar(20),
220+ Primary Key (id),
221+ foreign key (session_id) references session (id)
222+);
223+
224+CREATE TABLE "exit" (
225+ "id" serial NOT NULL,
226+ "session_id" int NOT NULL,
227+ "date" timestamp NOT NULL default now(),
228+ "total_bytes_written" bigint NOT NULL,
229+ "total_bytes_read" bigint NOT NULL,
230+ "total_size" bigint NOT NULL,
231+ "error_text" varchar(128) NOT NULL,
232+ "error_code" int NOT NULL,
233+ "error_file" varchar(64) NOT NULL,
234+ "error_line" int NOT NULL,
637ba3ff 235+ "process_id" int NOT NULL,
103bcb1d
WD
236+ Primary Key (id),
237+ foreign key (session_id) references session (id)
238+);
a9eff38d
WD
239+
240+CREATE TABLE "error" (
241+ "id" serial NOT NULL,
242+ "session_id" int NOT NULL,
243+ "date" timestamp NOT NULL default now(),
244+ "logcode" int NOT NULL,
245+ "error_number" int NOT NULL,
246+ "error_text" varchar(512),
247+ Primary Key (id),
248+ foreign key (session_id) references session (id)
249+
250+);
251+
252+CREATE TABLE "delete" (
253+ "id" serial NOT NULL,
254+ "session_id" int NOT NULL,
255+ "date" timestamp NOT NULL default now(),
256+ "path" varchar(512) NOT NULL,
257+ "mode" int NOT NULL,
258+ Primary Key (id),
259+ foreign key (session_id) references session (id)
260+);
261--- orig/dblog.c 2005-09-24 18:25:52
262+++ dblog.c 2005-09-24 18:25:52
263@@ -0,0 +1,549 @@
2c40f06f
WD
264+/*
265+ * ODBC Database logging functions
266+ *
267+ * Written by Steve Sether, April 2004
268+ * steve@vellmont.com
269+ */
270+
271+#include "rsync.h"
272+
637ba3ff 273+#ifdef HAVE_SQL_H
2c40f06f
WD
274+#include <sql.h>
275+#else
637ba3ff 276+#ifdef HAVE_ODBC_SQL_H
2c40f06f
WD
277+#include <odbc/sql.h>
278+#endif
279+#endif
280+
637ba3ff 281+#ifdef HAVE_SQLEXT_H
2c40f06f
WD
282+#include <sqlext.h>
283+#else
637ba3ff 284+#ifdef HAVE_ODBC_SQLEXT_H
2c40f06f
WD
285+#include <odbc/sqlext.h>
286+#endif
287+#endif
288+
637ba3ff 289+#ifdef HAVE_SQLTYPES_H
2c40f06f
WD
290+#include <sqltypes.h>
291+#else
637ba3ff 292+#ifdef HAVE_ODBC_SQLTYPES_H
2c40f06f
WD
293+#include <odbc/sqltypes.h>
294+#endif
295+#endif
296+
297+SQLHENV db_environ_handle; /* Handle ODBC environment */
298+long result; /* result of functions */
a9eff38d
WD
299+SQLHDBC db_handle_g = NULL; /* database connection handle for generator*/
300+SQLHDBC db_handle_r = NULL; /* database connection handle for sender */
301+SQLHSTMT sql_statement_handle_g; /* SQL statement handle for generator*/
302+SQLHSTMT sql_statement_handle_r; /* SQL statement handle for receiver*/
303+extern int am_daemon;
2c40f06f 304+extern int am_sender;
a9eff38d 305+extern int am_generator;
2c40f06f
WD
306+extern char *auth_user;
307+extern int module_id;
a9eff38d
WD
308+extern int dry_run;
309+
2c40f06f
WD
310+
311+char sql_status[10]; /* Status SQL */
312+SQLINTEGER V_OD_err, V_OD_rowanz, V_OD_id;
313+SQLSMALLINT V_OD_mlen, V_OD_colanz;
314+char V_OD_msg[200], V_OD_buffer[200];
315+SQLINTEGER session_id;
316+
317+
318+/* This function simply removes invalid characters from the SQL statement
319+ * to prevent SQL injection attacks. */
320+char *sanitizeSql(const char *input)
321+{
322+ char *out, *ptr;
323+ const char *c;
324+
325+ if (strlen(input) > ((~(unsigned int)0)>>1)-3)
326+ return 0;
327+ if (!(out = ptr = new_array(char, strlen(input) * 2 + 1)))
328+ return 0;
329+
330+ for (c = input; *c; c++) {
331+ switch (*c) {
332+ case '\'':
333+ *ptr++ = '\'';
334+ *ptr++ = '\'';
335+ break;
336+ case '\b':
337+ *ptr++ = '\\';
338+ *ptr++ = 'b';
339+ break;
340+ case '\n':
341+ *ptr++ = '\\';
342+ *ptr++ = 'n';
343+ break;
344+ case '\r':
345+ *ptr++ = '\\';
346+ *ptr++ = 'r';
347+ break;
348+ case '\t':
349+ *ptr++ = '\\';
350+ *ptr++ = 't';
351+ break;
352+ default:
353+ *ptr++ = *c;
354+ break;
355+ }
356+ }
357+ *ptr = '\0';
358+ return out;
359+}
360+
361+void db_log_open(void)
362+{
a9eff38d
WD
363+ if (!lp_database_logging(module_id))
364+ return;
2c40f06f 365+
a9eff38d
WD
366+ /* get ODBC environment handle */
367+ result = SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&db_environ_handle);
368+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
369+ rprintf(FERROR, "Error: couldn't get database environment handle\n");
370+ return;
371+ }
2c40f06f 372+
a9eff38d
WD
373+ /* Setting database enviroment */
374+ result = SQLSetEnvAttr(db_environ_handle, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
375+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
376+ rprintf(FERROR, "Error: couldn't set database environment.\n");
377+ SQLFreeHandle(SQL_HANDLE_ENV, db_environ_handle);
378+ db_environ_handle = NULL;
379+ return;
380+ }
381+ if (db_handle_g == NULL) {
382+ /* Get a database handle for the generator*/
383+ result = SQLAllocHandle(SQL_HANDLE_DBC, db_environ_handle, &db_handle_g);
384+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
385+ rprintf(FERROR, "Error: couldn't allocate database handle for generator\n");
386+ SQLFreeHandle(SQL_HANDLE_ENV, db_environ_handle);
387+ db_environ_handle = NULL;
388+ return;
389+ }
2c40f06f 390+
a9eff38d
WD
391+ /* Set connection attributes for the generator db connection */
392+ SQLSetConnectAttr(db_handle_g, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)5, 0);
2c40f06f 393+
a9eff38d
WD
394+ /* get the database connection for the generator. */
395+ result = SQLConnect(db_handle_g, (SQLCHAR*) lp_database_datasource(module_id), SQL_NTS,
396+ (SQLCHAR*) lp_database_username(module_id), SQL_NTS,
397+ (SQLCHAR*) lp_database_password(module_id), SQL_NTS);
2c40f06f 398+
a9eff38d
WD
399+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
400+ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle_g, 1,
401+ sql_status, &V_OD_err, V_OD_msg, 100, &V_OD_mlen);
402+ rprintf(FERROR,"Error Connecting to Database (generator) %s\n",V_OD_msg);
403+ SQLFreeHandle(SQL_HANDLE_DBC,db_handle_g);
404+ db_handle_g = NULL;
405+ SQLFreeHandle(SQL_HANDLE_ENV, db_environ_handle);
406+ db_environ_handle = NULL;
407+ return;
408+ }
409+ rprintf(FLOG,"Connected to database for generator!\n");
410+ } else {
411+ rprintf(FERROR,"Already connected to database for generator\n");
412+ }
413+ if (db_handle_r == NULL) {
414+ /* Get a database handle for the receiver */
415+ result = SQLAllocHandle(SQL_HANDLE_DBC, db_environ_handle, &db_handle_r);
416+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
417+ rprintf(FERROR, "Error: couldn't allocate database handle for receiver\n");
418+ SQLFreeHandle(SQL_HANDLE_ENV, db_environ_handle);
419+ db_environ_handle = NULL;
420+ return;
421+ }
2c40f06f 422+
a9eff38d
WD
423+ /* Set connection attributes for the receiver db connection */
424+ SQLSetConnectAttr(db_handle_r, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)5, 0);
425+
426+ /* get the generator connection for the receiver. */
427+ result = SQLConnect(db_handle_r, (SQLCHAR*) lp_database_datasource(module_id), SQL_NTS,
428+ (SQLCHAR*) lp_database_username(module_id), SQL_NTS,
429+ (SQLCHAR*) lp_database_password(module_id), SQL_NTS);
430+
431+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
432+ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle_r,1,
433+ sql_status, &V_OD_err,V_OD_msg,100,&V_OD_mlen);
434+ rprintf(FERROR,"Error Connecting to Database (receiver) %s\n",V_OD_msg);
435+ SQLFreeHandle(SQL_HANDLE_DBC,db_handle_r);
436+ db_handle_r = NULL;
437+ SQLFreeHandle(SQL_HANDLE_ENV, db_environ_handle);
438+ db_environ_handle = NULL;
439+ return;
2c40f06f 440+ }
a9eff38d
WD
441+ rprintf(FLOG,"Connected to database for receiver!\n");
442+ } else {
443+ rprintf(FERROR,"Already connected to database for receiver\n");
444+ }
445+
446+ /* get SQL statement handle for generator */
447+ result = SQLAllocHandle(SQL_HANDLE_STMT, db_handle_g, &sql_statement_handle_g);
448+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
449+ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle_g,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen);
450+ rprintf(FERROR,"Error in allocating SQL statement handle %s\n",V_OD_msg);
451+ SQLDisconnect(db_handle_g);
452+ SQLFreeHandle(SQL_HANDLE_DBC,db_handle_g);
453+ db_handle_g = NULL;
454+ SQLFreeHandle(SQL_HANDLE_ENV, db_environ_handle);
455+ db_environ_handle = NULL;
456+ return;
457+ }
458+
459+ /* get SQL statement handle for receiver */
460+ result = SQLAllocHandle(SQL_HANDLE_STMT, db_handle_r, &sql_statement_handle_r);
461+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
462+ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle_r,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen);
463+ rprintf(FERROR,"Error in allocating SQL statement handle %s\n",V_OD_msg);
464+ SQLDisconnect(db_handle_r);
465+ SQLFreeHandle(SQL_HANDLE_DBC,db_handle_r);
466+ db_handle_r = NULL;
467+ SQLFreeHandle(SQL_HANDLE_ENV, db_environ_handle);
468+ db_environ_handle = NULL;
469+ return;
2c40f06f
WD
470+ }
471+}
472+
473+void db_log_close()
474+{
a9eff38d
WD
475+ if (!lp_database_logging(module_id))
476+ return;
477+
478+ if (am_generator) {
479+ if (sql_statement_handle_g != NULL) {
2c40f06f 480+ /* free the statement handle first */
a9eff38d
WD
481+ SQLFreeHandle(SQL_HANDLE_STMT,sql_statement_handle_g);
482+ sql_statement_handle_g = NULL;
2c40f06f 483+ } else {
a9eff38d 484+ rprintf(FERROR,"No generator sql statement handle to close\n");
2c40f06f 485+ }
a9eff38d
WD
486+
487+ if (db_handle_g != NULL) {
2c40f06f 488+ /* disconnect, and free the database handle. */
a9eff38d
WD
489+ SQLDisconnect(db_handle_g);
490+ SQLFreeHandle(SQL_HANDLE_DBC,db_handle_g);
491+ db_handle_g = NULL;
2c40f06f 492+ } else {
a9eff38d 493+ rprintf(FERROR,"Generator database connection already closed\n");
2c40f06f 494+ }
a9eff38d
WD
495+ } else { /* must be receiver */
496+ if (sql_statement_handle_r != NULL) {
497+ /* free the statement handle first */
498+ SQLFreeHandle(SQL_HANDLE_STMT,sql_statement_handle_r);
499+ sql_statement_handle_r = NULL;
2c40f06f 500+ } else {
a9eff38d 501+ rprintf(FERROR,"No receiver sql statement handle to close\n");
2c40f06f 502+ }
a9eff38d
WD
503+
504+ if (db_handle_r != NULL) {
505+ /* disconnect, and free the database handle. */
506+ SQLDisconnect(db_handle_r);
507+ SQLFreeHandle(SQL_HANDLE_DBC,db_handle_r);
508+ db_handle_r = NULL;
509+ } else {
510+ rprintf(FERROR,"Receiver database connection already closed\n");
511+ }
512+ }
513+
514+ if (db_environ_handle != NULL) {
515+ /* free the environment handle */
516+ SQLFreeHandle(SQL_HANDLE_ENV, db_environ_handle);
517+ db_environ_handle = NULL;
518+ } else {
519+ rprintf(FERROR,"No environment handle to close\n");
2c40f06f
WD
520+ }
521+}
522+
523+static long get_unique_session_id()
524+{
525+ long unique;
526+ char strSqlStatement[1024];
a9eff38d
WD
527+ SQLHDBC db_handle = (am_generator) ? db_handle_g : db_handle_r;
528+ SQLHSTMT sql_statement_handle = (am_generator) ? sql_statement_handle_g : sql_statement_handle_r;
2c40f06f
WD
529+
530+ if (db_handle != NULL) {
531+ /* choose the appropriate select statement based upon which DBMS we're using.
532+ * different datbases use different methods to get a unique ID. Some use a counter
533+ * object (sequence), others use an auto increment datatype and have a method
534+ * to get the last ID inserted using this connection. */
535+ if (strcmp(lp_unique_id_method(module_id),"nextval-postgresql") == 0) {
a9eff38d
WD
536+ snprintf(strSqlStatement, sizeof strSqlStatement,
537+ "SELECT NEXTVAL('%s');", lp_sequence_name(module_id));
2c40f06f 538+ } else if (strcmp(lp_unique_id_method(module_id),"nextval-oracle") == 0) {
a9eff38d
WD
539+ snprintf(strSqlStatement, sizeof strSqlStatement,
540+ "SELECT %s.NEXTVAL FROM dual;", lp_sequence_name(module_id));
2c40f06f 541+ } else if (strcmp(lp_unique_id_method(module_id),"nextval-db2") == 0) {
a9eff38d
WD
542+ snprintf(strSqlStatement, sizeof strSqlStatement,
543+ "VALUES NEXTVAL FOR %s;",lp_sequence_name(module_id));
544+ } else if (strcmp(lp_unique_id_method(module_id),"last_insert_id") == 0) { /* MySql */
545+ snprintf(strSqlStatement, sizeof strSqlStatement,
546+ "SELECT LAST_INSERT_ID()");
547+ } else if (strcmp(lp_unique_id_method(module_id),"@@IDENTITY") == 0) { /* Sybase */
548+ snprintf(strSqlStatement, sizeof strSqlStatement,
549+ "SELECT @@IDENTITY");
550+ } else if (strcmp(lp_unique_id_method(module_id),"custom") == 0){ /* Users custom statement */
551+ snprintf(strSqlStatement, sizeof strSqlStatement,
552+ lp_custom_unique_id_select(module_id));
2c40f06f
WD
553+ }
554+
555+ /* bind the 1st column to unique */
556+ SQLBindCol(sql_statement_handle,1,SQL_C_LONG,&unique,150,&V_OD_err);
557+ /* execute the SQL statement */
558+ result = SQLExecDirect(sql_statement_handle,strSqlStatement,SQL_NTS);
559+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
560+ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen);
561+ rprintf(FERROR,"Error at get_sequence: Error in Select! %s %s\n",strSqlStatement,V_OD_msg);
562+ } else {
563+ result = SQLFetch(sql_statement_handle);
564+ if (result != SQL_NO_DATA && unique != 0) {
565+ rprintf(FINFO,"Got unique sequence! %ld\n",unique);
566+ } else {
567+ rprintf(FERROR,"Error at get_sequence: Didn't get unique session ID\n");
568+ }
569+ /* Close the cursor so the statement can be re-used */
570+ result = SQLFreeStmt(sql_statement_handle,SQL_CLOSE);
571+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
572+ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen);
573+ rprintf(FERROR,"Error at get_sequence: Error in closing SQL statement handle %s\n",V_OD_msg);
574+ return unique;
575+ }
576+ return unique;
577+ }
578+ }
579+ rprintf(FERROR,"Error at get_sequence: Not connected to database\n");
580+ return -1;
581+}
582+
2c40f06f
WD
583+void db_log_session()
584+{
585+ char strSqlStatement[1024];
586+ int gotSessionID = 0;
a9eff38d
WD
587+ SQLHDBC db_handle = (am_generator) ? db_handle_g : db_handle_r;
588+ SQLHSTMT sql_statement_handle = (am_generator) ? sql_statement_handle_g : sql_statement_handle_r;
589+
590+ if (!lp_database_logging(module_id))
591+ return;
592+
593+ if (db_handle != NULL) {
594+ /* if we're using a sequence via the nextval command to
595+ * get a unique ID, we need to get it before we do the
596+ * insert. We also get the unique ID now if custom,
597+ * and get_custom_id_before_insert is set. */
2c40f06f 598+ if (strcmp(lp_unique_id_method(module_id),"nextval-postgresql") == 0
a9eff38d
WD
599+ || strcmp(lp_unique_id_method(module_id),"nextval-oracle") == 0
600+ || strcmp(lp_unique_id_method(module_id),"nextval-db2") == 0
601+ || (strcmp(lp_unique_id_method(module_id),"custom") == 0
602+ && lp_get_custom_id_before_insert(module_id))) {
2c40f06f
WD
603+ session_id = get_unique_session_id();
604+ gotSessionID = 1;
a9eff38d
WD
605+ snprintf(strSqlStatement, sizeof strSqlStatement,
606+ "INSERT INTO %s (id, date, ip_address, username, module_name, module_path, process_id) VALUES ('%ld', '%s', '%s', '%s','%s','%s','%d');",
607+ lp_session_table_name(module_id), session_id, timestring(time(NULL)), client_addr(0),
608+ auth_user, lp_name(module_id), lp_path(module_id), getpid());
2c40f06f
WD
609+ } else {
610+ /* Otherwise the ID gets created automatically, and we get the ID it used after the insert. */
a9eff38d
WD
611+ snprintf(strSqlStatement, sizeof strSqlStatement,
612+ "INSERT INTO %s (date, ip_address, username, module_name, module_path, process_id) VALUES ('%s', '%s', '%s', '%s','%s','%d');",
613+ lp_session_table_name(module_id), timestring(time(NULL)), client_addr(0), auth_user,
614+ lp_name(module_id), lp_path(module_id), getpid());
2c40f06f
WD
615+ }
616+
617+ /* Insert the new session into the database */
618+ result = SQLExecDirect(sql_statement_handle,strSqlStatement,SQL_NTS);
619+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
620+ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen);
621+ rprintf(FERROR,"Error at db_log_session: Error in Insert %s %s\n",strSqlStatement,V_OD_msg);
622+ }
623+
624+ /* close the cursor so the statement handle can be re-used. */
625+ result = SQLFreeStmt(sql_statement_handle,SQL_CLOSE);
626+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
627+ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen);
628+ rprintf(FERROR,"Error in resetting SQL statement handle %s\n",V_OD_msg);
629+ }
630+ /* get the session ID for databases that give the unique ID after an insert */
631+ if (gotSessionID == 0) {
632+ session_id = get_unique_session_id();
633+ }
a9eff38d 634+ } else {
2c40f06f
WD
635+ rprintf(FERROR,"Error at db_log_session: Not connected to database!\n");
636+ }
637+}
638+
639+void db_log_transfer(struct file_struct *file,struct stats *initial_stats,char *operation)
640+{
641+ extern struct stats stats;
637ba3ff
WD
642+ char strSqlStatement[2048];
643+ char strFileName[MAXPATHLEN];
644+ char *strFileNamePtr;
2c40f06f
WD
645+ char strFileSize[255];
646+ int64 intBytesTransferred;
647+ int64 intCheckSumBytes;
a9eff38d
WD
648+ SQLHDBC db_handle = (am_generator) ? db_handle_g : db_handle_r;
649+ SQLHSTMT sql_statement_handle = (am_generator) ? sql_statement_handle_g : sql_statement_handle_r;
2c40f06f 650+
a9eff38d
WD
651+ if (!lp_database_logging(module_id))
652+ return;
637ba3ff 653+
a9eff38d 654+ if (db_handle != NULL) {
bd68c3c2 655+ strFileNamePtr = f_name(file, NULL);
a9eff38d
WD
656+ if (am_sender && file->dir.root) {
657+ pathjoin(strFileName, sizeof strFileName,
658+ file->dir.root, strFileNamePtr);
659+ strFileNamePtr = strFileName;
660+ }
661+ clean_fname(strFileNamePtr, 0);
662+ if (*strFileNamePtr == '/')
663+ strFileNamePtr++;
2c40f06f 664+
a9eff38d
WD
665+ snprintf(strFileSize, sizeof strFileSize, "%.0f", (double)file->length);
666+ if (am_sender) {
667+ intBytesTransferred = stats.total_written - initial_stats->total_written;
668+ } else {
669+ intBytesTransferred = stats.total_read - initial_stats->total_read;
670+ }
2c40f06f 671+
a9eff38d
WD
672+ if (!am_sender) {
673+ intCheckSumBytes = stats.total_written - initial_stats->total_written;
2c40f06f 674+ } else {
a9eff38d 675+ intCheckSumBytes = stats.total_read - initial_stats->total_read;
2c40f06f 676+ }
a9eff38d
WD
677+
678+ snprintf(strSqlStatement, sizeof strSqlStatement,
679+ "INSERT INTO %s (session_id,date, file_name, file_size, bytes_transferred, checksum_bytes_transferred, operation) VALUES ('%ld','%s','%s','%s','%Ld','%Ld','%s');",
680+ lp_transfer_table_name(module_id), session_id, timestring(time(NULL)),
681+ sanitizeSql(strFileNamePtr), strFileSize, intBytesTransferred,
682+ intCheckSumBytes, operation);
683+ result = SQLExecDirect(sql_statement_handle,strSqlStatement,SQL_NTS);
684+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
685+ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen);
686+ rprintf(FERROR,"Error at db_log_transfer: Error in Insert %s %s\n",strSqlStatement,V_OD_msg);
687+ if (result == SQL_INVALID_HANDLE)
688+ rprintf(FERROR,"INVALID HANDLE\n");
689+ }
690+ } else {
691+ rprintf(FERROR,"Error at db_log_transfer: Not connected to database!\n");
2c40f06f
WD
692+ }
693+}
694+
2c40f06f
WD
695+void db_log_exit(int code, const char *file, int line)
696+{
697+ char strSqlStatement[2048];
698+ const char *error_text;
699+ extern struct stats stats;
a9eff38d
WD
700+ SQLHDBC db_handle = (am_generator) ? db_handle_g : db_handle_r;
701+ SQLHSTMT sql_statement_handle = (am_generator) ? sql_statement_handle_g : sql_statement_handle_r;
702+
703+ if (!lp_database_logging(module_id))
704+ return;
705+
2c40f06f 706+ if (db_handle != NULL) {
a9eff38d
WD
707+ if (code != 0) {
708+ error_text = rerr_name(code);
709+ if (!error_text) {
710+ error_text = "unexplained error";
2c40f06f 711+ }
a9eff38d
WD
712+ } else {
713+ error_text = "";
714+ }
715+ snprintf(strSqlStatement, sizeof strSqlStatement,
716+ "INSERT INTO %s (session_id, date, total_bytes_written,total_bytes_read,total_size,error_text,error_code,error_file,error_line,process_id) VALUES ('%ld','%s','%Ld','%Ld','%Ld','%s','%d','%s','%d','%d');",
717+ lp_exit_table_name(module_id), session_id, timestring(time(NULL)), stats.total_written,
718+ stats.total_read, stats.total_size, error_text, code, file, line, getpid());
2c40f06f 719+
a9eff38d 720+ result = SQLExecDirect(sql_statement_handle,strSqlStatement,SQL_NTS);
2c40f06f 721+
a9eff38d
WD
722+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
723+ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen);
724+ rprintf(FERROR,"Error at db_log_exit: Error in Insert %s %s\n",strSqlStatement,V_OD_msg);
2c40f06f
WD
725+ }
726+ } else {
727+ rprintf(FERROR,"Error at db_log_exit: Not connected to database!\n");
728+ }
729+}
a9eff38d
WD
730+
731+void db_log_delete(char *fname, int mode)
732+{
733+ char strSqlStatement[2048];
734+ SQLHDBC db_handle = (am_generator) ? db_handle_g : db_handle_r;
735+ SQLHSTMT sql_statement_handle = (am_generator) ? sql_statement_handle_g : sql_statement_handle_r;
736+
737+ if (!am_daemon || dry_run || !lp_database_logging(module_id))
738+ return;
739+
740+ if (db_handle != NULL) {
741+ snprintf(strSqlStatement, sizeof strSqlStatement,
742+ "INSERT INTO %s (session_id, date, path, mode) VALUES ('%ld','%s','%s','%d');",
743+ lp_delete_table_name(module_id), session_id, timestring(time(NULL)), sanitizeSql(fname), mode);
744+
745+ result = SQLExecDirect(sql_statement_handle,strSqlStatement,SQL_NTS);
746+
747+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
748+ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen);
749+ rprintf(FERROR,"Error at db_log_delete: Error in Insert %s %s\n",strSqlStatement,V_OD_msg);
750+ }
751+ } else {
752+ rprintf(FERROR,"Error at db_log_delete: Not connected to database!\n");
753+ }
754+}
755+
756+void db_log_error(enum logcode code, int errcode, const char *format,...)
757+{
758+ char strSqlStatement[MAXPATHLEN+1024];
759+ va_list ap;
760+ char buf[MAXPATHLEN+512];
761+ size_t len;
762+ SQLHDBC db_handle = (am_generator) ? db_handle_g : db_handle_r;
763+ SQLHSTMT sql_statement_handle = (am_generator) ? sql_statement_handle_g : sql_statement_handle_r;
764+
765+ if (!lp_database_logging(module_id))
766+ return;
767+
768+ va_start(ap, format);
769+ len = vsnprintf(buf, sizeof buf, format, ap);
770+ va_end(ap);
771+
772+ /* Deal with buffer overruns. Instead of panicking, just
773+ * truncate the resulting string. (Note that configure ensures
774+ * that we have a vsnprintf() that doesn't ever return -1.) */
775+ if (len > sizeof buf - 1) {
776+ const char ellipsis[] = "[...]";
777+
778+ /* Reset length, and zero-terminate the end of our buffer */
779+ len = sizeof buf - 1;
780+ buf[len] = '\0';
781+
782+ /* Copy the ellipsis to the end of the string, but give
783+ * us one extra character:
784+ *
785+ * v--- null byte at buf[sizeof buf - 1]
786+ * abcdefghij0
787+ * -> abcd[...]00 <-- now two null bytes at end
788+ *
789+ * If the input format string has a trailing newline,
790+ * we copy it into that extra null; if it doesn't, well,
791+ * all we lose is one byte. */
792+ strncpy(buf+len-sizeof ellipsis, ellipsis, sizeof ellipsis);
793+ if (format[strlen(format)-1] == '\n') {
794+ buf[len-1] = '\n';
795+ }
796+ }
797+
798+ if (db_handle != NULL) {
799+ snprintf(strSqlStatement, sizeof strSqlStatement,
800+ "INSERT INTO %s (session_id, date, logcode, error_number, error_text) VALUES ('%ld','%s','%d','%d','%s');",
801+ lp_error_table_name(module_id), session_id, timestring(time(NULL)), code, errcode, sanitizeSql(buf));
802+
803+ result = SQLExecDirect(sql_statement_handle,strSqlStatement,SQL_NTS);
804+
805+ if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
806+ SQLGetDiagRec(SQL_HANDLE_DBC, db_handle,1, sql_status,&V_OD_err,V_OD_msg,100,&V_OD_mlen);
807+ rprintf(FERROR,"Error at db_log_error: Error in Insert %s %s\n",strSqlStatement,V_OD_msg);
808+ }
809+ } else {
810+ rprintf(FERROR,"Error at db_log_error: Not connected to database!\n");
811+ }
812+}
813--- orig/instructions 2005-09-23 15:58:24
814+++ instructions 2005-09-23 15:58:24
815@@ -0,0 +1,84 @@
816+This patch adds the following options:
817+
818+"database logging"
819+ If set to True, rsync will attempt to connect to
820+ the specified datasource and write to the named tables.
821+ Defaults to False.
822+
823+"database datasource"
824+ Specifies the name of the ODBC data source to use.
825+
826+"database username"
827+ The username to use when connecting to the database.
828+
829+"database password"
830+ The password to use when connecting to the database.
831+
832+"transfer table name"
833+ The name of the transfer table to log to. This table contains individual
834+ filenames, file sizes, bytes transferred, checksum bytes transferred,
835+ operation (send or receive), and a timestamp.
836+
837+"session table name"
838+ The name of the session table to log to. This table contains the username,
839+ module name, module path, ip address, process ID, and a timestamp.
840+
841+"exit table name"
842+
843+ The name of the exit table to log to. This table contains the total bytes
844+ read, total bytes written, total size of all files, error code, line the
845+ error occured at, file the error occured at and the text of the error.
846+ (most of which will be blank if the program exited normally).
847+
848+"delete table name"
849+
850+ The name of the table to log deleted files/directories to.
851+
852+"error table name"
853+
854+ The name of the table errors will be logged to.
855+
856+"unique id method"
857+ Different databases use different methods to get a unique identifier.
858+ Some databases support sequence objects, and use various forms of the
859+ nextval command to retrieve a unique identifier from it. Other databases
860+ support an autonumber field, and support different methds of retrieving
861+ the ID used in the last insert. Valid values for this option are:
862+
863+ nextval-postgres
864+ uses the syntax of nextval for PostgreSQL databases
865+
866+ nextval-oracle
867+ uses the syntax of nextval for Oracle databases
868+
869+ nextval-db2
870+ uses the syntax of nextval for DB2 databases
871+
872+ last_insert_id
873+ uses the last_insert_id() command for the MySQL databases
874+
875+ @@IDENTITY
876+ uses the @@IDENTITY command for Sybase databases
877+
878+ custom
879+ Define your own method to get a unique identifier. See the
880+ "custom unique id select", and the "get custom id before select"
881+ parameters.
882+
883+"sequence name"
884+ If your database supports sequences, list the name of the sequence to use
885+ for the session unique identifier.
886+
887+"custom unique id select"
888+ Only used if you specify the custom method in "unique id method". This is
889+ a SQL statement to be executed to get a unique ID. This SQL statement must
890+ return one column with the unique ID to use for the session ID. Should be
891+ used in concert with the "get custom id before select" parameter.
892+
893+"get custom id before insert"
894+ This parameter is ignored unless the "unique id method" is set to custom.
895+ If set to true, the "custom unique id select" statement will be executed
896+ BEFORE the session row is inserted into the database. (as is done when a
897+ sequence is used for unique IDs). If False the statement will be executed
898+ after the session row is inserted (as is done when the session ID is
899+ automatically generates unique IDs). Defaults to True.
32f6df4b 900--- orig/loadparm.c 2005-09-19 17:21:10
a9eff38d
WD
901+++ loadparm.c 2005-09-24 18:29:59
902@@ -120,9 +120,16 @@ typedef struct
51b0132f
WD
903 {
904 char *auth_users;
905 char *comment;
906+ char *custom_unique_id_select;
2c40f06f 907+ char *database_datasource;
2c40f06f 908+ char *database_password;
51b0132f 909+ char *database_username;
a9eff38d 910+ char *delete_table_name;
51b0132f 911 char *dont_compress;
a9eff38d 912+ char *error_table_name;
51b0132f
WD
913 char *exclude;
914 char *exclude_from;
2c40f06f 915+ char *exit_table_name;
51b0132f
WD
916 char *filter;
917 char *gid;
918 char *hosts_allow;
a9eff38d 919@@ -137,13 +144,19 @@ typedef struct
51b0132f
WD
920 char *prexfer_exec;
921 char *refuse_options;
922 char *secrets_file;
2c40f06f 923+ char *sequence_name;
51b0132f
WD
924+ char *session_table_name;
925 char *temp_dir;
926+ char *transfer_table_name;
927 char *uid;
2c40f06f 928+ char *unique_id_method;
51b0132f
WD
929
930 int max_connections;
931 int max_verbosity;
932 int timeout;
933
934+ BOOL database_logging;
2c40f06f
WD
935+ BOOL get_custom_id_before_insert;
936 BOOL ignore_errors;
51b0132f
WD
937 BOOL ignore_nonreadable;
938 BOOL list;
a9eff38d 939@@ -163,9 +176,16 @@ static service sDefault =
51b0132f 940 {
32f6df4b
WD
941 /* auth_users; */ NULL,
942 /* comment; */ NULL,
943+ /* custom_unique_id_select; */ NULL,
944+ /* database_datasource; */ NULL,
945+ /* database_password; */ NULL,
946+ /* database_username; */ NULL,
a9eff38d 947+ /* delete_table_name; */ NULL,
32f6df4b 948 /* dont_compress; */ "*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz",
a9eff38d 949+ /* error_table_name; */ NULL,
32f6df4b
WD
950 /* exclude; */ NULL,
951 /* exclude_from; */ NULL,
952+ /* exit_table_name; */ NULL,
953 /* filter; */ NULL,
954 /* gid; */ NOBODY_GROUP,
955 /* hosts_allow; */ NULL,
a9eff38d 956@@ -180,13 +200,19 @@ static service sDefault =
32f6df4b
WD
957 /* prexfer_exec; */ NULL,
958 /* refuse_options; */ NULL,
959 /* secrets_file; */ NULL,
960+ /* sequence_name; */ NULL,
961+ /* session_table_name; */ NULL,
962 /* temp_dir; */ NULL,
963+ /* transfer_table_name; */ NULL,
964 /* uid; */ NOBODY_USER,
965+ /* unique_id_method; */ NULL,
51b0132f 966
32f6df4b
WD
967 /* max_connections; */ 0,
968 /* max_verbosity; */ 1,
969 /* timeout; */ 0,
51b0132f 970
32f6df4b
WD
971+ /* database_logging; */ False,
972+ /* get_custom_id_before_insert; */ True,
973 /* ignore_errors; */ False,
974 /* ignore_nonreadable; */ False,
975 /* list; */ True,
a9eff38d 976@@ -287,10 +313,19 @@ static struct parm_struct parm_table[] =
51b0132f
WD
977
978 {"auth users", P_STRING, P_LOCAL, &sDefault.auth_users, NULL,0},
979 {"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL,0},
980+ {"custom unique id select",P_STRING,P_LOCAL,&sDefault.custom_unique_id_select,NULL,0},
981+ {"database datasource",P_STRING,P_LOCAL, &sDefault.database_datasource,NULL,0},
982+ {"database logging", P_BOOL, P_LOCAL, &sDefault.database_logging, NULL,0},
983+ {"database password", P_STRING, P_LOCAL, &sDefault.database_password, NULL,0},
984+ {"database username", P_STRING, P_LOCAL, &sDefault.database_username, NULL,0},
a9eff38d 985+ {"delete table name", P_STRING, P_LOCAL, &sDefault.delete_table_name, NULL,0},
51b0132f 986 {"dont compress", P_STRING, P_LOCAL, &sDefault.dont_compress, NULL,0},
a9eff38d 987+ {"error table name", P_STRING, P_LOCAL, &sDefault.error_table_name, NULL,0},
51b0132f
WD
988 {"exclude from", P_STRING, P_LOCAL, &sDefault.exclude_from, NULL,0},
989 {"exclude", P_STRING, P_LOCAL, &sDefault.exclude, NULL,0},
990+ {"exit table name", P_STRING, P_LOCAL, &sDefault.exit_table_name, NULL,0},
991 {"filter", P_STRING, P_LOCAL, &sDefault.filter, NULL,0},
992+ {"get custom id before insert",P_BOOL,P_LOCAL,&sDefault.get_custom_id_before_insert,NULL,0},
993 {"gid", P_STRING, P_LOCAL, &sDefault.gid, NULL,0},
994 {"hosts allow", P_STRING, P_LOCAL, &sDefault.hosts_allow, NULL,0},
995 {"hosts deny", P_STRING, P_LOCAL, &sDefault.hosts_deny, NULL,0},
a9eff38d
WD
996@@ -312,11 +347,15 @@ static struct parm_struct parm_table[] =
997 {"read only", P_BOOL, P_LOCAL, &sDefault.read_only, NULL,0},
998 {"refuse options", P_STRING, P_LOCAL, &sDefault.refuse_options, NULL,0},
999 {"secrets file", P_STRING, P_LOCAL, &sDefault.secrets_file, NULL,0},
51b0132f
WD
1000+ {"sequence name", P_STRING, P_LOCAL, &sDefault.sequence_name, NULL,0},
1001+ {"session table name",P_STRING, P_LOCAL, &sDefault.session_table_name,NULL,0},
a9eff38d
WD
1002 {"strict modes", P_BOOL, P_LOCAL, &sDefault.strict_modes, NULL,0},
1003 {"temp dir", P_PATH, P_LOCAL, &sDefault.temp_dir, NULL,0},
1004 {"timeout", P_INTEGER,P_LOCAL, &sDefault.timeout, NULL,0},
1005 {"transfer logging", P_BOOL, P_LOCAL, &sDefault.transfer_logging, NULL,0},
51b0132f 1006+ {"transfer table name",P_STRING,P_LOCAL, &sDefault.transfer_table_name,NULL,0},
a9eff38d 1007 {"uid", P_STRING, P_LOCAL, &sDefault.uid, NULL,0},
51b0132f 1008+ {"unique id method", P_STRING, P_LOCAL, &sDefault.unique_id_method, NULL,0},
a9eff38d
WD
1009 {"use chroot", P_BOOL, P_LOCAL, &sDefault.use_chroot, NULL,0},
1010 {"write only", P_BOOL, P_LOCAL, &sDefault.write_only, NULL,0},
1011 {NULL, P_BOOL, P_NONE, NULL, NULL,0}
1012@@ -377,9 +416,16 @@ FN_GLOBAL_INTEGER(lp_syslog_facility, &G
51b0132f
WD
1013
1014 FN_LOCAL_STRING(lp_auth_users, auth_users)
1015 FN_LOCAL_STRING(lp_comment, comment)
1016+FN_LOCAL_STRING(lp_custom_unique_id_select,custom_unique_id_select)
2c40f06f 1017+FN_LOCAL_STRING(lp_database_datasource, database_datasource)
2c40f06f 1018+FN_LOCAL_STRING(lp_database_password, database_password)
51b0132f 1019+FN_LOCAL_STRING(lp_database_username, database_username)
a9eff38d 1020+FN_LOCAL_STRING(lp_delete_table_name,delete_table_name)
51b0132f 1021 FN_LOCAL_STRING(lp_dont_compress, dont_compress)
a9eff38d 1022+FN_LOCAL_STRING(lp_error_table_name,error_table_name)
51b0132f
WD
1023 FN_LOCAL_STRING(lp_exclude, exclude)
1024 FN_LOCAL_STRING(lp_exclude_from, exclude_from)
2c40f06f 1025+FN_LOCAL_STRING(lp_exit_table_name, exit_table_name)
51b0132f
WD
1026 FN_LOCAL_STRING(lp_filter, filter)
1027 FN_LOCAL_STRING(lp_gid, gid)
1028 FN_LOCAL_STRING(lp_hosts_allow, hosts_allow)
a9eff38d 1029@@ -394,13 +440,19 @@ FN_LOCAL_STRING(lp_postxfer_exec, postxf
51b0132f
WD
1030 FN_LOCAL_STRING(lp_prexfer_exec, prexfer_exec)
1031 FN_LOCAL_STRING(lp_refuse_options, refuse_options)
1032 FN_LOCAL_STRING(lp_secrets_file, secrets_file)
2c40f06f 1033+FN_LOCAL_STRING(lp_sequence_name,sequence_name)
51b0132f
WD
1034+FN_LOCAL_STRING(lp_session_table_name,session_table_name)
1035 FN_LOCAL_STRING(lp_temp_dir, temp_dir)
1036+FN_LOCAL_STRING(lp_transfer_table_name, transfer_table_name)
1037 FN_LOCAL_STRING(lp_uid, uid)
2c40f06f 1038+FN_LOCAL_STRING(lp_unique_id_method,unique_id_method)
51b0132f
WD
1039
1040 FN_LOCAL_INTEGER(lp_max_connections, max_connections)
1041 FN_LOCAL_INTEGER(lp_max_verbosity, max_verbosity)
1042 FN_LOCAL_INTEGER(lp_timeout, timeout)
1043
1044+FN_LOCAL_BOOL(lp_database_logging, database_logging)
2c40f06f
WD
1045+FN_LOCAL_BOOL(lp_get_custom_id_before_insert,get_custom_id_before_insert)
1046 FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors)
1047 FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable)
51b0132f 1048 FN_LOCAL_BOOL(lp_list, list)
bd68c3c2 1049--- orig/log.c 2006-01-17 02:16:40
a9eff38d 1050+++ log.c 2005-09-23 16:01:13
bd68c3c2 1051@@ -87,7 +87,7 @@ struct {
2c40f06f
WD
1052 /*
1053 * Map from rsync error code to name, or return NULL.
1054 */
1055-static char const *rerr_name(int code)
1056+char const *rerr_name(int code)
1057 {
1058 int i;
1059 for (i = 0; rerr_names[i].name; i++) {
bd68c3c2 1060--- orig/main.c 2006-01-15 14:46:15
a9eff38d 1061+++ main.c 2005-09-23 16:01:22
6849cd84 1062@@ -159,6 +159,9 @@ static void handle_stats(int f)
2c40f06f
WD
1063
1064 if (am_daemon) {
1065 log_exit(0, __FILE__, __LINE__);
637ba3ff 1066+#ifdef HAVE_LIBODBC
2c40f06f
WD
1067+ db_log_exit(0,__FILE__,__LINE__);
1068+#endif
7628f156
WD
1069 if (f == -1 || !am_sender)
1070 return;
2c40f06f 1071 }
bd68c3c2 1072--- orig/receiver.c 2006-01-14 20:27:09
93ca4d27
WD
1073+++ receiver.c 2006-01-14 08:27:51
1074@@ -174,6 +174,10 @@ static int get_tmpname(char *fnametmp, c
1075
a9eff38d 1076 if (maxname < 1) {
93ca4d27 1077 rprintf(FERROR, "temporary filename too long: %s\n", fname);
a9eff38d
WD
1078+#ifdef HAVE_LIBODBC
1079+ db_log_error(FERROR,13, "temporary filename too long: %s\n",
93ca4d27 1080+ fname);
a9eff38d
WD
1081+#endif
1082 fnametmp[0] = '\0';
1083 return 0;
1084 }
93ca4d27 1085@@ -290,6 +294,11 @@ static int receive_data(int f_in, char *
a9eff38d
WD
1086 rsyserr(FERROR, errno,
1087 "lseek failed on %s",
1088 full_fname(fname));
1089+#ifdef HAVE_LIBODBC
1090+ db_log_error(FERROR, 14,
1091+ "lseek failed on %s",
1092+ full_fname(fname));
1093+#endif
1094 exit_cleanup(RERR_FILEIO);
1095 }
1096 continue;
93ca4d27 1097@@ -315,6 +324,9 @@ static int receive_data(int f_in, char *
a9eff38d
WD
1098 report_write_error:
1099 rsyserr(FERROR, errno, "write failed on %s",
1100 full_fname(fname));
1101+#ifdef HAVE_LIBODBC
1102+ db_log_error(FERROR, 15, "write failed on %s",full_fname(fname));
1103+#endif
1104 exit_cleanup(RERR_FILEIO);
1105 }
1106
93ca4d27
WD
1107@@ -358,6 +370,12 @@ static void handle_delayed_updates(struc
1108 rsyserr(FERROR, errno,
a9eff38d 1109 "rename failed for %s (from %s)",
93ca4d27 1110 full_fname(fname), partialptr);
a9eff38d
WD
1111+#ifdef HAVE_LIBODBC
1112+ db_log_error(FERROR, 16,
1113+ "rename failed for %s (from %s)",
1114+ full_fname(fname),
93ca4d27 1115+ partialptr);
a9eff38d
WD
1116+#endif
1117 } else {
1118 if (remove_sent_files
1119 || (preserve_hard_links
93ca4d27 1120@@ -480,6 +498,9 @@ int recv_files(int f_in, struct file_lis
a9eff38d
WD
1121 if (server_filter_list.head
1122 && check_filter(&server_filter_list, fname, 0) < 0) {
1123 rprintf(FERROR, "attempt to hack rsync failed.\n");
1124+#ifdef HAVE_LIBODBC
1125+ db_log_error(FERROR,17,"attempt to hack rsync failed.");
1126+#endif
1127 exit_cleanup(RERR_PROTOCOL);
1128 }
1129
93ca4d27 1130@@ -535,6 +556,11 @@ int recv_files(int f_in, struct file_lis
a9eff38d
WD
1131 rprintf(FERROR,
1132 "invalid basis_dir index: %d.\n",
1133 fnamecmp_type);
1134+#ifdef HAVE_LIBODBC
1135+ db_log_error(FERROR, 18,
1136+ "invalid basis_dir index: %d.\n",
1137+ fnamecmp_type);
1138+#endif
1139 exit_cleanup(RERR_PROTOCOL);
1140 }
1141 pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
93ca4d27 1142@@ -580,6 +606,9 @@ int recv_files(int f_in, struct file_lis
a9eff38d
WD
1143 if (fd1 != -1 && do_fstat(fd1,&st) != 0) {
1144 rsyserr(FERROR, errno, "fstat %s failed",
1145 full_fname(fnamecmp));
1146+#ifdef HAVE_LIBODBC
1147+ db_log_error(FERROR, 19,"fstat %s failed",full_fname(fnamecmp));
1148+#endif
1149 discard_receive_data(f_in, file->length);
1150 close(fd1);
1151 continue;
93ca4d27 1152@@ -593,6 +622,9 @@ int recv_files(int f_in, struct file_lis
a9eff38d
WD
1153 */
1154 rprintf(FERROR,"recv_files: %s is a directory\n",
1155 full_fname(fnamecmp));
1156+#ifdef HAVE_LIBODBC
1157+ db_log_error(FERROR,20,"recv_files: %s is a directory",full_fname(fnamecmp));
1158+#endif
1159 discard_receive_data(f_in, file->length);
1160 close(fd1);
1161 continue;
93ca4d27 1162@@ -616,6 +648,9 @@ int recv_files(int f_in, struct file_lis
a9eff38d
WD
1163 if (fd2 == -1) {
1164 rsyserr(FERROR, errno, "open %s failed",
1165 full_fname(fname));
1166+#ifdef HAVE_LIBODBC
1167+ db_log_error(FERROR,22, "open %s failed", full_fname(fname));
1168+#endif
1169 discard_receive_data(f_in, file->length);
1170 if (fd1 != -1)
1171 close(fd1);
93ca4d27 1172@@ -649,6 +684,10 @@ int recv_files(int f_in, struct file_lis
a9eff38d
WD
1173 if (fd2 == -1) {
1174 rsyserr(FERROR, errno, "mkstemp %s failed",
1175 full_fname(fnametmp));
1176+#ifdef HAVE_LIBODBC
1177+ db_log_error(FERROR, 22, "mkstemp %s failed",
1178+ full_fname(fnametmp));
1179+#endif
1180 discard_receive_data(f_in, file->length);
1181 if (fd1 != -1)
1182 close(fd1);
93ca4d27 1183@@ -671,12 +710,19 @@ int recv_files(int f_in, struct file_lis
2c40f06f 1184
4e75164f 1185 if (!log_before_transfer)
d608ca23 1186 log_item(file, &initial_stats, iflags, NULL);
637ba3ff 1187+#ifdef HAVE_LIBODBC
13bed3dd 1188+ db_log_transfer(file, &initial_stats, "receive");
2c40f06f 1189+#endif
dc3ae351 1190
13bed3dd 1191 if (fd1 != -1)
dc3ae351 1192 close(fd1);
a9eff38d
WD
1193 if (close(fd2) < 0) {
1194 rsyserr(FERROR, errno, "close failed on %s",
1195 full_fname(fnametmp));
1196+#ifdef HAVE_LIBODBC
1197+ db_log_error(FERROR, 23, "close failed on %s",
1198+ full_fname(fnametmp));
1199+#endif
1200 exit_cleanup(RERR_FILEIO);
1201 }
1202
93ca4d27
WD
1203@@ -727,6 +773,12 @@ int recv_files(int f_in, struct file_lis
1204 rprintf(msgtype,
a9eff38d 1205 "%s: %s failed verification -- update %s%s.\n",
93ca4d27 1206 errstr, fname, keptstr, redostr);
a9eff38d
WD
1207+#ifdef HAVE_LIBODBC
1208+ db_log_error(msgtype,24,
1209+ "%s: %s failed verification -- update %s%s.\n",
93ca4d27 1210+ errstr, fname,
a9eff38d
WD
1211+ keptstr, redostr);
1212+#endif
1213 }
1214 if (!phase) {
1215 SIVAL(numbuf, 0, i);
bd68c3c2 1216--- orig/sender.c 2006-01-14 20:27:10
a9eff38d 1217+++ sender.c 2005-09-23 16:01:44
93ca4d27 1218@@ -352,6 +352,9 @@ void send_files(struct file_list *flist,
36bbf3d1 1219
4e75164f 1220 if (!log_before_transfer)
d608ca23 1221 log_item(file, &initial_stats, iflags, NULL);
637ba3ff 1222+#ifdef HAVE_LIBODBC
9be39c35 1223+ db_log_transfer(file, &initial_stats,"send");
2c40f06f 1224+#endif
2c40f06f 1225
9be39c35
WD
1226 if (mbuf) {
1227 j = unmap_file(mbuf);