From 71025c877b28da7326d650dd3598b9bd64d00e23 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Fri, 30 May 2003 14:44:53 +0000 Subject: [PATCH] See kes-1.31 for details git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@556 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/ReleaseNotes | 3 +- bacula/kernstodo | 149 ++++--- bacula/src/cats/bdb.c | 3 +- bacula/src/cats/bdb_list.c | 12 +- bacula/src/cats/cats.h | 337 +++++++-------- bacula/src/cats/drop_mysql_tables.in | 2 + bacula/src/cats/make_mysql_tables.in | 59 ++- bacula/src/cats/make_sqlite_tables.in | 26 +- bacula/src/cats/mysql.c | 10 +- bacula/src/cats/protos.h | 16 +- bacula/src/cats/sql.c | 15 +- bacula/src/cats/sql_create.c | 22 +- bacula/src/cats/sql_find.c | 35 +- bacula/src/cats/sql_get.c | 5 +- bacula/src/cats/sql_list.c | 42 +- bacula/src/cats/sqlite.c | 10 +- bacula/src/console/console.c | 30 +- bacula/src/dird/Makefile.in | 4 +- bacula/src/dird/backup.c | 51 ++- bacula/src/dird/dird.c | 4 +- bacula/src/dird/dird_conf.h | 70 ++-- bacula/src/dird/fd_cmds.c | 4 +- bacula/src/dird/getmsg.c | 8 +- bacula/src/dird/inc_conf.c | 6 +- bacula/src/dird/msgchan.c | 2 +- bacula/src/dird/protos.h | 54 ++- bacula/src/dird/query.sql | 2 +- bacula/src/dird/restore.c | 8 +- bacula/src/dird/sql_cmds.c | 2 +- bacula/src/dird/ua.h | 4 +- bacula/src/dird/ua_cmds.c | 26 +- bacula/src/dird/ua_input.c | 2 +- bacula/src/dird/ua_output.c | 8 +- bacula/src/dird/ua_query.c | 287 +++++++++++++ bacula/src/dird/ua_restore.c | 8 +- bacula/src/dird/ua_select.c | 4 +- bacula/src/dird/verify.c | 6 +- bacula/src/filed/filed_conf.h | 19 +- bacula/src/lib/Makefile.in | 6 +- bacula/src/lib/edit.c | 20 +- bacula/src/lib/message.c | 19 +- bacula/src/lib/parse_conf.c | 15 - bacula/src/lib/parse_conf.h | 14 +- bacula/src/lib/protos.h | 31 +- bacula/src/lib/scan.c | 241 +++++++++++ bacula/src/lib/smartall.c | 577 +++++++++++++------------- bacula/src/lib/util.c | 209 +--------- bacula/src/stored/acquire.c | 2 +- bacula/src/stored/askdir.c | 2 +- bacula/src/stored/block.c | 24 +- bacula/src/stored/block.h | 9 +- bacula/src/stored/bls.c | 8 +- bacula/src/stored/bsr.h | 83 ++-- bacula/src/stored/dev.c | 15 +- bacula/src/stored/device.c | 3 + bacula/src/stored/dircmd.c | 9 +- bacula/src/stored/job.c | 10 +- bacula/src/stored/label.c | 6 +- bacula/src/stored/mount.c | 4 +- bacula/src/stored/parse_bsr.c | 10 +- bacula/src/stored/read.c | 31 +- bacula/src/stored/read_record.c | 4 +- bacula/src/stored/record.h | 16 +- bacula/src/stored/stored_conf.h | 2 +- bacula/src/version.h | 4 +- 65 files changed, 1569 insertions(+), 1160 deletions(-) create mode 100644 bacula/src/dird/ua_query.c create mode 100644 bacula/src/lib/scan.c diff --git a/bacula/ReleaseNotes b/bacula/ReleaseNotes index fa4ee40bcb..6e6a4cf09b 100644 --- a/bacula/ReleaseNotes +++ b/bacula/ReleaseNotes @@ -1,7 +1,7 @@ Release Notes for Bacula 1.31 - Bacula code: Total files = 241 Total lines = 69,771 (*.h *.c *.in) + Bacula code: Total files = 243 Total lines = 70,151 (*.h *.c *.in) Major Changes this Release: - Support to save and restore all files on WinNT/2K/XP systems @@ -41,4 +41,3 @@ Items to note: !!!!! option on the ./configure. - Version 1.31 and 1.30 daemons/Director are not compatible. You must upgrade all or nothing. - diff --git a/bacula/kernstodo b/bacula/kernstodo index fec3d93a0e..48a7507f33 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -1,5 +1,5 @@ Kern's ToDo List - 26 May 2003 + 30 May 2003 Documentation to do: (any release a little bit at a time) - Document running a test version. @@ -13,6 +13,9 @@ Documentation to do: (any release a little bit at a time) hours of operation. - Lookup HP cleaning recommendations. - Lookup HP tape replacement recommendations (see trouble shooting autochanger) +- Document FInclude ... +- Document need to add "-u root" to most of MySQL script calls + (./create_mys... ./make_my...). Testing to do: (painful) @@ -22,39 +25,74 @@ Testing to do: (painful) - Test if rewind at end of tape waits for tape to rewind. - Test cancel at EOM. - Test not zeroing Autochanger slot when it is wrong. +- Test multiple simultaneous Volumes - Figure out how to use ssh or stunnel to protect Bacula communications. For 1.31 release: -- Currently in mount.c:236 the SD simply creates a Volume. It should have - explicit permission to do so. It should also mark the tape in error - if there is an error. +- Implement FileSet VolIndex. +- Sort JobIds entered into recover tree. +- Should Bacula make an Append tape as Purged when purging? +- Test a second language e.g. french. +- Start working on Base jobs. +- Make "make binary-release" work from any directory. +- Document c:/working directory better than /working directory. +- Unsaved Flag in Job record. +- Base Flag in Job record. +- Implement UnsavedFiles DB record. +- The "List last 20 Jobs run" doesnt work correctly. + It doesnt show the last 20 jobs , but some older ones. - The bsr for Dan's job has file indexes covering the whole range rather than only the range contained on the volume. Constrain FileIndex to be within range for Volume. +- Fix Verify VolumeToCatalog to use BSRs -- it is broken. +- Use switch() in backup.c and restore.c in FD instead of giant if statement. +- Implement argc/argv for daemon command line scanning using table driven + stuff below. +- Implement table driven single argc/argv scanner to pickup all arguments. + Much like xxx_conf.c scan table. + keyword, handler(store_routine), store_address, code, flags, default. +- Make | and < work on FD side. +- Pass prefix_links to FD. +- Implement a M_SECURITY message class. +- From Phil Stracchino: + It would probably be a per-client option, and would be called + something like, say, "Automatically purge obsoleted jobs". What it + would do is, when you successfully complete a Differential backup of a + client, it would automatically purge all Incremental backups for that + client that are rendered redundant by that Differential. Likewise, + when a Full backup on a client completed, it would automatically purge + all Differential and Incremental jobs obsoleted by that Full backup. + This would let people minimize the number of tapes they're keeping on + hand without having to master the art of retention times. +- Prohibit backing up archive device (findlib/find_one.c:128) +- Make Restore report an error if FD or SD term codes are not OK. +- Add JobLevel in FD status (but make sure it is defined). +- Make Pool resource handle Counter resources. +- Restrict characters permitted in a Resource name, and don't permit + duplicate names. +- Implement new serialize subroutines + send(socket, "string", &Vol, "uint32", &i, NULL) +- Audit all UA commands to ensure that we always prompt where possible. + + +After 1.31: +- Currently in mount.c:236 the SD simply creates a Volume. It should have + explicit permission to do so. It should also mark the tape in error + if there is an error. - Make sure all restore counters are working correctly in the FD. - SD Bytes Read is wrong. - Configure mtx-changer to have correct path to mtx. - Look at ALL higher level routines that call block.c to be sure they don't expect something in errmsg. - -- Fix Verify VolumeToCatalog to use BSRs -- it is broken. - -- Use switch() in backup.c and restore.c in FD instead of giant if statement. - Investigate doing RAW backup of Win32 partition. - Add JobName= to VerifyToCatalog so that all verifies can be done at the end. - Add thread specific data to hold the jcr -- send error messages from low level routines by accessing it and using Jmsg(). -- Default duration with no qualifier is sec should be 1 day -- Find a solution for the multiple FileSet problem (when it is changed). Add date? - Cancel waiting for Client connect in SD if FD goes away. - Testing Tibs job erred and hung director on Storage resource. This was because there were a whole pile of jobs hanging around in the SD waiting for a connection from the FD that was never coming. -- Make restore more robust in counting error and not immediately bailing - out. Also print error message once, but try to continue. -- Add code to check that blocks are sequential on restore. -- Should Bacula make an Append tape as Purged when purging? - Possibly update all client records at startup. - Add Progress command that periodically reports the progress of @@ -63,15 +101,8 @@ For 1.31 release: - One block was orphaned in the SD probably after cancel. - Add all command line arguments to "update", e.g. slot=nn volStatus=append, ... -- Implement argc/argv for daemon command line scanning using table driven - stuff below. -- Implement table driven single argc/argv scanner to pickup all arguments. - Much like xxx_conf.c scan table. - keyword, handler(store_routine), store_address, code, flags, default. - Examine Bare Metal restore problem (a FD crash exists somewhere ...). -- Test multiple simultaneous Volumes -- Document FInclude ... - Implement timeout in response() when it should come quickly. - Implement console @echo command. - Implement a Slot priority (loaded/not loaded). @@ -93,30 +124,16 @@ For 1.31 release: - Implement restore "current system", but take all files without doing selection tree -- so that jobs without File records can be restored. -- Make | and < work on FD side. -- Pass prefix_links to FD. -- Implement a M_SECURITY message class. - Implement disk spooling. Two parts: 1. Spool to disk then immediately to tape to speed up tape operations. 2. Spool to disk only when the tape is full, then when a tape is hung move it to tape. -- From Phil Stracchino: - It would probably be a per-client option, and would be called - something like, say, "Automatically purge obsoleted jobs". What it - would do is, when you successfully complete a Differential backup of a - client, it would automatically purge all Incremental backups for that - client that are rendered redundant by that Differential. Likewise, - when a Full backup on a client completed, it would automatically purge - all Differential and Incremental jobs obsoleted by that Full backup. - This would let people minimize the number of tapes they're keeping on - hand without having to master the art of retention times. - Implement a relocatable bacula.spec - Allow multiple Storage specifications (or multiple names on a single Storage specification) in the Job record. Thus a job can be backed up to a number of storage devices. - Implement dump/print label to UA - Add prefixlinks to where or not where absolute links to FD. -- Look at Python for a Bacula scripting language -- www.python.org - Issue message to mount a new tape before the rewind. - Simplified client job initiation for portables. - If SD cannot open a drive, make it periodically retry. @@ -159,20 +176,16 @@ For 1.31 release: - Program files (i.e. execute a program to read/write files). Pass read date of last backup, size of file last time. - Add Signature type to File DB record. -- Make Restore report an error if FD or SD term codes are not OK. - CD into subdirectory when open()ing files for backup to speed up things. Test with testfind(). - Priority job to go to top of list. -- Find out why Full saves run slower and slower (hashing?) - Why are save/restore of device different sizes (sparse?) Yup! Fix it. - Implement some way for the Console to dynamically create a job. - Restore to a particular time -- e.g. before date, after date. - Solaris -I on tar for include list -- Prohibit backing up archive device (findlib/find_one.c:128) - Need a verbose mode in restore, perhaps to bsr. - bscan without -v is too quiet -- perhaps show jobs. - Add code to reject whole blocks if not wanted on restore. -- Start working on Base jobs. - Check if we can increase Bacula FD priorty in Win2000 - Make sure the MaxVolFiles is fully implemented in SD - Check if both CatalogFiles and UseCatalog are set to SD. @@ -183,17 +196,11 @@ For 1.31 release: - Possibly add email to Watchdog if drive is unmounted too long and a job is waiting on the drive. - Use read_record.c in SD code. -- Why don't we get an error message from Win32 FD when bootstrap - file cannot be created for restore command? -- When Marking a file in Restore that is a hard link, also - mark the link so that the data will be reloaded. - Restore program that errors in SD due to no tape reports OK incorrectly in output. - After unmount, if restore job started, ask to mount. - Convert all %x substitution variables, which are hard to remember and read to %(variable-name). Idea from TMDA. -- Add JobLevel in FD status (but make sure it is defined). -- Make Pool resource handle Counter resources. - Remove NextId for SQLite. Optimize. - Move all SQL statements into a single location. - Add UA rc and history files. @@ -202,15 +209,11 @@ For 1.31 release: - Enhance time and size scanning routines. - Fix Autoprune for Volumes to respect need for full save. - Fix Win32 config file definition name on /install -- No READLINE_SRC if found in alternate directory. -- Test a second language e.g. french. - Compare tape to Client files (attributes, or attributes and data) - Make all database Ids 64 bit. - Write an applet for Linux. - Add estimate to Console commands -- Find solution to blank filename (i.e. path only) problem. - Implement new daemon communications protocol. -- Remove PoolId from Job table, it exists in Media. - Allow console commands to detach or run in background. - Fix status delay on storage daemon during rewind. - Add SD message variables to control operator wait time @@ -222,31 +225,20 @@ For 1.31 release: Verify level=Catalog, level=InitCatalog - Events file - Add keyword search to show command in Console. -- Fix Win2000 error with no messages during startup. - Events : tape has more than xxx bytes. -- Restrict characters permitted in a Resource name. - Complete code in Bacula Resources -- this will permit reading a new config file at any time. - Handle ctl-c in Console - Implement script driven addition of File daemon to config files. - Think about how to make Bacula work better with File (non-tape) archives. - Write Unix emulator for Windows. -- Implement new serialize subroutines - send(socket, "string", &Vol, "uint32", &i, NULL) -- Audit all UA commands to ensure that we always prompt where possible. -- If ./btape is called without /dev, assume argument is a Storage resource name. - Put memory utilization in Status output of each daemon if full status requested or if some level of debug on. - Make database type selectable by .conf files i.e. at runtime - Set flag for uname -a. Add to Volume label. - Implement throttled work queue. -- Check for EOT at ENOSPC or EIO or ENXIO (unix Pc) - Restore files modified after date - Restore file modified before date -- Emergency restore info: - - Backup Bacula - - Backup working directory - - Backup Catalog - Restore -- do nothing but show what would happen - SET LD_RUN_PATH=$HOME/mysql/lib/mysql - Implement Restore FileSet= @@ -254,16 +246,11 @@ For 1.31 release: are concentrated. - Remove duplicate fields from jcr (e.g. jcr.level and jcr.jr.Level, ...). - Timout a job or terminate if link goes down, or reopen link and query. -- Find general solution for sscanf size problems (as well - as sprintf. Do at run time? - Concept of precious tapes (cannot be reused). - Make bcopy copy with a single tape drive. - Permit changing ownership during restore. - Autolabel should be specified by DIR instead of SD. -- Find out how to get the system tape block limits, e.g.: - Apr 22 21:22:10 polymatou kernel: st1: Block limits 1 - 245760 bytes. - Apr 22 21:22:10 polymatou kernel: st0: Block limits 2 - 16777214 bytes. - Storage daemon - Add media capacity - AutoScan (check checksum of tape) @@ -302,13 +289,6 @@ For 1.31 release: times out jobs by asking the deamons where they are. - Enhance Jmsg code to permit buffering and saving to disk. - device driver = "xxxx" for drives. -- restart: paranoid: read label fsf to - eom read append block, and go - super-paranoid: read label, read all files - in between, read append block, and go - verify: backspace, read append block, and go - permissive: same as above but frees drive - if tape is not valid. - Verify from Volume - Ensure that /dev/null works - Need report class for messages. Perhaps @@ -317,7 +297,7 @@ For 1.31 release: fill in code for "since" option - Director needs a time after which the report status is sent anyway -- or better yet, a retry time for the job. - Don't reschedule a job if previous incarnation is still running. +- Don't reschedule a job if previous incarnation is still running. - Some way to automatically backup everything is needed???? - Need a structure for pending actions: - buffered messages @@ -332,9 +312,6 @@ For 1.31 release: Longer term to do: - Design at hierarchial storage for Bacula. Migration and Clone. - Implement FSM (File System Modules). -- Identify unchanged or "system" files and save them to a - special tape thus removing them from the standard - backup FileSet -- BASE backup. - Audit M_ error codes to ensure they are correct and consistent. - Add variable break characters to lex analyzer. Either a bit mask or a string of chars so that @@ -917,3 +894,23 @@ Done: (see kernsdone for more) - Shell expansion fails for working_directory in SD from time to time. - File the Automatically selected: xxx to say Automatically selected Pool: xxx +- Default duration with no qualifier is sec should be 1 day +- zap sd_auth_key in SD after FD connection. +- Find a solution for the multiple FileSet problem (when it is changed). Add date? +- Look at Python for a Bacula scripting language -- www.python.org +- When Marking a file in Restore that is a hard link, also + mark the link so that the data will be reloaded. +- Emergency restore info: + - Backup Bacula + - Backup working directory + - Backup Catalog +- Why don't we get an error message from Win32 FD when bootstrap + file cannot be created for restore command? +- Fix Win2000 error with no messages during startup. +- Make restore more robust in counting error and not immediately bailing + out. Also print error message once, but try to continue. +- Add code to check that blocks are sequential on restore. +- Remove "rufus" and such references from regress. +- No READLINE_SRC if found in alternate directory. +- If ./btape is called without /dev, assume argument is a Storage resource name. +- Find general solution for sscanf size problems (as well as sprintf. Do at run time? diff --git a/bacula/src/cats/bdb.c b/bacula/src/cats/bdb.c index 39da83fb00..980a12b8e1 100644 --- a/bacula/src/cats/bdb.c +++ b/bacula/src/cats/bdb.c @@ -44,7 +44,7 @@ #ifdef HAVE_BACULA_DB -char catalog_db[] = "Interal"; +uint32_t bacula_db_version = 0; /* Forward referenced functions */ @@ -228,6 +228,7 @@ Please reinitialize the working directory.\n"), BDB_VERSION, mdb->control.bdb_version); badctl = 1; } + bacula_db_version = mdb->control.bdb_version; if (badctl) { V(mutex); return 0; diff --git a/bacula/src/cats/bdb_list.c b/bacula/src/cats/bdb_list.c index 2dba3e01c0..a56e7d5fb5 100644 --- a/bacula/src/cats/bdb_list.c +++ b/bacula/src/cats/bdb_list.c @@ -278,31 +278,31 @@ void db_list_client_records(void *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void { } int db_list_sql_query(void *jcr, B_DB *mdb, char *query, DB_LIST_HANDLER *sendit, - void *ctx, int verbose, int full) + void *ctx, int verbose, e_list_type type) { return 0; } void -db_list_pool_records(void *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, int full) +db_list_pool_records(void *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type) { } void db_list_media_records(void *jcr, B_DB *mdb, MEDIA_DBR *mdbr, - DB_LIST_HANDLER *sendit, void *ctx, int full) + DB_LIST_HANDLER *sendit, void *ctx, e_list_type type) { } void db_list_jobmedia_records(void *jcr, B_DB *mdb, uint32_t JobId, - DB_LIST_HANDLER *sendit, void *ctx, int full) + DB_LIST_HANDLER *sendit, void *ctx, e_list_type type) { } void db_list_job_records(void *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, - void *ctx, int full) + void *ctx, e_list_type type) { } void -db_list_client_records(void *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, int full) +db_list_client_records(void *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type) { } diff --git a/bacula/src/cats/cats.h b/bacula/src/cats/cats.h index 37c09504a6..a3c1da5bcb 100644 --- a/bacula/src/cats/cats.h +++ b/bacula/src/cats/cats.h @@ -48,7 +48,7 @@ typedef int (DB_RESULT_HANDLER)(void *, int, char **); #ifdef HAVE_SQLITE -#define BDB_VERSION 5 +#define BDB_VERSION 6 #include @@ -57,70 +57,70 @@ struct sqlite { char dummy; }; -#define IS_NUM(x) ((x) == 1) -#define IS_NOT_NULL(x) ((x) == 1) +#define IS_NUM(x) ((x) == 1) +#define IS_NOT_NULL(x) ((x) == 1) typedef struct s_sql_field { - char *name; /* name of column */ - uint32_t length; /* length */ - uint32_t max_length; /* max length */ - uint32_t type; /* type */ - uint32_t flags; /* flags */ + char *name; /* name of column */ + uint32_t length; /* length */ + uint32_t max_length; /* max length */ + uint32_t type; /* type */ + uint32_t flags; /* flags */ } SQL_FIELD; /* * This is the "real" definition that should only be * used inside sql.c and associated database interface * subroutines. - * S Q L I T E + * S Q L I T E */ typedef struct s_db { - BQUEUE bq; /* queue control */ - brwlock_t lock; /* transaction lock */ + BQUEUE bq; /* queue control */ + brwlock_t lock; /* transaction lock */ struct sqlite *db; char **result; - int nrow; /* nrow returned from sqlite */ - int ncolumn; /* ncolum returned from sqlite */ - int num_rows; /* used by code */ - int row; /* seek row */ - int have_insert_id; /* do not have insert id */ - int fields_defined; /* set when fields defined */ - int field; /* seek field */ - SQL_FIELD **fields; /* defined fields */ + int nrow; /* nrow returned from sqlite */ + int ncolumn; /* ncolum returned from sqlite */ + int num_rows; /* used by code */ + int row; /* seek row */ + int have_insert_id; /* do not have insert id */ + int fields_defined; /* set when fields defined */ + int field; /* seek field */ + SQL_FIELD **fields; /* defined fields */ int ref_count; char *db_name; char *db_user; - char *db_address; /* host name address */ - char *db_socket; /* socket for local access */ + char *db_address; /* host name address */ + char *db_socket; /* socket for local access */ char *db_password; - int db_port; /* port for host name address */ + int db_port; /* port for host name address */ int connected; - char *sqlite_errmsg; /* error message returned by sqlite */ - POOLMEM *errmsg; /* nicely edited error message */ - POOLMEM *cmd; /* SQL command string */ - POOLMEM *cached_path; /* cached path name */ - int cached_path_len; /* length of cached path */ - uint32_t cached_path_id; /* cached path id */ - int transaction; /* transaction started */ - int changes; /* changes during transaction */ - POOLMEM *fname; /* Filename only */ - POOLMEM *path; /* Path only */ - POOLMEM *esc_name; /* Escaped file/path name */ - int fnl; /* file name length */ - int pnl; /* path name length */ + char *sqlite_errmsg; /* error message returned by sqlite */ + POOLMEM *errmsg; /* nicely edited error message */ + POOLMEM *cmd; /* SQL command string */ + POOLMEM *cached_path; /* cached path name */ + int cached_path_len; /* length of cached path */ + uint32_t cached_path_id; /* cached path id */ + int transaction; /* transaction started */ + int changes; /* changes during transaction */ + POOLMEM *fname; /* Filename only */ + POOLMEM *path; /* Path only */ + POOLMEM *esc_name; /* Escaped file/path name */ + int fnl; /* file name length */ + int pnl; /* path name length */ } B_DB; /* * "Generic" names for easier conversion * - * S Q L I T E + * S Q L I T E */ #define sql_store_result(x) x->result #define sql_free_result(x) my_sqlite_free_table(x) #define sql_fetch_row(x) my_sqlite_fetch_row(x) #define sql_query(x, y) my_sqlite_query(x, y) -#define sql_close(x) sqlite_close((x)->db) +#define sql_close(x) sqlite_close((x)->db) #define sql_strerror(x) (x)->sqlite_errmsg?(x)->sqlite_errmsg:"unknown" #define sql_num_rows(x) (x)->nrow #define sql_data_seek(x, i) (x)->row = i @@ -129,7 +129,7 @@ typedef struct s_db { #define sql_field_seek(x, y) my_sqlite_field_seek(x, y) #define sql_fetch_field(x) my_sqlite_fetch_field(x) #define sql_num_fields(x) (unsigned)((x)->ncolumn) -#define SQL_ROW char** +#define SQL_ROW char** @@ -142,7 +142,7 @@ extern void my_sqlite_free_table(B_DB *mdb); #ifdef HAVE_MYSQL -#define BDB_VERSION 5 +#define BDB_VERSION 6 #include @@ -151,11 +151,11 @@ extern void my_sqlite_free_table(B_DB *mdb); * used inside sql.c and associated database interface * subroutines. * - * M Y S Q L + * M Y S Q L */ typedef struct s_db { - BQUEUE bq; /* queue control */ - brwlock_t lock; /* transaction lock */ + BQUEUE bq; /* queue control */ + brwlock_t lock; /* transaction lock */ MYSQL mysql; MYSQL *db; MYSQL_RES *result; @@ -164,22 +164,22 @@ typedef struct s_db { char *db_name; char *db_user; char *db_password; - char *db_address; /* host address */ - char *db_socket; /* socket for local access */ - int db_port; /* port of host address */ - int have_insert_id; /* do have insert_id() */ + char *db_address; /* host address */ + char *db_socket; /* socket for local access */ + int db_port; /* port of host address */ + int have_insert_id; /* do have insert_id() */ int connected; - POOLMEM *errmsg; /* nicely edited error message */ - POOLMEM *cmd; /* SQL command string */ + POOLMEM *errmsg; /* nicely edited error message */ + POOLMEM *cmd; /* SQL command string */ POOLMEM *cached_path; - int cached_path_len; /* length of cached path */ + int cached_path_len; /* length of cached path */ uint32_t cached_path_id; - int changes; /* changes made to db */ - POOLMEM *fname; /* Filename only */ - POOLMEM *path; /* Path only */ - POOLMEM *esc_name; /* Escaped file/path name */ - int fnl; /* file name length */ - int pnl; /* path name length */ + int changes; /* changes made to db */ + POOLMEM *fname; /* Filename only */ + POOLMEM *path; /* Path only */ + POOLMEM *esc_name; /* Escaped file/path name */ + int fnl; /* file name length */ + int pnl; /* path name length */ } B_DB; @@ -188,7 +188,7 @@ typedef struct s_db { #define sql_free_result(x) mysql_free_result((x)->result) #define sql_fetch_row(x) mysql_fetch_row((x)->result) #define sql_query(x, y) mysql_query((x)->db, y) -#define sql_close(x) mysql_close((x)->db) +#define sql_close(x) mysql_close((x)->db) #define sql_strerror(x) mysql_error((x)->db) #define sql_num_rows(x) mysql_num_rows((x)->result) #define sql_data_seek(x, i) mysql_data_seek((x)->result, i) @@ -197,8 +197,8 @@ typedef struct s_db { #define sql_field_seek(x, y) mysql_field_seek((x)->result, y) #define sql_fetch_field(x) mysql_fetch_field((x)->result) #define sql_num_fields(x) mysql_num_fields((x)->result) -#define SQL_ROW MYSQL_ROW -#define SQL_FIELD MYSQL_FIELD +#define SQL_ROW MYSQL_ROW +#define SQL_FIELD MYSQL_FIELD #else /* USE BACULA DB routines */ @@ -207,17 +207,17 @@ typedef struct s_db { /* Change this each time there is some incompatible * file format change!!!! */ -#define BDB_VERSION 11 /* file version number */ +#define BDB_VERSION 12 /* file version number */ struct s_control { - int bdb_version; /* Version number */ - uint32_t JobId; /* next Job Id */ - uint32_t PoolId; /* next Pool Id */ - uint32_t MediaId; /* next Media Id */ - uint32_t JobMediaId; /* next JobMedia Id */ - uint32_t ClientId; /* next Client Id */ - uint32_t FileSetId; /* nest FileSet Id */ - time_t time; /* time file written */ + int bdb_version; /* Version number */ + uint32_t JobId; /* next Job Id */ + uint32_t PoolId; /* next Pool Id */ + uint32_t MediaId; /* next Media Id */ + uint32_t JobMediaId; /* next JobMedia Id */ + uint32_t ClientId; /* next Client Id */ + uint32_t FileSetId; /* nest FileSet Id */ + time_t time; /* time file written */ }; @@ -225,23 +225,23 @@ struct s_control { * Bacula internal DB */ typedef struct s_db { - BQUEUE bq; /* queue control */ -/* pthread_mutex_t mutex; */ /* single thread lock */ - brwlock_t lock; /* transaction lock */ - int ref_count; /* number of times opened */ - struct s_control control; /* control file structure */ - int cfd; /* control file device */ - FILE *jobfd; /* Jobs records file descriptor */ - FILE *poolfd; /* Pool records fd */ - FILE *mediafd; /* Media records fd */ - FILE *jobmediafd; /* JobMedia records fd */ - FILE *clientfd; /* Client records fd */ - FILE *filesetfd; /* FileSet records fd */ - char *db_name; /* name of database */ - POOLMEM *errmsg; /* nicely edited error message */ - POOLMEM *cmd; /* Command string */ + BQUEUE bq; /* queue control */ +/* pthread_mutex_t mutex; */ /* single thread lock */ + brwlock_t lock; /* transaction lock */ + int ref_count; /* number of times opened */ + struct s_control control; /* control file structure */ + int cfd; /* control file device */ + FILE *jobfd; /* Jobs records file descriptor */ + FILE *poolfd; /* Pool records fd */ + FILE *mediafd; /* Media records fd */ + FILE *jobmediafd; /* JobMedia records fd */ + FILE *clientfd; /* Client records fd */ + FILE *filesetfd; /* FileSet records fd */ + char *db_name; /* name of database */ + POOLMEM *errmsg; /* nicely edited error message */ + POOLMEM *cmd; /* Command string */ POOLMEM *cached_path; - int cached_path_len; /* length of cached path */ + int cached_path_len; /* length of cached path */ uint32_t cached_path_id; } B_DB; @@ -255,19 +255,21 @@ typedef struct s_db { #define DELETE_DB(jcr, db, cmd) DeleteDB(__FILE__, __LINE__, jcr, db, cmd) -#else /* not __SQL_C */ +#else /* not __SQL_C */ /* This is a "dummy" definition for use outside of sql.c */ -typedef struct s_db { - int dummy; /* for SunOS compiler */ +typedef struct s_db { + int dummy; /* for SunOS compiler */ } B_DB; #endif /* __SQL_C */ +extern uint32_t bacula_db_version; + /* ***FIXME*** FileId_t should be uint64_t */ typedef uint32_t FileId_t; -typedef uint32_t DBId_t; /* general DB id type */ +typedef uint32_t DBId_t; /* general DB id type */ typedef uint32_t JobId_t; #define faddr_t long @@ -281,18 +283,18 @@ typedef uint32_t JobId_t; /* Job record */ struct JOB_DBR { JobId_t JobId; - char Job[MAX_NAME_LENGTH]; /* Job unique name */ - char Name[MAX_NAME_LENGTH]; /* Job base name */ - int Type; /* actually char(1) */ - int Level; /* actually char(1) */ - int JobStatus; /* actually char(1) */ - uint32_t ClientId; /* Id of client */ - uint32_t PoolId; /* Id of pool */ - uint32_t FileSetId; /* Id of FileSet */ - time_t SchedTime; /* Time job scheduled */ - time_t StartTime; /* Job start time */ - time_t EndTime; /* Job termination time */ - utime_t JobTDate; /* Backup time/date in seconds */ + char Job[MAX_NAME_LENGTH]; /* Job unique name */ + char Name[MAX_NAME_LENGTH]; /* Job base name */ + int Type; /* actually char(1) */ + int Level; /* actually char(1) */ + int JobStatus; /* actually char(1) */ + uint32_t ClientId; /* Id of client */ + uint32_t PoolId; /* Id of pool */ + uint32_t FileSetId; /* Id of FileSet */ + time_t SchedTime; /* Time job scheduled */ + time_t StartTime; /* Job start time */ + time_t EndTime; /* Job termination time */ + utime_t JobTDate; /* Backup time/date in seconds */ uint32_t VolSessionId; uint32_t VolSessionTime; uint32_t JobFiles; @@ -303,8 +305,8 @@ struct JOB_DBR { /* Note, FirstIndex, LastIndex, Start/End File and Block * are only used in the JobMedia record. */ - uint32_t FirstIndex; /* First index this Volume */ - uint32_t LastIndex; /* Last index this Volume */ + uint32_t FirstIndex; /* First index this Volume */ + uint32_t LastIndex; /* Last index this Volume */ uint32_t StartFile; uint32_t EndFile; uint32_t StartBlock; @@ -322,28 +324,28 @@ struct JOB_DBR { */ /* JobMedia record */ struct JOBMEDIA_DBR { - uint32_t JobMediaId; /* record id */ - JobId_t JobId; /* JobId */ - uint32_t MediaId; /* MediaId */ - uint32_t FirstIndex; /* First index this Volume */ - uint32_t LastIndex; /* Last index this Volume */ - uint32_t StartFile; /* File for start of data */ - uint32_t EndFile; /* End file on Volume */ - uint32_t StartBlock; /* start block on tape */ - uint32_t EndBlock; /* last block */ + uint32_t JobMediaId; /* record id */ + JobId_t JobId; /* JobId */ + uint32_t MediaId; /* MediaId */ + uint32_t FirstIndex; /* First index this Volume */ + uint32_t LastIndex; /* Last index this Volume */ + uint32_t StartFile; /* File for start of data */ + uint32_t EndFile; /* End file on Volume */ + uint32_t StartBlock; /* start block on tape */ + uint32_t EndBlock; /* last block */ }; /* Volume Parameter structure */ struct VOL_PARAMS { char VolumeName[MAX_NAME_LENGTH]; /* Volume name */ - uint32_t VolIndex; /* Volume seqence no. */ - uint32_t FirstIndex; /* First index this Volume */ - uint32_t LastIndex; /* Last index this Volume */ - uint32_t StartFile; /* File for start of data */ - uint32_t EndFile; /* End file on Volume */ - uint32_t StartBlock; /* start block on tape */ - uint32_t EndBlock; /* last block */ + uint32_t VolIndex; /* Volume seqence no. */ + uint32_t FirstIndex; /* First index this Volume */ + uint32_t LastIndex; /* Last index this Volume */ + uint32_t StartFile; /* File for start of data */ + uint32_t EndFile; /* End file on Volume */ + uint32_t StartBlock; /* start block on tape */ + uint32_t EndBlock; /* last block */ }; @@ -352,9 +354,9 @@ struct VOL_PARAMS { * records (e.g. pathname, filename, fileattributes). */ struct ATTR_DBR { - char *fname; /* full path & filename */ - char *link; /* link if any */ - char *attr; /* attributes statp */ + char *fname; /* full path & filename */ + char *link; /* link if any */ + char *attr; /* attributes statp */ uint32_t FileIndex; uint32_t Stream; JobId_t JobId; @@ -376,26 +378,26 @@ struct FILE_DBR { char LStat[256]; /* int Status; */ char SIG[50]; - int SigType; /* NO_SIG/MD5_SIG/SHA1_SIG */ + int SigType; /* NO_SIG/MD5_SIG/SHA1_SIG */ }; /* Pool record -- same format as database */ struct POOL_DBR { uint32_t PoolId; - char Name[MAX_NAME_LENGTH]; /* Pool name */ - uint32_t NumVols; /* total number of volumes */ - uint32_t MaxVols; /* max allowed volumes */ - int UseOnce; /* set to use once only */ - int UseCatalog; /* set to use catalog */ - int AcceptAnyVolume; /* set to accept any volume sequence */ - int AutoPrune; /* set to prune automatically */ - int Recycle; /* default Vol recycle flag */ - utime_t VolRetention; /* retention period in seconds */ - utime_t VolUseDuration; /* time in secs volume can be used */ - uint32_t MaxVolJobs; /* Max Jobs on Volume */ - uint32_t MaxVolFiles; /* Max files on Volume */ - uint64_t MaxVolBytes; /* Max bytes on Volume */ - char PoolType[MAX_NAME_LENGTH]; + char Name[MAX_NAME_LENGTH]; /* Pool name */ + uint32_t NumVols; /* total number of volumes */ + uint32_t MaxVols; /* max allowed volumes */ + int UseOnce; /* set to use once only */ + int UseCatalog; /* set to use catalog */ + int AcceptAnyVolume; /* set to accept any volume sequence */ + int AutoPrune; /* set to prune automatically */ + int Recycle; /* default Vol recycle flag */ + utime_t VolRetention; /* retention period in seconds */ + utime_t VolUseDuration; /* time in secs volume can be used */ + uint32_t MaxVolJobs; /* Max Jobs on Volume */ + uint32_t MaxVolFiles; /* Max files on Volume */ + uint64_t MaxVolBytes; /* Max bytes on Volume */ + char PoolType[MAX_NAME_LENGTH]; char LabelFormat[MAX_NAME_LENGTH]; /* Extra stuff not in DB */ faddr_t rec_addr; @@ -403,34 +405,34 @@ struct POOL_DBR { /* Media record -- same as the database */ struct MEDIA_DBR { - uint32_t MediaId; /* Unique volume id */ + uint32_t MediaId; /* Unique volume id */ char VolumeName[MAX_NAME_LENGTH]; /* Volume name */ char MediaType[MAX_NAME_LENGTH]; /* Media type */ - uint32_t PoolId; /* Pool id */ - time_t FirstWritten; /* Time Volume first written */ - time_t LastWritten; /* Time Volume last written */ - time_t LabelDate; /* Date/Time Volume labeled */ - uint32_t VolJobs; /* number of jobs on this medium */ - uint32_t VolFiles; /* Number of files */ - uint32_t VolBlocks; /* Number of blocks */ - uint32_t VolMounts; /* Number of times mounted */ - uint32_t VolErrors; /* Number of read/write errors */ - uint32_t VolWrites; /* Number of writes */ - uint32_t VolReads; /* Number of reads */ - uint64_t VolBytes; /* Number of bytes written */ - uint64_t MaxVolBytes; /* Max bytes to write to Volume */ - uint64_t VolCapacityBytes; /* capacity estimate */ - utime_t VolRetention; /* Volume retention in seconds */ - utime_t VolUseDuration; /* time in secs volume can be used */ - uint32_t MaxVolJobs; /* Max Jobs on Volume */ - uint32_t MaxVolFiles; /* Max files on Volume */ - int Recycle; /* recycle yes/no */ - int32_t Slot; /* slot in changer */ - char VolStatus[20]; /* Volume status */ + uint32_t PoolId; /* Pool id */ + time_t FirstWritten; /* Time Volume first written */ + time_t LastWritten; /* Time Volume last written */ + time_t LabelDate; /* Date/Time Volume labeled */ + uint32_t VolJobs; /* number of jobs on this medium */ + uint32_t VolFiles; /* Number of files */ + uint32_t VolBlocks; /* Number of blocks */ + uint32_t VolMounts; /* Number of times mounted */ + uint32_t VolErrors; /* Number of read/write errors */ + uint32_t VolWrites; /* Number of writes */ + uint32_t VolReads; /* Number of reads */ + uint64_t VolBytes; /* Number of bytes written */ + uint64_t MaxVolBytes; /* Max bytes to write to Volume */ + uint64_t VolCapacityBytes; /* capacity estimate */ + utime_t VolRetention; /* Volume retention in seconds */ + utime_t VolUseDuration; /* time in secs volume can be used */ + uint32_t MaxVolJobs; /* Max Jobs on Volume */ + uint32_t MaxVolFiles; /* Max files on Volume */ + int Recycle; /* recycle yes/no */ + int32_t Slot; /* slot in changer */ + char VolStatus[20]; /* Volume status */ /* Extra stuff not in DB */ - faddr_t rec_addr; /* found record address */ + faddr_t rec_addr; /* found record address */ /* Since the database returns times as strings, this is how we pass - * them back. + * them back. */ char cFirstWritten[MAX_TIME_LENGTH]; /* FirstWritten returned from DB */ char cLastWritten[MAX_TIME_LENGTH]; /* LastWritten returned from DB */ @@ -439,19 +441,26 @@ struct MEDIA_DBR { /* Client record -- same as the database */ struct CLIENT_DBR { - uint32_t ClientId; /* Unique Client id */ + uint32_t ClientId; /* Unique Client id */ int AutoPrune; utime_t FileRetention; utime_t JobRetention; - char Name[MAX_NAME_LENGTH]; /* Client name */ - char Uname[256]; /* Uname for client */ + char Name[MAX_NAME_LENGTH]; /* Client name */ + char Uname[256]; /* Uname for client */ }; /* FileSet record -- same as the database */ struct FILESET_DBR { - uint32_t FileSetId; /* Unique FileSet id */ + uint32_t FileSetId; /* Unique FileSet id */ char FileSet[MAX_NAME_LENGTH]; /* FileSet name */ - char MD5[50]; /* MD5 signature of include/exclude */ + char MD5[50]; /* MD5 signature of include/exclude */ + time_t CreateTime; /* date created */ + /* + * This is where we return CreateTime + */ + char cCreateTime[MAX_TIME_LENGTH]; /* CreateTime as returned from DB */ + /* Not in DB but returned by db_create_fileset() */ + bool created; /* set when record newly created */ }; diff --git a/bacula/src/cats/drop_mysql_tables.in b/bacula/src/cats/drop_mysql_tables.in index e538d2ed13..ff97be8fad 100644 --- a/bacula/src/cats/drop_mysql_tables.in +++ b/bacula/src/cats/drop_mysql_tables.in @@ -20,6 +20,8 @@ DROP TABLE IF EXISTS FileSave; DROP TABLE IF EXISTS FileSet; DROP TABLE IF EXISTS Version; DROP TABLE IF EXISTS Counters; +DROP TABLE IF EXISTS BaseFiles; +DROP TABLE IF EXISTS UnsavedFiles; END-OF-DATA then echo "Deletion of Bacula MySQL tables succeeded." diff --git a/bacula/src/cats/make_mysql_tables.in b/bacula/src/cats/make_mysql_tables.in index a6ffa0a139..e9b63202f0 100644 --- a/bacula/src/cats/make_mysql_tables.in +++ b/bacula/src/cats/make_mysql_tables.in @@ -27,7 +27,7 @@ CREATE TABLE File ( FileIndex INTEGER UNSIGNED NOT NULL, JobId INTEGER UNSIGNED NOT NULL REFERENCES Job, PathId INTEGER UNSIGNED NOT NULL REFERENCES Path, - FilenameId INTEGER NOT NULL REFERENCES Filename, + FilenameId INTEGER UNSIGNED NOT NULL REFERENCES Filename, MarkId INTEGER UNSIGNED NOT NULL DEFAULT 0, LStat TINYBLOB NOT NULL, MD5 TINYBLOB NOT NULL, @@ -42,7 +42,6 @@ CREATE TABLE Job ( JobId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, Job TINYBLOB NOT NULL, Name TINYBLOB NOT NULL, - PurgedFiles TINYINT NOT NULL DEFAULT 0, Type BINARY(1) NOT NULL, Level BINARY(1) NOT NULL, ClientId INTEGER NOT NULL REFERENCES Client, @@ -59,6 +58,8 @@ CREATE TABLE Job ( JobMissingFiles INTEGER UNSIGNED NOT NULL, PoolId INTEGER UNSIGNED NOT NULL REFERENCES Pool, FileSetId INTEGER UNSIGNED NOT NULL REFERENCES FileSet, + PurgedFiles TINYINT NOT NULL DEFAULT 0, + HasBase TINYINT NOT NULL DEFAULT 0, PRIMARY KEY(JobId), INDEX (Name(128)) ); @@ -68,6 +69,7 @@ CREATE TABLE FileSet ( FileSetId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, FileSet TINYBLOB NOT NULL, MD5 TINYBLOB NOT NULL, + CreateTime DATETIME NOT NULL, PRIMARY KEY(FileSetId) ); @@ -81,6 +83,7 @@ CREATE TABLE JobMedia ( EndFile INTEGER UNSIGNED NOT NULL, StartBlock INTEGER UNSIGNED NOT NULL, EndBlock INTEGER UNSIGNED NOT NULL, + VolIndex INTEGER UNSIGNED NOT NULL, PRIMARY KEY(JobMediaId), INDEX (JobId, MediaId) ); @@ -148,12 +151,29 @@ CREATE TABLE Client ( PRIMARY KEY(ClientId) ); +CREATE TABLE BaseFiles ( + BaseId INTEGER UNSIGNED AUTO_INCREMENT, + JobId INTEGER UNSIGNED NOT NULL REFERENCES Job, + FileId INTEGER UNSIGNED NOT NULL REFERENCES File, + FileIndex INTEGER UNSIGNED, + PRIMARY KEY(BaseId) + ); + +CREATE TABLE UnsavedFiles ( + UnsavedId INTEGER UNSIGNED AUTO_INCREMENT, + JobId INTEGER UNSIGNED NOT NULL REFERENCES Job, + PathId INTEGER UNSIGNED NOT NULL REFERENCES Path, + FilenameId INTEGER UNSIGNED NOT NULL REFERENCES Filename, + PRIMARY KEY (UnsavedId) + ); + + CREATE TABLE Version ( VersionId INTEGER UNSIGNED NOT NULL ); -- Initialize Version -INSERT INTO Version (VersionId) VALUES (5); +INSERT INTO Version (VersionId) VALUES (6); CREATE TABLE Counters ( Counter TINYBLOB NOT NULL, @@ -164,40 +184,11 @@ CREATE TABLE Counters ( WrapCounter TINYBLOB NOT NULL ); -## Experimental -#CREATE TABLE FileSave ( -# FileSaveId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, -# FileIndex INTEGER UNSIGNED NOT NULL, -# JobId INTEGER UNSIGNED NOT NULL REFERENCES Job, -# FileId INTEGER UNSIGNED NOT NULL REFERENCES File, -# VLStat TINYBLOB NOT NULL, -# PRIMARY KEY(FileSaveId), -# ); - -# Experimental stuff below. Not used. -# Invariant part of File -#CREATE TABLE BaseFile ( -# FileId INTEGER UNSIGNED AUTOINCREMENT, -# PathId INTEGER UNSIGNED REFERENCES Path NOT NULL, -# FilenameId INTEGER REFERENCES Filename NOT NULL, -# LStat VARCHAR(255) NOT NULL, -# MD5 VARCHAR(25) NOT NULL, -# PRIMARY KEY(FileId) -# ); - -# Variable part of File -#CREATE TABLE FileSave ( -# FileId INTEGER UNSIGNED REFERENCES BaseFile NOT NULL, -# FileIndex INTEGER UNSIGNED NOT NULL, -# JobId INTEGER UNSIGNED REFERENCES Job NOT NULL, -# PRIMARY KEY(FileId) -# ); - END-OF-DATA then - echo "Creation of Bacula tables succeeded." + echo "Creation of Bacula MySQL tables succeeded." else - echo "Creation of Bacula tables failed." + echo "Creation of Bacula MySQL tables failed." fi exit 0 diff --git a/bacula/src/cats/make_sqlite_tables.in b/bacula/src/cats/make_sqlite_tables.in index 4859d35540..2275f4659c 100644 --- a/bacula/src/cats/make_sqlite_tables.in +++ b/bacula/src/cats/make_sqlite_tables.in @@ -28,7 +28,7 @@ CREATE TABLE File ( FileIndex INTEGER UNSIGNED NOT NULL, JobId INTEGER UNSIGNED REFERENCES Job NOT NULL, PathId INTEGER UNSIGNED REFERENCES Path NOT NULL, - FilenameId INTEGER REFERENCES Filename NOT NULL, + FilenameId INTEGER UNSIGNED REFERENCES Filename NOT NULL, MarkId INTEGER UNSIGNED DEFAULT 0, LStat VARCHAR(255) NOT NULL, MD5 VARCHAR(255) NOT NULL, @@ -43,7 +43,6 @@ CREATE TABLE Job ( JobId INTEGER UNSIGNED NOT NULL, Job VARCHAR(128) NOT NULL, Name VARCHAR(128) NOT NULL, - PurgedFiles TINYINT DEFAULT 0, Type CHAR NOT NULL, Level CHAR NOT NULL, ClientId INTEGER REFERENCES Client DEFAULT 0, @@ -60,6 +59,8 @@ CREATE TABLE Job ( JobMissingFiles INTEGER UNSIGNED DEFAULT 0, PoolId INTEGER UNSIGNED REFERENCES Pool DEFAULT 0, FileSetId INTEGER UNSIGNED REFERENCES FileSet DEFAULT 0, + PurgedFiles TINYINT DEFAULT 0, + HasBase TINYINT DEFAULT 0, PRIMARY KEY(JobId) ); @@ -69,6 +70,7 @@ CREATE TABLE FileSet ( FileSetId INTEGER UNSIGNED AUTOINCREMENT, FileSet VARCHAR(128) NOT NULL, MD5 VARCHAR(25) NOT NULL, + CreateTime DATETIME DEFAULT 0, PRIMARY KEY(FileSetId) ); @@ -82,6 +84,7 @@ CREATE TABLE JobMedia ( EndFile INTEGER UNSIGNED DEFAULT 0, StartBlock INTEGER UNSIGNED DEFAULT 0, EndBlock INTEGER UNSIGNED DEFAULT 0, + VolIndex INTEGER UNSIGNED DEFAULT 0, PRIMARY KEY(JobMediaId) ); @@ -150,6 +153,23 @@ CREATE TABLE Client ( PRIMARY KEY(ClientId) ); +CREATE TABLE BaseFiles ( + BaseId INTEGER UNSIGNED AUTOINCREMENT, + JobId INTEGER UNSIGNED REFERENCES Job NOT NULL, + FileId INTEGER UNSIGNED REFERENCES File NOT NULL, + FileIndex INTEGER UNSIGNED, + PRIMARY KEY(BaseId) + ); + +CREATE TABLE UnsavedFiles ( + UnsavedId INTEGER UNSIGNED AUTOINCREMENT, + JobId INTEGER UNSIGNED REFERENCES Job NOT NULL, + PathId INTEGER UNSIGNED REFERENCES Path NOT NULL, + FilenameId INTEGER UNSIGNED REFERENCES Filename NOT NULL, + PRIMARY KEY (UnsavedId) + ); + + CREATE TABLE NextId ( id INTEGER UNSIGNED DEFAULT 0, TableName TEXT NOT NULL, @@ -164,7 +184,7 @@ CREATE TABLE Version ( ); -- Initialize Version -INSERT INTO Version (VersionId) VALUES (5); +INSERT INTO Version (VersionId) VALUES (6); CREATE TABLE Counters ( Counter TEXT NOT NULL, diff --git a/bacula/src/cats/mysql.c b/bacula/src/cats/mysql.c index 2a86026340..fff10ba24d 100644 --- a/bacula/src/cats/mysql.c +++ b/bacula/src/cats/mysql.c @@ -352,7 +352,7 @@ list_dashes(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx) * list on one line horizontally. */ void -list_result(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, int full_list) +list_result(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, e_list_type type) { SQL_FIELD *field; SQL_ROW row; @@ -368,7 +368,7 @@ list_result(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, int full_list) for (i = 0; i < sql_num_fields(mdb); i++) { field = sql_fetch_field(mdb); col_len = strlen(field->name); - if (full_list) { + if (type == VERT_LIST) { if (col_len > max_len) { max_len = col_len; } @@ -386,8 +386,8 @@ list_result(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, int full_list) } } - if (full_list) { - goto horizontal_list; + if (type == VERT_LIST) { + goto vertical_list; } list_dashes(mdb, send, ctx); @@ -421,7 +421,7 @@ list_result(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, int full_list) list_dashes(mdb, send, ctx); return; -horizontal_list: +vertical_list: while ((row = sql_fetch_row(mdb)) != NULL) { sql_field_seek(mdb, 0); diff --git a/bacula/src/cats/protos.h b/bacula/src/cats/protos.h index 1f292d364d..90822e2679 100644 --- a/bacula/src/cats/protos.h +++ b/bacula/src/cats/protos.h @@ -81,14 +81,18 @@ int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr); /* list.c */ -void db_list_pool_records(JCR *jcr, B_DB *db, DB_LIST_HANDLER sendit, void *ctx, int full); -void db_list_job_records(JCR *jcr, B_DB *db, JOB_DBR *jr, DB_LIST_HANDLER sendit, void *ctx, int full); +enum e_list_type { + HORZ_LIST, + VERT_LIST +}; +void db_list_pool_records(JCR *jcr, B_DB *db, DB_LIST_HANDLER sendit, void *ctx, e_list_type type); +void db_list_job_records(JCR *jcr, B_DB *db, JOB_DBR *jr, DB_LIST_HANDLER sendit, void *ctx, e_list_type type); void db_list_job_totals(JCR *jcr, B_DB *db, JOB_DBR *jr, DB_LIST_HANDLER sendit, void *ctx); void db_list_files_for_job(JCR *jcr, B_DB *db, uint32_t jobid, DB_LIST_HANDLER sendit, void *ctx); -void db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr, DB_LIST_HANDLER *sendit, void *ctx, int full); -void db_list_jobmedia_records(JCR *jcr, B_DB *mdb, uint32_t JobId, DB_LIST_HANDLER *sendit, void *ctx, int full); -int db_list_sql_query(JCR *jcr, B_DB *mdb, char *query, DB_LIST_HANDLER *sendit, void *ctx, int verbose, int full); -void db_list_client_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, int full); +void db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type); +void db_list_jobmedia_records(JCR *jcr, B_DB *mdb, uint32_t JobId, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type); +int db_list_sql_query(JCR *jcr, B_DB *mdb, char *query, DB_LIST_HANDLER *sendit, void *ctx, int verbose, e_list_type type); +void db_list_client_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type); /* update.c */ int db_update_job_start_record(JCR *jcr, B_DB *db, JOB_DBR *jr); diff --git a/bacula/src/cats/sql.c b/bacula/src/cats/sql.c index cf2dd5792d..d8eb522741 100644 --- a/bacula/src/cats/sql.c +++ b/bacula/src/cats/sql.c @@ -39,11 +39,7 @@ #if HAVE_MYSQL | HAVE_SQLITE -#ifdef HAVE_MYSQL -char catalog_db[] = "MySQL"; -#else -char catalog_db[] = "SQLite"; -#endif +uint32_t bacula_db_version = 0; /* Forward referenced subroutines */ void print_dashes(B_DB *mdb); @@ -73,14 +69,13 @@ static int int_handler(void *ctx, int num_fields, char **row) /* Check that the tables correspond to the version we want */ int check_tables_version(JCR *jcr, B_DB *mdb) { - uint32_t version; char *query = "SELECT VersionId FROM Version"; - version = 0; - db_sql_query(mdb, query, int_handler, (void *)&version); - if (version != BDB_VERSION) { + bacula_db_version = 0; + db_sql_query(mdb, query, int_handler, (void *)&bacula_db_version); + if (bacula_db_version != BDB_VERSION) { Mmsg(&mdb->errmsg, "Version error for database \"%s\". Wanted %d, got %d\n", - mdb->db_name, BDB_VERSION, version); + mdb->db_name, BDB_VERSION, bacula_db_version); Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg); return 0; } diff --git a/bacula/src/cats/sql_create.c b/bacula/src/cats/sql_create.c index 55b7eb13a5..0cc5deb0e2 100644 --- a/bacula/src/cats/sql_create.c +++ b/bacula/src/cats/sql_create.c @@ -360,10 +360,12 @@ int db_create_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr) { SQL_ROW row; int stat; + struct tm tm; db_lock(mdb); - Mmsg(&mdb->cmd, "SELECT FileSetId FROM FileSet WHERE \ -FileSet='%s' and MD5='%s'", fsr->FileSet, fsr->MD5); + fsr->created = false; + Mmsg(&mdb->cmd, "SELECT FileSetId,CreateTime FROM FileSet WHERE " +"FileSet='%s' AND MD5='%s'", fsr->FileSet, fsr->MD5); fsr->FileSetId = 0; if (QUERY_DB(jcr, mdb, mdb->cmd)) { @@ -383,6 +385,11 @@ FileSet='%s' and MD5='%s'", fsr->FileSet, fsr->MD5); return 0; } fsr->FileSetId = atoi(row[0]); + if (row[1] == NULL) { + fsr->cCreateTime[0] = 0; + } else { + bstrncpy(fsr->cCreateTime, row[1], sizeof(fsr->cCreateTime)); + } sql_free_result(mdb); db_unlock(mdb); return 1; @@ -390,9 +397,15 @@ FileSet='%s' and MD5='%s'", fsr->FileSet, fsr->MD5); sql_free_result(mdb); } + if (fsr->CreateTime == 0 && fsr->cCreateTime[0] == 0) { + fsr->CreateTime = time(NULL); + } + localtime_r(&fsr->CreateTime, &tm); + strftime(fsr->cCreateTime, sizeof(fsr->cCreateTime), "%Y-%m-%d %T", &tm); + /* Must create it */ - Mmsg(&mdb->cmd, "INSERT INTO FileSet (FileSet, MD5) VALUES \ -('%s', '%s')", fsr->FileSet, fsr->MD5); + Mmsg(&mdb->cmd, "INSERT INTO FileSet (FileSet,MD5,CreateTime) " +"VALUES ('%s','%s','%s')", fsr->FileSet, fsr->MD5, fsr->cCreateTime); if (!INSERT_DB(jcr, mdb, mdb->cmd)) { Mmsg2(&mdb->errmsg, _("Create DB FileSet record %s failed. ERR=%s\n"), @@ -402,6 +415,7 @@ FileSet='%s' and MD5='%s'", fsr->FileSet, fsr->MD5); stat = 0; } else { fsr->FileSetId = sql_insert_id(mdb); + fsr->created = true; stat = 1; } diff --git a/bacula/src/cats/sql_find.c b/bacula/src/cats/sql_find.c index 1f7f8e12eb..8ed28dd9b6 100644 --- a/bacula/src/cats/sql_find.c +++ b/bacula/src/cats/sql_find.c @@ -63,7 +63,7 @@ int db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime) { SQL_ROW row; - int JobId; + uint32_t JobId; db_lock(mdb); @@ -73,16 +73,16 @@ db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime) /* Differential is since last Full backup */ if (jr->Level == L_DIFFERENTIAL) { Mmsg(&mdb->cmd, -"SELECT JobId FROM Job WHERE JobStatus='T' AND Type='%c' AND \ -Level='%c' AND Name='%s' AND ClientId=%d AND FileSetId=%d \ -ORDER BY StartTime DESC LIMIT 1", +"SELECT JobId FROM Job WHERE JobStatus='T' AND Type='%c' AND " +"Level='%c' AND Name='%s' AND ClientId=%u AND FileSetId=%u " +"ORDER BY StartTime DESC LIMIT 1", jr->Type, L_FULL, jr->Name, jr->ClientId, jr->FileSetId); /* Incremental is since last Full, Incremental, or Differential */ } else if (jr->Level == L_INCREMENTAL) { Mmsg(&mdb->cmd, -"SELECT JobId FROM Job WHERE JobStatus='T' AND Type='%c' AND \ -Level IN ('%c','%c','%c') AND Name='%s' AND ClientId=%d \ -ORDER BY StartTime DESC LIMIT 1", +"SELECT JobId FROM Job WHERE JobStatus='T' AND Type='%c' AND " +"Level IN ('%c','%c','%c') AND Name='%s' AND ClientId=%u " +"ORDER BY StartTime DESC LIMIT 1", jr->Type, L_INCREMENTAL, L_DIFFERENTIAL, L_FULL, jr->Name, jr->ClientId); } else { @@ -92,12 +92,14 @@ ORDER BY StartTime DESC LIMIT 1", } Dmsg1(100, "Submitting: %s\n", mdb->cmd); if (!QUERY_DB(jcr, mdb, mdb->cmd)) { - Mmsg1(&mdb->errmsg, _("Query error for start time request: %s\n"), mdb->cmd); + Mmsg2(&mdb->errmsg, _("Query error for start time request: ERR=%s\nCMD=%s\n"), + sql_strerror(mdb), mdb->cmd); db_unlock(mdb); return 0; } if ((row = sql_fetch_row(mdb)) == NULL) { sql_free_result(mdb); + Mmsg0(&mdb->errmsg, _("No Job Found.\n")); db_unlock(mdb); return 0; } @@ -108,17 +110,18 @@ ORDER BY StartTime DESC LIMIT 1", } Dmsg1(100, "Submitting: %s\n", mdb->cmd); - Mmsg(&mdb->cmd, "SELECT StartTime FROM Job WHERE Job.JobId=%d", JobId); + Mmsg(&mdb->cmd, "SELECT StartTime FROM Job WHERE Job.JobId=%u", JobId); if (!QUERY_DB(jcr, mdb, mdb->cmd)) { - Mmsg1(&mdb->errmsg, _("Query error for start time request: %s\n"), mdb->cmd); + pm_strcpy(stime, ""); /* set EOS */ + Mmsg2(&mdb->errmsg, _("Query error for start time request: ERR=%s\nCMD=%s\n"), + sql_strerror(mdb), mdb->cmd); db_unlock(mdb); return 0; } if ((row = sql_fetch_row(mdb)) == NULL) { - pm_strcpy(stime, ""); /* set EOS */ - Mmsg2(&mdb->errmsg, _("No Job found for JobId=%d: %s\n"), JobId, sql_strerror(mdb)); + Mmsg2(&mdb->errmsg, _("No Job found for JobId=%u: ERR=%s\n"), JobId, sql_strerror(mdb)); sql_free_result(mdb); db_unlock(mdb); return 0; @@ -149,13 +152,13 @@ db_find_last_jobid(JCR *jcr, B_DB *mdb, JOB_DBR *jr) db_lock(mdb); if (jr->Level == L_VERIFY_CATALOG) { Mmsg(&mdb->cmd, -"SELECT JobId FROM Job WHERE Type='%c' AND Level='%c' AND Name='%s' AND \ -ClientId=%d ORDER BY StartTime DESC LIMIT 1", +"SELECT JobId FROM Job WHERE Type='%c' AND Level='%c' AND Name='%s' AND " +"ClientId=%u ORDER BY StartTime DESC LIMIT 1", JT_VERIFY, L_VERIFY_INIT, jr->Name, jr->ClientId); } else if (jr->Level == L_VERIFY_VOLUME_TO_CATALOG) { Mmsg(&mdb->cmd, -"SELECT JobId FROM Job WHERE Type='%c' AND \ -ClientId=%d ORDER BY StartTime DESC LIMIT 1", +"SELECT JobId FROM Job WHERE Type='%c' AND " +"ClientId=%u ORDER BY StartTime DESC LIMIT 1", JT_BACKUP, jr->ClientId); } else { Mmsg1(&mdb->errmsg, _("Unknown Job level=%c\n"), jr->Level); diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c index 1863060138..1adaa39e2e 100644 --- a/bacula/src/cats/sql_get.c +++ b/bacula/src/cats/sql_get.c @@ -623,11 +623,11 @@ int db_get_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr) db_lock(mdb); if (fsr->FileSetId != 0) { /* find by id */ Mmsg(&mdb->cmd, - "SELECT FileSetId, FileSet, MD5 FROM FileSet " + "SELECT FileSetId,FileSet,MD5,CreateTime FROM FileSet " "WHERE FileSetId=%u", fsr->FileSetId); } else { /* find by name */ Mmsg(&mdb->cmd, - "SELECT FileSetId, FileSet, MD5 FROM FileSet " + "SELECT FileSetId,FileSet,CreateTime MD5,FROM FileSet " "WHERE FileSet='%s'", fsr->FileSet); } @@ -645,6 +645,7 @@ int db_get_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr) fsr->FileSetId = atoi(row[0]); bstrncpy(fsr->FileSet, row[1]!=NULL?row[1]:"", sizeof(fsr->FileSet)); bstrncpy(fsr->MD5, row[2]!=NULL?row[2]:"", sizeof(fsr->MD5)); + bstrncpy(fsr->cCreateTime, row[3]!=NULL?row[3]:"", sizeof(fsr->cCreateTime)); stat = fsr->FileSetId; } sql_free_result(mdb); diff --git a/bacula/src/cats/sql_list.c b/bacula/src/cats/sql_list.c index 7cf72d8209..9ebd839f80 100644 --- a/bacula/src/cats/sql_list.c +++ b/bacula/src/cats/sql_list.c @@ -44,7 +44,7 @@ */ /* Imported subroutines */ -extern void list_result(B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, int full_list); +extern void list_result(B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type); extern int QueryDB(char *file, int line, JCR *jcr, B_DB *db, char *select_cmd); @@ -52,7 +52,7 @@ extern int QueryDB(char *file, int line, JCR *jcr, B_DB *db, char *select_cmd); * Submit general SQL query */ int db_list_sql_query(JCR *jcr, B_DB *mdb, char *query, DB_LIST_HANDLER *sendit, - void *ctx, int verbose, int full) + void *ctx, int verbose, e_list_type type) { db_lock(mdb); if (sql_query(mdb, query) != 0) { @@ -67,7 +67,7 @@ int db_list_sql_query(JCR *jcr, B_DB *mdb, char *query, DB_LIST_HANDLER *sendit, mdb->result = sql_store_result(mdb); if (mdb->result) { - list_result(mdb, sendit, ctx, full); + list_result(mdb, sendit, ctx, type); sql_free_result(mdb); } db_unlock(mdb); @@ -75,10 +75,10 @@ int db_list_sql_query(JCR *jcr, B_DB *mdb, char *query, DB_LIST_HANDLER *sendit, } void -db_list_pool_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, int full) +db_list_pool_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type) { db_lock(mdb); - if (full) { + if (type == VERT_LIST) { Mmsg(&mdb->cmd, "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog," "AcceptAnyVolume,VolRetention,VolUseDuration,MaxVolJobs,MaxVolBytes," "AutoPrune,Recycle,PoolType,LabelFormat " @@ -93,17 +93,17 @@ db_list_pool_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, in return; } - list_result(mdb, sendit, ctx, full); + list_result(mdb, sendit, ctx, type); sql_free_result(mdb); db_unlock(mdb); } void -db_list_client_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, int full) +db_list_client_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type) { db_lock(mdb); - if (full) { + if (type == VERT_LIST) { Mmsg(&mdb->cmd, "SELECT ClientId,Name,Uname,AutoPrune,FileRetention," "FileRetention,JobRetention " "FROM Client ORDER BY ClientId"); @@ -117,7 +117,7 @@ db_list_client_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, return; } - list_result(mdb, sendit, ctx, full); + list_result(mdb, sendit, ctx, type); sql_free_result(mdb); db_unlock(mdb); @@ -130,10 +130,10 @@ db_list_client_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, */ void db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr, - DB_LIST_HANDLER *sendit, void *ctx, int full) + DB_LIST_HANDLER *sendit, void *ctx, e_list_type type) { db_lock(mdb); - if (full) { + if (type == VERT_LIST) { if (mdbr->VolumeName[0] != 0) { Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,Slot,PoolId," "MediaType,FirstWritten,LastWritten,LabelDate,VolJobs," @@ -166,17 +166,17 @@ db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr, return; } - list_result(mdb, sendit, ctx, full); + list_result(mdb, sendit, ctx, type); sql_free_result(mdb); db_unlock(mdb); } void db_list_jobmedia_records(JCR *jcr, B_DB *mdb, uint32_t JobId, - DB_LIST_HANDLER *sendit, void *ctx, int full) + DB_LIST_HANDLER *sendit, void *ctx, e_list_type type) { db_lock(mdb); - if (full) { + if (type == VERT_LIST) { if (JobId > 0) { /* do by JobId */ Mmsg(&mdb->cmd, "SELECT JobMediaId,JobId,MediaId,Media.VolumeName," "FirstIndex,LastIndex,StartFile,EndFile,StartBlock,EndBlock " @@ -203,7 +203,7 @@ void db_list_jobmedia_records(JCR *jcr, B_DB *mdb, uint32_t JobId, return; } - list_result(mdb, sendit, ctx, full); + list_result(mdb, sendit, ctx, type); sql_free_result(mdb); db_unlock(mdb); @@ -219,10 +219,10 @@ void db_list_jobmedia_records(JCR *jcr, B_DB *mdb, uint32_t JobId, */ void db_list_job_records(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, - void *ctx, int full) + void *ctx, e_list_type type) { db_lock(mdb); - if (full) { + if (type == VERT_LIST) { if (jr->JobId == 0 && jr->Job[0] == 0) { Mmsg(&mdb->cmd, "SELECT JobId,Job,Job.Name,PurgedFiles,Type,Level," @@ -258,7 +258,7 @@ db_list_job_records(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, db_unlock(mdb); return; } - list_result(mdb, sendit, ctx, full); + list_result(mdb, sendit, ctx, type); sql_free_result(mdb); db_unlock(mdb); @@ -282,7 +282,7 @@ AS Files, sum(JobBytes) AS Bytes, Name AS Job FROM Job GROUP BY Name"); return; } - list_result(mdb, sendit, ctx, 0); + list_result(mdb, sendit, ctx, HORZ_LIST); sql_free_result(mdb); @@ -295,7 +295,7 @@ AS Files,sum(JobBytes) As Bytes FROM Job"); return; } - list_result(mdb, sendit, ctx, 0); + list_result(mdb, sendit, ctx, HORZ_LIST); sql_free_result(mdb); db_unlock(mdb); @@ -317,7 +317,7 @@ AND Path.PathId=File.PathId", return; } - list_result(mdb, sendit, ctx, 0); + list_result(mdb, sendit, ctx, HORZ_LIST); sql_free_result(mdb); db_unlock(mdb); diff --git a/bacula/src/cats/sqlite.c b/bacula/src/cats/sqlite.c index d0bc1144db..928a43f864 100644 --- a/bacula/src/cats/sqlite.c +++ b/bacula/src/cats/sqlite.c @@ -406,7 +406,7 @@ list_dashes(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx) * list on one line horizontally. */ void -list_result(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, int full_list) +list_result(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, e_list_type type) { SQL_FIELD *field; SQL_ROW row; @@ -422,7 +422,7 @@ list_result(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, int full_list) for (i = 0; i < sql_num_fields(mdb); i++) { field = sql_fetch_field(mdb); col_len = strlen(field->name); - if (full_list) { + if (type == VERT_LIST) { if (col_len > max_len) { max_len = col_len; } @@ -440,8 +440,8 @@ list_result(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, int full_list) } } - if (full_list) { - goto horizontal_list; + if (type == VERT_LIST) { + goto vertical_list; } list_dashes(mdb, send, ctx); @@ -475,7 +475,7 @@ list_result(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, int full_list) list_dashes(mdb, send, ctx); return; -horizontal_list: +vertical_list: while ((row = sql_fetch_row(mdb)) != NULL) { sql_field_seek(mdb, 0); diff --git a/bacula/src/console/console.c b/bacula/src/console/console.c index 64268bd653..a05ee37f0f 100644 --- a/bacula/src/console/console.c +++ b/bacula/src/console/console.c @@ -76,7 +76,7 @@ static int sleepcmd(FILE *input, BSOCK *UA_sock); static void usage() { - fprintf(stderr, + fprintf(stderr, _( "\nVersion: " VERSION " (" BDATE ")\n\n" "Usage: console [-s] [-c config_file] [-d debug_level] [config_file]\n" " -c set configuration file to file\n" @@ -84,7 +84,7 @@ static void usage() " -s no signals\n" " -t test - read configuration and exit\n" " -? print this message.\n" -"\n"); +"\n")); exit(1); } @@ -196,7 +196,7 @@ static void read_and_process_input(FILE *input, BSOCK *UA_sock) at_prompt = FALSE; /* @ => internal command for us */ if (UA_sock->msg[0] == '@') { - parse_command_args(UA_sock->msg, args, &argc, argk, argv); + parse_args(UA_sock->msg, args, &argc, argk, argv, MAX_CMD_ARGS); if (!do_a_command(input, UA_sock)) { break; } @@ -313,8 +313,8 @@ int main(int argc, char *argv[]) } UnlockRes(); if (ndir == 0) { - Emsg1(M_ERROR_TERM, 0, "No Director resource defined in %s\n\ -Without that I don't how to speak to the Director :-(\n", configfile); + Emsg1(M_ERROR_TERM, 0, _("No Director resource defined in %s\n\ +Without that I don't how to speak to the Director :-(\n"), configfile); } if (test_config) { @@ -327,20 +327,20 @@ Without that I don't how to speak to the Director :-(\n", configfile); if (ndir > 1) { UA_sock = init_bsock(NULL, 0, "", "", 0); try_again: - sendit("Available Directors:\n"); + sendit(_("Available Directors:\n")); LockRes(); ndir = 0; for (dir = NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) { - fprintf(output, "%d %s at %s:%d\n", 1+ndir++, dir->hdr.name, dir->address, + fprintf(output, _("%d %s at %s:%d\n"), 1+ndir++, dir->hdr.name, dir->address, dir->DIRport); } UnlockRes(); - if (get_cmd(stdin, "Select Director: ", UA_sock, 600) < 0) { + if (get_cmd(stdin, _("Select Director: "), UA_sock, 600) < 0) { return 1; } item = atoi(UA_sock->msg); if (item < 0 || item > ndir) { - sendit("You must enter a number between 1 and %d\n", ndir); + sendit(_("You must enter a number between 1 and %d\n"), ndir); goto try_again; } LockRes(); @@ -357,7 +357,7 @@ try_again: } - sendit("Connecting to Director %s:%d\n", dir->address,dir->DIRport); + sendit(_("Connecting to Director %s:%d\n"), dir->address,dir->DIRport); UA_sock = bnet_connect(NULL, 5, 15, "Director daemon", dir->address, NULL, dir->DIRport, 0); if (UA_sock == NULL) { @@ -512,16 +512,16 @@ static int inputcmd(FILE *input, BSOCK *UA_sock) FILE *fd; if (argc > 2) { - sendit("Too many arguments.\n"); + sendit(_("Too many arguments.\n")); return 0; } if (argc == 1) { - sendit("First argument must be a filename.\n"); + sendit(_("First argument must be a filename.\n")); return 0; } fd = fopen(argk[1], "r"); if (!fd) { - sendit("Cannot open file. ERR=%s\n", strerror(errno)); + sendit(_("Cannot open file. ERR=%s\n"), strerror(errno)); return 0; } read_and_process_input(fd, UA_sock); @@ -548,7 +548,7 @@ static int do_outputcmd(FILE *input, BSOCK *UA_sock) char *mode = "a+"; if (argc > 3) { - sendit("Too many arguments.\n"); + sendit(_("Too many arguments.\n")); return 1; } if (argc == 1) { @@ -564,7 +564,7 @@ static int do_outputcmd(FILE *input, BSOCK *UA_sock) } fd = fopen(argk[1], mode); if (!fd) { - sendit("Cannot open file. ERR=%s\n", strerror(errno)); + sendit(_("Cannot open file. ERR=%s\n"), strerror(errno)); return 1; } output = fd; diff --git a/bacula/src/dird/Makefile.in b/bacula/src/dird/Makefile.in index 30208e19ca..bb8a01711a 100644 --- a/bacula/src/dird/Makefile.in +++ b/bacula/src/dird/Makefile.in @@ -30,7 +30,7 @@ SVRSRCS = dird.c admin.c authenticate.c \ recycle.c restore.c run_conf.c \ scheduler.c sql_cmds.c \ ua_cmds.c ua_dotcmds.c \ - ua_db_query.c ua_retention.c \ + ua_query.c ua_retention.c \ ua_input.c ua_label.c ua_output.c ua_prune.c \ ua_purge.c ua_restore.c ua_run.c \ ua_select.c ua_server.c \ @@ -43,7 +43,7 @@ SVROBJS = dird.o admin.o authenticate.o \ recycle.o restore.o run_conf.o \ scheduler.o sql_cmds.o \ ua_cmds.o ua_dotcmds.o \ - ua_db_query.o ua_retention.o \ + ua_query.o ua_retention.o \ ua_input.o ua_label.o ua_output.o ua_prune.o \ ua_purge.o ua_restore.o ua_run.o \ ua_select.o ua_server.o \ diff --git a/bacula/src/dird/backup.c b/bacula/src/dird/backup.c index 277537a856..ea8782c279 100644 --- a/bacula/src/dird/backup.c +++ b/bacula/src/dird/backup.c @@ -52,7 +52,7 @@ static char EndBackup[] = "2801 End Backup Job TermCode=%d JobFiles=%u " /* Forward referenced functions */ -static void backup_cleanup(JCR *jcr, int TermCode, char *since); +static void backup_cleanup(JCR *jcr, int TermCode, char *since, FILESET_DBR *fsr); static int wait_for_job_termination(JCR *jcr); /* External functions */ @@ -83,24 +83,28 @@ int do_backup(JCR *jcr) * Get or Create FileSet record */ memset(&fsr, 0, sizeof(fsr)); - strcpy(fsr.FileSet, jcr->fileset->hdr.name); + bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet)); if (jcr->fileset->have_MD5) { struct MD5Context md5c; unsigned char signature[16]; memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c)); MD5Final(signature, &md5c); bin_to_base64(fsr.MD5, (char *)signature, 16); /* encode 16 bytes */ - strcpy(jcr->fileset->MD5, fsr.MD5); + bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5)); } else { Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 signature not found.\n")); } if (!db_create_fileset_record(jcr, jcr->db, &fsr)) { - Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet record. ERR=%s\n"), - db_strerror(jcr->db)); + Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"), + fsr.FileSet, db_strerror(jcr->db)); goto bail_out; } jcr->jr.FileSetId = fsr.FileSetId; - Dmsg2(119, "Created FileSet %s record %d\n", jcr->fileset->hdr.name, + if (fsr.created) { + Jmsg(jcr, M_INFO, 0, _("Created new FileSet record \"%s\" at %s\n"), + fsr.FileSet, fsr.cCreateTime); + } + Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name, jcr->jr.FileSetId); /* Look up the last @@ -116,10 +120,13 @@ int do_backup(JCR *jcr) /* Look up start time of last job */ jcr->jr.JobId = 0; if (!db_find_job_start_time(jcr, jcr->db, &jcr->jr, &jcr->stime)) { + Jmsg(jcr, M_INFO, 0, "%s", db_strerror(jcr->db)); Jmsg(jcr, M_INFO, 0, _("No prior or suitable FULL backup found. Doing FULL backup.\n")); + bsnprintf(since, sizeof(since), " (upgraded from %s)", + level_to_str(jcr->jr.Level)); jcr->JobLevel = jcr->jr.Level = L_FULL; } else { - strcpy(since, ", since="); + bstrncpy(since, ", since=", sizeof(since)); bstrncat(since, jcr->stime, sizeof(since)); } Dmsg1(115, "Last start time = %s\n", jcr->stime); @@ -136,17 +143,17 @@ int do_backup(JCR *jcr) jcr->fname = (char *) get_pool_memory(PM_FNAME); /* Print Job Start message */ - Jmsg(jcr, M_INFO, 0, _("Start Backup JobId %d, Job=%s\n"), + Jmsg(jcr, M_INFO, 0, _("Start Backup JobId %u, Job=%s\n"), jcr->JobId, jcr->Job); /* * Get the Pool record */ memset(&pr, 0, sizeof(pr)); - strcpy(pr.Name, jcr->pool->hdr.name); + bstrncpy(pr.Name, jcr->pool->hdr.name, sizeof(pr.Name)); while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */ /* Try to create the pool */ - if (create_pool(jcr, jcr->db, jcr->pool, 1) < 0) { + if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) { Jmsg(jcr, M_FATAL, 0, _("Pool %s not in database. %s"), pr.Name, db_strerror(jcr->db)); goto bail_out; @@ -209,7 +216,7 @@ int do_backup(JCR *jcr) } bnet_fsend(fd, storaddr, jcr->store->address, jcr->store->SDDport, jcr->store->enable_ssl); - if (!response(fd, OKstore, "Storage", 1)) { + if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) { goto bail_out; } @@ -236,19 +243,19 @@ int do_backup(JCR *jcr) goto bail_out; } Dmsg1(120, ">filed: %s", fd->msg); - if (!response(fd, OKlevel, "Level", 1)) { + if (!response(jcr, fd, OKlevel, "Level", DISPLAY_ERROR)) { goto bail_out; } /* Send backup command */ bnet_fsend(fd, backupcmd); - if (!response(fd, OKbackup, "backup", 1)) { + if (!response(jcr, fd, OKbackup, "backup", DISPLAY_ERROR)) { goto bail_out; } /* Pickup Job termination data */ stat = wait_for_job_termination(jcr); - backup_cleanup(jcr, stat, since); + backup_cleanup(jcr, stat, since, &fsr); return 1; bail_out: @@ -256,7 +263,7 @@ bail_out: free_pool_memory(jcr->stime); jcr->stime = NULL; } - backup_cleanup(jcr, JS_ErrorTerminated, since); + backup_cleanup(jcr, JS_ErrorTerminated, since, &fsr); return 0; } @@ -309,7 +316,7 @@ static int wait_for_job_termination(JCR *jcr) /* * Release resources allocated during backup. */ -static void backup_cleanup(JCR *jcr, int TermCode, char *since) +static void backup_cleanup(JCR *jcr, int TermCode, char *since, FILESET_DBR *fsr) { char sdt[50], edt[50]; char ec1[30], ec2[30], ec3[30], compress[50]; @@ -332,7 +339,7 @@ static void backup_cleanup(JCR *jcr, int TermCode, char *since) set_jcr_job_status(jcr, JS_ErrorTerminated); } - strcpy(mr.VolumeName, jcr->VolumeName); + bstrncpy(mr.VolumeName, jcr->VolumeName, sizeof(mr.VolumeName)); if (!db_get_media_record(jcr, jcr->db, &mr)) { Jmsg(jcr, M_WARNING, 0, _("Error getting Media record for Volume \"%s\": ERR=%s"), mr.VolumeName, db_strerror(jcr->db)); @@ -440,13 +447,13 @@ static void backup_cleanup(JCR *jcr, int TermCode, char *since) } if (jcr->ReadBytes == 0) { - strcpy(compress, "None"); + bstrncpy(compress, "None", sizeof(compress)); } else { compression = (double)100 - 100.0 * ((double)jcr->JobBytes / (double)jcr->ReadBytes); if (compression < 0.5) { - strcpy(compress, "None"); + bstrncpy(compress, "None", sizeof(compress)); } else { - sprintf(compress, "%.1f %%", (float)compression); + bsnprintf(compress, sizeof(compress), "%.1f %%", (float)compression); } } jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg)); @@ -455,9 +462,9 @@ static void backup_cleanup(JCR *jcr, int TermCode, char *since) Jmsg(jcr, msg_type, 0, _("Bacula " VERSION " (" LSMDATE "): %s\n\ JobId: %d\n\ Job: %s\n\ -FileSet: %s\n\ Backup Level: %s%s\n\ Client: %s\n\ +FileSet: \"%s\" %s\n\ Start time: %s\n\ End time: %s\n\ Files Written: %s\n\ @@ -475,9 +482,9 @@ Termination: %s\n\n"), edt, jcr->jr.JobId, jcr->jr.Job, - jcr->fileset->hdr.name, level_to_str(jcr->JobLevel), since, jcr->client->hdr.name, + jcr->fileset->hdr.name, fsr->cCreateTime, sdt, edt, edit_uint64_with_commas(jcr->jr.JobFiles, ec1), diff --git a/bacula/src/dird/dird.c b/bacula/src/dird/dird.c index ae26f68e16..0df270545d 100644 --- a/bacula/src/dird/dird.c +++ b/bacula/src/dird/dird.c @@ -370,13 +370,13 @@ Without that I don't know who I am :-(\n"), configfile); catalog->db_password, catalog->db_address, catalog->db_port, catalog->db_socket); if (!db_open_database(NULL, db)) { - Jmsg(NULL, M_FATAL, 0, "%s", db_strerror(db)); + OK = FALSE; /* Error message already printed */ } else { /* If a pool is defined for this job, create the pool DB * record if it is not already created. */ if (job->pool) { - create_pool(NULL, db, job->pool, 0); /* update request */ + create_pool(NULL, db, job->pool, POOL_OP_UPDATE); /* update request */ } db_close_database(NULL, db); } diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h index 62531405af..f9f28dca6c 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -30,31 +30,31 @@ /* * Resource codes -- they must be sequential for indexing */ -#define R_FIRST 1001 - -#define R_DIRECTOR 1001 -#define R_CLIENT 1002 -#define R_JOB 1003 -#define R_STORAGE 1004 -#define R_CATALOG 1005 -#define R_SCHEDULE 1006 -#define R_FILESET 1007 -#define R_GROUP 1008 -#define R_POOL 1009 -#define R_MSGS 1010 -#define R_COUNTER 1011 -#define R_CONSOLE 1012 - -#define R_LAST R_CONSOLE +#define R_FIRST 1001 + +#define R_DIRECTOR 1001 +#define R_CLIENT 1002 +#define R_JOB 1003 +#define R_STORAGE 1004 +#define R_CATALOG 1005 +#define R_SCHEDULE 1006 +#define R_FILESET 1007 +#define R_GROUP 1008 +#define R_POOL 1009 +#define R_MSGS 1010 +#define R_COUNTER 1011 +#define R_CONSOLE 1012 + +#define R_LAST R_CONSOLE /* * Some resource attributes */ -#define R_NAME 1020 -#define R_ADDRESS 1021 -#define R_PASSWORD 1022 -#define R_TYPE 1023 -#define R_BACKUP 1024 +#define R_NAME 1020 +#define R_ADDRESS 1021 +#define R_PASSWORD 1022 +#define R_TYPE 1023 +#define R_BACKUP 1024 /* Used for certain KeyWord tables */ @@ -99,7 +99,7 @@ struct DIRRES { char *pid_directory; /* PidDirectory */ char *subsys_directory; /* SubsysDirectory */ int require_ssl; /* Require SSL for all connections */ - struct s_res_msgs *messages; /* Daemon message handler */ + MSGS *messages; /* Daemon message handler */ uint32_t MaxConcurrentJobs; /* Max concurrent jobs for whole director */ utime_t FDConnectTimeout; /* timeout for connect in seconds */ utime_t SDConnectTimeout; /* timeout in seconds */ @@ -306,19 +306,19 @@ struct POOL { * resource structure definitions. */ union URES { - DIRRES res_dir; - CONRES res_con; - CLIENT res_client; - STORE res_store; - CAT res_cat; - JOB res_job; - FILESET res_fs; - SCHED res_sch; - GROUP res_group; - POOL res_pool; - MSGS res_msgs; - COUNTER res_counter; - RES hdr; + DIRRES res_dir; + CONRES res_con; + CLIENT res_client; + STORE res_store; + CAT res_cat; + JOB res_job; + FILESET res_fs; + SCHED res_sch; + GROUP res_group; + POOL res_pool; + MSGS res_msgs; + COUNTER res_counter; + RES hdr; }; diff --git a/bacula/src/dird/fd_cmds.c b/bacula/src/dird/fd_cmds.c index 7b2440e450..2d08770bc4 100644 --- a/bacula/src/dird/fd_cmds.c +++ b/bacula/src/dird/fd_cmds.c @@ -233,10 +233,10 @@ static int send_list(JCR *jcr, int list) } bnet_sig(fd, BNET_EOD); /* end of data */ if (list == INC_LIST) { - if (!response(fd, OKinc, "Include", 1)) { + if (!response(jcr, fd, OKinc, "Include", DISPLAY_ERROR)) { goto bail_out; } - } else if (!response(fd, OKexc, "Exclude", 1)) { + } else if (!response(jcr, fd, OKexc, "Exclude", DISPLAY_ERROR)) { goto bail_out; } return 1; diff --git a/bacula/src/dird/getmsg.c b/bacula/src/dird/getmsg.c index 37fd753b7f..0e5eceae06 100644 --- a/bacula/src/dird/getmsg.c +++ b/bacula/src/dird/getmsg.c @@ -209,7 +209,7 @@ static char *find_msg_start(char *msg) * Returns: 0 on failure * 1 on success */ -int response(BSOCK *fd, char *resp, char *cmd, int prtmsg) +int response(JCR *jcr, BSOCK *fd, char *resp, char *cmd, e_prtmsg prtmsg) { int n; @@ -221,13 +221,13 @@ int response(BSOCK *fd, char *resp, char *cmd, int prtmsg) if (strcmp(fd->msg, resp) == 0) { return 1; } - if (prtmsg) { - Emsg3(M_FATAL, 0, _("FD gave bad response to %s command: wanted %s got: %s\n"), + if (prtmsg == DISPLAY_ERROR) { + Jmsg(jcr, M_FATAL, 0, _("FD gave bad response to %s command: wanted %s got: %s\n"), cmd, resp, fd->msg); } return 0; } - Emsg2(M_FATAL, 0, _("Socket error from Filed on %s command: ERR=%s\n"), + Jmsg(jcr, M_FATAL, 0, _("Socket error from Filed on %s command: ERR=%s\n"), cmd, bnet_strerror(fd)); return 0; } diff --git a/bacula/src/dird/inc_conf.c b/bacula/src/dird/inc_conf.c index 7883627618..4dcfe3f156 100644 --- a/bacula/src/dird/inc_conf.c +++ b/bacula/src/dird/inc_conf.c @@ -297,7 +297,7 @@ void store_inc(LEX *lc, struct res_items *item, int index, int pass) } } /* Note, MD5Final is done in backup.c */ - } else { /* pass 1 */ + } else { /* pass 2 */ while (lex_get_token(lc, T_ALL) != T_EOB) {} } @@ -318,6 +318,10 @@ void store_finc(LEX *lc, struct res_items *item, int index, int pass) int token, i; INCEXE *incexe; + if (!res_all.res_fs.have_MD5) { + MD5Init(&res_all.res_fs.md5c); + res_all.res_fs.have_MD5 = TRUE; + } res_all.res_fs.finclude = TRUE; token = lex_get_token(lc, T_ALL); if (token != T_BOB) { diff --git a/bacula/src/dird/msgchan.c b/bacula/src/dird/msgchan.c index 808b63c42b..e3289d9b9d 100644 --- a/bacula/src/dird/msgchan.c +++ b/bacula/src/dird/msgchan.c @@ -156,7 +156,7 @@ int start_storage_daemon_job(JCR *jcr) device_name_len + media_type_len + pool_type_len + pool_name_len); bnet_fsend(sd, use_device, device_name, media_type, pool_name, pool_type); Dmsg1(110, ">stored: %s", sd->msg); - status = response(sd, OK_device, "Use Device", 0); + status = response(jcr, sd, OK_device, "Use Device", NO_DISPLAY); if (!status) { pm_strcpy(&pool_type, sd->msg); /* save message */ Jmsg(jcr, M_FATAL, 0, _("\n" diff --git a/bacula/src/dird/protos.h b/bacula/src/dird/protos.h index 388511b0bf..8a4fcd1dc1 100644 --- a/bacula/src/dird/protos.h +++ b/bacula/src/dird/protos.h @@ -48,13 +48,20 @@ extern char *level_to_str(int level); /* fd_cmds.c */ extern int connect_to_file_daemon(JCR *jcr, int retry_interval, - int max_retry_time, int verbose); + int max_retry_time, int verbose); extern int send_include_list(JCR *jcr); extern int send_exclude_list(JCR *jcr); extern int get_attributes_and_put_in_catalog(JCR *jcr); extern int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId); extern int put_file_into_catalog(JCR *jcr, long file_index, char *fname, - char *link, char *attr, int stream); + char *link, char *attr, int stream); + +/* getmsg.c */ +enum e_prtmsg { + DISPLAY_ERROR, + NO_DISPLAY +}; +extern int response(JCR *jcr, BSOCK *fd, char *resp, char *cmd, e_prtmsg prtmsg); /* job.c */ extern void set_jcr_defaults(JCR *jcr, JOB *job); @@ -67,11 +74,10 @@ extern void mount_request(JCR *jcr, BSOCK *bs, char *buf); /* msgchan.c */ extern int connect_to_storage_daemon(JCR *jcr, int retry_interval, - int max_retry_time, int verbose); + int max_retry_time, int verbose); extern int start_storage_daemon_job(JCR *jcr); extern int start_storage_daemon_message_thread(JCR *jcr); extern int bget_dirmsg(BSOCK *bs); -extern int response(BSOCK *fd, char *resp, char *cmd, int prtmsg); extern void wait_for_storage_daemon_termination(JCR *jcr); /* newvol.c */ @@ -83,7 +89,11 @@ int do_a_dot_command(UAContext *ua, char *cmd); int qmessagescmd(UAContext *ua, char *cmd); int open_db(UAContext *ua); void close_db(UAContext *ua); -int create_pool(JCR *jcr, B_DB *db, POOL *pool, int create); +enum e_pool_op { + POOL_OP_UPDATE, + POOL_OP_CREATE +}; +int create_pool(JCR *jcr, B_DB *db, POOL *pool, e_pool_op op); void set_pool_dbr_defaults_in_media_dbr(MEDIA_DBR *mr, POOL_DBR *pr); /* ua_input.c */ @@ -102,28 +112,28 @@ void prtit(void *ctx, char *msg); void bsendmsg(void *sock, char *fmt, ...); /* ua_select.c */ -STORE *select_storage_resource(UAContext *ua); -JOB *select_job_resource(UAContext *ua); -JOB *select_restore_job_resource(UAContext *ua); -CLIENT *select_client_resource(UAContext *ua); +STORE *select_storage_resource(UAContext *ua); +JOB *select_job_resource(UAContext *ua); +JOB *select_restore_job_resource(UAContext *ua); +CLIENT *select_client_resource(UAContext *ua); FILESET *select_fileset_resource(UAContext *ua); -int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr); -int select_media_dbr(UAContext *ua, MEDIA_DBR *mr); -int select_pool_dbr(UAContext *ua, POOL_DBR *pr); -int select_client_dbr(UAContext *ua, CLIENT_DBR *cr); - -void start_prompt(UAContext *ua, char *msg); -void add_prompt(UAContext *ua, char *prompt); -int do_prompt(UAContext *ua, char *automsg, char *msg, char *prompt, int max_prompt); -CAT *get_catalog_resource(UAContext *ua); +int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr); +int select_media_dbr(UAContext *ua, MEDIA_DBR *mr); +int select_pool_dbr(UAContext *ua, POOL_DBR *pr); +int select_client_dbr(UAContext *ua, CLIENT_DBR *cr); + +void start_prompt(UAContext *ua, char *msg); +void add_prompt(UAContext *ua, char *prompt); +int do_prompt(UAContext *ua, char *automsg, char *msg, char *prompt, int max_prompt); +CAT *get_catalog_resource(UAContext *ua); STORE *get_storage_resource(UAContext *ua, int use_default); -int get_media_type(UAContext *ua, char *MediaType, int max_media); -int get_pool_dbr(UAContext *ua, POOL_DBR *pr); -int get_client_dbr(UAContext *ua, CLIENT_DBR *cr); +int get_media_type(UAContext *ua, char *MediaType, int max_media); +int get_pool_dbr(UAContext *ua, POOL_DBR *pr); +int get_client_dbr(UAContext *ua, CLIENT_DBR *cr); POOL *get_pool_resource(UAContext *ua); POOL *select_pool_resource(UAContext *ua); CLIENT *get_client_resource(UAContext *ua); -int get_job_dbr(UAContext *ua, JOB_DBR *jr); +int get_job_dbr(UAContext *ua, JOB_DBR *jr); int find_arg_keyword(UAContext *ua, char **list); int find_arg(UAContext *ua, char *keyword); diff --git a/bacula/src/dird/query.sql b/bacula/src/dird/query.sql index 11b09a2ad7..0cecb5b45f 100644 --- a/bacula/src/dird/query.sql +++ b/bacula/src/dird/query.sql @@ -41,7 +41,7 @@ SELECT Job.JobId, StartTime AS JobStartTime, VolumeName, Client.Name AS ClientNa :List last 20 Full Backups for a Client: *Enter Client name: Select Job.JobId,Client.Name as Client,StartTime,JobFiles,JobBytes, -JobMedia.StartFile as VolFile, VolumeName +JobMedia.StartFile as VolFile,VolumeName FROM Client,Job,JobMedia,Media WHERE Client.Name='%1' AND Client.ClientId=Job.ClientId diff --git a/bacula/src/dird/restore.c b/bacula/src/dird/restore.c index 38dc16ba16..a866320387 100644 --- a/bacula/src/dird/restore.c +++ b/bacula/src/dird/restore.c @@ -192,7 +192,7 @@ int do_restore(JCR *jcr) } bnet_fsend(fd, storaddr, jcr->store->address, jcr->store->SDDport); Dmsg1(6, "dird>filed: %s\n", fd->msg); - if (!response(fd, OKstore, "Storage", 1)) { + if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) { restore_cleanup(jcr, JS_ErrorTerminated); return 0; } @@ -219,7 +219,7 @@ int do_restore(JCR *jcr) rjr.VolSessionId, rjr.VolSessionTime, rjr.StartFile, rjr.EndFile, rjr.StartBlock, rjr.EndBlock); - if (!response(fd, OKsession, "Session", 1)) { + if (!response(jcr, fd, OKsession, "Session", DISPLAY_ERROR)) { restore_cleanup(jcr, JS_ErrorTerminated); return 0; } @@ -246,7 +246,7 @@ int do_restore(JCR *jcr) bnet_fsend(fd, restorecmd, replace, where); unbash_spaces(where); - if (!response(fd, OKrestore, "Restore", 1)) { + if (!response(jcr, fd, OKrestore, "Restore", DISPLAY_ERROR)) { restore_cleanup(jcr, JS_ErrorTerminated); return 0; } @@ -385,7 +385,7 @@ static int send_bootstrap_file(JCR *jcr) } bnet_sig(fd, BNET_EOD); fclose(bs); - if (!response(fd, OKbootstrap, "Bootstrap", 1)) { + if (!response(jcr, fd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) { set_jcr_job_status(jcr, JS_ErrorTerminated); return 0; } diff --git a/bacula/src/dird/sql_cmds.c b/bacula/src/dird/sql_cmds.c index e77ad04978..1e4d0a2e7c 100644 --- a/bacula/src/dird/sql_cmds.c +++ b/bacula/src/dird/sql_cmds.c @@ -227,7 +227,7 @@ char *uar_sel_all_temp1 = "SELECT * FROM temp1"; /* Select filesets for this Client */ char *uar_sel_fileset = - "SELECT FileSet.FileSetId,FileSet.FileSet,FileSet.MD5 FROM Job," + "SELECT FileSet.FileSetId,FileSet.FileSet,FileSet.CreateTime FROM Job," "Client,FileSet WHERE Job.FileSetId=FileSet.FileSetId " "AND Job.ClientId=%u AND Client.ClientId=%u " "GROUP BY FileSet.FileSetId ORDER BY FileSet.FileSetId"; diff --git a/bacula/src/dird/ua.h b/bacula/src/dird/ua.h index 73aa81f9ff..f46992802b 100644 --- a/bacula/src/dird/ua.h +++ b/bacula/src/dird/ua.h @@ -29,7 +29,7 @@ #define __UA_H_ 1 -typedef struct s_ua_context { +struct UAContext { BSOCK *UA_sock; BSOCK *sd; JCR *jcr; @@ -50,6 +50,6 @@ typedef struct s_ua_context { int verbose; /* set for normal UA verbosity */ uint32_t pint32_val; /* positive integer */ int32_t int32_val; /* positive/negative */ -} UAContext; +}; #endif diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index f39890d573..62a6ada498 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -211,7 +211,7 @@ static int addcmd(UAContext *ua, char *cmd) /* Get media type */ if ((store = get_storage_resource(ua, 0)) != NULL) { - strcpy(mr.MediaType, store->media_type); + bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType)); } else if (!get_media_type(ua, mr.MediaType, sizeof(mr.MediaType))) { return 1; } @@ -223,7 +223,7 @@ static int addcmd(UAContext *ua, char *cmd) } for (;;) { char buf[100]; - sprintf(buf, _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max); + bsnprintf(buf, sizeof(buf), _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max); if (!get_pint(ua, buf)) { return 1; } @@ -257,7 +257,7 @@ getVolName: goto getVolName; } - strcpy(name, ua->cmd); + bstrncpy(name, ua->cmd, sizeof(name)); if (num > 0) { strcat(name, "%04d"); @@ -286,7 +286,7 @@ getVolName: set_pool_dbr_defaults_in_media_dbr(&mr, &pr); for (i=startnum; i < num+startnum; i++) { - sprintf(mr.VolumeName, name, i); + bsnprintf(mr.VolumeName, sizeof(mr.VolumeName), name, i); mr.Slot = slot++; Dmsg1(200, "Create Volume %s\n", mr.VolumeName); if (!db_create_media_record(ua->jcr, ua->db, &mr)) { @@ -484,10 +484,10 @@ static int cancelcmd(UAContext *ua, char *cmd) * depending on if we are creating the Pool or we are * simply bringing it into agreement with the resource (updage). */ -void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, int create) +static void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op) { strcpy(pr->PoolType, pool->pool_type); - if (create) { + if (op == POOL_OP_CREATE) { pr->MaxVols = pool->max_volumes; pr->NumVols = 0; } else { /* update pool */ @@ -523,7 +523,7 @@ void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, int create) * 1 record created */ -int create_pool(JCR *jcr, B_DB *db, POOL *pool, int create) +int create_pool(JCR *jcr, B_DB *db, POOL *pool, e_pool_op op) { POOL_DBR pr; @@ -533,14 +533,14 @@ int create_pool(JCR *jcr, B_DB *db, POOL *pool, int create) if (db_get_pool_record(jcr, db, &pr)) { /* Pool Exists */ - if (!create) { /* update request */ - set_pooldbr_from_poolres(&pr, pool, 0); + if (op == POOL_OP_UPDATE) { /* update request */ + set_pooldbr_from_poolres(&pr, pool, op); db_update_pool_record(jcr, db, &pr); } return 0; /* exists */ } - set_pooldbr_from_poolres(&pr, pool, 1); + set_pooldbr_from_poolres(&pr, pool, op); if (!db_create_pool_record(jcr, db, &pr)) { return -1; /* error */ @@ -567,7 +567,7 @@ static int createcmd(UAContext *ua, char *cmd) return 1; } - switch (create_pool(ua->jcr, ua->db, pool, 1)) { + switch (create_pool(ua->jcr, ua->db, pool, POOL_OP_CREATE)) { case 0: bsendmsg(ua, _("Error: Pool %s already exists.\n\ Use update to change it.\n"), pool->hdr.name); @@ -911,7 +911,7 @@ static int update_pool(UAContext *ua) return 0; } - set_pooldbr_from_poolres(&pr, pool, 0); /* update */ + set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE); /* update */ id = db_update_pool_record(ua->jcr, ua->db, &pr); if (id <= 0) { @@ -920,7 +920,7 @@ static int update_pool(UAContext *ua) } query = get_pool_memory(PM_MESSAGE); Mmsg(&query, list_pool, pr.PoolId); - db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, 0); + db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST); free_pool_memory(query); bsendmsg(ua, _("Pool DB record updated from resource.\n")); return 1; diff --git a/bacula/src/dird/ua_input.c b/bacula/src/dird/ua_input.c index 646d349195..65505a716c 100644 --- a/bacula/src/dird/ua_input.c +++ b/bacula/src/dird/ua_input.c @@ -131,5 +131,5 @@ int get_yesno(UAContext *ua, char *prompt) void parse_ua_args(UAContext *ua) { - return parse_command_args(ua->cmd, ua->args, &ua->argc, ua->argk, ua->argv); + parse_args(ua->cmd, ua->args, &ua->argc, ua->argk, ua->argv, MAX_CMD_ARGS); } diff --git a/bacula/src/dird/ua_output.c b/bacula/src/dird/ua_output.c index a2edf426bb..76045c7038 100644 --- a/bacula/src/dird/ua_output.c +++ b/bacula/src/dird/ua_output.c @@ -46,7 +46,7 @@ extern brwlock_t con_lock; /* Imported functions */ /* Forward referenced functions */ -static int do_listcmd(UAContext *ua, char *cmd, int llist); +static int do_listcmd(UAContext *ua, char *cmd, e_list_type llist); /* @@ -194,16 +194,16 @@ int showcmd(UAContext *ua, char *cmd) /* Do long or full listing */ int llistcmd(UAContext *ua, char *cmd) { - return do_listcmd(ua, cmd, 1); + return do_listcmd(ua, cmd, VERT_LIST); } /* Do short or summary listing */ int listcmd(UAContext *ua, char *cmd) { - return do_listcmd(ua, cmd, 0); + return do_listcmd(ua, cmd, HORZ_LIST); } -static int do_listcmd(UAContext *ua, char *cmd, int llist) +static int do_listcmd(UAContext *ua, char *cmd, e_list_type llist) { POOLMEM *VolumeName; int jobid, n; diff --git a/bacula/src/dird/ua_query.c b/bacula/src/dird/ua_query.c new file mode 100644 index 0000000000..8cffb370f5 --- /dev/null +++ b/bacula/src/dird/ua_query.c @@ -0,0 +1,287 @@ +/* + * + * Bacula Director -- User Agent Database Query Commands + * + * Kern Sibbald, December MMI + * + * Version $Id$ + */ + +/* + Copyright (C) 2000-2003 Kern Sibbald and John Walker + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + */ + +#include "bacula.h" +#include "dird.h" + +extern DIRRES *director; + +static char *substitute_prompts(UAContext *ua, + char *query, char **prompt, int nprompt); + +/* + * Read a file containing SQL queries and prompt + * the user to select which one. + * + * File format: + * # => comment + * :prompt for query + * *prompt for subst %1 + * *prompt for subst %2 + * ... + * SQL statement possibly terminated by ; + * :next query prompt + */ +int querycmd(UAContext *ua, char *cmd) +{ + FILE *fd; + POOLMEM *query = get_pool_memory(PM_MESSAGE); + char line[1000]; + int i, item, len; + char *prompt[9]; + int nprompt; + char *query_file = director->query_file; + + if (!open_db(ua)) { + free_pool_memory(query); + return 1; + } + if ((fd=fopen(query_file, "r")) == NULL) { + bsendmsg(ua, "Could not open %s: ERR=%s\n", query_file, + strerror(errno)); + free_pool_memory(query); + return 1; + } + + start_prompt(ua, _("Available queries:\n")); + while (fgets(line, sizeof(line), fd) != NULL) { + if (line[0] == ':') { + strip_trailing_junk(line); + add_prompt(ua, line+1); + } + } + if ((item=do_prompt(ua, "", _("Choose a query"), NULL, 0)) < 0) { + fclose(fd); + free_pool_memory(query); + return 1; + } + rewind(fd); + i = -1; + while (fgets(line, sizeof(line), fd) != NULL) { + if (line[0] == ':') { + i++; + } + if (i == item) { + break; + } + } + if (i != item) { + bsendmsg(ua, _("Could not find query.\n")); + fclose(fd); + free_pool_memory(query); + return 1; + } + query[0] = 0; + for (i=0; i<9; i++) { + prompt[i] = NULL; + } + nprompt = 0; + while (fgets(line, sizeof(line), fd) != NULL) { + if (line[0] == '#') { + continue; + } + if (line[0] == ':') { + break; + } + strip_trailing_junk(line); + len = strlen(line); + if (line[0] == '*') { /* prompt */ + if (nprompt >= 9) { + bsendmsg(ua, _("Too many prompts in query, max is 9.\n")); + } else { + line[len++] = ' '; + line[len] = 0; + prompt[nprompt++] = bstrdup(line+1); + continue; + } + } + query = check_pool_memory_size(query, len + 1); + if (*query != 0) { + strcat(query, " "); + } + strcat(query, line); + if (line[len-1] != ';') { + continue; + } + line[len-1] = 0; /* zap ; */ + if (query[0] != 0) { + query = substitute_prompts(ua, query, prompt, nprompt); + Dmsg1(100, "Query2=%s\n", query); + if (query[0] == '!') { + db_list_sql_query(ua->jcr, ua->db, query+1, prtit, ua, 0, VERT_LIST); + } else if (!db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST)) { + bsendmsg(ua, "%s\n", query); + } + query[0] = 0; + } + } /* end while */ + + if (query[0] != 0) { + query = substitute_prompts(ua, query, prompt, nprompt); + Dmsg1(100, "Query2=%s\n", query); + if (query[0] == '!') { + db_list_sql_query(ua->jcr, ua->db, query+1, prtit, ua, 0, VERT_LIST); + } else if (!db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST)) { + bsendmsg(ua, "%s\n", query); + } + } + free_pool_memory(query); + for (i=0; icmd); + p = (char *)malloc(len * 2 + 1); + db_escape_string(p, ua->cmd, len); + subst[n] = p; + o = (char *)check_pool_memory_size(o, olen + strlen(p) + 1); + while (*p) { + *o++ = *p++; + olen++; + } + } else { + bsendmsg(ua, _("Warning prompt %d missing.\n"), n+1); + } + q += 2; + break; + case '%': + *o++ = '%'; + olen++; + q += 2; + break; + default: + *o++ = '%'; + olen++; + q++; + break; + } + } + } + o = (char *)check_pool_memory_size(o, olen + strlen(q) + 1); + while (*q) { + *o++ = *q++; + } + *o = 0; + for (i=0; i<9; i++) { + if (subst[i]) { + free(subst[i]); + } + } + free_pool_memory(query); + return new_query; +} + +/* + * Get general SQL query for Catalog + */ +int sqlquerycmd(UAContext *ua, char *cmd) +{ + POOLMEM *query = get_pool_memory(PM_MESSAGE); + int len; + char *msg; + + if (!open_db(ua)) { + free_pool_memory(query); + return 1; + } + *query = 0; + + bsendmsg(ua, _("Entering SQL query mode.\n\ +Terminate each query with a semicolon.\n\ +Terminate query mode with a blank line.\n")); + msg = "Enter SQL query: "; + while (get_cmd(ua, msg)) { + len = strlen(ua->cmd); + Dmsg2(400, "len=%d cmd=%s:\n", len, ua->cmd); + if (len == 0) { + break; + } + query = check_pool_memory_size(query, len + 1); + if (*query != 0) { + strcat(query, " "); + } + strcat(query, ua->cmd); + if (ua->cmd[len-1] == ';') { + ua->cmd[len-1] = 0; /* zap ; */ + /* Submit query */ + db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST); + *query = 0; /* start new query */ + msg = _("Enter SQL query: "); + } else { + msg = _("Add to SQL query: "); + } + } + free_pool_memory(query); + bsendmsg(ua, _("End query mode.\n")); + return 1; +} diff --git a/bacula/src/dird/ua_restore.c b/bacula/src/dird/ua_restore.c index 47bc7401f2..40428f5512 100644 --- a/bacula/src/dird/ua_restore.c +++ b/bacula/src/dird/ua_restore.c @@ -341,7 +341,7 @@ static int user_select_jobids(UAContext *ua, JOBIDS *ji) case -1: /* error */ return 0; case 0: /* list last 20 Jobs run */ - db_list_sql_query(ua->jcr, ua->db, uar_list_jobs, prtit, ua, 1, 0); + db_list_sql_query(ua->jcr, ua->db, uar_list_jobs, prtit, ua, 1, HORZ_LIST); done = 0; break; case 1: /* list where a file is saved */ @@ -356,7 +356,7 @@ static int user_select_jobids(UAContext *ua, JOBIDS *ji) query = get_pool_memory(PM_MESSAGE); Mmsg(&query, uar_file, fname); free(fname); - db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, 0); + db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST); free_pool_memory(query); done = 0; break; @@ -370,7 +370,7 @@ static int user_select_jobids(UAContext *ua, JOBIDS *ji) if (!get_cmd(ua, _("Enter SQL list command: "))) { return 0; } - db_list_sql_query(ua->jcr, ua->db, ua->cmd, prtit, ua, 1, 0); + db_list_sql_query(ua->jcr, ua->db, ua->cmd, prtit, ua, 1, HORZ_LIST); done = 0; break; case 4: /* Select the most recent backups */ @@ -438,7 +438,7 @@ static int user_select_jobids(UAContext *ua, JOBIDS *ji) bsendmsg(ua, "%s\n", db_strerror(ua->db)); } free_pool_memory(query); - db_list_sql_query(ua->jcr, ua->db, uar_list_temp, prtit, ua, 1, 0); + db_list_sql_query(ua->jcr, ua->db, uar_list_temp, prtit, ua, 1, HORZ_LIST); if (!db_sql_query(ua->db, uar_sel_jobid_temp, jobid_handler, (void *)ji)) { bsendmsg(ua, "%s\n", db_strerror(ua->db)); diff --git a/bacula/src/dird/ua_select.c b/bacula/src/dird/ua_select.c index b6ec85e84c..39cf261c8c 100644 --- a/bacula/src/dird/ua_select.c +++ b/bacula/src/dird/ua_select.c @@ -489,7 +489,7 @@ int select_media_dbr(UAContext *ua, MEDIA_DBR *mr) return 0; } mr->PoolId = pr.PoolId; - db_list_media_records(ua->jcr, ua->db, mr, prtit, ua, 0); + db_list_media_records(ua->jcr, ua->db, mr, prtit, ua, HORZ_LIST); if (!get_cmd(ua, _("Enter MediaId or Volume name: "))) { return 0; } @@ -554,7 +554,7 @@ POOL *get_pool_resource(UAContext *ua) */ int select_job_dbr(UAContext *ua, JOB_DBR *jr) { - db_list_job_records(ua->jcr, ua->db, jr, prtit, ua, 0); + db_list_job_records(ua->jcr, ua->db, jr, prtit, ua, HORZ_LIST); if (!get_pint(ua, _("Enter the JobId to select: "))) { return 0; } diff --git a/bacula/src/dird/verify.c b/bacula/src/dird/verify.c index 85b5d24501..4df5ca6eb6 100644 --- a/bacula/src/dird/verify.c +++ b/bacula/src/dird/verify.c @@ -220,7 +220,7 @@ int do_verify(JCR *jcr) jcr->store->SDDport = jcr->store->SDport; } bnet_fsend(fd, storaddr, jcr->store->address, jcr->store->SDDport); - if (!response(fd, OKstore, "Storage", 1)) { + if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) { goto bail_out; } /* @@ -232,7 +232,7 @@ int do_verify(JCR *jcr) jr.VolSessionId, jr.VolSessionTime, jr.StartFile, jr.EndFile, jr.StartBlock, jr.EndBlock); - if (!response(fd, OKsession, "Session", 1)) { + if (!response(jcr, fd, OKsession, "Session", DISPLAY_ERROR)) { goto bail_out; } level = "volume"; @@ -249,7 +249,7 @@ int do_verify(JCR *jcr) * Send verify command/level to File daemon */ bnet_fsend(fd, verifycmd, level); - if (!response(fd, OKverify, "Verify", 1)) { + if (!response(jcr, fd, OKverify, "Verify", DISPLAY_ERROR)) { goto bail_out; } diff --git a/bacula/src/filed/filed_conf.h b/bacula/src/filed/filed_conf.h index 377c8c0a98..2e27898dd5 100644 --- a/bacula/src/filed/filed_conf.h +++ b/bacula/src/filed/filed_conf.h @@ -46,15 +46,14 @@ /* Definition of the contents of each Resource */ -struct s_res_dir { +struct DIRRES { RES hdr; char *password; /* Director password */ char *address; /* Director address or zero */ int enable_ssl; /* Use SSL for this Director */ }; -typedef struct s_res_dir DIRRES; -struct s_res_client { +struct CLIENT { RES hdr; int FDport; /* where we listen for Directors */ char *FDaddr; /* bind address */ @@ -62,22 +61,20 @@ struct s_res_client { char *pid_directory; char *subsys_directory; int require_ssl; /* Require SSL on all connections */ - struct s_res_msgs *messages; /* daemon message handler */ + MSGS *messages; /* daemon message handler */ int MaxConcurrentJobs; utime_t heartbeat_interval; /* Interval to send heartbeats to Dir */ }; -typedef struct s_res_client CLIENT; /* Define the Union of all the above * resource structure definitions. */ -union u_res { - struct s_res_dir res_dir; - struct s_res_client res_client; - struct s_res_msgs res_msgs; - RES hdr; +union URES { + DIRRES res_dir; + CLIENT res_client; + MSGS res_msgs; + RES hdr; }; -typedef union u_res URES; diff --git a/bacula/src/lib/Makefile.in b/bacula/src/lib/Makefile.in index 367b49e303..03fccf1956 100644 --- a/bacula/src/lib/Makefile.in +++ b/bacula/src/lib/Makefile.in @@ -37,11 +37,10 @@ LIBSRCS = alloc.c base64.c bsys.c bget_msg.c \ cram-md5.c crc32.c daemon.c edit.c fnmatch.c \ hmac.c idcache.c jcr.c lex.c \ md5.c message.c mem_pool.c parse_conf.c \ - queue.c rwlock.c serial.c sha1.c \ + queue.c rwlock.c scan.c serial.c sha1.c \ semlock.c signal.c smartall.c tree.c \ util.c watchdog.c workq.c -# immortal.c filesys.c LIBOBJS = alloc.o base64.o bsys.o bget_msg.o \ bnet.o bnet_server.o \ @@ -49,11 +48,10 @@ LIBOBJS = alloc.o base64.o bsys.o bget_msg.o \ cram-md5.o crc32.o daemon.o edit.o fnmatch.o \ hmac.o idcache.o jcr.o lex.o \ md5.o message.o mem_pool.o parse_conf.o \ - queue.o rwlock.o serial.o sha1.o \ + queue.o rwlock.o scan.o serial.o sha1.o \ semlock.o signal.o smartall.o tree.o \ util.o watchdog.o workq.o -# immortal.o filesys.o EXTRAOBJS = @OBJLIST@ diff --git a/bacula/src/lib/edit.c b/bacula/src/lib/edit.c index b601c53c06..0e147bcf93 100644 --- a/bacula/src/lib/edit.c +++ b/bacula/src/lib/edit.c @@ -27,6 +27,7 @@ */ #include "bacula.h" +#include /* We assume ASCII input and don't worry about overflow */ uint64_t str_to_uint64(char *str) @@ -189,7 +190,7 @@ int size_to_uint64(char *str, int str_len, uint64_t *rtn_value) 1099511627776};/* terabyte */ #endif - Dmsg0(400, "Enter sized to uint64\n"); + Dmsg1(400, "Enter sized to uint64 str=%s\n", str); /* Look for modifier */ ch = str[str_len - 1]; @@ -209,16 +210,15 @@ int size_to_uint64(char *str, int str_len, uint64_t *rtn_value) if (mod[i] == 0 || !is_a_number(str)) { return 0; } - Dmsg3(400, "size str=:%s: %f i=%d\n", str, strtod(str, NULL), i); + Dmsg3(400, "size str=:%s: %lf i=%d\n", str, strtod(str, NULL), i); - value = (uint64_t)strtod(str, NULL); - Dmsg1(400, "Int value = %d\n", (int)value); + value = strtod(str, NULL); if (errno != 0 || value < 0) { return 0; } *rtn_value = (uint64_t)(value * mult[i]); - Dmsg2(400, "Full value = %f %" lld "\n", strtod(str, NULL) * mult[i], - value *mult[i]); + Dmsg2(400, "Full value = %lf %" lld "\n", value * mult[i], + (uint64_t)(value * mult[i])); return 1; } @@ -228,13 +228,13 @@ int size_to_uint64(char *str, int str_len, uint64_t *rtn_value) */ int is_a_number(const char *n) { - int digit_seen = 0; + bool digit_seen = false; if( *n == '-' || *n == '+' ) { n++; } while (B_ISDIGIT(*n)) { - digit_seen = 1; + digit_seen = true; n++; } if (digit_seen && *n == '.') { @@ -254,9 +254,9 @@ int is_a_number(const char *n) */ int is_an_integer(const char *n) { - int digit_seen = 0; + bool digit_seen = false; while (B_ISDIGIT(*n)) { - digit_seen = 1; + digit_seen = true; n++; } return digit_seen && *n==0; diff --git a/bacula/src/lib/message.c b/bacula/src/lib/message.c index 80676ef253..da1c76c3b7 100755 --- a/bacula/src/lib/message.c +++ b/bacula/src/lib/message.c @@ -33,22 +33,35 @@ #define FULL_LOCATION 1 /* set for file:line in Debug messages */ +/* + * This is where we define "Globals" because all the + * daemons include this file. + */ char *working_directory = NULL; /* working directory path stored here */ int verbose = 0; /* increase User messages */ int debug_level = 0; /* debug level */ time_t daemon_start_time = 0; /* Daemon start time */ char *version = VERSION " (" BDATE ")"; - -char my_name[20]; /* daemon name is stored here */ +char my_name[30]; /* daemon name is stored here */ char *exepath = (char *)NULL; char *exename = (char *)NULL; int console_msg_pending = 0; char con_fname[500]; /* Console filename */ FILE *con_fd = NULL; /* Console file descriptor */ brwlock_t con_lock; /* Console lock structure */ - FILE *trace_fd = NULL; +#ifdef HAVE_MYSQL +char catalog_db[] = "MySQL"; +#endif +#ifdef HAVE_SQLITE +char catalog_db[] = "SQLite"; +#endif +#ifdef HAVE_BACULA_DB +char catlog_db[] = "Internal"; +#endif + + /* Forward referenced functions */ /* Imported functions */ diff --git a/bacula/src/lib/parse_conf.c b/bacula/src/lib/parse_conf.c index 6a13469ded..217a4d50e6 100755 --- a/bacula/src/lib/parse_conf.c +++ b/bacula/src/lib/parse_conf.c @@ -456,7 +456,6 @@ void store_int64(LEX *lc, struct res_items *item, int index, int pass) void store_size(LEX *lc, struct res_items *item, int index, int pass) { int token; - double dvalue; uint64_t uvalue; Dmsg0(400, "Enter store_size\n"); @@ -464,13 +463,6 @@ void store_size(LEX *lc, struct res_items *item, int index, int pass) errno = 0; switch (token) { case T_NUMBER: - Dmsg2(400, "size num=:%s: %f\n", lc->str, strtod(lc->str, NULL)); - dvalue = strtod(lc->str, NULL); - if (errno != 0 || token < 0) { - scan_err1(lc, "expected a size number, got: %s", lc->str); - } - *(uint64_t *)(item->value) = (uint64_t)dvalue; - break; case T_IDENTIFIER: case T_UNQUOTED_STRING: if (!size_to_uint64(lc->str, lc->str_len, &uvalue)) { @@ -492,19 +484,12 @@ void store_size(LEX *lc, struct res_items *item, int index, int pass) void store_time(LEX *lc, struct res_items *item, int index, int pass) { int token; - double value; utime_t utime; token = lex_get_token(lc, T_ALL); errno = 0; switch (token) { case T_NUMBER: - value = strtod(lc->str, NULL); - if (errno != 0 || value < 0) { - scan_err1(lc, "expected a time period, got: %s", lc->str); - } - *(utime_t *)(item->value) = (utime_t)value; - break; case T_IDENTIFIER: case T_UNQUOTED_STRING: if (!duration_to_utime(lc->str, &utime)) { diff --git a/bacula/src/lib/parse_conf.h b/bacula/src/lib/parse_conf.h index 9f2f47ff3e..ea51399922 100644 --- a/bacula/src/lib/parse_conf.h +++ b/bacula/src/lib/parse_conf.h @@ -47,8 +47,8 @@ struct res_items { * at the beginning of every resource * record. */ -struct s_reshdr { - struct s_reshdr *next; /* pointer to next resource of this type */ +struct RES { + RES *next; /* pointer to next resource of this type */ char *name; /* resource name */ char *desc; /* resource description */ int rcode; /* resource id or type */ @@ -56,7 +56,6 @@ struct s_reshdr { char item_present[MAX_RES_ITEMS]; /* set if item is present in conf file */ }; -typedef struct s_reshdr RES; /* * Master Resource configuration structure definition @@ -79,26 +78,23 @@ struct s_res { #define ITEM_NO_EQUALS 0x4 /* Don't scan = after name */ /* Message Resource */ -struct s_res_msgs { +struct MSGS { RES hdr; char *mail_cmd; /* mail command */ char *operator_cmd; /* Operator command */ DEST *dest_chain; /* chain of destinations */ char send_msg[nbytes_for_bits(M_MAX+1)]; /* bit array of types */ }; -typedef struct s_res_msgs MSGS; /* Define the Union of all the above common * resource structure definitions. */ -union cu_res { - struct s_res_msgs res_msgs; +union CURES { + MSGS res_msgs; RES hdr; }; -typedef union cu_res CURES; - /* Configuration routines */ void parse_config(char *cf); diff --git a/bacula/src/lib/protos.h b/bacula/src/lib/protos.h index 513bd45e8e..d7cffe259c 100644 --- a/bacula/src/lib/protos.h +++ b/bacula/src/lib/protos.h @@ -31,7 +31,7 @@ int to_base64 (intmax_t value, char *where); int from_base64 (intmax_t *value, char *where); int bin_to_base64 (char *buf, char *bin, int len); -/* bmisc.c */ +/* bsys.c */ char *bstrncpy (char *dest, const char *src, int maxlen); char *bstrncat (char *dest, const char *src, int maxlen); void *b_malloc (char *file, int line, size_t size); @@ -78,6 +78,11 @@ void bnet_suppress_error_messages(BSOCK *bsock, int flag); /* bget_msg.c */ int bget_msg(BSOCK *sock); +/* bpipe.c */ +BPIPE * open_bpipe(char *prog, int wait, char *mode); +int close_wpipe(BPIPE *bpipe); +int close_bpipe(BPIPE *bpipe); + /* cram-md5.c */ int cram_md5_get_auth(BSOCK *bs, char *password, int ssl_need); int cram_md5_auth(BSOCK *bs, char *password, int ssl_need); @@ -138,19 +143,24 @@ BSOCK * bnet_accept (BSOCK *bsock, char *who); void init_signals (void terminate(int sig)); void init_stack_dump (void); -/* util.c */ -void lcase (char *str); -void bash_spaces (char *str); -void unbash_spaces (char *str); +/* scan.c */ void strip_trailing_junk (char *str); void strip_trailing_slashes (char *dir); int skip_spaces (char **msg); int skip_nonspaces (char **msg); int fstrsch (char *a, char *b); +int parse_args(POOLMEM *cmd, POOLMEM *args, int *argc, + char **argk, char **argv, int max_args); +char *next_arg(char **s); + +/* util.c */ +int is_buf_zero (char *buf, int len); +void lcase (char *str); +void bash_spaces (char *str); +void unbash_spaces (char *str); char * encode_time (time_t time, char *buf); char * encode_mode (mode_t mode, char *buf); int do_shell_expansion (char *name, int name_len); -int is_buf_zero (char *buf, int len); void jobstatus_to_ascii (int JobStatus, char *msg, int maxlen); void pm_strcat (POOLMEM **pm, char *str); void pm_strcpy (POOLMEM **pm, char *str); @@ -158,16 +168,11 @@ int run_program (char *prog, int wait, POOLMEM *results char * job_type_to_str (int type); char * job_status_to_str (int stat); char * job_level_to_str (int level); -void makeSessionKey (char *key, char *seed, int mode); -BPIPE * open_bpipe(char *prog, int wait, char *mode); -int close_wpipe(BPIPE *bpipe); -int close_bpipe(BPIPE *bpipe); +void make_session_key (char *key, char *seed, int mode); POOLMEM *edit_job_codes(JCR *jcr, char *omsg, char *imsg, char *to); -void parse_command_args(POOLMEM *cmd, POOLMEM *args, int *argc, - char **argk, char **argv); -char *next_arg(char **s); void set_working_directory(char *wd); + /* watchdog.c */ int start_watchdog(void); int stop_watchdog(void); diff --git a/bacula/src/lib/scan.c b/bacula/src/lib/scan.c new file mode 100644 index 0000000000..376e3fd393 --- /dev/null +++ b/bacula/src/lib/scan.c @@ -0,0 +1,241 @@ +/* + * scan.c -- scanning routines for Bacula + * + * Kern Sibbald, MM separated from util.c MMIII + * + * Version $Id$ + */ + +/* + Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + */ + +#include "bacula.h" +#include "jcr.h" +#include "findlib/find.h" + + +/* Strip any trailing junk from the command */ +void strip_trailing_junk(char *cmd) +{ + char *p; + p = cmd + strlen(cmd) - 1; + + /* strip trailing junk from command */ + while ((p >= cmd) && (*p == '\n' || *p == '\r' || *p == ' ')) + *p-- = 0; +} + +/* Strip any trailing slashes from a directory path */ +void strip_trailing_slashes(char *dir) +{ + char *p; + p = dir + strlen(dir) - 1; + + /* strip trailing slashes */ + while ((p >= dir) && (*p == '/')) + *p-- = 0; +} + +/* + * Skip spaces + * Returns: 0 on failure (EOF) + * 1 on success + * new address in passed parameter + */ +int skip_spaces(char **msg) +{ + char *p = *msg; + if (!p) { + return 0; + } + while (*p && *p == ' ') { + p++; + } + *msg = p; + return *p ? 1 : 0; +} + +/* + * Skip nonspaces + * Returns: 0 on failure (EOF) + * 1 on success + * new address in passed parameter + */ +int skip_nonspaces(char **msg) +{ + char *p = *msg; + + if (!p) { + return 0; + } + while (*p && *p != ' ') { + p++; + } + *msg = p; + return *p ? 1 : 0; +} + +/* folded search for string - case insensitive */ +int +fstrsch(char *a, char *b) /* folded case search */ +{ + register char *s1,*s2; + register char c1, c2; + + s1=a; + s2=b; + while (*s1) { /* do it the fast way */ + if ((*s1++ | 0x20) != (*s2++ | 0x20)) + return 0; /* failed */ + } + while (*a) { /* do it over the correct slow way */ + if (B_ISUPPER(c1 = *a)) { + c1 = tolower((int)c1); + } + if (B_ISUPPER(c2 = *b)) { + c2 = tolower((int)c2); + } + if (c1 != c2) { + return 0; + } + a++; + b++; + } + return 1; +} + + +/* + * Return next argument from command line. Note, this + * routine is destructive. + */ +char *next_arg(char **s) +{ + char *p, *q, *n; + bool in_quote = false; + + /* skip past spaces to next arg */ + for (p=*s; *p && B_ISSPACE(*p); ) { + p++; + } + Dmsg1(400, "Next arg=%s\n", p); + for (n = q = p; *p ; ) { + if (*p == '\\') { + p++; + if (*p) { + *q++ = *p++; + } else { + *q++ = *p; + } + continue; + } + if (*p == '"') { /* start or end of quote */ + if (in_quote) { + p++; /* skip quote */ + in_quote = false; + continue; + } + in_quote = true; + p++; + continue; + } + if (!in_quote && B_ISSPACE(*p)) { /* end of field */ + p++; + break; + } + *q++ = *p++; + } + *q = 0; + *s = p; + Dmsg2(400, "End arg=%s next=%s\n", n, p); + return n; +} + +/* + * This routine parses the input command line. + * It makes a copy in args, then builds an + * argc, argv like list where + * + * argc = count of arguments + * argk[i] = argument keyword (part preceding =) + * argv[i] = argument value (part after =) + * + * example: arg1 arg2=abc arg3= + * + * argc = c + * argk[0] = arg1 + * argv[0] = NULL + * argk[1] = arg2 + * argv[1] = abc + * argk[2] = arg3 + * argv[2] = + */ + +int parse_args(POOLMEM *cmd, POOLMEM *args, int *argc, + char **argk, char **argv, int max_args) +{ + char *p, *q, *n; + int len; + + len = strlen(cmd) + 1; + args = check_pool_memory_size(args, len); + bstrncpy(args, cmd, len); + strip_trailing_junk(args); + *argc = 0; + p = args; + /* Pick up all arguments */ + while (*argc < max_args) { + n = next_arg(&p); + if (*n) { + argk[*argc] = n; + argv[(*argc)++] = NULL; + } else { + break; + } + } + /* Separate keyword and value */ + for (int i=0; i < *argc; i++) { + p = strchr(argk[i], '='); + if (p) { + *p++ = 0; /* terminate keyword and point to value */ + /* Unquote quoted values */ + if (*p == '"') { + for (n = q = ++p; *p && *p != '"'; ) { + if (*p == '\\') { + p++; + } + *q++ = *p++; + } + *q = 0; /* terminate string */ + p = n; /* point to string */ + } + if (strlen(p) > MAX_NAME_LENGTH-1) { + p[MAX_NAME_LENGTH-1] = 0; /* truncate to max len */ + } + } + argv[i] = p; /* save ptr to value or NULL */ + } + return 1; +#ifdef xxxx + for (i=0; i 0); - - nbytes += HEAD_SIZE + 1; - if ((buf = (char *)malloc(nbytes)) != NULL) { - P(mutex); - /* Enqueue buffer on allocated list */ - qinsert(&abqueue, (struct b_queue *) buf); - ((struct abufhead *) buf)->ablen = nbytes; - ((struct abufhead *) buf)->abfname = bufimode ? NULL : fname; - ((struct abufhead *) buf)->ablineno = (sm_ushort) lineno; - /* Emplace end-clobber detector at end of buffer */ - buf[nbytes - 1] = (((long) buf) & 0xFF) ^ 0xC5; - buf += HEAD_SIZE; /* Increment to user data start */ - V(mutex); - } else { - Emsg0(M_ABORT, 0, _("Out of memory\n")); - } - Dmsg4(1150, "smalloc %d at %x from %s:%d\n", nbytes, buf, fname, lineno); - return (void *)buf; + char *buf; + + /* Note: Unix MALLOC actually permits a zero length to be + passed and allocates a valid block with zero user bytes. + Such a block can later be expanded with realloc(). We + disallow this based on the belief that it's better to make + a special case and allocate one byte in the rare case this + is desired than to miss all the erroneous occurrences where + buffer length calculation code results in a zero. */ + + ASSERT(nbytes > 0); + + nbytes += HEAD_SIZE + 1; + if ((buf = (char *)malloc(nbytes)) != NULL) { + P(mutex); + /* Enqueue buffer on allocated list */ + qinsert(&abqueue, (struct b_queue *) buf); + ((struct abufhead *) buf)->ablen = nbytes; + ((struct abufhead *) buf)->abfname = bufimode ? NULL : fname; + ((struct abufhead *) buf)->ablineno = (sm_ushort) lineno; + /* Emplace end-clobber detector at end of buffer */ + buf[nbytes - 1] = (((long) buf) & 0xFF) ^ 0xC5; + buf += HEAD_SIZE; /* Increment to user data start */ + V(mutex); + } else { + Emsg0(M_ABORT, 0, _("Out of memory\n")); + } + Dmsg4(1150, "smalloc %d at %x from %s:%d\n", nbytes, buf, fname, lineno); + return (void *)buf; } /* SM_NEW_OWNER -- Update the File and line number for a buffer @@ -119,10 +119,10 @@ static void *smalloc(char *fname, int lineno, unsigned int nbytes) void sm_new_owner(char *fname, int lineno, char *buf) { - buf -= HEAD_SIZE; /* Decrement to header */ - ((struct abufhead *)buf)->abfname = bufimode ? NULL : fname; - ((struct abufhead *)buf)->ablineno = (sm_ushort) lineno; - return; + buf -= HEAD_SIZE; /* Decrement to header */ + ((struct abufhead *)buf)->abfname = bufimode ? NULL : fname; + ((struct abufhead *)buf)->ablineno = (sm_ushort) lineno; + return; } /* SM_FREE -- Update free pool availability. FREE is never called @@ -132,55 +132,55 @@ void sm_new_owner(char *fname, int lineno, char *buf) void sm_free(char *file, int line, void *fp) { - char *cp = (char *) fp; - struct b_queue *qp; - - if (cp == NULL) { - Emsg2(M_ABORT, 0, "Attempt to free NULL called from %s:%d\n", file, line); - } - - cp -= HEAD_SIZE; - qp = (struct b_queue *) cp; - - P(mutex); - Dmsg4(1150, "sm_free %d at %x from %s:%d\n", - ((struct abufhead *)cp)->ablen, fp, - ((struct abufhead *)cp)->abfname, ((struct abufhead *)cp)->ablineno); - - /* The following assertions will catch virtually every release - of an address which isn't an allocated buffer. */ - if (qp->qnext->qprev != qp) { - V(mutex); - Emsg2(M_ABORT, 0, "qp->qnext->qprev != qp called from %s:%d\n", file, line); - } - if (qp->qprev->qnext != qp) { - V(mutex); - Emsg2(M_ABORT, 0, "qp->qprev->qnext != qp called from %s:%d\n", file, line); - } - - /* The following assertion detects storing off the end of the - allocated space in the buffer by comparing the end of buffer - checksum with the address of the buffer. */ - - if (((unsigned char *) cp)[((struct abufhead *) cp)->ablen - 1] != - ((((long) cp) & 0xFF) ^ 0xC5)) { - V(mutex); - Emsg2(M_ABORT, 0, "Buffer overrun called from %s:%d\n", file, line); - } - - - qdchain(qp); - V(mutex); - - /* Now we wipe the contents of the just-released buffer with - "designer garbage" (Duff Kurland's phrase) of alternating - bits. This is intended to ruin the day for any miscreant who - attempts to access data through a pointer into storage that's - been previously released. */ - - memset(cp, 0xAA, (int) ((struct abufhead *) cp)->ablen); - - free(cp); + char *cp = (char *) fp; + struct b_queue *qp; + + if (cp == NULL) { + Emsg2(M_ABORT, 0, "Attempt to free NULL called from %s:%d\n", file, line); + } + + cp -= HEAD_SIZE; + qp = (struct b_queue *) cp; + + P(mutex); + Dmsg4(1150, "sm_free %d at %x from %s:%d\n", + ((struct abufhead *)cp)->ablen, fp, + ((struct abufhead *)cp)->abfname, ((struct abufhead *)cp)->ablineno); + + /* The following assertions will catch virtually every release + of an address which isn't an allocated buffer. */ + if (qp->qnext->qprev != qp) { + V(mutex); + Emsg2(M_ABORT, 0, "qp->qnext->qprev != qp called from %s:%d\n", file, line); + } + if (qp->qprev->qnext != qp) { + V(mutex); + Emsg2(M_ABORT, 0, "qp->qprev->qnext != qp called from %s:%d\n", file, line); + } + + /* The following assertion detects storing off the end of the + allocated space in the buffer by comparing the end of buffer + checksum with the address of the buffer. */ + + if (((unsigned char *) cp)[((struct abufhead *) cp)->ablen - 1] != + ((((long) cp) & 0xFF) ^ 0xC5)) { + V(mutex); + Emsg2(M_ABORT, 0, "Buffer overrun called from %s:%d\n", file, line); + } + + + qdchain(qp); + V(mutex); + + /* Now we wipe the contents of the just-released buffer with + "designer garbage" (Duff Kurland's phrase) of alternating + bits. This is intended to ruin the day for any miscreant who + attempts to access data through a pointer into storage that's + been previously released. */ + + memset(cp, 0xAA, (int) ((struct abufhead *) cp)->ablen); + + free(cp); } /* SM_MALLOC -- Allocate buffer. NULL is returned if no memory @@ -188,19 +188,19 @@ void sm_free(char *file, int line, void *fp) void *sm_malloc(char *fname, int lineno, unsigned int nbytes) { - void *buf; + void *buf; - if ((buf = smalloc(fname, lineno, nbytes)) != NULL) { + if ((buf = smalloc(fname, lineno, nbytes)) != NULL) { - /* To catch sloppy code that assumes buffers obtained from - malloc() are zeroed, we preset the buffer contents to - "designer garbage" consisting of alternating bits. */ + /* To catch sloppy code that assumes buffers obtained from + malloc() are zeroed, we preset the buffer contents to + "designer garbage" consisting of alternating bits. */ - memset(buf, 0x55, (int) nbytes); - } else { - Emsg0(M_ABORT, 0, _("Out of memory\n")); - } - return buf; + memset(buf, 0x55, (int) nbytes); + } else { + Emsg0(M_ABORT, 0, _("Out of memory\n")); + } + return buf; } /* SM_CALLOC -- Allocate an array and clear it to zero. */ @@ -208,14 +208,14 @@ void *sm_malloc(char *fname, int lineno, unsigned int nbytes) void *sm_calloc(char *fname, int lineno, unsigned int nelem, unsigned int elsize) { - void *buf; - - if ((buf = smalloc(fname, lineno, nelem * elsize)) != NULL) { - memset(buf, 0, (int) (nelem * elsize)); - } else { - Emsg0(M_ABORT, 0, _("Out of memory\n")); - } - return buf; + void *buf; + + if ((buf = smalloc(fname, lineno, nelem * elsize)) != NULL) { + memset(buf, 0, (int) (nelem * elsize)); + } else { + Emsg0(M_ABORT, 0, _("Out of memory\n")); + } + return buf; } /* SM_REALLOC -- Adjust the size of a previously allocated buffer. @@ -229,51 +229,51 @@ void *sm_calloc(char *fname, int lineno, void *sm_realloc(char *fname, int lineno, void *ptr, unsigned int size) { - unsigned osize; - void *buf; - char *cp = (char *) ptr; - - Dmsg4(400, "sm_realloc %s:%d 0x%x %d\n", fname, lineno, ptr, size); - if (size <= 0) { - e_msg(fname, lineno, M_ABORT, 0, "sm_realloc size: %d\n", size); - } - - /* If the old block pointer is NULL, treat realloc() as a - malloc(). SVID is silent on this, but many C libraries - permit this. */ - - if (ptr == NULL) { - return sm_malloc(fname, lineno, size); - } - - /* If the old and new sizes are the same, be a nice guy and just - return the buffer passed in. */ - - cp -= HEAD_SIZE; - osize = ((struct abufhead *) cp)->ablen - (HEAD_SIZE + 1); - if (size == osize) { - return ptr; - } - - /* Sizes differ. Allocate a new buffer of the requested size. - If we can't obtain such a buffer, act as defined in SVID: - return NULL from realloc() and leave the buffer in PTR - intact. */ - - if ((buf = smalloc(fname, lineno, size)) != NULL) { - memcpy(buf, ptr, (int) sm_min(size, osize)); - /* If the new buffer is larger than the old, fill the balance - of it with "designer garbage". */ - if (size > osize) { - memset(((char *) buf) + osize, 0x55, (int) (size - osize)); - } - - /* All done. Free and dechain the original buffer. */ - - sm_free(__FILE__, __LINE__, ptr); - } - Dmsg4(150, "sm_realloc %d at %x from %s:%d\n", size, buf, fname, lineno); - return buf; + unsigned osize; + void *buf; + char *cp = (char *) ptr; + + Dmsg4(400, "sm_realloc %s:%d 0x%x %d\n", fname, lineno, ptr, size); + if (size <= 0) { + e_msg(fname, lineno, M_ABORT, 0, "sm_realloc size: %d\n", size); + } + + /* If the old block pointer is NULL, treat realloc() as a + malloc(). SVID is silent on this, but many C libraries + permit this. */ + + if (ptr == NULL) { + return sm_malloc(fname, lineno, size); + } + + /* If the old and new sizes are the same, be a nice guy and just + return the buffer passed in. */ + + cp -= HEAD_SIZE; + osize = ((struct abufhead *) cp)->ablen - (HEAD_SIZE + 1); + if (size == osize) { + return ptr; + } + + /* Sizes differ. Allocate a new buffer of the requested size. + If we can't obtain such a buffer, act as defined in SVID: + return NULL from realloc() and leave the buffer in PTR + intact. */ + + if ((buf = smalloc(fname, lineno, size)) != NULL) { + memcpy(buf, ptr, (int) sm_min(size, osize)); + /* If the new buffer is larger than the old, fill the balance + of it with "designer garbage". */ + if (size > osize) { + memset(((char *) buf) + osize, 0x55, (int) (size - osize)); + } + + /* All done. Free and dechain the original buffer. */ + + sm_free(__FILE__, __LINE__, ptr); + } + Dmsg4(150, "sm_realloc %d at %x from %s:%d\n", size, buf, fname, lineno); + return buf; } /* ACTUALLYMALLOC -- Call the system malloc() function to obtain @@ -283,7 +283,7 @@ void *sm_realloc(char *fname, int lineno, void *ptr, unsigned int size) void *actuallymalloc(unsigned int size) { - return malloc(size); + return malloc(size); } /* ACTUALLYCALLOC -- Call the system calloc() function to obtain @@ -293,7 +293,7 @@ void *actuallymalloc(unsigned int size) void *actuallycalloc(unsigned int nelem, unsigned int elsize) { - return calloc(nelem, elsize); + return calloc(nelem, elsize); } /* ACTUALLYREALLOC -- Call the system realloc() function to obtain @@ -303,8 +303,8 @@ void *actuallycalloc(unsigned int nelem, unsigned int elsize) void *actuallyrealloc(void *ptr, unsigned int size) { - Dmsg2(400, "Actuallyrealloc 0x%x %d\n", ptr, size); - return realloc(ptr, size); + Dmsg2(400, "Actuallyrealloc 0x%x %d\n", ptr, size); + return realloc(ptr, size); } /* ACTUALLYFREE -- Interface to system free() function to release @@ -312,7 +312,7 @@ void *actuallyrealloc(void *ptr, unsigned int size) void actuallyfree(void *cp) { - free(cp); + free(cp); } /* SM_DUMP -- Print orphaned buffers (and dump them if BUFDUMP is @@ -322,58 +322,58 @@ void actuallyfree(void *cp) */ void sm_dump(Boolean bufdump) { - struct abufhead *ap; - - P(mutex); - - ap = (struct abufhead *)abqueue.qnext; - - while (ap != (struct abufhead *) &abqueue) { - - if ((ap == NULL) || - (ap->abq.qnext->qprev != (struct b_queue *) ap) || - (ap->abq.qprev->qnext != (struct b_queue *) ap)) { - fprintf(stderr, - "\nOrphaned buffers exist. Dump terminated following\n"); - fprintf(stderr, - " discovery of bad links in chain of orphaned buffers.\n"); - fprintf(stderr, - " Buffer address with bad links: %lx\n", (long) ap); - break; - } - - if (ap->abfname != NULL) { - unsigned memsize = ap->ablen - (HEAD_SIZE + 1); - char errmsg[80]; - - sprintf(errmsg, - "Orphaned buffer: %6u bytes allocated at line %d of %s %s\n", - memsize, ap->ablineno, my_name, ap->abfname - ); - fprintf(stderr, "%s", errmsg); - if (bufdump) { - unsigned llen = 0; - char *cp = ((char *) ap) + HEAD_SIZE; - - errmsg[0] = EOS; - while (memsize) { - if (llen >= 16) { - strcat(errmsg, "\n"); - llen = 0; - fprintf(stderr, "%s", errmsg); - errmsg[0] = EOS; - } - sprintf(errmsg + strlen(errmsg), " %02X", - (*cp++) & 0xFF); - llen++; - memsize--; - } - fprintf(stderr, "%s\n", errmsg); - } - } - ap = (struct abufhead *) ap->abq.qnext; - } - V(mutex); + struct abufhead *ap; + + P(mutex); + + ap = (struct abufhead *)abqueue.qnext; + + while (ap != (struct abufhead *) &abqueue) { + + if ((ap == NULL) || + (ap->abq.qnext->qprev != (struct b_queue *) ap) || + (ap->abq.qprev->qnext != (struct b_queue *) ap)) { + fprintf(stderr, + "\nOrphaned buffers exist. Dump terminated following\n"); + fprintf(stderr, + " discovery of bad links in chain of orphaned buffers.\n"); + fprintf(stderr, + " Buffer address with bad links: %lx\n", (long) ap); + break; + } + + if (ap->abfname != NULL) { + unsigned memsize = ap->ablen - (HEAD_SIZE + 1); + char errmsg[80]; + + sprintf(errmsg, + "Orphaned buffer: %6u bytes allocated at line %d of %s %s\n", + memsize, ap->ablineno, my_name, ap->abfname + ); + fprintf(stderr, "%s", errmsg); + if (bufdump) { + unsigned llen = 0; + char *cp = ((char *) ap) + HEAD_SIZE; + + errmsg[0] = EOS; + while (memsize) { + if (llen >= 16) { + strcat(errmsg, "\n"); + llen = 0; + fprintf(stderr, "%s", errmsg); + errmsg[0] = EOS; + } + sprintf(errmsg + strlen(errmsg), " %02X", + (*cp++) & 0xFF); + llen++; + memsize--; + } + fprintf(stderr, "%s\n", errmsg); + } + } + ap = (struct abufhead *) ap->abq.qnext; + } + V(mutex); } #undef sm_check @@ -390,79 +390,79 @@ void sm_check(char *fname, int lineno, Boolean bufdump) /* SM_CHECK_RTN -- Check the buffers and return 1 if OK otherwise 0 */ int sm_check_rtn(char *fname, int lineno, Boolean bufdump) { - struct abufhead *ap; - int bad, badbuf = 0; - - P(mutex); - ap = (struct abufhead *) abqueue.qnext; - while (ap != (struct abufhead *) &abqueue) { - bad = 0; - if ((ap == NULL) || - (ap->abq.qnext->qprev != (struct b_queue *) ap)) { - bad = 0x1; - } - if (ap->abq.qprev->qnext != (struct b_queue *) ap) { - bad |= 0x2; - } - if (((unsigned char *) ap)[((struct abufhead *) ap)->ablen - 1] != - ((((long) ap) & 0xFF) ^ 0xC5)) { - bad |= 0x4; - } - badbuf |= bad; - if (bad) { - fprintf(stderr, - "\nDamaged buffers found at %s:%d\n", fname, lineno); - - if (bad & 0x1) { - fprintf(stderr, " discovery of bad prev link.\n"); - } - if (bad & 0x2) { - fprintf(stderr, " discovery of bad next link.\n"); - } - if (bad & 0x4) { - fprintf(stderr, " discovery of data overrun.\n"); - } - - fprintf(stderr, " Buffer address: %lx\n", (long) ap); - - if (ap->abfname != NULL) { - unsigned memsize = ap->ablen - (HEAD_SIZE + 1); - char errmsg[80]; - - fprintf(stderr, - "Damaged buffer: %6u bytes allocated at line %d of %s %s\n", - memsize, ap->ablineno, my_name, ap->abfname - ); - if (bufdump) { - unsigned llen = 0; - char *cp = ((char *) ap) + HEAD_SIZE; - - errmsg[0] = EOS; - while (memsize) { - if (llen >= 16) { - strcat(errmsg, "\n"); - llen = 0; - fprintf(stderr, "%s", errmsg); - errmsg[0] = EOS; - } - if (*cp < 0x20) { - sprintf(errmsg + strlen(errmsg), " %02X", - (*cp++) & 0xFF); - } else { - sprintf(errmsg + strlen(errmsg), " %c ", - (*cp++) & 0xFF); - } - llen++; - memsize--; - } - fprintf(stderr, "%s\n", errmsg); - } - } - } - ap = (struct abufhead *) ap->abq.qnext; - } - V(mutex); - return badbuf ? 0 : 1; + struct abufhead *ap; + int bad, badbuf = 0; + + P(mutex); + ap = (struct abufhead *) abqueue.qnext; + while (ap != (struct abufhead *) &abqueue) { + bad = 0; + if ((ap == NULL) || + (ap->abq.qnext->qprev != (struct b_queue *) ap)) { + bad = 0x1; + } + if (ap->abq.qprev->qnext != (struct b_queue *) ap) { + bad |= 0x2; + } + if (((unsigned char *) ap)[((struct abufhead *) ap)->ablen - 1] != + ((((long) ap) & 0xFF) ^ 0xC5)) { + bad |= 0x4; + } + badbuf |= bad; + if (bad) { + fprintf(stderr, + "\nDamaged buffers found at %s:%d\n", fname, lineno); + + if (bad & 0x1) { + fprintf(stderr, " discovery of bad prev link.\n"); + } + if (bad & 0x2) { + fprintf(stderr, " discovery of bad next link.\n"); + } + if (bad & 0x4) { + fprintf(stderr, " discovery of data overrun.\n"); + } + + fprintf(stderr, " Buffer address: %lx\n", (long) ap); + + if (ap->abfname != NULL) { + unsigned memsize = ap->ablen - (HEAD_SIZE + 1); + char errmsg[80]; + + fprintf(stderr, + "Damaged buffer: %6u bytes allocated at line %d of %s %s\n", + memsize, ap->ablineno, my_name, ap->abfname + ); + if (bufdump) { + unsigned llen = 0; + char *cp = ((char *) ap) + HEAD_SIZE; + + errmsg[0] = EOS; + while (memsize) { + if (llen >= 16) { + strcat(errmsg, "\n"); + llen = 0; + fprintf(stderr, "%s", errmsg); + errmsg[0] = EOS; + } + if (*cp < 0x20) { + sprintf(errmsg + strlen(errmsg), " %02X", + (*cp++) & 0xFF); + } else { + sprintf(errmsg + strlen(errmsg), " %c ", + (*cp++) & 0xFF); + } + llen++; + memsize--; + } + fprintf(stderr, "%s\n", errmsg); + } + } + } + ap = (struct abufhead *) ap->abq.qnext; + } + V(mutex); + return badbuf ? 0 : 1; } @@ -475,7 +475,22 @@ int sm_check_rtn(char *fname, int lineno, Boolean bufdump) void sm_static(int mode) { - bufimode = (Boolean) (mode != 0); + bufimode = (Boolean) (mode != 0); +} + +/* + * Here we overload C++'s global new and delete operators + * so that the memory is allocated through smartalloc. + */ + +void * operator new(size_t size) +{ + return sm_malloc(__FILE__, __LINE__, size); +} + +void operator delete(void *buf) +{ + sm_free(__FILE__, __LINE__, buf); } #endif diff --git a/bacula/src/lib/util.c b/bacula/src/lib/util.c index 4433febb4f..8331f3899b 100644 --- a/bacula/src/lib/util.c +++ b/bacula/src/lib/util.c @@ -95,96 +95,6 @@ unbash_spaces(char *str) } } -/* Strip any trailing junk from the command */ -void strip_trailing_junk(char *cmd) -{ - char *p; - p = cmd + strlen(cmd) - 1; - - /* strip trailing junk from command */ - while ((p >= cmd) && (*p == '\n' || *p == '\r' || *p == ' ')) - *p-- = 0; -} - -/* Strip any trailing slashes from a directory path */ -void strip_trailing_slashes(char *dir) -{ - char *p; - p = dir + strlen(dir) - 1; - - /* strip trailing slashes */ - while ((p >= dir) && (*p == '/')) - *p-- = 0; -} - -/* - * Skip spaces - * Returns: 0 on failure (EOF) - * 1 on success - * new address in passed parameter - */ -int skip_spaces(char **msg) -{ - char *p = *msg; - if (!p) { - return 0; - } - while (*p && *p == ' ') { - p++; - } - *msg = p; - return *p ? 1 : 0; -} - -/* - * Skip nonspaces - * Returns: 0 on failure (EOF) - * 1 on success - * new address in passed parameter - */ -int skip_nonspaces(char **msg) -{ - char *p = *msg; - - if (!p) { - return 0; - } - while (*p && *p != ' ') { - p++; - } - *msg = p; - return *p ? 1 : 0; -} - -/* folded search for string - case insensitive */ -int -fstrsch(char *a, char *b) /* folded case search */ -{ - register char *s1,*s2; - register char c1, c2; - - s1=a; - s2=b; - while (*s1) { /* do it the fast way */ - if ((*s1++ | 0x20) != (*s2++ | 0x20)) - return 0; /* failed */ - } - while (*a) { /* do it over the correct slow way */ - if (B_ISUPPER(c1 = *a)) { - c1 = tolower((int)c1); - } - if (B_ISUPPER(c2 = *b)) { - c2 = tolower((int)c2); - } - if (c1 != c2) { - return 0; - } - a++; - b++; - } - return 1; -} - char *encode_time(time_t time, char *buf) { @@ -513,7 +423,7 @@ int do_shell_expansion(char *name, int name_len) from SpeakFreely by John Walker */ -void makeSessionKey(char *key, char *seed, int mode) +void make_session_key(char *key, char *seed, int mode) { int j, k; struct MD5Context md5c; @@ -657,123 +567,6 @@ POOLMEM *edit_job_codes(JCR *jcr, char *omsg, char *imsg, char *to) return omsg; } -/* - * Return next argument from command line. Note, this - * routine is destructive. - */ -char *next_arg(char **s) -{ - char *p, *q, *n; - int in_quote = 0; - - /* skip past spaces to next arg */ - for (p=*s; *p && *p == ' '; ) { - p++; - } - Dmsg1(400, "Next arg=%s\n", p); - for (n = q = p; *p ; ) { - if (*p == '\\') { - p++; - if (*p) { - *q++ = *p++; - } else { - *q++ = *p; - } - continue; - } - if (*p == '"') { /* start or end of quote */ - if (in_quote) { - p++; /* skip quote */ - in_quote = 0; - continue; - } - in_quote = 1; - p++; - continue; - } - if (!in_quote && *p == ' ') { /* end of field */ - p++; - break; - } - *q++ = *p++; - } - *q = 0; - *s = p; - Dmsg2(400, "End arg=%s next=%s\n", n, p); - return n; -} - -/* - * This routine parses the input command line. - * It makes a copy in args, then builds an - * argc, argv like list where - * - * argc = count of arguments - * argk[i] = argument keyword (part preceding =) - * argv[i] = argument value (part after =) - * - * example: arg1 arg2=abc arg3= - * - * argc = c - * argk[0] = arg1 - * argv[0] = NULL - * argk[1] = arg2 - * argv[1] = abc - * argk[2] = arg3 - * argv[2] = - */ - -void parse_command_args(POOLMEM *cmd, POOLMEM *args, int *argc, - char **argk, char **argv) -{ - char *p, *q, *n; - int len; - - len = strlen(cmd) + 1; - args = check_pool_memory_size(args, len); - bstrncpy(args, cmd, len); - strip_trailing_junk(args); - *argc = 0; - p = args; - /* Pick up all arguments */ - while (*argc < MAX_CMD_ARGS) { - n = next_arg(&p); - if (*n) { - argk[*argc] = n; - argv[(*argc)++] = NULL; - } else { - break; - } - } - /* Separate keyword and value */ - for (int i=0; i < *argc; i++) { - p = strchr(argk[i], '='); - if (p) { - *p++ = 0; /* terminate keyword and point to value */ - /* Unquote quoted values */ - if (*p == '"') { - for (n = q = ++p; *p && *p != '"'; ) { - if (*p == '\\') { - p++; - } - *q++ = *p++; - } - *q = 0; /* terminate string */ - p = n; /* point to string */ - } - if (strlen(p) > MAX_NAME_LENGTH-1) { - p[MAX_NAME_LENGTH-1] = 0; /* truncate to max len */ - } - } - argv[i] = p; /* save ptr to value or NULL */ - } -#ifdef xxxx - for (i=0; iVolumeName, dev->VolHdr.VolName); + pm_strcpy(&jcr->VolumeName, dev->VolHdr.VolName); if (!dir_get_volume_info(jcr, 1) && !(dir_find_next_appendable_volume(jcr) && strcmp(dev->VolHdr.VolName, jcr->VolumeName) == 0)) { /* wrong tape mounted */ diff --git a/bacula/src/stored/askdir.c b/bacula/src/stored/askdir.c index 59286b8ad4..781ee94941 100644 --- a/bacula/src/stored/askdir.c +++ b/bacula/src/stored/askdir.c @@ -115,7 +115,7 @@ int dir_get_volume_info(JCR *jcr, int writing) { BSOCK *dir = jcr->dir_bsock; - strcpy(jcr->VolCatInfo.VolCatName, jcr->VolumeName); + bstrncpy(jcr->VolCatInfo.VolCatName, jcr->VolumeName, sizeof(jcr->VolCatInfo.VolCatName)); Dmsg1(200, "dir_get_volume_info=%s\n", jcr->VolCatInfo.VolCatName); bash_spaces(jcr->VolCatInfo.VolCatName); bnet_fsend(dir, Get_Vol_Info, jcr->Job, jcr->VolCatInfo.VolCatName, writing); diff --git a/bacula/src/stored/block.c b/bacula/src/stored/block.c index 95a424d24b..0eeea9e4af 100644 --- a/bacula/src/stored/block.c +++ b/bacula/src/stored/block.c @@ -144,7 +144,8 @@ void empty_block(DEV_BLOCK *block) block->binbuf = WRITE_BLKHDR_LENGTH; block->bufp = block->buf + block->binbuf; block->read_len = 0; - block->failed_write = FALSE; + block->write_failed = false; + block->block_read = false; } /* @@ -355,7 +356,7 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) } Jmsg(jcr, M_INFO, 0, _("User defined maximum volume capacity %s exceeded on device %s.\n"), edit_uint64(max_cap, ed1), dev->dev_name); - block->failed_write = TRUE; + block->write_failed = true; dev->EndBlock = dev->block_num; dev->EndFile = dev->file; weof_dev(dev, 1); /* end the tape */ @@ -401,7 +402,7 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) Jmsg3(jcr, M_INFO, 0, _("End of medium on device %s. Write of %u bytes got %d.\n"), dev->dev_name, wlen, stat); } - block->failed_write = TRUE; + block->write_failed = true; dev->EndBlock = dev->block_num; dev->EndFile = dev->file; weof_dev(dev, 1); /* end the tape */ @@ -516,7 +517,7 @@ reread: if (retry == 1) { dev->VolCatInfo.VolCatErrors++; } - } while (stat == -1 && (errno == EINTR || errno == EIO) && retry++ < 6); + } while (stat == -1 && (errno == EINTR || errno == EIO) && retry++ < 11); if (stat < 0) { Dmsg1(90, "Read device got: ERR=%s\n", strerror(errno)); clrerror_dev(dev, -1); @@ -524,13 +525,16 @@ reread: Mmsg2(&dev->errmsg, _("Read error on device %s. ERR=%s.\n"), dev->dev_name, strerror(dev->dev_errno)); Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); + if (dev->state & ST_EOF) { /* EOF just seen? */ + dev->state |= ST_EOT; /* yes, error => EOT */ + } return 0; } Dmsg1(90, "Read device got %d bytes\n", stat); if (stat == 0) { /* Got EOF ! */ dev->block_num = block->read_len = 0; Mmsg1(&dev->errmsg, _("Read zero bytes on device %s.\n"), dev->dev_name); - if (dev->state & ST_EOF) { /* EOF alread read? */ + if (dev->state & ST_EOF) { /* EOF already read? */ dev->state |= ST_EOT; /* yes, 2 EOFs => EOT */ block->read_len = 0; return 0; @@ -557,15 +561,6 @@ reread: return 0; } -#ifdef somehow_working - if (check_block_numbers) { - if (BlockNumber != block->BlockNumber) { - Jmsg(jcr, M_ERROR, 0, _("Incorrect block sequence number. Expected %u, got %u\n"), - BlockNumber, block->BlockNumber); - } - } -#endif - /* * If the block is bigger than the buffer, we reposition for * re-reading the block, allocate a buffer of the correct size, @@ -640,5 +635,6 @@ reread: } Dmsg2(200, "Exit read_block read_len=%d block_len=%d\n", block->read_len, block->block_len); + block->block_read = true; return 1; } diff --git a/bacula/src/stored/block.h b/bacula/src/stored/block.h index 9d9c98267c..551804c20d 100644 --- a/bacula/src/stored/block.h +++ b/bacula/src/stored/block.h @@ -82,8 +82,8 @@ * * This is the memory structure for a device block. */ -typedef struct s_dev_block { - struct s_dev_block *next; /* pointer to next one */ +struct DEV_BLOCK { + DEV_BLOCK *next; /* pointer to next one */ void *dev; /* pointer to device (DEVICE not defined yet) */ /* binbuf is the number of bytes remaining * in the buffer. For writes, it is bytes not yet written. @@ -97,12 +97,13 @@ typedef struct s_dev_block { uint32_t VolSessionId; /* */ uint32_t VolSessionTime; /* */ int BlockVer; /* block version 1 or 2 */ - int failed_write; /* set if write failed */ + bool write_failed; /* set if write failed */ + bool block_read; /* set when block read */ char *bufp; /* pointer into buffer */ POOLMEM *buf; /* actual data buffer. This is a * Pool buffer! */ -} DEV_BLOCK; +}; #define block_is_empty(block) !((block)->read_len) diff --git a/bacula/src/stored/bls.c b/bacula/src/stored/bls.c index cdb642de8e..1e0a3b908a 100644 --- a/bacula/src/stored/bls.c +++ b/bacula/src/stored/bls.c @@ -239,7 +239,8 @@ static void do_blocks(char *infname) Dmsg1(100, "!read_block(): ERR=%s\n", strerror_dev(dev)); if (dev->state & ST_EOT) { if (!mount_next_read_volume(jcr, dev, block)) { - printf("End of File on device\n"); + Jmsg(jcr, M_INFO, 0, _("Got EOM at file %u on device %s, Volume \"%s\"\n"), + dev->file, dev_name(dev), jcr->VolumeName); break; } /* Read and discard Volume label */ @@ -249,10 +250,11 @@ static void do_blocks(char *infname) read_record_from_block(block, record); get_session_record(dev, record, &sessrec); free_record(record); - printf("Volume %s mounted.\n", jcr->VolumeName); + Jmsg(jcr, M_INFO, 0, _("Mounted Volume \"%s\".\n"), jcr->VolumeName); } else if (dev->state & ST_EOF) { - Jmsg(jcr, M_INFO, 0, "Got EOF on device %s\n", dev_name(dev)); + Jmsg(jcr, M_INFO, 0, _("Got EOF at file %u on device %s, Volume \"%s\"\n"), + dev->file, dev_name(dev), jcr->VolumeName); Dmsg0(20, "read_record got eof. try again\n"); continue; } else if (dev->state & ST_SHORT) { diff --git a/bacula/src/stored/bsr.h b/bacula/src/stored/bsr.h index c0d1c433e9..8dcaf57f0e 100644 --- a/bacula/src/stored/bsr.h +++ b/bacula/src/stored/bsr.h @@ -34,13 +34,12 @@ * List of Volume names to be read by Storage daemon. * Formed by Storage daemon from BSR */ -struct s_vol_list { - struct s_vol_list *next; +struct VOL_LIST { + VOL_LIST *next; char VolumeName[MAX_NAME_LENGTH]; int Slot; int start_file; }; -typedef struct s_vol_list VOL_LIST; /* @@ -52,80 +51,80 @@ typedef struct s_vol_list VOL_LIST; * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -typedef struct s_bsr_volume { - struct s_bsr_volume *next; +struct BSR_VOLUME { + BSR_VOLUME *next; char VolumeName[MAX_NAME_LENGTH]; -} BSR_VOLUME; +}; -typedef struct s_bsr_client { - struct s_bsr_client *next; +struct BSR_CLIENT { + BSR_CLIENT *next; char ClientName[MAX_NAME_LENGTH]; -} BSR_CLIENT; +}; -typedef struct s_bsr_sessid { - struct s_bsr_sessid *next; +struct BSR_SESSID { + BSR_SESSID *next; uint32_t sessid; uint32_t sessid2; int done; /* local done */ -} BSR_SESSID; +}; -typedef struct s_bsr_sesstime { - struct s_bsr_sesstime *next; +struct BSR_SESSTIME { + BSR_SESSTIME *next; uint32_t sesstime; int done; /* local done */ -} BSR_SESSTIME; +}; -typedef struct s_bsr_volfile { - struct s_bsr_volfile *next; +struct BSR_VOLFILE { + BSR_VOLFILE *next; uint32_t sfile; /* start file */ uint32_t efile; /* end file */ int done; /* local done */ -} BSR_VOLFILE; +}; -typedef struct s_bsr_volblock { - struct s_bsr_volblock *next; +struct BSR_VOLBLOCK { + BSR_VOLBLOCK *next; uint32_t sblock; /* start block */ uint32_t eblock; /* end block */ int done; /* local done */ -} BSR_VOLBLOCK; +}; -typedef struct s_bsr_findex { - struct s_bsr_findex *next; +struct BSR_FINDEX { + BSR_FINDEX *next; int32_t findex; /* start file index */ int32_t findex2; /* end file index */ int done; /* local done */ -} BSR_FINDEX; +}; -typedef struct s_bsr_jobid { - struct s_bsr_jobid *next; +struct BSR_JOBID { + BSR_JOBID *next; uint32_t JobId; uint32_t JobId2; -} BSR_JOBID; +}; -typedef struct s_bsr_jobtype { - struct s_bsr_jobtype *next; +struct BSR_JOBTYPE { + BSR_JOBTYPE *next; uint32_t JobType; -} BSR_JOBTYPE; +}; -typedef struct s_bsr_joblevel { - struct s_bsr_joblevel *next; +struct BSR_JOBLEVEL { + BSR_JOBLEVEL *next; uint32_t JobLevel; -} BSR_JOBLEVEL; +}; -typedef struct s_bsr_job { - struct s_bsr_job *next; +struct BSR_JOB { + BSR_JOB *next; char Job[MAX_NAME_LENGTH]; int done; -} BSR_JOB; +}; -typedef struct s_bsr_stream { - struct s_bsr_stream *next; +struct BSR_STREAM { + BSR_STREAM *next; int32_t stream; /* stream desired */ -} BSR_STREAM; +}; -typedef struct s_bsr { - struct s_bsr *next; /* pointer to next one */ +struct BSR { + BSR *next; /* pointer to next one */ int done; /* set when everything found */ BSR_VOLUME *volume; int32_t Slot; /* Slot */ @@ -142,7 +141,7 @@ typedef struct s_bsr { BSR_JOBTYPE *JobType; BSR_JOBLEVEL *JobLevel; BSR_STREAM *stream; -} BSR; +}; #endif diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index 104e70cbf0..eeb8a84dd0 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -227,7 +227,7 @@ open_dev(DEVICE *dev, char *VolName, int mode) return dev->fd; } if (VolName) { - strcpy(dev->VolCatInfo.VolCatName, VolName); + bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName)); } Dmsg3(29, "open_dev: tape=%d dev_name=%s vol=%s\n", dev_is_tape(dev), @@ -288,6 +288,11 @@ open_dev(DEVICE *dev, char *VolName, int mode) /* * Handle opening of File Archive (not a tape) */ + if (VolName == NULL || *VolName == 0) { + Mmsg(&dev->errmsg, _("Could not open file device %s. No Volume name given.\n"), + dev->dev_name); + return -1; + } archive_name = get_pool_memory(PM_FNAME); pm_strcpy(&archive_name, dev->dev_name); if (archive_name[strlen(archive_name)] != '/') { @@ -1199,8 +1204,12 @@ term_dev(DEVICE *dev) } } - - +/* + * We attach a jcr to the device so that when + * the Volume is full during writing, a + * JobMedia record will be created for this + * Job. + */ void attach_jcr_to_device(DEVICE *dev, JCR *jcr) { jcr->prev_dev = (JCR *)NULL; diff --git a/bacula/src/stored/device.c b/bacula/src/stored/device.c index c7a355b00d..939e052a0c 100644 --- a/bacula/src/stored/device.c +++ b/bacula/src/stored/device.c @@ -91,6 +91,9 @@ int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) */ Dmsg1(100, "Walk attached jcrs. Volume=%s\n", dev->VolCatInfo.VolCatName); for (JCR *mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) { + if (mjcr->JobId == 0) { + continue; /* ignore console */ + } Dmsg1(100, "create JobMedia for Job %s\n", mjcr->Job); if (dev->state & ST_TAPE) { mjcr->EndBlock = dev->EndBlock; diff --git a/bacula/src/stored/dircmd.c b/bacula/src/stored/dircmd.c index 433940f7a2..03c260a0f3 100644 --- a/bacula/src/stored/dircmd.c +++ b/bacula/src/stored/dircmd.c @@ -361,7 +361,7 @@ static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname, steal_device_lock(dev, &hold, BST_WRITING_LABEL); - strcpy(jcr->VolumeName, newname); + pm_strcpy(&jcr->VolumeName, newname); jcr->VolCatInfo.Slot = slot; autoload_device(jcr, dev, 0, dir); /* autoload if possible */ block = new_block(dev); @@ -695,7 +695,10 @@ static int autochanger_cmd(JCR *jcr) jcr->device = device; dev = device->dev; P(dev->mutex); /* Use P to avoid indefinite block */ - if (!(dev->state & ST_OPENED)) { + if (!dev_is_tape(dev)) { + bnet_fsend(dir, _("3995 Device %s is not an autochanger.\n"), + dev_name(dev)); + } else if (!(dev->state & ST_OPENED)) { if (open_dev(dev, NULL, READ_WRITE) < 0) { bnet_fsend(dir, _("3994 Connot open device: %s\n"), strerror_dev(dev)); } else { @@ -723,7 +726,7 @@ static int autochanger_cmd(JCR *jcr) } else { bnet_fsend(dir, _("3999 Device %s not found\n"), devname); } - } else { + } else { /* error on scanf */ pm_strcpy(&jcr->errmsg, dir->msg); bnet_fsend(dir, _("3907 Error scanning autocharger list command: %s\n"), jcr->errmsg); diff --git a/bacula/src/stored/job.c b/bacula/src/stored/job.c index e0846894e5..04e7ff3a96 100644 --- a/bacula/src/stored/job.c +++ b/bacula/src/stored/job.c @@ -136,16 +136,18 @@ int job_cmd(JCR *jcr) srandom(tv.tv_usec + tv.tv_sec); sprintf(auth_key, "%ld", (long)random()); #endif - makeSessionKey(auth_key, NULL, 1); + make_session_key(auth_key, NULL, 1); bnet_fsend(dir, OKjob, jcr->VolSessionId, jcr->VolSessionTime, auth_key); Dmsg1(110, ">dird: %s", dir->msg); jcr->sd_auth_key = bstrdup(auth_key); + memset(auth_key, 0, sizeof(auth_key)); /* * Wait for the device, media, and pool information */ if (!use_device_cmd(jcr)) { set_jcr_job_status(jcr, JS_ErrorTerminated); + memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key)); return 0; } @@ -171,6 +173,8 @@ int job_cmd(JCR *jcr) } V(jcr->mutex); + memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key)); + if (jcr->authenticated && !job_canceled(jcr)) { run_job(jcr); /* Run the job */ } @@ -181,7 +185,7 @@ int job_cmd(JCR *jcr) * This entry point is only called if we have a separate * Storage Daemon Data port. Otherwise, the connection * is made to the main port, and if it is a File daemon - * calling, handl_filed_connection() is called directly. + * calling, handle_filed_connection() is called directly. */ void connection_from_filed(void *arg) { @@ -236,7 +240,7 @@ void handle_filed_connection(BSOCK *fd, char *job_name) P(jcr->mutex); if (!jcr->authenticated) { - jcr->JobStatus = JS_ErrorTerminated; + set_jcr_job_status(jcr, JS_ErrorTerminated); } pthread_cond_signal(&jcr->job_start_wait); /* wake waiting job */ V(jcr->mutex); diff --git a/bacula/src/stored/label.c b/bacula/src/stored/label.c index 74ea5157b2..3867976b5d 100644 --- a/bacula/src/stored/label.c +++ b/bacula/src/stored/label.c @@ -68,7 +68,7 @@ int read_dev_volume_label(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) if (dev->state & ST_LABEL) { /* did we already read label? */ /* Compare Volume Names allow special wild card */ if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolName, VolName) != 0) { - Mmsg(&jcr->errmsg, _("Volume name mismatch on device %s: Wanted %s got %s\n"), + Mmsg(&jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"), dev_name(dev), VolName, dev->VolHdr.VolName); /* * Cancel Job if too many label errors @@ -134,8 +134,8 @@ because:\n %s"), dev_name(dev), strerror_dev(dev)); /* Compare Volume Names */ Dmsg2(30, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolName); if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolName, VolName) != 0) { - Mmsg(&jcr->errmsg, _("Volume name mismatch. Wanted %s got %s\n"), - VolName, dev->VolHdr.VolName); + Mmsg(&jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"), + dev_name(dev), VolName, dev->VolHdr.VolName); /* * Cancel Job if too many label errors * => we are in a loop diff --git a/bacula/src/stored/mount.c b/bacula/src/stored/mount.c index 609fea59e8..1ebf5ed269 100644 --- a/bacula/src/stored/mount.c +++ b/bacula/src/stored/mount.c @@ -356,7 +356,7 @@ mount_error: dev_file(dev)); } else { Jmsg(jcr, M_ERROR, 0, _("I canot write on this volume because:\n\ -The number of files mismatch! Volume=%d Catalog=%d\n"), +The number of files mismatch! Volume=%u Catalog=%u\n"), dev_file(dev), dev->VolCatInfo.VolCatFiles); strcpy(dev->VolCatInfo.VolCatStatus, "Error"); Dmsg0(200, "dir_update_vol_info. Set Error.\n"); @@ -386,7 +386,7 @@ int mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) close_dev(dev); dev->state &= ~ST_READ; if (!acquire_device_for_read(jcr, dev, block)) { - Emsg2(M_FATAL, 0, "Cannot open Dev=%s, Vol=%s\n", dev_name(dev), + Jmsg2(jcr, M_FATAL, 0, "Cannot open Dev=%s, Vol=%s\n", dev_name(dev), jcr->VolumeName); return 0; } diff --git a/bacula/src/stored/parse_bsr.c b/bacula/src/stored/parse_bsr.c index 2707477600..73e76e16e9 100755 --- a/bacula/src/stored/parse_bsr.c +++ b/bacula/src/stored/parse_bsr.c @@ -191,7 +191,7 @@ static BSR *store_vol(LEX *lc, BSR *bsr) } volume = (BSR_VOLUME *)malloc(sizeof(BSR_VOLUME)); memset(volume, 0, sizeof(BSR_VOLUME)); - strcpy(volume->VolumeName, p); + bstrncpy(volume->VolumeName, p, sizeof(volume->VolumeName)); /* Add it to the end of the volume chain */ if (!bsr->volume) { bsr->volume = volume; @@ -218,7 +218,7 @@ static BSR *store_client(LEX *lc, BSR *bsr) } client = (BSR_CLIENT *)malloc(sizeof(BSR_CLIENT)); memset(client, 0, sizeof(BSR_CLIENT)); - strcpy(client->ClientName, lc->str); + bstrncpy(client->ClientName, lc->str, sizeof(client->ClientName)); /* Add it to the end of the client chain */ if (!bsr->client) { bsr->client = client; @@ -248,7 +248,7 @@ static BSR *store_job(LEX *lc, BSR *bsr) } job = (BSR_JOB *)malloc(sizeof(BSR_JOB)); memset(job, 0, sizeof(BSR_JOB)); - strcpy(job->Job, lc->str); + bstrncpy(job->Job, lc->str, sizeof(job->Job)); /* Add it to the end of the client chain */ if (!bsr->job) { bsr->job = job; @@ -801,7 +801,7 @@ void create_vol_list(JCR *jcr) /* Now add volumes for this bsr */ for (bsrvol = bsr->volume; bsrvol; bsrvol=bsrvol->next) { vol = new_vol(); - strcpy(vol->VolumeName, bsrvol->VolumeName); + bstrncpy(vol->VolumeName, bsrvol->VolumeName, sizeof(vol->VolumeName)); vol->start_file = sfile; if (add_vol(jcr, vol)) { jcr->NumVolumes++; @@ -821,7 +821,7 @@ void create_vol_list(JCR *jcr) *n++ = 0; /* Terminate name */ } vol = new_vol(); - strcpy(vol->VolumeName, p); + bstrncpy(vol->VolumeName, p, sizeof(vol->VolumeName)); if (add_vol(jcr, vol)) { jcr->NumVolumes++; } else { diff --git a/bacula/src/stored/read.c b/bacula/src/stored/read.c index 332125d7dd..3434eb260c 100644 --- a/bacula/src/stored/read.c +++ b/bacula/src/stored/read.c @@ -31,20 +31,11 @@ /* Forward referenced subroutines */ static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec); -/* Variables used by Child process */ -/* Global statistics */ -/* Note, these probably should be in shared memory so that - * they are truly global for all processes - */ -extern struct s_shm *shm; /* shared memory structure */ -extern int FiledDataChan; /* File daemon data channel (port) */ - /* Responses sent to the File daemon */ static char OK_data[] = "3000 OK data\n"; static char rec_header[] = "rechdr %ld %ld %ld %ld %ld"; - /* * Read Data and send to File Daemon * Returns: 0 on failure @@ -61,6 +52,7 @@ int do_read_data(JCR *jcr) DEV_BLOCK *block; POOLMEM *hdr; SESSION_LABEL sessrec; /* session record */ + uint32_t BlockNumber = 0; Dmsg0(20, "Start read data.\n"); @@ -195,13 +187,24 @@ int do_read_data(JCR *jcr) } } + if (block->block_read) { + if (++BlockNumber != block->BlockNumber) { + Jmsg(jcr, M_ERROR, 0, _("Invalid block number. Expected %u, got %u\n"), + BlockNumber, block->BlockNumber); + } + BlockNumber = block->BlockNumber; + block->block_read = false; + } + if (is_partial_record(rec)) { break; /* Go read full record */ } - /* Generate Header parameters and send to File daemon + /* + * We "finally" have a full record here. Now + * generate Header parameters and send to File daemon * Note, we build header in hdr buffer to avoid wiping - * out the data record + * out the data record */ ds->msg = hdr; Dmsg5(400, "Send to FD: SessId=%u SessTim=%u FI=%d Strm=%d, len=%d\n", @@ -212,6 +215,8 @@ int do_read_data(JCR *jcr) Dmsg1(30, ">filed: Error Hdr=%s\n", ds->msg); hdr = ds->msg; ds->msg = rec->data; + Jmsg1(jcr, M_FATAL, 0, _("Error sending to File daemon. ERR=%s\n"), + bnet_strerror(ds)); ok = FALSE; break; } else { @@ -233,8 +238,8 @@ int do_read_data(JCR *jcr) ok = FALSE; break; } - } - } + } /* end for loop reading records */ + } /* end for loop reading blocks */ /* Send end of data to FD */ bnet_sig(ds, BNET_EOD); diff --git a/bacula/src/stored/read_record.c b/bacula/src/stored/read_record.c index d2287dea60..273be3d2d9 100644 --- a/bacula/src/stored/read_record.c +++ b/bacula/src/stored/read_record.c @@ -94,8 +94,8 @@ int read_records(JCR *jcr, DEVICE *dev, goto next_record; /* go read new tape */ } else if (dev->state & ST_EOF) { - Jmsg(jcr, M_INFO, 0, "Got EOF on device %s, Volume \"%s\"\n", - dev_name(dev), jcr->VolumeName); + Jmsg(jcr, M_INFO, 0, "Got EOF at file %u on device %s, Volume \"%s\"\n", + dev->file, dev_name(dev), jcr->VolumeName); Dmsg0(20, "read_record got eof. try again\n"); continue; } else if (dev->state & ST_SHORT) { diff --git a/bacula/src/stored/record.h b/bacula/src/stored/record.h index 327b2d525e..4da29976d0 100644 --- a/bacula/src/stored/record.h +++ b/bacula/src/stored/record.h @@ -61,12 +61,12 @@ */ /* Record state bit definitions */ -#define REC_NO_HEADER 0x01 /* No header read */ -#define REC_PARTIAL_RECORD 0x02 /* returning partial record */ -#define REC_BLOCK_EMPTY 0x04 /* not enough data in block */ -#define REC_NO_MATCH 0x08 /* No match on continuation data */ -#define REC_CONTINUATION 0x10 /* Continuation record found */ -#define REC_ISTAPE 0x20 /* Set if device is tape */ +#define REC_NO_HEADER (1<<0) /* No header read */ +#define REC_PARTIAL_RECORD (1<<1) /* returning partial record */ +#define REC_BLOCK_EMPTY (1<<2) /* not enough data in block */ +#define REC_NO_MATCH (1<<3) /* No match on continuation data */ +#define REC_CONTINUATION (1<<4) /* Continuation record found */ +#define REC_ISTAPE (1<<5) /* Set if device is tape */ #define is_partial_record(r) ((r)->state & REC_PARTIAL_RECORD) #define is_block_empty(r) ((r)->state & REC_BLOCK_EMPTY) @@ -77,7 +77,7 @@ * * This is the memory structure for the record header. */ -typedef struct s_dev_rec { +struct DEV_RECORD { int sync; /* synchronous */ /* File and Block are always returned on reading records, but * only returned on writing if sync is set (obviously). @@ -93,7 +93,7 @@ typedef struct s_dev_rec { uint32_t state; /* state bits */ uint8_t ser_buf[WRITE_RECHDR_LENGTH]; /* serialized record header goes here */ POOLMEM *data; /* Record data. This MUST be a memory pool item */ -} DEV_RECORD; +}; /* diff --git a/bacula/src/stored/stored_conf.h b/bacula/src/stored/stored_conf.h index 9dcd977b1e..14ac5972f5 100644 --- a/bacula/src/stored/stored_conf.h +++ b/bacula/src/stored/stored_conf.h @@ -62,7 +62,7 @@ struct s_res_store { char *subsys_directory; int require_ssl; /* Require SSL on all connections */ uint32_t max_concurrent_jobs; /* maximum concurrent jobs to run */ - struct s_res_msgs *messages; /* Daemon message handler */ + MSGS *messages; /* Daemon message handler */ utime_t heartbeat_interval; /* Interval to send hb to FD */ }; typedef struct s_res_store STORES; diff --git a/bacula/src/version.h b/bacula/src/version.h index 959ec6f3d8..8dfa9bb282 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -1,8 +1,8 @@ /* */ #define VERSION "1.31" #define VSTRING "1" -#define BDATE "26 May 2003" -#define LSMDATE "26May03" +#define BDATE "30 May 2003" +#define LSMDATE "30May03" /* Debug flags */ #define DEBUG 1 -- 2.39.5