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
option on the ./configure.
- Version 1.31 and 1.30 daemons/Director are not compatible. You must
upgrade all or nothing.
-
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.
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)
- 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
- 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).
- 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.
- 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.
- 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.
- 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
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=
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)
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
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
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
- 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?
#ifdef HAVE_BACULA_DB
-char catalog_db[] = "Interal";
+uint32_t bacula_db_version = 0;
/* Forward referenced functions */
BDB_VERSION, mdb->control.bdb_version);
badctl = 1;
}
+ bacula_db_version = mdb->control.bdb_version;
if (badctl) {
V(mutex);
return 0;
{ }
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)
{ }
#ifdef HAVE_SQLITE
-#define BDB_VERSION 5
+#define BDB_VERSION 6
#include <sqlite.h>
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
#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**
#ifdef HAVE_MYSQL
-#define BDB_VERSION 5
+#define BDB_VERSION 6
#include <mysql.h>
* 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;
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;
#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)
#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 */
/* 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 */
};
* 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;
#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
/* 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;
/* 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;
*/
/* 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 */
};
* 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;
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;
/* 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 */
/* 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 */
};
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."
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,
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,
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))
);
FileSetId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
FileSet TINYBLOB NOT NULL,
MD5 TINYBLOB NOT NULL,
+ CreateTime DATETIME NOT NULL,
PRIMARY KEY(FileSetId)
);
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)
);
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,
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
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,
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,
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)
);
FileSetId INTEGER UNSIGNED AUTOINCREMENT,
FileSet VARCHAR(128) NOT NULL,
MD5 VARCHAR(25) NOT NULL,
+ CreateTime DATETIME DEFAULT 0,
PRIMARY KEY(FileSetId)
);
EndFile INTEGER UNSIGNED DEFAULT 0,
StartBlock INTEGER UNSIGNED DEFAULT 0,
EndBlock INTEGER UNSIGNED DEFAULT 0,
+ VolIndex INTEGER UNSIGNED DEFAULT 0,
PRIMARY KEY(JobMediaId)
);
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,
);
-- Initialize Version
-INSERT INTO Version (VersionId) VALUES (5);
+INSERT INTO Version (VersionId) VALUES (6);
CREATE TABLE Counters (
Counter TEXT NOT NULL,
* 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;
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;
}
}
}
- if (full_list) {
- goto horizontal_list;
+ if (type == VERT_LIST) {
+ goto vertical_list;
}
list_dashes(mdb, send, ctx);
list_dashes(mdb, send, ctx);
return;
-horizontal_list:
+vertical_list:
while ((row = sql_fetch_row(mdb)) != NULL) {
sql_field_seek(mdb, 0);
/* 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);
#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);
/* 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;
}
{
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)) {
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;
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"),
stat = 0;
} else {
fsr->FileSetId = sql_insert_id(mdb);
+ fsr->created = true;
stat = 1;
}
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);
/* 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 {
}
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;
}
}
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;
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);
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);
}
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);
*/
/* 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);
* 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) {
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);
}
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 "
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");
return;
}
- list_result(mdb, sendit, ctx, full);
+ list_result(mdb, sendit, ctx, type);
sql_free_result(mdb);
db_unlock(mdb);
*/
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,"
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 "
return;
}
- list_result(mdb, sendit, ctx, full);
+ list_result(mdb, sendit, ctx, type);
sql_free_result(mdb);
db_unlock(mdb);
*/
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,"
db_unlock(mdb);
return;
}
- list_result(mdb, sendit, ctx, full);
+ list_result(mdb, sendit, ctx, type);
sql_free_result(mdb);
db_unlock(mdb);
return;
}
- list_result(mdb, sendit, ctx, 0);
+ list_result(mdb, sendit, ctx, HORZ_LIST);
sql_free_result(mdb);
return;
}
- list_result(mdb, sendit, ctx, 0);
+ list_result(mdb, sendit, ctx, HORZ_LIST);
sql_free_result(mdb);
db_unlock(mdb);
return;
}
- list_result(mdb, sendit, ctx, 0);
+ list_result(mdb, sendit, ctx, HORZ_LIST);
sql_free_result(mdb);
db_unlock(mdb);
* 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;
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;
}
}
}
- if (full_list) {
- goto horizontal_list;
+ if (type == VERT_LIST) {
+ goto vertical_list;
}
list_dashes(mdb, send, ctx);
list_dashes(mdb, send, ctx);
return;
-horizontal_list:
+vertical_list:
while ((row = sql_fetch_row(mdb)) != NULL) {
sql_field_seek(mdb, 0);
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 <file> set configuration file to file\n"
" -s no signals\n"
" -t test - read configuration and exit\n"
" -? print this message.\n"
-"\n");
+"\n"));
exit(1);
}
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;
}
}
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) {
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();
}
- 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) {
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);
char *mode = "a+";
if (argc > 3) {
- sendit("Too many arguments.\n");
+ sendit(_("Too many arguments.\n"));
return 1;
}
if (argc == 1) {
}
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;
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 \
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 \
/* 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 */
* 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
/* 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);
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;
}
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;
}
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:
free_pool_memory(jcr->stime);
jcr->stime = NULL;
}
- backup_cleanup(jcr, JS_ErrorTerminated, since);
+ backup_cleanup(jcr, JS_ErrorTerminated, since, &fsr);
return 0;
}
/*
* 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];
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));
}
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));
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\
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),
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);
}
/*
* 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 */
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 */
* 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;
};
}
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;
* 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;
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;
}
}
}
/* Note, MD5Final is done in backup.c */
- } else { /* pass 1 */
+ } else { /* pass 2 */
while (lex_get_token(lc, T_ALL) != T_EOB)
{}
}
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) {
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"
/* 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);
/* 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 */
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 */
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);
: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
}
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;
}
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;
}
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;
}
}
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;
}
/* 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";
#define __UA_H_ 1
-typedef struct s_ua_context {
+struct UAContext {
BSOCK *UA_sock;
BSOCK *sd;
JCR *jcr;
int verbose; /* set for normal UA verbosity */
uint32_t pint32_val; /* positive integer */
int32_t int32_val; /* positive/negative */
-} UAContext;
+};
#endif
/* 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;
}
}
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;
}
goto getVolName;
}
- strcpy(name, ua->cmd);
+ bstrncpy(name, ua->cmd, sizeof(name));
if (num > 0) {
strcat(name, "%04d");
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)) {
* 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 */
* 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;
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 */
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);
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) {
}
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;
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);
}
/* 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);
/*
/* 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;
--- /dev/null
+/*
+ *
+ * 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; i<nprompt; i++) {
+ free(prompt[i]);
+ }
+ return 1;
+}
+
+static char *substitute_prompts(UAContext *ua,
+ char *query, char **prompt, int nprompt)
+{
+ char *new_query, *p, *q, *o;
+ int i, n, len, olen;
+ char *subst[9];
+
+ if (nprompt == 0) {
+ return query;
+ }
+ for (i=0; i<9; i++) {
+ subst[i] = NULL;
+ }
+ new_query = (char *)get_pool_memory(PM_MESSAGE);
+ new_query = (char *)check_pool_memory_size(new_query, strlen(query) +100);
+ o = new_query;
+ olen = 0;
+ for (q=query; (p=strchr(q, '%')); ) {
+ if (p) {
+ while (q < p) { /* copy up to % */
+ *o++ = *q++;
+ olen++;
+ }
+ p++;
+ switch (*p) {
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ n = (int)(*p) - (int)'1';
+ if (prompt[n]) {
+ if (!subst[n]) {
+ if (!get_cmd(ua, prompt[n])) {
+ q += 2;
+ break;
+ }
+ }
+ len = strlen(ua->cmd);
+ 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;
+}
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 */
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;
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 */
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));
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;
}
*/
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;
}
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;
}
/*
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";
* 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;
}
/* 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 */
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;
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 \
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@
*/
#include "bacula.h"
+#include <math.h>
/* We assume ASCII input and don't worry about overflow */
uint64_t str_to_uint64(char *str)
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];
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;
}
*/
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 == '.') {
*/
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;
#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 */
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");
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)) {
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)) {
* 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 */
char item_present[MAX_RES_ITEMS]; /* set if item is present in conf file */
};
-typedef struct s_reshdr RES;
/*
* Master Resource configuration structure definition
#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);
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);
/* 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);
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);
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);
--- /dev/null
+/*
+ * 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<argc; i++) {
+ Dmsg3(000, "Arg %d: kw=%s val=%s\n", i, argk[i], argv[i]?argv[i]:"NULL");
+ }
+#endif
+}
/* Memory allocation control structures and storage. */
struct abufhead {
- struct b_queue abq; /* Links on allocated queue */
- unsigned ablen; /* Buffer length in bytes */
- char *abfname; /* File name pointer */
- sm_ushort ablineno; /* Line number of allocation */
+ struct b_queue abq; /* Links on allocated queue */
+ unsigned ablen; /* Buffer length in bytes */
+ char *abfname; /* File name pointer */
+ sm_ushort ablineno; /* Line number of allocation */
};
static struct b_queue abqueue = { /* Allocated buffer queue */
- &abqueue, &abqueue
+ &abqueue, &abqueue
};
static Boolean bufimode = False; /* Buffers not tracked when True */
static void *smalloc(char *fname, int lineno, unsigned int nbytes)
{
- 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;
+ 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
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
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
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. */
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.
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
void *actuallymalloc(unsigned int size)
{
- return malloc(size);
+ return malloc(size);
}
/* ACTUALLYCALLOC -- Call the system calloc() function to obtain
void *actuallycalloc(unsigned int nelem, unsigned int elsize)
{
- return calloc(nelem, elsize);
+ return calloc(nelem, elsize);
}
/* ACTUALLYREALLOC -- Call the system realloc() function to obtain
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
void actuallyfree(void *cp)
{
- free(cp);
+ free(cp);
}
/* SM_DUMP -- Print orphaned buffers (and dump them if BUFDUMP is
*/
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
/* 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;
}
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
}
}
-/* 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)
{
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;
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; i<argc; i++) {
- Dmsg3(000, "Arg %d: kw=%s val=%s\n", i, argk[i], argv[i]?argv[i]:"NULL");
- }
-#endif
-}
-
void set_working_directory(char *wd)
{
struct stat stat_buf;
* otherwise mount desired volume obtained from
* dir_find_next_appendable_volume
*/
- strcpy(jcr->VolumeName, 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 */
{
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);
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;
}
/*
}
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 */
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 */
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);
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;
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,
}
Dmsg2(200, "Exit read_block read_len=%d block_len=%d\n",
block->read_len, block->block_len);
+ block->block_read = true;
return 1;
}
*
* 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.
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)
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 */
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) {
* 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;
/*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/
-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 */
BSR_JOBTYPE *JobType;
BSR_JOBLEVEL *JobLevel;
BSR_STREAM *stream;
-} BSR;
+};
#endif
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),
/*
* 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)] != '/') {
}
}
-
-
+/*
+ * 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;
*/
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;
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);
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 {
} 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);
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;
}
}
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 */
}
* 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)
{
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);
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
/* 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
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");
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;
}
}
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;
}
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;
}
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;
/* 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++;
*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 {
/* 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
DEV_BLOCK *block;
POOLMEM *hdr;
SESSION_LABEL sessrec; /* session record */
+ uint32_t BlockNumber = 0;
Dmsg0(20, "Start read data.\n");
}
}
+ 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",
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 {
ok = FALSE;
break;
}
- }
- }
+ } /* end for loop reading records */
+ } /* end for loop reading blocks */
/* Send end of data to FD */
bnet_sig(ds, BNET_EOD);
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) {
*/
/* 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)
*
* 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).
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;
+};
/*
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;
/* */
#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