From: Kern Sibbald Date: Wed, 10 Mar 2004 20:12:32 +0000 (+0000) Subject: Implement Device Spool directory and sizes X-Git-Tag: Release-1.34.0~63 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=f37fe95fd8644a41bd9816f2ba892259e9b24595;p=bacula%2Fbacula Implement Device Spool directory and sizes git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1121 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h index 56bddbdc8d..ee63b8a6be 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -42,33 +42,35 @@ enum { R_MSGS, R_COUNTER, R_CONSOLE, - R_JOBDEFS + R_JOBDEFS, + R_FIRST = R_DIRECTOR, + R_LAST = R_JOBDEFS /* keep this updated */ }; -#define R_FIRST R_DIRECTOR -#define R_LAST R_JOBDEFS /* * Some resource attributes */ -#define R_NAME 1020 -#define R_ADDRESS 1021 -#define R_PASSWORD 1022 -#define R_TYPE 1023 -#define R_BACKUP 1024 +enum { + R_NAME = 1020, + R_ADDRESS, + R_PASSWORD, + R_TYPE, + R_BACKUP +}; /* Used for certain KeyWord tables */ -struct s_kw { +struct s_kw { char *name; - int token; + int token; }; /* Job Level keyword structure */ struct s_jl { - char *level_name; /* level keyword */ - int level; /* level */ - int job_type; /* JobType permitting this level */ + char *level_name; /* level keyword */ + int level; /* level */ + int job_type; /* JobType permitting this level */ }; /* Job Type keyword structure */ @@ -86,24 +88,24 @@ struct POOL; struct RUN; /* - * Director Resource + * Director Resource * */ struct DIRRES { - RES hdr; - int DIRport; /* where we listen -- UA port server port */ - char *DIRaddr; /* bind address */ - char *password; /* Password for UA access */ - int enable_ssl; /* Use SSL for UA */ - char *query_file; /* SQL query file */ - char *working_directory; /* WorkingDirectory */ - char *pid_directory; /* PidDirectory */ - char *subsys_directory; /* SubsysDirectory */ - int require_ssl; /* Require SSL for all connections */ - 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 */ + RES hdr; + int DIRport; /* where we listen -- UA port server port */ + char *DIRaddr; /* bind address */ + char *password; /* Password for UA access */ + int enable_ssl; /* Use SSL for UA */ + char *query_file; /* SQL query file */ + char *working_directory; /* WorkingDirectory */ + char *pid_directory; /* PidDirectory */ + char *subsys_directory; /* SubsysDirectory */ + int require_ssl; /* Require SSL for all connections */ + 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 */ }; @@ -120,17 +122,17 @@ enum { Command_ACL, FileSet_ACL, Catalog_ACL, - Num_ACL /* keep last */ + Num_ACL /* keep last */ }; /* * Console Resource */ struct CONRES { - RES hdr; - char *password; /* UA server password */ - int enable_ssl; /* Use SSL */ - alist *ACL_lists[Num_ACL]; /* pointers to ACLs */ + RES hdr; + char *password; /* UA server password */ + int enable_ssl; /* Use SSL */ + alist *ACL_lists[Num_ACL]; /* pointers to ACLs */ }; @@ -139,11 +141,11 @@ struct CONRES { * */ struct CAT { - RES hdr; + RES hdr; - int db_port; /* Port -- not yet implemented */ - char *db_address; /* host name for remote access */ - char *db_socket; /* Socket for local access */ + int db_port; /* Port -- not yet implemented */ + char *db_address; /* host name for remote access */ + char *db_socket; /* Socket for local access */ char *db_password; char *db_user; char *db_name; @@ -155,18 +157,18 @@ struct CAT { * */ struct CLIENT { - RES hdr; + RES hdr; - int FDport; /* Where File daemon listens */ - int AutoPrune; /* Do automatic pruning? */ - utime_t FileRetention; /* file retention period in seconds */ - utime_t JobRetention; /* job retention period in seconds */ + int FDport; /* Where File daemon listens */ + int AutoPrune; /* Do automatic pruning? */ + utime_t FileRetention; /* file retention period in seconds */ + utime_t JobRetention; /* job retention period in seconds */ char *address; char *password; - CAT *catalog; /* Catalog resource */ - uint32_t MaxConcurrentJobs; /* Maximume concurrent jobs */ - uint32_t NumConcurrentJobs; /* number of concurrent jobs running */ - int enable_ssl; /* Use SSL */ + CAT *catalog; /* Catalog resource */ + uint32_t MaxConcurrentJobs; /* Maximume concurrent jobs */ + uint32_t NumConcurrentJobs; /* number of concurrent jobs running */ + int enable_ssl; /* Use SSL */ }; /* @@ -174,18 +176,18 @@ struct CLIENT { * */ struct STORE { - RES hdr; + RES hdr; - int SDport; /* port where Directors connect */ - int SDDport; /* data port for File daemon */ + int SDport; /* port where Directors connect */ + int SDDport; /* data port for File daemon */ char *address; char *password; char *media_type; char *dev_name; - int autochanger; /* set if autochanger */ - uint32_t MaxConcurrentJobs; /* Maximume concurrent jobs */ - uint32_t NumConcurrentJobs; /* number of concurrent jobs running */ - int enable_ssl; /* Use SSL */ + int autochanger; /* set if autochanger */ + uint32_t MaxConcurrentJobs; /* Maximume concurrent jobs */ + uint32_t NumConcurrentJobs; /* number of concurrent jobs running */ + int enable_ssl; /* Use SSL */ }; @@ -193,66 +195,66 @@ struct STORE { * Job Resource */ struct JOB { - RES hdr; - - int JobType; /* job type (backup, verify, restore */ - int level; /* default backup/verify level */ - int Priority; /* Job priority */ - int RestoreJobId; /* What -- JobId to restore */ - char *RestoreWhere; /* Where on disk to restore -- directory */ - char *RestoreBootstrap; /* Bootstrap file */ - char *RunBeforeJob; /* Run program before Job */ - char *RunAfterJob; /* Run program after Job */ - char *RunAfterFailedJob; /* Run program after Job that errs */ - char *ClientRunBeforeJob; /* Run client program before Job */ - char *ClientRunAfterJob; /* Run client program after Job */ - char *WriteBootstrap; /* Where to write bootstrap Job updates */ - int replace; /* How (overwrite, ..) */ - utime_t MaxRunTime; /* max run time in seconds */ - utime_t MaxWaitTime; /* max blocking time in seconds */ - utime_t MaxStartDelay; /* max start delay in seconds */ - int PrefixLinks; /* prefix soft links with Where path */ - int PruneJobs; /* Force pruning of Jobs */ - int PruneFiles; /* Force pruning of Files */ - int PruneVolumes; /* Force pruning of Volumes */ - int SpoolAttributes; /* Set to spool attributes in SD */ - int spool_data; /* Set to spool data in SD */ - uint32_t MaxConcurrentJobs; /* Maximume concurrent jobs */ - int RescheduleOnError; /* Set to reschedule on error */ - int RescheduleTimes; /* Number of times to reschedule job */ - utime_t RescheduleInterval; /* Reschedule interval */ - utime_t JobRetention; /* job retention period in seconds */ + RES hdr; + + int JobType; /* job type (backup, verify, restore */ + int level; /* default backup/verify level */ + int Priority; /* Job priority */ + int RestoreJobId; /* What -- JobId to restore */ + char *RestoreWhere; /* Where on disk to restore -- directory */ + char *RestoreBootstrap; /* Bootstrap file */ + char *RunBeforeJob; /* Run program before Job */ + char *RunAfterJob; /* Run program after Job */ + char *RunAfterFailedJob; /* Run program after Job that errs */ + char *ClientRunBeforeJob; /* Run client program before Job */ + char *ClientRunAfterJob; /* Run client program after Job */ + char *WriteBootstrap; /* Where to write bootstrap Job updates */ + int replace; /* How (overwrite, ..) */ + utime_t MaxRunTime; /* max run time in seconds */ + utime_t MaxWaitTime; /* max blocking time in seconds */ + utime_t MaxStartDelay; /* max start delay in seconds */ + int PrefixLinks; /* prefix soft links with Where path */ + int PruneJobs; /* Force pruning of Jobs */ + int PruneFiles; /* Force pruning of Files */ + int PruneVolumes; /* Force pruning of Volumes */ + int SpoolAttributes; /* Set to spool attributes in SD */ + int spool_data; /* Set to spool data in SD */ + uint32_t MaxConcurrentJobs; /* Maximume concurrent jobs */ + int RescheduleOnError; /* Set to reschedule on error */ + int RescheduleTimes; /* Number of times to reschedule job */ + utime_t RescheduleInterval; /* Reschedule interval */ + utime_t JobRetention; /* job retention period in seconds */ - MSGS *messages; /* How and where to send messages */ - SCHED *schedule; /* When -- Automatic schedule */ - CLIENT *client; /* Who to backup */ - FILESET *fileset; /* What to backup -- Fileset */ - STORE *storage; /* Where is device -- Storage daemon */ - POOL *pool; /* Where is media -- Media Pool */ - POOL *full_pool; /* Pool for Full backups */ - POOL *inc_pool; /* Pool for Incremental backups */ - POOL *dif_pool; /* Pool for Differental backups */ - JOB *verify_job; /* Job name to verify */ - JOB *jobdefs; /* Job defaults */ - uint32_t NumConcurrentJobs; /* number of concurrent jobs running */ + MSGS *messages; /* How and where to send messages */ + SCHED *schedule; /* When -- Automatic schedule */ + CLIENT *client; /* Who to backup */ + FILESET *fileset; /* What to backup -- Fileset */ + STORE *storage; /* Where is device -- Storage daemon */ + POOL *pool; /* Where is media -- Media Pool */ + POOL *full_pool; /* Pool for Full backups */ + POOL *inc_pool; /* Pool for Incremental backups */ + POOL *dif_pool; /* Pool for Differental backups */ + JOB *verify_job; /* Job name to verify */ + JOB *jobdefs; /* Job defaults */ + uint32_t NumConcurrentJobs; /* number of concurrent jobs running */ }; #define MAX_FOPTS 30 /* File options structure */ struct FOPTS { - char opts[MAX_FOPTS]; /* options string */ - alist match; /* match string(s) */ - alist base_list; /* list of base names */ + char opts[MAX_FOPTS]; /* options string */ + alist match; /* match string(s) */ + alist base_list; /* list of base names */ }; /* This is either an include item or an exclude item */ struct INCEXE { - FOPTS *current_opts; /* points to current options structure */ - FOPTS **opts_list; /* options list */ - int num_opts; /* number of options items */ - alist name_list; /* filename list -- holds char * */ + FOPTS *current_opts; /* points to current options structure */ + FOPTS **opts_list; /* options list */ + int num_opts; /* number of options items */ + alist name_list; /* filename list -- holds char * */ }; /* @@ -260,16 +262,16 @@ struct INCEXE { * */ struct FILESET { - RES hdr; + RES hdr; - int new_include; /* Set if new include used */ - INCEXE **include_items; /* array of incexe structures */ - int num_includes; /* number in array */ + int new_include; /* Set if new include used */ + INCEXE **include_items; /* array of incexe structures */ + int num_includes; /* number in array */ INCEXE **exclude_items; int num_excludes; - int have_MD5; /* set if MD5 initialized */ - struct MD5Context md5c; /* MD5 of include/exclude */ - char MD5[30]; /* base 64 representation of MD5 */ + int have_MD5; /* set if MD5 initialized */ + struct MD5Context md5c; /* MD5 of include/exclude */ + char MD5[30]; /* base 64 representation of MD5 */ }; @@ -278,7 +280,7 @@ struct FILESET { * */ struct SCHED { - RES hdr; + RES hdr; RUN *run; }; @@ -287,14 +289,14 @@ struct SCHED { * Counter Resource */ struct COUNTER { - RES hdr; - - int32_t MinValue; /* Minimum value */ - int32_t MaxValue; /* Maximum value */ - int32_t CurrentValue; /* Current value */ - COUNTER *WrapCounter; /* Wrap counter name */ - CAT *Catalog; /* Where to store */ - bool created; /* Created in DB */ + RES hdr; + + int32_t MinValue; /* Minimum value */ + int32_t MaxValue; /* Maximum value */ + int32_t CurrentValue; /* Current value */ + COUNTER *WrapCounter; /* Wrap counter name */ + CAT *Catalog; /* Where to store */ + bool created; /* Created in DB */ }; /* @@ -302,26 +304,26 @@ struct COUNTER { * */ struct POOL { - RES hdr; - - char *pool_type; /* Pool type */ - char *label_format; /* Label format string */ - char *cleaning_prefix; /* Cleaning label prefix */ - int use_catalog; /* maintain catalog for media */ - int catalog_files; /* maintain file entries in catalog */ - int use_volume_once; /* write on volume only once */ - int accept_any_volume; /* accept any volume */ - int purge_oldest_volume; /* purge oldest volume */ - int recycle_oldest_volume; /* attempt to recycle oldest volume */ - int recycle_current_volume; /* attempt recycle of current volume */ - uint32_t max_volumes; /* max number of volumes */ - utime_t VolRetention; /* volume retention period in seconds */ - utime_t VolUseDuration; /* duration volume can be used */ - uint32_t MaxVolJobs; /* Maximum jobs on the Volume */ - uint32_t MaxVolFiles; /* Maximum files on the Volume */ - uint64_t MaxVolBytes; /* Maximum bytes on the Volume */ - int AutoPrune; /* default for pool auto prune */ - int Recycle; /* default for media recycle yes/no */ + RES hdr; + + char *pool_type; /* Pool type */ + char *label_format; /* Label format string */ + char *cleaning_prefix; /* Cleaning label prefix */ + int use_catalog; /* maintain catalog for media */ + int catalog_files; /* maintain file entries in catalog */ + int use_volume_once; /* write on volume only once */ + int accept_any_volume; /* accept any volume */ + int purge_oldest_volume; /* purge oldest volume */ + int recycle_oldest_volume; /* attempt to recycle oldest volume */ + int recycle_current_volume; /* attempt recycle of current volume */ + uint32_t max_volumes; /* max number of volumes */ + utime_t VolRetention; /* volume retention period in seconds */ + utime_t VolUseDuration; /* duration volume can be used */ + uint32_t MaxVolJobs; /* Maximum jobs on the Volume */ + uint32_t MaxVolFiles; /* Maximum files on the Volume */ + uint64_t MaxVolBytes; /* Maximum bytes on the Volume */ + int AutoPrune; /* default for pool auto prune */ + int Recycle; /* default for media recycle yes/no */ }; @@ -333,37 +335,37 @@ union URES { CONRES res_con; CLIENT res_client; STORE res_store; - CAT res_cat; - JOB res_job; + CAT res_cat; + JOB res_job; FILESET res_fs; SCHED res_sch; POOL res_pool; MSGS res_msgs; COUNTER res_counter; - RES hdr; + RES hdr; }; /* Run structure contained in Schedule Resource */ struct RUN { - RUN *next; /* points to next run record */ - int level; /* level override */ - int Priority; /* priority override */ + RUN *next; /* points to next run record */ + int level; /* level override */ + int Priority; /* priority override */ int job_type; - bool spool_data; /* Data spooling override */ - bool spool_data_set; /* Data spooling override given */ - POOL *pool; /* Pool override */ - POOL *full_pool; /* Pool override */ - POOL *inc_pool; /* Pool override */ - POOL *dif_pool; /* Pool override */ - STORE *storage; /* Storage override */ - MSGS *msgs; /* Messages override */ + bool spool_data; /* Data spooling override */ + bool spool_data_set; /* Data spooling override given */ + POOL *pool; /* Pool override */ + POOL *full_pool; /* Pool override */ + POOL *inc_pool; /* Pool override */ + POOL *dif_pool; /* Pool override */ + STORE *storage; /* Storage override */ + MSGS *msgs; /* Messages override */ char *since; int level_no; - int minute; /* minute to run job */ - time_t last_run; /* last time run */ - time_t next_run; /* next time to run */ + int minute; /* minute to run job */ + time_t last_run; /* last time run */ + time_t next_run; /* next time to run */ char hour[nbytes_for_bits(24)]; /* bit set for each hour */ char mday[nbytes_for_bits(31)]; /* bit set for each day of month */ char month[nbytes_for_bits(12)]; /* bit set for each month */ diff --git a/bacula/src/lib/bsock.h b/bacula/src/lib/bsock.h index 49af7fbc53..39fc21af99 100644 --- a/bacula/src/lib/bsock.h +++ b/bacula/src/lib/bsock.h @@ -32,48 +32,48 @@ */ struct BSOCK { - uint64_t read_seqno; /* read sequence number */ - uint32_t in_msg_no; /* input message number */ - uint32_t out_msg_no; /* output message number */ - int fd; /* socket file descriptor */ - int32_t msglen; /* message length */ - int b_errno; /* bsock errno */ - int port; /* desired port */ - volatile bool errors: 1; /* set if errors on socket */ + uint64_t read_seqno; /* read sequence number */ + uint32_t in_msg_no; /* input message number */ + uint32_t out_msg_no; /* output message number */ + int fd; /* socket file descriptor */ + int32_t msglen; /* message length */ + int b_errno; /* bsock errno */ + int port; /* desired port */ + volatile bool errors: 1; /* set if errors on socket */ volatile bool suppress_error_msgs: 1; /* set to suppress error messages */ - volatile bool timed_out: 1; /* timed out in read/write */ + volatile bool timed_out: 1; /* timed out in read/write */ volatile bool terminated: 1; /* set when BNET_TERMINATE arrives */ - bool duped: 1; /* set if duped BSOCK */ - bool spool: 1; /* set for spooling */ + bool duped: 1; /* set if duped BSOCK */ + bool spool: 1; /* set for spooling */ volatile time_t timer_start; /* time started read/write */ - volatile time_t timeout; /* timeout BSOCK after this interval */ - POOLMEM *msg; /* message pool buffer */ - char *who; /* Name of daemon to which we are talking */ - char *host; /* Host name/IP */ - POOLMEM *errmsg; /* edited error message (to be implemented) */ - RES *res; /* Resource to which we are connected */ - BSOCK *next; /* next BSOCK if duped */ - FILE *spool_fd; /* spooling file */ - JCR *jcr; /* jcr or NULL for error msgs */ + volatile time_t timeout; /* timeout BSOCK after this interval */ + POOLMEM *msg; /* message pool buffer */ + char *who; /* Name of daemon to which we are talking */ + char *host; /* Host name/IP */ + POOLMEM *errmsg; /* edited error message (to be implemented) */ + RES *res; /* Resource to which we are connected */ + BSOCK *next; /* next BSOCK if duped */ + FILE *spool_fd; /* spooling file */ + JCR *jcr; /* jcr or NULL for error msgs */ struct sockaddr_in client_addr; /* client's IP address */ -}; +}; /* Signal definitions for use in bnet_sig() */ enum { - BNET_EOD = -1, /* End of data stream, new data may follow */ - BNET_EOD_POLL = -2, /* End of data and poll all in one */ - BNET_STATUS = -3, /* Send full status */ - BNET_TERMINATE = -4, /* Conversation terminated, doing close() */ + BNET_EOD = -1, /* End of data stream, new data may follow */ + BNET_EOD_POLL = -2, /* End of data and poll all in one */ + BNET_STATUS = -3, /* Send full status */ + BNET_TERMINATE = -4, /* Conversation terminated, doing close() */ BNET_POLL = -5, /* Poll request, I'm hanging on a read */ - BNET_HEARTBEAT = -6, /* Heartbeat Response requested */ - BNET_HB_RESPONSE = -7, /* Only response permited to HB */ - BNET_PROMPT = -8, /* Prompt for UA */ - BNET_BTIME = -9, /* Send UTC btime */ - BNET_BREAK = -10 /* Stop current command -- ctl-c */ + BNET_HEARTBEAT = -6, /* Heartbeat Response requested */ + BNET_HB_RESPONSE = -7, /* Only response permited to HB */ + BNET_PROMPT = -8, /* Prompt for UA */ + BNET_BTIME = -9, /* Send UTC btime */ + BNET_BREAK = -10 /* Stop current command -- ctl-c */ }; -#define BNET_SETBUF_READ 1 /* Arg for bnet_set_buffer_size */ -#define BNET_SETBUF_WRITE 2 /* Arg for bnet_set_buffer_size */ +#define BNET_SETBUF_READ 1 /* Arg for bnet_set_buffer_size */ +#define BNET_SETBUF_WRITE 2 /* Arg for bnet_set_buffer_size */ /* Return status from bnet_recv() */ #define BNET_SIGNAL -1 @@ -81,25 +81,25 @@ enum { #define BNET_ERROR -3 /* SSL enabling values */ -#define BNET_SSL_NONE 0 /* cannot do SSL */ -#define BNET_SSL_OK 1 /* can do, but not required on my end */ -#define BNET_SSL_REQUIRED 2 /* SSL is required */ +#define BNET_SSL_NONE 0 /* cannot do SSL */ +#define BNET_SSL_OK 1 /* can do, but not required on my end */ +#define BNET_SSL_REQUIRED 2 /* SSL is required */ /* * This is the structure of the in memory BPKT */ typedef struct s_bpkt { - char *id; /* String identifier or name of field */ - uint8_t type; /* field type */ - uint32_t len; /* field length for string, name, bytes */ - void *value; /* pointer to value */ + char *id; /* String identifier or name of field */ + uint8_t type; /* field type */ + uint32_t len; /* field length for string, name, bytes */ + void *value; /* pointer to value */ } BPKT; /* * These are the data types that can be sent. * For all values other than string, the storage space * is assumed to be allocated in the receiving packet. - * For BP_STRING if the *value is non-zero, it is a + * For BP_STRING if the *value is non-zero, it is a * pointer to a POOLMEM buffer, and the Memory Pool * routines will be used to assure that the length is * adequate. NOTE!!! This pointer will be changed @@ -107,13 +107,13 @@ typedef struct s_bpkt { * does). If the pointer is NULL, a POOLMEM * buffer will be allocated. */ -#define BP_EOF 0 /* end of file */ -#define BP_CHAR 1 /* Character */ -#define BP_INT32 1 /* 32 bit integer */ -#define BP_UINT32 3 /* Unsigned 32 bit integer */ -#define BP_INT64 4 /* 64 bit integer */ -#define BP_STRING 5 /* string */ -#define BP_NAME 6 /* Name string -- limited length */ -#define BP_BYTES 7 /* Binary bytes */ -#define BP_FLOAT32 8 /* 32 bit floating point */ -#define BP_FLOAT64 9 /* 64 bit floating point */ +#define BP_EOF 0 /* end of file */ +#define BP_CHAR 1 /* Character */ +#define BP_INT32 1 /* 32 bit integer */ +#define BP_UINT32 3 /* Unsigned 32 bit integer */ +#define BP_INT64 4 /* 64 bit integer */ +#define BP_STRING 5 /* string */ +#define BP_NAME 6 /* Name string -- limited length */ +#define BP_BYTES 7 /* Binary bytes */ +#define BP_FLOAT32 8 /* 32 bit floating point */ +#define BP_FLOAT64 9 /* 64 bit floating point */ diff --git a/bacula/src/lib/message.c b/bacula/src/lib/message.c index 77de72c4e9..c8f9aac557 100755 --- a/bacula/src/lib/message.c +++ b/bacula/src/lib/message.c @@ -339,39 +339,6 @@ void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where) } } -static void make_unique_spool_filename(JCR *jcr, POOLMEM **name, int fd) -{ - Mmsg(name, "%s/%s.spool.%s.%d", working_directory, my_name, - jcr->Job, fd); -} - -int open_spool_file(JCR *jcr, BSOCK *bs) -{ - POOLMEM *name = get_pool_memory(PM_MESSAGE); - - make_unique_spool_filename(jcr, &name, bs->fd); - bs->spool_fd = fopen(mp_chr(name), "w+"); - if (!bs->spool_fd) { - Jmsg(jcr, M_ERROR, 0, "fopen spool file %s failed: ERR=%s\n", name, strerror(errno)); - free_pool_memory(name); - return 0; - } - free_pool_memory(name); - return 1; -} - -int close_spool_file(JCR *jcr, BSOCK *bs) -{ - POOLMEM *name = get_pool_memory(PM_MESSAGE); - - make_unique_spool_filename(jcr, &name, bs->fd); - fclose(bs->spool_fd); - unlink(mp_chr(name)); - free_pool_memory(name); - bs->spool_fd = NULL; - bs->spool = 0; - return 1; -} /* * Create a unique filename for the mail command diff --git a/bacula/src/lib/protos.h b/bacula/src/lib/protos.h index 6269700a6f..fa2d82b6a4 100644 --- a/bacula/src/lib/protos.h +++ b/bacula/src/lib/protos.h @@ -26,99 +26,99 @@ struct JCR; /* attr.c */ -ATTR *new_attr(); -void free_attr(ATTR *attr); -int unpack_attributes_record(JCR *jcr, int32_t stream, char *rec, ATTR *attr); -void build_attr_output_fnames(JCR *jcr, ATTR *attr); -void print_ls_output(JCR *jcr, ATTR *attr); +ATTR *new_attr(); +void free_attr(ATTR *attr); +int unpack_attributes_record(JCR *jcr, int32_t stream, char *rec, ATTR *attr); +void build_attr_output_fnames(JCR *jcr, ATTR *attr); +void print_ls_output(JCR *jcr, ATTR *attr); /* base64.c */ -void base64_init (void); -int to_base64 (intmax_t value, char *where); -int from_base64 (intmax_t *value, char *where); -int bin_to_base64 (char *buf, char *bin, int len); +void base64_init (void); +int to_base64 (intmax_t value, char *where); +int from_base64 (intmax_t *value, char *where); +int bin_to_base64 (char *buf, char *bin, int len); /* bsys.c */ -char *bstrncpy (char *dest, const char *src, int maxlen); -char *bstrncat (char *dest, const char *src, int maxlen); -void *b_malloc (const char *file, int line, size_t size); +char *bstrncpy (char *dest, const char *src, int maxlen); +char *bstrncat (char *dest, const char *src, int maxlen); +void *b_malloc (const char *file, int line, size_t size); #ifndef DEBUG -void *bmalloc (size_t size); +void *bmalloc (size_t size); #endif -void *brealloc (void *buf, size_t size); -void *bcalloc (size_t size1, size_t size2); -int bsnprintf (char *str, int32_t size, const char *format, ...); -int bvsnprintf (char *str, int32_t size, const char *format, va_list ap); -int pool_sprintf (char *pool_buf, const char *fmt, ...); -void create_pid_file (char *dir, const char *progname, int port); -int delete_pid_file (char *dir, const char *progname, int port); -void drop (char *uid, char *gid); -int bmicrosleep (time_t sec, long usec); -char *bfgets (char *s, int size, FILE *fd); -void make_unique_filename (POOLMEM **name, int Id, char *what); +void *brealloc (void *buf, size_t size); +void *bcalloc (size_t size1, size_t size2); +int bsnprintf (char *str, int32_t size, const char *format, ...); +int bvsnprintf (char *str, int32_t size, const char *format, va_list ap); +int pool_sprintf (char *pool_buf, const char *fmt, ...); +void create_pid_file (char *dir, const char *progname, int port); +int delete_pid_file (char *dir, const char *progname, int port); +void drop (char *uid, char *gid); +int bmicrosleep (time_t sec, long usec); +char *bfgets (char *s, int size, FILE *fd); +void make_unique_filename (POOLMEM **name, int Id, char *what); #ifndef HAVE_STRTOLL -long long int strtoll (const char *ptr, char **endptr, int base); +long long int strtoll (const char *ptr, char **endptr, int base); #endif void read_state_file(char *dir, const char *progname, int port); /* bnet.c */ -int32_t bnet_recv (BSOCK *bsock); -int bnet_send (BSOCK *bsock); -int bnet_fsend (BSOCK *bs, const char *fmt, ...); -int bnet_set_buffer_size (BSOCK *bs, uint32_t size, int rw); -int bnet_sig (BSOCK *bs, int sig); -int bnet_ssl_server (BSOCK *bsock, char *password, int ssl_need, int ssl_has); -int bnet_ssl_client (BSOCK *bsock, char *password, int ssl_need); -BSOCK * bnet_connect (JCR *jcr, int retry_interval, - int max_retry_time, const char *name, char *host, char *service, - int port, int verbose); -void bnet_close (BSOCK *bsock); -BSOCK * init_bsock (JCR *jcr, int sockfd, const char *who, char *ip, - int port, struct sockaddr_in *client_addr); -BSOCK * dup_bsock (BSOCK *bsock); -void term_bsock (BSOCK *bsock); -char * bnet_strerror (BSOCK *bsock); -char * bnet_sig_to_ascii (BSOCK *bsock); -int bnet_wait_data (BSOCK *bsock, int sec); -int bnet_wait_data_intr (BSOCK *bsock, int sec); -int bnet_despool_to_bsock (BSOCK *bsock); -int is_bnet_stop (BSOCK *bsock); -int is_bnet_error (BSOCK *bsock); -void bnet_suppress_error_messages(BSOCK *bsock, int flag); +int32_t bnet_recv (BSOCK *bsock); +int bnet_send (BSOCK *bsock); +int bnet_fsend (BSOCK *bs, const char *fmt, ...); +int bnet_set_buffer_size (BSOCK *bs, uint32_t size, int rw); +int bnet_sig (BSOCK *bs, int sig); +int bnet_ssl_server (BSOCK *bsock, char *password, int ssl_need, int ssl_has); +int bnet_ssl_client (BSOCK *bsock, char *password, int ssl_need); +BSOCK * bnet_connect (JCR *jcr, int retry_interval, + int max_retry_time, const char *name, char *host, char *service, + int port, int verbose); +void bnet_close (BSOCK *bsock); +BSOCK * init_bsock (JCR *jcr, int sockfd, const char *who, char *ip, + int port, struct sockaddr_in *client_addr); +BSOCK * dup_bsock (BSOCK *bsock); +void term_bsock (BSOCK *bsock); +char * bnet_strerror (BSOCK *bsock); +char * bnet_sig_to_ascii (BSOCK *bsock); +int bnet_wait_data (BSOCK *bsock, int sec); +int bnet_wait_data_intr (BSOCK *bsock, int sec); +int bnet_despool_to_bsock (BSOCK *bsock); +int is_bnet_stop (BSOCK *bsock); +int is_bnet_error (BSOCK *bsock); +void bnet_suppress_error_messages(BSOCK *bsock, int flag); /* bget_msg.c */ -int bget_msg(BSOCK *sock); +int bget_msg(BSOCK *sock); /* bpipe.c */ -BPIPE * open_bpipe(char *prog, int wait, const char *mode); -int close_wpipe(BPIPE *bpipe); -int close_bpipe(BPIPE *bpipe); +BPIPE * open_bpipe(char *prog, int wait, const 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 hmac_md5(uint8_t* text, int text_len, uint8_t* key, - int key_len, uint8_t *hmac); + int key_len, uint8_t *hmac); /* crc32.c */ uint32_t bcrc32(uint8_t *buf, int len); /* daemon.c */ -void daemon_start (); +void daemon_start (); /* edit.c */ -uint64_t str_to_uint64(char *str); -int64_t str_to_int64(char *str); -char * edit_uint64_with_commas (uint64_t val, char *buf); -char * add_commas (char *val, char *buf); -char * edit_uint64 (uint64_t val, char *buf); -int duration_to_utime (char *str, utime_t *value); -int size_to_uint64(char *str, int str_len, uint64_t *rtn_value); -char *edit_utime (utime_t val, char *buf); -int is_a_number (const char *num); -int is_an_integer (const char *n); -bool is_name_valid (char *name, POOLMEM **msg); +uint64_t str_to_uint64(char *str); +int64_t str_to_int64(char *str); +char * edit_uint64_with_commas (uint64_t val, char *buf); +char * add_commas (char *val, char *buf); +char * edit_uint64 (uint64_t val, char *buf); +int duration_to_utime (char *str, utime_t *value); +int size_to_uint64(char *str, int str_len, uint64_t *rtn_value); +char *edit_utime (utime_t val, char *buf); +int is_a_number (const char *num); +int is_an_integer (const char *n); +bool is_name_valid (char *name, POOLMEM **msg); /* jcr.c (most definitions are in src/jcr.h) */ void init_last_jobs_list(); @@ -132,38 +132,36 @@ void job_end_push(JCR *jcr, void job_end_cb(JCR *jcr)); /* lex.c */ -LEX * lex_close_file (LEX *lf); -LEX * lex_open_file (LEX *lf, char *fname, LEX_ERROR_HANDLER *scan_error); -int lex_get_char (LEX *lf); -void lex_unget_char (LEX *lf); -const char * lex_tok_to_str (int token); -int lex_get_token (LEX *lf, int expect); +LEX * lex_close_file (LEX *lf); +LEX * lex_open_file (LEX *lf, char *fname, LEX_ERROR_HANDLER *scan_error); +int lex_get_char (LEX *lf); +void lex_unget_char (LEX *lf); +const char * lex_tok_to_str (int token); +int lex_get_token (LEX *lf, int expect); /* message.c */ -void my_name_is (int argc, char *argv[], const char *name); -void init_msg (JCR *jcr, MSGS *msg); -void term_msg (void); -void close_msg (JCR *jcr); -void add_msg_dest (MSGS *msg, int dest, int type, char *where, char *dest_code); -void rem_msg_dest (MSGS *msg, int dest, int type, char *where); -void Jmsg (JCR *jcr, int type, int level, const char *fmt, ...); -void dispatch_message (JCR *jcr, int type, int level, char *buf); -void init_console_msg (char *wd); -void free_msgs_res (MSGS *msgs); -int open_spool_file (JCR *jcr, BSOCK *bs); -int close_spool_file (JCR *jcr, BSOCK *bs); -void dequeue_messages (JCR *jcr); -void set_trace (int trace_flag); +void my_name_is (int argc, char *argv[], const char *name); +void init_msg (JCR *jcr, MSGS *msg); +void term_msg (void); +void close_msg (JCR *jcr); +void add_msg_dest (MSGS *msg, int dest, int type, char *where, char *dest_code); +void rem_msg_dest (MSGS *msg, int dest, int type, char *where); +void Jmsg (JCR *jcr, int type, int level, const char *fmt, ...); +void dispatch_message (JCR *jcr, int type, int level, char *buf); +void init_console_msg (char *wd); +void free_msgs_res (MSGS *msgs); +void dequeue_messages (JCR *jcr); +void set_trace (int trace_flag); /* bnet_server.c */ -void bnet_thread_server(char *bind_addr, int port, int max_clients, workq_t *client_wq, - void *handle_client_request(void *bsock)); -void bnet_stop_thread_server(pthread_t tid); -void bnet_server (int port, void handle_client_request(BSOCK *bsock)); -int net_connect (int port); -BSOCK * bnet_bind (int port); -BSOCK * bnet_accept (BSOCK *bsock, char *who); +void bnet_thread_server(char *bind_addr, int port, int max_clients, workq_t *client_wq, + void *handle_client_request(void *bsock)); +void bnet_stop_thread_server(pthread_t tid); +void bnet_server (int port, void handle_client_request(BSOCK *bsock)); +int net_connect (int port); +BSOCK * bnet_bind (int port); +BSOCK * bnet_accept (BSOCK *bsock, char *who); /* idcache.c */ char *getuser(uid_t uid); @@ -173,37 +171,37 @@ void free_getgroup_cache(); /* signal.c */ -void init_signals (void terminate(int sig)); -void init_stack_dump (void); +void init_signals (void terminate(int sig)); +void init_stack_dump (void); /* scan.c */ -void strip_trailing_junk (char *str); -void strip_trailing_slashes (char *dir); -bool skip_spaces (char **msg); -bool 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); +void strip_trailing_junk (char *str); +void strip_trailing_slashes (char *dir); +bool skip_spaces (char **msg); +bool 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); -void jobstatus_to_ascii (int JobStatus, char *msg, int maxlen); -int pm_strcat (POOLMEM **pm, const char *str); -int pm_strcpy (POOLMEM **pm, const char *str); -int run_program (char *prog, int wait, POOLMEM *results); -char * job_type_to_str (int type); -char * job_status_to_str (int stat); -char * job_level_to_str (int level); -void make_session_key (char *key, char *seed, int mode); -POOLMEM *edit_job_codes(JCR *jcr, char *omsg, char *imsg, const char *to); -void set_working_directory(char *wd); +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); +void jobstatus_to_ascii (int JobStatus, char *msg, int maxlen); +int pm_strcat (POOLMEM **pm, const char *str); +int pm_strcpy (POOLMEM **pm, const char *str); +int run_program (char *prog, int wait, POOLMEM *results); +char * job_type_to_str (int type); +char * job_status_to_str (int stat); +char * job_level_to_str (int level); +void make_session_key (char *key, char *seed, int mode); +POOLMEM *edit_job_codes(JCR *jcr, char *omsg, char *imsg, const char *to); +void set_working_directory(char *wd); /* watchdog.c */ diff --git a/bacula/src/stored/acquire.c b/bacula/src/stored/acquire.c index c3a57d5503..8cafa06f25 100644 --- a/bacula/src/stored/acquire.c +++ b/bacula/src/stored/acquire.c @@ -42,6 +42,7 @@ DCR *new_dcr(JCR *jcr, DEVICE *dev) dcr->block = new_block(dev); dcr->record = new_record(); dcr->spool_fd = -1; + dcr->max_spool_size = dev->device->max_spool_size; return dcr; } @@ -129,7 +130,7 @@ DCR *acquire_device_for_read(JCR *jcr) */ for ( ; !(dev->state & ST_OPENED); ) { Dmsg1(120, "bstored: open vol=%s\n", jcr->VolumeName); - if (open_dev(dev, dcr->VolumeName, READ_ONLY) < 0) { + if (open_dev(dev, dcr->VolumeName, OPEN_READ_ONLY) < 0) { Jmsg(jcr, M_FATAL, 0, _("Open device %s volume %s failed, ERR=%s\n"), dev_name(dev), dcr->VolumeName, strerror_dev(dev)); goto get_out; diff --git a/bacula/src/stored/append.c b/bacula/src/stored/append.c index b22d6cad9f..9375fd8f7c 100644 --- a/bacula/src/stored/append.c +++ b/bacula/src/stored/append.c @@ -205,17 +205,17 @@ int do_append_data(JCR *jcr) stream == STREAM_UNIX_ATTRIBUTES_EX || stream == STREAM_SHA1_SIGNATURE) { if (!jcr->no_attributes) { if (are_attributes_spooled(jcr)) { - jcr->dir_bsock->spool = 1; + jcr->dir_bsock->spool = true; } Dmsg0(200, "Send attributes.\n"); if (!dir_update_file_attributes(jcr, &rec)) { + jcr->dir_bsock->spool = false; Jmsg(jcr, M_FATAL, 0, _("Error updating file attributes. ERR=%s\n"), bnet_strerror(jcr->dir_bsock)); ok = false; - jcr->dir_bsock->spool = 0; break; } - jcr->dir_bsock->spool = 0; + jcr->dir_bsock->spool = false; } } } diff --git a/bacula/src/stored/bcopy.c b/bacula/src/stored/bcopy.c index 7d334c2ea8..98732aa2c3 100644 --- a/bacula/src/stored/bcopy.c +++ b/bacula/src/stored/bcopy.c @@ -154,7 +154,7 @@ int main (int argc, char *argv[]) } /* For we must now acquire the device for writing */ lock_device(out_dev); - if (open_dev(out_dev, out_jcr->VolumeName, READ_WRITE) < 0) { + if (open_dev(out_dev, out_jcr->VolumeName, OPEN_READ_WRITE) < 0) { Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg); unlock_device(out_dev); exit(1); diff --git a/bacula/src/stored/block.c b/bacula/src/stored/block.c index f04cbd93e7..afb880c585 100644 --- a/bacula/src/stored/block.c +++ b/bacula/src/stored/block.c @@ -322,7 +322,9 @@ int write_block_to_device(DCR *dcr, DEV_BLOCK *block) return stat; } - lock_device(dev); + if (!dcr->dev_locked) { + lock_device(dev); + } /* * If a new volume has been mounted since our last write @@ -336,8 +338,8 @@ int write_block_to_device(DCR *dcr, DEV_BLOCK *block) Jmsg(jcr, M_ERROR, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"), jcr->VolCatInfo.VolCatName, jcr->Job); set_new_volume_parameters(jcr, dev); - unlock_device(dev); - return 0; + stat = 0; + goto bail_out; } if (dcr->NewVol) { /* Note, setting a new volume also handles any pending new file */ @@ -352,7 +354,10 @@ int write_block_to_device(DCR *dcr, DEV_BLOCK *block) stat = fixup_device_block_write_error(jcr, dev, block); } - unlock_device(dev); +bail_out: + if (!dcr->dev_locked) { + unlock_device(dev); + } return stat; } diff --git a/bacula/src/stored/btape.c b/bacula/src/stored/btape.c index ac7f24f2be..408d6dd41a 100644 --- a/bacula/src/stored/btape.c +++ b/bacula/src/stored/btape.c @@ -295,7 +295,7 @@ static bool open_the_device() lock_device(dev); if (!(dev->state & ST_OPENED)) { Dmsg1(200, "Opening device %s\n", jcr->VolumeName); - if (open_dev(dev, jcr->VolumeName, READ_WRITE) < 0) { + if (open_dev(dev, jcr->VolumeName, OPEN_READ_WRITE) < 0) { Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), dev->errmsg); unlock_device(dev); free_block(block); diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index 8a8965116b..2a208dd709 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -2,7 +2,7 @@ * * dev.c -- low level operations on device (storage device) * - * Kern Sibbald + * Kern Sibbald, MM * * NOTE!!!! None of these routines are reentrant. You must * use lock_device() and unlock_device() at a higher level, @@ -57,15 +57,13 @@ * to include ST_EOT, which is ephimeral, and ST_WEOT, which is * persistent. Lots of routines clear ST_EOT, but ST_WEOT is * cleared only when the problem goes away. Now when ST_WEOT - * is set all calls to write_dev() are handled as usual. However, - * in write_block() instead of attempting to write the block to - * the physical device, it is chained into a list of blocks written - * after the EOT condition. In addition, all threads are blocked - * from writing on the tape by calling lock(), and thread other + * is set all calls to write_block_to_device() call the fix_up + * routine. In addition, all threads are blocked + * from writing on the tape by calling lock_dev(), and thread other * than the first thread to hit the EOT will block on a condition * variable. The first thread to hit the EOT will continue to * be able to read and write the tape (he sort of tunnels through - * the locking mechanism -- see lock() for details). + * the locking mechanism -- see lock_dev() for details). * * Now presumably somewhere higher in the chain of command * (device.c), someone will notice the EOT condition and @@ -149,6 +147,7 @@ init_dev(DEVICE *dev, DEVRES *device) dev->max_open_wait = device->max_open_wait; dev->max_open_vols = device->max_open_vols; dev->vol_poll_interval = device->vol_poll_interval; + dev->max_spool_size = device->max_spool_size; /* Sanity check */ if (dev->vol_poll_interval && dev->vol_poll_interval < 60) { dev->vol_poll_interval = 60; @@ -192,6 +191,11 @@ init_dev(DEVICE *dev, DEVRES *device) Mmsg1(&dev->errmsg, _("Unable to init cond variable: ERR=%s\n"), strerror(errstat)); Emsg0(M_FATAL, 0, dev->errmsg); } + if ((errstat = pthread_mutex_init(&dev->spool_mutex, NULL)) != 0) { + dev->dev_errno = errstat; + Mmsg1(&dev->errmsg, _("Unable to init mutex: ERR=%s\n"), strerror(errstat)); + Emsg0(M_FATAL, 0, dev->errmsg); + } dev->fd = -1; dev->attached_dcrs = new dlist(dcr, &dcr->dev_link); Dmsg2(29, "init_dev: tape=%d dev_name=%s\n", dev_is_tape(dev), dev->dev_name); @@ -1391,6 +1395,7 @@ term_dev(DEVICE *dev) pthread_mutex_destroy(&dev->mutex); pthread_cond_destroy(&dev->wait); pthread_cond_destroy(&dev->wait_next_vol); + pthread_mutex_destroy(&dev->spool_mutex); if (dev->attached_dcrs) { delete dev->attached_dcrs; dev->attached_dcrs = NULL; diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index a48d93d538..f43a5bc1bb 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -43,11 +43,11 @@ #define give_back_device_lock(d, p) _give_back_device_lock(__FILE__, __LINE__, (d), (p)) /* Arguments to open_dev() */ -#define READ_WRITE 0 -#define READ_ONLY 1 -#define OPEN_READ_WRITE 0 -#define OPEN_READ_ONLY 1 -#define OPEN_WRITE_ONLY 2 +enum { + OPEN_READ_WRITE = 0, + OPEN_READ_ONLY, + OPEN_WRITE_ONLY +}; /* Generic status bits returned from status_dev() */ #define BMT_TAPE (1<<0) /* is tape device */ @@ -106,13 +106,15 @@ #define ST_SHORT (1<<13) /* Short block read */ /* dev_blocked states (mutually exclusive) */ -#define BST_NOT_BLOCKED 0 /* not blocked */ -#define BST_UNMOUNTED 1 /* User unmounted device */ -#define BST_WAITING_FOR_SYSOP 2 /* Waiting for operator to mount tape */ -#define BST_DOING_ACQUIRE 3 /* Opening/validating/moving tape */ -#define BST_WRITING_LABEL 4 /* Labeling a tape */ -#define BST_UNMOUNTED_WAITING_FOR_SYSOP 5 /* Closed by user during mount request */ -#define BST_MOUNT 6 /* Mount request */ +enum { + BST_NOT_BLOCKED = 0, /* not blocked */ + BST_UNMOUNTED, /* User unmounted device */ + BST_WAITING_FOR_SYSOP, /* Waiting for operator to mount tape */ + BST_DOING_ACQUIRE, /* Opening/validating/moving tape */ + BST_WRITING_LABEL, /* Labeling a tape */ + BST_UNMOUNTED_WAITING_FOR_SYSOP, /* Closed by user during mount request */ + BST_MOUNT /* Mount request */ +}; /* Volume Catalog Information structure definition */ struct VOLUME_CAT_INFO { @@ -141,9 +143,9 @@ struct VOLUME_CAT_INFO { typedef struct s_steal_lock { - pthread_t no_wait_id; /* id of no wait thread */ - int dev_blocked; /* state */ - int dev_prev_blocked; /* previous blocked state */ + pthread_t no_wait_id; /* id of no wait thread */ + int dev_blocked; /* state */ + int dev_prev_blocked; /* previous blocked state */ } bsteal_lock_t; struct DEVRES; /* Device resource defined in stored_conf.h */ @@ -160,6 +162,7 @@ public: JCR *attached_jcrs; /* attached JCR list */ dlist *attached_dcrs; /* attached DCR list */ pthread_mutex_t mutex; /* access control */ + pthread_mutex_t spool_mutex; /* mutex for updating spool_size */ pthread_cond_t wait; /* thread wait variable */ pthread_cond_t wait_next_vol; /* wait for tape to be mounted */ pthread_t no_wait_id; /* this thread must not wait */ @@ -186,6 +189,8 @@ public: uint64_t max_volume_size; /* max bytes to put on one volume */ uint64_t max_file_size; /* max file size to put in one file on volume */ uint64_t volume_capacity; /* advisory capacity */ + uint64_t max_spool_size; /* maximum spool file size */ + uint64_t spool_size; /* curren spool size */ uint32_t max_rewind_wait; /* max secs to allow for rewind */ uint32_t max_open_wait; /* max secs to allow for open */ uint32_t max_open_vols; /* max simultaneous open volumes */ @@ -221,6 +226,7 @@ struct DCR { DEV_RECORD *record; /* pointer to record */ bool spool_data; /* set to spool data */ bool spooling; /* set when actually spooling */ + bool dev_locked; /* set if dev already locked */ int spool_fd; /* fd if spooling */ bool NewVol; /* set if new Volume mounted */ bool WroteVol; /* set if Volume written */ @@ -232,6 +238,8 @@ struct DCR { uint32_t StartFile; /* Start write file */ uint32_t StartBlock; /* Start write block */ uint32_t EndBlock; /* Ending block written */ + uint64_t spool_size; /* Current spool size */ + uint64_t max_spool_size; /* Max job spool size */ char VolumeName[MAX_NAME_LENGTH]; /* Volume name */ VOLUME_CAT_INFO VolCatInfo; /* Catalog info for desired volume */ }; diff --git a/bacula/src/stored/dircmd.c b/bacula/src/stored/dircmd.c index bd309d5694..1ec7d09b19 100644 --- a/bacula/src/stored/dircmd.c +++ b/bacula/src/stored/dircmd.c @@ -362,7 +362,7 @@ static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname, /* Ensure that the device is open -- autoload_device() closes it */ for ( ; !(dev->state & ST_OPENED); ) { - if (open_dev(dev, jcr->VolumeName, READ_WRITE) < 0) { + if (open_dev(dev, jcr->VolumeName, OPEN_READ_WRITE) < 0) { bnet_fsend(dir, _("3910 Unable to open device %s. ERR=%s\n"), dev_name(dev), strerror_dev(dev)); goto bail_out; @@ -498,7 +498,7 @@ static int mount_cmd(JCR *jcr) case BST_UNMOUNTED_WAITING_FOR_SYSOP: case BST_UNMOUNTED: /* We freed the device, so reopen it and wake any waiting threads */ - if (open_dev(dev, NULL, READ_WRITE) < 0) { + if (open_dev(dev, NULL, OPEN_READ_WRITE) < 0) { bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"), strerror_dev(dev)); break; @@ -550,7 +550,7 @@ static int mount_cmd(JCR *jcr) bnet_fsend(dir, _("3906 cannot mount non-tape.\n")); break; } - if (open_dev(dev, NULL, READ_WRITE) < 0) { + if (open_dev(dev, NULL, OPEN_READ_WRITE) < 0) { bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"), strerror_dev(dev)); break; @@ -838,7 +838,7 @@ static void read_volume_label(JCR *jcr, DEVICE *dev, int Slot) /* Ensure that the device is open -- autoload_device() closes it */ for ( ; !dev_state(dev, ST_OPENED); ) { - if (open_dev(dev, jcr->VolumeName, READ_WRITE) < 0) { + if (open_dev(dev, jcr->VolumeName, OPEN_READ_WRITE) < 0) { bnet_fsend(dir, _("3910 Unable to open device \"%s\". ERR=%s\n"), dev_name(dev), strerror_dev(dev)); goto bail_out; diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h index 8c25d83545..4fd66f71f5 100644 --- a/bacula/src/stored/protos.h +++ b/bacula/src/stored/protos.h @@ -200,11 +200,13 @@ int read_records(JCR *jcr, DEVICE *dev, int mount_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)); /* From spool.c */ -int begin_data_spool(JCR *jcr); -int discard_data_spool(JCR *jcr); -int commit_data_spool(JCR *jcr); -bool are_attributes_spooled(JCR *jcr); -int begin_attribute_spool(JCR *jcr); -int discard_attribute_spool(JCR *jcr); -int commit_attribute_spool(JCR *jcr); -bool write_block_to_spool_file(DCR *dcr, DEV_BLOCK *block); +bool begin_data_spool (JCR *jcr); +bool discard_data_spool (JCR *jcr); +bool commit_data_spool (JCR *jcr); +bool are_attributes_spooled (JCR *jcr); +bool begin_attribute_spool (JCR *jcr); +bool discard_attribute_spool (JCR *jcr); +bool commit_attribute_spool (JCR *jcr); +bool write_block_to_spool_file (DCR *dcr, DEV_BLOCK *block); +bool open_spool_file (JCR *jcr, BSOCK *bs); +bool close_spool_file (JCR *jcr, BSOCK *bs); diff --git a/bacula/src/stored/spool.c b/bacula/src/stored/spool.c index 3f1aefe67f..b9f6942a37 100644 --- a/bacula/src/stored/spool.c +++ b/bacula/src/stored/spool.c @@ -47,9 +47,9 @@ enum { RB_OK }; -int begin_data_spool(JCR *jcr) +bool begin_data_spool(JCR *jcr) { - int stat = 1; + bool stat = true; if (jcr->spool_data) { Dmsg0(100, "Turning on data spooling\n"); jcr->dcr->spool_data = true; @@ -61,16 +61,16 @@ int begin_data_spool(JCR *jcr) return stat; } -int discard_data_spool(JCR *jcr) +bool discard_data_spool(JCR *jcr) { if (jcr->dcr->spooling) { Dmsg0(100, "Data spooling discarded\n"); return close_data_spool_file(jcr); } - return 1; + return true; } -int commit_data_spool(JCR *jcr) +bool commit_data_spool(JCR *jcr) { bool stat; if (jcr->dcr->spooling) { @@ -79,17 +79,22 @@ int commit_data_spool(JCR *jcr) if (!stat) { Dmsg1(000, "Bad return from despool WroteVol=%d\n", jcr->dcr->WroteVol); close_data_spool_file(jcr); - return 0; + return false; } return close_data_spool_file(jcr); } - return 1; + return true; } static void make_unique_data_spool_filename(JCR *jcr, POOLMEM **name) { - Mmsg(name, "%s/%s.data.spool.%s.%s", working_directory, my_name, - jcr->Job, jcr->device->hdr.name); + char *dir; + if (jcr->dcr->dev->device->spool_directory) { + dir = jcr->dcr->dev->device->spool_directory; + } else { + dir = working_directory; + } + Mmsg(name, "%s/%s.data.spool.%s.%s", dir, my_name, jcr->Job, jcr->device->hdr.name); } @@ -130,13 +135,14 @@ static bool despool_data(DCR *dcr) { DEVICE *rdev; DCR *rdcr; - dcr->spooling = false; bool ok = true; DEV_BLOCK *block; JCR *jcr = dcr->jcr; int stat; -// lock_device(dcr->dev); + dcr->spooling = false; + lock_device(dcr->dev); + dcr->dev_locked = true; Dmsg0(100, "Despooling data\n"); /* Set up a dev structure to read */ rdev = (DEVICE *)malloc(sizeof(DEVICE)); @@ -145,6 +151,7 @@ static bool despool_data(DCR *dcr) strcpy(rdev->dev_name, "spool"); rdev->errmsg = get_pool_memory(PM_EMSG); *rdev->errmsg = 0; + rdev->device = dcr->dev->device; rdcr = new_dcr(NULL, rdev); rdcr->spool_fd = dcr->spool_fd; rdcr->jcr = jcr; /* set a valid jcr */ @@ -170,12 +177,19 @@ static bool despool_data(DCR *dcr) Dmsg1(000, "Bad return from ftruncate. ERR=%s\n", strerror(errno)); ok = false; } + + P(dcr->dev->spool_mutex); + dcr->dev->spool_size -= dcr->spool_size; + dcr->spool_size = 0; /* zap size in input dcr */ + V(dcr->dev->spool_mutex); + free_memory(rdev->dev_name); free_pool_memory(rdev->errmsg); free(rdev); rdcr->jcr = NULL; free_dcr(rdcr); -// unlock_device(dcr->dev); + unlock_device(dcr->dev); + dcr->dev_locked = false; return ok; } @@ -238,12 +252,31 @@ static int read_block_from_spool_file(DCR *dcr, DEV_BLOCK *block) bool write_block_to_spool_file(DCR *dcr, DEV_BLOCK *block) { ssize_t stat = 0; - uint32_t wlen; /* length to write */ + uint32_t wlen, hlen; /* length to write */ int retry = 0; spool_hdr hdr; + bool despool = false; ASSERT(block->binbuf == ((uint32_t) (block->bufp - block->buf))); - + hlen = sizeof(hdr); + wlen = block->binbuf; + P(dcr->dev->spool_mutex); + dcr->spool_size += hlen + wlen; + dcr->dev->spool_size += hlen + wlen; + if ((dcr->max_spool_size > 0 && dcr->spool_size >= dcr->max_spool_size) || + (dcr->dev->spool_size > 0 && dcr->dev->spool_size >= dcr->dev->max_spool_size)) { + despool = true; + } + V(dcr->dev->spool_mutex); + if (despool) { + if (!despool_data(dcr)) { + return false; + } + P(dcr->dev->spool_mutex); + dcr->spool_size += hlen + wlen; + dcr->dev->spool_size += hlen + wlen; + V(dcr->dev->spool_mutex); + } if (block->binbuf <= WRITE_BLKHDR_LENGTH) { /* Does block have data in it? */ Dmsg0(100, "return write_block_to_dev no data to write\n"); return true; @@ -252,10 +285,9 @@ bool write_block_to_spool_file(DCR *dcr, DEV_BLOCK *block) hdr.FirstIndex = block->FirstIndex; hdr.LastIndex = block->LastIndex; hdr.len = block->binbuf; - wlen = sizeof(hdr); write_hdr_again: - stat = write(dcr->spool_fd, (char*)&hdr, (size_t)wlen); - if (stat != (ssize_t)wlen) { + stat = write(dcr->spool_fd, (char*)&hdr, (size_t)hlen); + if (stat != (ssize_t)hlen) { if (!despool_data(dcr)) { return false; } @@ -266,7 +298,6 @@ write_hdr_again: } - wlen = block->binbuf; Dmsg2(300, "Wrote block FI=%d LI=%d\n", block->FirstIndex, block->LastIndex); write_again: stat = write(dcr->spool_fd, block->buf, (size_t)wlen); @@ -280,38 +311,79 @@ write_again: goto write_again; } + empty_block(block); return true; } - bool are_attributes_spooled(JCR *jcr) { return jcr->spool_attributes && jcr->dir_bsock->spool_fd; } -int begin_attribute_spool(JCR *jcr) +/* + * Create spool file for attributes. + * This is done by "attaching" to the bsock, and when + * it is called, the output is written to a file. + * The actual spooling is turned on and off in + * append.c only during writing of the attributes. + */ +bool begin_attribute_spool(JCR *jcr) { if (!jcr->no_attributes && jcr->spool_attributes) { return open_spool_file(jcr, jcr->dir_bsock); } - return 1; + return true; } -int discard_attribute_spool(JCR *jcr) +bool discard_attribute_spool(JCR *jcr) { if (are_attributes_spooled(jcr)) { return close_spool_file(jcr, jcr->dir_bsock); } - return 1; + return true; } -int commit_attribute_spool(JCR *jcr) +bool commit_attribute_spool(JCR *jcr) { if (are_attributes_spooled(jcr)) { bnet_despool_to_bsock(jcr->dir_bsock); return close_spool_file(jcr, jcr->dir_bsock); } - return 1; + return true; +} + +static void make_unique_spool_filename(JCR *jcr, POOLMEM **name, int fd) +{ + Mmsg(name, "%s/%s.spool.%s.%d", working_directory, my_name, + jcr->Job, fd); +} + +bool open_spool_file(JCR *jcr, BSOCK *bs) +{ + POOLMEM *name = get_pool_memory(PM_MESSAGE); + + make_unique_spool_filename(jcr, &name, bs->fd); + bs->spool_fd = fopen(mp_chr(name), "w+"); + if (!bs->spool_fd) { + Jmsg(jcr, M_ERROR, 0, "fopen spool file %s failed: ERR=%s\n", name, strerror(errno)); + free_pool_memory(name); + return false; + } + free_pool_memory(name); + return true; +} + +bool close_spool_file(JCR *jcr, BSOCK *bs) +{ + POOLMEM *name = get_pool_memory(PM_MESSAGE); + + make_unique_spool_filename(jcr, &name, bs->fd); + fclose(bs->spool_fd); + unlink(mp_chr(name)); + free_pool_memory(name); + bs->spool_fd = NULL; + bs->spool = false; + return true; } diff --git a/bacula/src/stored/stored_conf.c b/bacula/src/stored/stored_conf.c index 5916143e6d..f29bd0a027 100644 --- a/bacula/src/stored/stored_conf.c +++ b/bacula/src/stored/stored_conf.c @@ -114,6 +114,9 @@ static RES_ITEM dev_items[] = { {"maximumvolumesize", store_size, ITEM(res_dev.max_volume_size), 0, 0, 0}, {"maximumfilesize", store_size, ITEM(res_dev.max_file_size), 0, ITEM_DEFAULT, 1000000000}, {"volumecapacity", store_size, ITEM(res_dev.volume_capacity), 0, 0, 0}, + {"spooldirectory", store_dir, ITEM(res_dev.spool_directory), 0, 0, 0}, + {"maximumspoolsize", store_size, ITEM(res_dev.max_spool_size), 0, 0, 0}, + {"maximumjobspoolsize", store_size, ITEM(res_dev.max_job_spool_size), 0, 0, 0}, {NULL, NULL, 0, 0, 0, 0} }; @@ -130,7 +133,7 @@ RES_TABLE resources[] = { {"storage", store_items, R_STORAGE, NULL}, {"device", dev_items, R_DEVICE, NULL}, {"messages", msgs_items, R_MSGS, NULL}, - {NULL, NULL, 0, NULL} + {NULL, NULL, 0, NULL} }; @@ -146,7 +149,7 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ... return; } sendit(sock, "dump_resource type=%d\n", type); - if (type < 0) { /* no recursion */ + if (type < 0) { /* no recursion */ type = - type; recurse = 0; } @@ -156,22 +159,25 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ... break; case R_STORAGE: sendit(sock, "Storage: name=%s SDaddr=%s SDport=%d SDDport=%d HB=%s\n", - res->res_store.hdr.name, NPRT(res->res_store.SDaddr), - res->res_store.SDport, res->res_store.SDDport, - edit_utime(res->res_store.heartbeat_interval, buf)); + res->res_store.hdr.name, NPRT(res->res_store.SDaddr), + res->res_store.SDport, res->res_store.SDDport, + edit_utime(res->res_store.heartbeat_interval, buf)); break; case R_DEVICE: sendit(sock, "Device: name=%s MediaType=%s Device=%s\n", - res->res_dev.hdr.name, - res->res_dev.media_type, res->res_dev.device_name); + res->res_dev.hdr.name, + res->res_dev.media_type, res->res_dev.device_name); sendit(sock, " rew_wait=%d min_bs=%d max_bs=%d\n", - res->res_dev.max_rewind_wait, res->res_dev.min_block_size, - res->res_dev.max_block_size); + res->res_dev.max_rewind_wait, res->res_dev.min_block_size, + res->res_dev.max_block_size); sendit(sock, " max_jobs=%d max_files=%" lld " max_size=%" lld "\n", - res->res_dev.max_volume_jobs, res->res_dev.max_volume_files, - res->res_dev.max_volume_size); + res->res_dev.max_volume_jobs, res->res_dev.max_volume_files, + res->res_dev.max_volume_size); sendit(sock, " max_file_size=%" lld " capacity=%" lld "\n", - res->res_dev.max_file_size, res->res_dev.volume_capacity); + res->res_dev.max_file_size, res->res_dev.volume_capacity); + sendit(sock, " spool_directory=%s\n", res->res_dev.spool_directory); + sendit(sock, " max_spool_size=%" lld " max_job_spool_size=%" lld "\n", + res->res_dev.max_spool_size, res->res_dev.max_job_spool_size); strcpy(buf, " "); if (res->res_dev.cap_bits & CAP_EOF) { bstrncat(buf, "CAP_EOF ", sizeof(buf)); @@ -254,57 +260,60 @@ void free_resource(RES *sres, int type) switch (type) { case R_DIRECTOR: - if (res->res_dir.password) { - free(res->res_dir.password); - } - if (res->res_dir.address) { - free(res->res_dir.address); - } - break; + if (res->res_dir.password) { + free(res->res_dir.password); + } + if (res->res_dir.address) { + free(res->res_dir.address); + } + break; case R_STORAGE: - if (res->res_store.address) { /* ***FIXME*** deprecated */ - free(res->res_store.address); - } - if (res->res_store.SDaddr) { - free(res->res_store.SDaddr); - } - if (res->res_store.working_directory) { - free(res->res_store.working_directory); - } - if (res->res_store.pid_directory) { - free(res->res_store.pid_directory); - } - if (res->res_store.subsys_directory) { - free(res->res_store.subsys_directory); - } - break; + if (res->res_store.address) { /* ***FIXME*** deprecated */ + free(res->res_store.address); + } + if (res->res_store.SDaddr) { + free(res->res_store.SDaddr); + } + if (res->res_store.working_directory) { + free(res->res_store.working_directory); + } + if (res->res_store.pid_directory) { + free(res->res_store.pid_directory); + } + if (res->res_store.subsys_directory) { + free(res->res_store.subsys_directory); + } + break; case R_DEVICE: - if (res->res_dev.media_type) { - free(res->res_dev.media_type); - } - if (res->res_dev.device_name) { - free(res->res_dev.device_name); - } - if (res->res_dev.changer_name) { - free(res->res_dev.changer_name); - } - if (res->res_dev.changer_command) { - free(res->res_dev.changer_command); - } - break; + if (res->res_dev.media_type) { + free(res->res_dev.media_type); + } + if (res->res_dev.device_name) { + free(res->res_dev.device_name); + } + if (res->res_dev.changer_name) { + free(res->res_dev.changer_name); + } + if (res->res_dev.changer_command) { + free(res->res_dev.changer_command); + } + if (res->res_dev.spool_directory) { + free(res->res_dev.spool_directory); + } + break; case R_MSGS: - if (res->res_msgs.mail_cmd) { - free(res->res_msgs.mail_cmd); - } - if (res->res_msgs.operator_cmd) { - free(res->res_msgs.operator_cmd); - } - free_msgs_res((MSGS *)res); /* free message resource */ - res = NULL; - break; + if (res->res_msgs.mail_cmd) { + free(res->res_msgs.mail_cmd); + } + if (res->res_msgs.operator_cmd) { + free(res->res_msgs.operator_cmd); + } + free_msgs_res((MSGS *)res); /* free message resource */ + res = NULL; + break; default: Dmsg1(0, "Unknown resource type %d\n", type); - break; + break; } /* Common stuff again -- free the resource, recurse to next one */ if (res) { @@ -331,10 +340,10 @@ void save_resource(int type, RES_ITEM *items, int pass) */ for (i=0; items[i].name; i++) { if (items[i].flags & ITEM_REQUIRED) { - if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) { + if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) { Emsg2(M_ABORT, 0, _("%s item is required in %s resource, but not found.\n"), - items[i].name, resources[rindex]); - } + items[i].name, resources[rindex]); + } } /* If this triggers, take a look at lib/parse_conf.h */ if (i >= MAX_RES_ITEMS) { @@ -349,33 +358,33 @@ void save_resource(int type, RES_ITEM *items, int pass) */ if (pass == 2) { switch (type) { - /* Resources not containing a resource */ - case R_DIRECTOR: - case R_DEVICE: - case R_MSGS: - break; - - /* Resources containing a resource */ - case R_STORAGE: - if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) { + /* Resources not containing a resource */ + case R_DIRECTOR: + case R_DEVICE: + case R_MSGS: + break; + + /* Resources containing a resource */ + case R_STORAGE: + if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) { Emsg1(M_ABORT, 0, "Cannot find Storage resource %s\n", res_all.res_dir.hdr.name); - } - res->res_store.messages = res_all.res_store.messages; - break; - default: + } + res->res_store.messages = res_all.res_store.messages; + break; + default: printf("Unknown resource type %d\n", type); - error = 1; - break; + error = 1; + break; } if (res_all.res_dir.hdr.name) { - free(res_all.res_dir.hdr.name); - res_all.res_dir.hdr.name = NULL; + free(res_all.res_dir.hdr.name); + res_all.res_dir.hdr.name = NULL; } if (res_all.res_dir.hdr.desc) { - free(res_all.res_dir.hdr.desc); - res_all.res_dir.hdr.desc = NULL; + free(res_all.res_dir.hdr.desc); + res_all.res_dir.hdr.desc = NULL; } return; } @@ -383,42 +392,42 @@ void save_resource(int type, RES_ITEM *items, int pass) /* The following code is only executed on pass 1 */ switch (type) { case R_DIRECTOR: - size = sizeof(DIRRES); - break; + size = sizeof(DIRRES); + break; case R_STORAGE: - size = sizeof(STORES); - break; + size = sizeof(STORES); + break; case R_DEVICE: - size = sizeof(DEVRES); - break; + size = sizeof(DEVRES); + break; case R_MSGS: - size = sizeof(MSGS); - break; + size = sizeof(MSGS); + break; default: printf("Unknown resource type %d\n", type); - error = 1; - size = 1; - break; + error = 1; + size = 1; + break; } /* Common */ if (!error) { res = (URES *)malloc(size); memcpy(res, &res_all, size); if (!resources[rindex].res_head) { - resources[rindex].res_head = (RES *)res; /* store first entry */ + resources[rindex].res_head = (RES *)res; /* store first entry */ } else { - RES *next; - /* Add new res to end of chain */ - for (next=resources[rindex].res_head; next->next; next=next->next) { - if (strcmp(next->name, res->res_dir.hdr.name) == 0) { - Emsg2(M_ERROR_TERM, 0, + RES *next; + /* Add new res to end of chain */ + for (next=resources[rindex].res_head; next->next; next=next->next) { + if (strcmp(next->name, res->res_dir.hdr.name) == 0) { + Emsg2(M_ERROR_TERM, 0, _("Attempt to define second %s resource named \"%s\" is not permitted.\n"), - resources[rindex].name, res->res_dir.hdr.name); - } - } - next->next = (RES *)res; + resources[rindex].name, res->res_dir.hdr.name); + } + } + next->next = (RES *)res; Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type), - res->res_dir.hdr.name); + res->res_dir.hdr.name); } } } diff --git a/bacula/src/stored/stored_conf.h b/bacula/src/stored/stored_conf.h index 05a9c6d325..56e3aa60f3 100644 --- a/bacula/src/stored/stored_conf.h +++ b/bacula/src/stored/stored_conf.h @@ -23,21 +23,22 @@ */ -#define R_FIRST 3001 - -#define R_DIRECTOR 3001 -#define R_STORAGE 3002 -#define R_DEVICE 3003 -#define R_MSGS 3004 - -#define R_LAST R_MSGS - +enum { + R_DIRECTOR = 3001, + R_STORAGE, + R_DEVICE, + R_MSGS, + R_FIRST = R_DIRECTOR, + R_LAST = R_MSGS /* keep this updated */ +}; -#define R_NAME 3020 -#define R_ADDRESS 3021 -#define R_PASSWORD 3022 -#define R_TYPE 3023 -#define R_BACKUP 3024 +enum { + R_NAME = 3020, + R_ADDRESS, + R_PASSWORD, + R_TYPE, + R_BACKUP +}; /* Definition of the contents of each Resource */ struct DIRRES { @@ -75,6 +76,7 @@ struct DEVRES { char *device_name; /* Archive device name */ char *changer_name; /* Changer device name */ char *changer_command; /* Changer command -- external program */ + char *spool_directory; /* Spool file directory */ uint32_t cap_bits; /* Capabilities of this device */ uint32_t max_changer_wait; /* Changer timeout */ uint32_t max_rewind_wait; /* maximum secs to wait for rewind */ @@ -89,6 +91,8 @@ struct DEVRES { int64_t max_volume_size; /* max bytes to put on one volume */ int64_t max_file_size; /* max file size in bytes */ int64_t volume_capacity; /* advisory capacity */ + int64_t max_spool_size; /* Max spool size for all jobs */ + int64_t max_job_spool_size; /* Max spool size for any single job */ DEVICE *dev; /* Pointer to phyical dev -- set at runtime */ }; diff --git a/bacula/src/version.h b/bacula/src/version.h index 0f407c0dd2..8a57e22b5a 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -2,8 +2,8 @@ #undef VERSION #define VERSION "1.33.4" #define VSTRING "1" -#define BDATE "09 Mar 2004" -#define LSMDATE "09Mar04" +#define BDATE "10 Mar 2004" +#define LSMDATE "10Mar04" /* Debug flags */ #undef DEBUG