From: Kern Sibbald Date: Thu, 22 Jan 2004 22:59:31 +0000 (+0000) Subject: SetIP command + CloseOnPoll + Full,Inc,Diff Pools + more access control checks X-Git-Tag: Release-1.34.0~156 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=cfc4a6ca1c7c5cc2a5c9bf45067e74f171e059e3;p=bacula%2Fbacula SetIP command + CloseOnPoll + Full,Inc,Diff Pools + more access control checks git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1017 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/ReleaseNotes b/bacula/ReleaseNotes index adad977359..185f50dfb6 100644 --- a/bacula/ReleaseNotes +++ b/bacula/ReleaseNotes @@ -1,9 +1,48 @@ Release Notes for Bacula 1.33 - Bacula code: Total files = 281 Total lines = 83,815 (*.h *.c *.in) + Bacula code: Total files = 283 Total lines = 84,818 (*.h *.c *.in) + +New directives: +- "Close on Poll = yes/no" in SD Device resource. +- "Volume Poll Interval = time-interval" in SD Device resource. +- "Two EOF = yes/no" in SD Device resource. +- "Close on Poll = yes/no" in SD Device resource. +- "Maximum Network Buffer Size = size" in SD Device resource. +- "Maximum Network Buffer Size = size" in FD FileDaemon (or Client) resource. +- "Console" new resource in Director conf file. + New directives: Name, Description, Password, JobACL, ClientACL, + StorageACL, ScheduleACL, RunACL, PoolACL, CommandACL, + FileSetACL, CatalogACL. +- "Max Run Time = duration" in Director Job resource. +- "Max Wait Time = duration" in Director Job resource (not fully implemented). +- "JobDefs = name-of-resource" in Director Job resource. +- "Jobdefs" new resource in Director. Same directives as for a Job. +- "Full Backup Pool = xxx" in Job resource in the Director. +- "Incremental Backup Pool = xxx" in Job resource in the Director. +- "Differential Backup Pool = xxx" in Job resource in the Director. +- Three new options on the Run override statement in a Schedule resource: + FullPool=xxx + IncrementalPool=xxx + DifferentialPool=xxx + +New Commands: +- "SetIP" +- Added "pool=xxx" to restore command line. +- Added "fileset=xxx" to restore command line. +- Fixed "storage=xxx" on restore command line. +- "markdir" command in restore tree. +- "unmarkdir" command in restore tree. +- "quit" command in restore tree. Most Significant Changes since 1.32d +- The ability to ask the Storage daemon on a device by device basis + to "poll" the tape drive at a given interval (minimum 1 minute). If + a tape is found, its label is read and if appropriate it is used. + This eliminates the need to do "mount" commands. +- The ability to close and re-open the device when a poll occurs. + This permits dealing with certain recalcitrant autochangers that + invalidate devices (typically on FreeBSD). - Dan Langille has written a PostgreSQL driver for Bacula. - Implement "update slots scan" that reads the volume label(s). - The full form of the scan is "scan=1,2,4-5,7". With no specification, diff --git a/bacula/autoconf/configure.in b/bacula/autoconf/configure.in index 2306ef0153..b937190b92 100644 --- a/bacula/autoconf/configure.in +++ b/bacula/autoconf/configure.in @@ -576,7 +576,7 @@ AC_ARG_WITH(tcp-wrappers, # ------------------------------------------ # Where to place working dir # ------------------------------------------ -working_dir=`eval echo ${sysconfdir}/working` +working_dir=`eval echo ${prefix}/var/bacula/working` AC_ARG_WITH(working-dir, [ --with-working-dir=PATH specify path of Bacula working directory], [ @@ -1285,7 +1285,7 @@ WLDFLAGS= PFILES="platforms/Makefile" PSCMD="ps -e" WIN32= -hostname=`uname -n` +hostname=`uname -n | cut -d '.' -f 1` case "$DISTNAME" in aix) DISTVER=`uname -r` @@ -1319,7 +1319,6 @@ bsdi) platforms/bsdi/bacula-fd \ platforms/bsdi/bacula-sd \ platforms/bsdi/bacula-dir" - hostname=`hostname -s` largefile_support="yes" ;; cygwin) @@ -1333,7 +1332,6 @@ darwin) DISTVER=`uname -r` TAPEDRIVE="/dev/nst0" PSCMD="ps -e -o pid,command" - hostname=`hostname -s` PFILES="${PFILES} \ platforms/darwin/Makefile" ;; @@ -1341,7 +1339,6 @@ debian) DISTVER=`cat /etc/debian_version` TAPEDRIVE="/dev/nrst0" PSCMD="ps -e -o pid,command" - hostname=`hostname -s` ;; freebsd) DISTVER=`uname -a |awk '{print $3}'` @@ -1359,7 +1356,6 @@ freebsd) platforms/freebsd/bacula-fd \ platforms/freebsd/bacula-sd \ platforms/freebsd/bacula-dir" - hostname=`hostname -s` largefile_support="yes" ;; hpux) @@ -1431,7 +1427,6 @@ mandrake) platforms/mandrake/bacula-dir \ platforms/mandrake/bacula.spec \ " - hostname=`hostname -s` ;; gentoo) DISTVER=`awk '/version / {print $5}' < /etc/gentoo-release` @@ -1442,14 +1437,12 @@ gentoo) platforms/gentoo/bacula-fd \ platforms/gentoo/bacula-sd \ platforms/gentoo/bacula-dir" - hostname=`hostname -s` ;; slackware) DISTVER=`cat /etc/slackware-version` TAPEDRIVE="/dev/nst0" PSCMD="ps -e -o pid,command" - hostname=`hostname -s` ;; solaris) DISTVER=`uname -r` @@ -1469,7 +1462,6 @@ suse) cut -f 3 -d ' '` TAPEDRIVE="/dev/nst0" PSCMD="ps -e -o pid,command" - hostname=`hostname -s` PFILES="${PFILES} \ platforms/suse/Makefile \ platforms/suse/bacula-fd \ @@ -1481,7 +1473,6 @@ suse5) DISTVER=5.x TAPEDRIVE="/dev/nst0" PSCMD="ps -e -o pid,command" - hostname=`hostname -s` PFILES="${PFILES} \ platforms/suse/Makefile \ platforms/suse/bacula-fd \ diff --git a/bacula/configure b/bacula/configure index 354cc14ec9..0f814c7548 100755 --- a/bacula/configure +++ b/bacula/configure @@ -6685,7 +6685,7 @@ fi; # ------------------------------------------ # Where to place working dir # ------------------------------------------ -working_dir=`eval echo ${sysconfdir}/working` +working_dir=`eval echo ${prefix}/var/bacula/working` # Check whether --with-working-dir or --without-working-dir was given. if test "${with_working_dir+set}" = set; then @@ -17956,7 +17956,6 @@ slackware) DISTVER=`cat /etc/slackware-version` TAPEDRIVE="/dev/nst0" PSCMD="ps -e -o pid,command" - hostname=`hostname -s` ;; solaris) DISTVER=`uname -r` diff --git a/bacula/kernstodo b/bacula/kernstodo index 1851d9feb5..89de4c46fa 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -35,6 +35,7 @@ Testing to do: (painful) - Test cancel at EOM. For 1.33 Testing/Documentation: +- Newly labeled tapes are chosen before ones already in use. - Document new alias records in Director. SDAddress SDDeviceName, SDPassword. FDPassword, FDAddress, DBAddress, DBPort, DBPassword. - Document new Include/Exclude ... @@ -56,9 +57,37 @@ For 1.33 Testing/Documentation: purge, ... - Add subsections to the Disaster Recovery index section. - Document Pool keyword for restore. - +- If you use restore replace=never, the directory attributes for + non-existent directories will not be restored properly. +- In the Bacula User Guide you write:"Note, one major disadvantage of + writing to a NFS mounted volume as I do isthat if the other machine goes + down, the OS will wait forever on the fopen()call that Bacula makes. As + a consequence, Bacula will completely stall untilthe machine exporting + the NSF mounts comes back up. If someone knows a wayaround this, please + let me know."I haven't tried using NFS in years, but I think that the + "soft" and "intr"remount options may well help you. The only way of + being sure would be totry it.See, for example, + http://howtos.linux.com/guides/nag2/x-087-2-nfs.mountd.shtml + For 1.33 -- Fix restore to only pull in last Differential and later Incrementals. +- Rescue builds incorrect script files on Rufus. +- Write a Qmsg() to be used in bnet.c to prevent recursion. Queue the + message. If dequeueing toss the messages. Lock while dequeuing so that + it cannot be called recursively and set dequeuing flag. +- Look at ASSERT() at 384 src/lib/bnet.c +- Add all pools in Dir conf to DB. +- Symbolic link a directory to another one, then backup the symbolic + link. +- Build console in client-only build. +- Restore attributes of directory if replace=never set but directory + did not exist. +- Check why Phil's Verify exclude does not work. +- Phil says that Windows file sizes mismatch in Verify when they should, + and that either the file size or the catalog size was zero. +- Fix option 2 of restore -- list where file is backed up -- require Client, + then list last 20 backups. +- Allow browsing the catalog to see all versions of a file (with + stat data on each file). - Finish code passing files=nnn to restore start. - Add level to estimate command. - Check time/dates printed during restore when using Win32 API. @@ -131,6 +160,67 @@ For 1.33 F Number Number of filenames to follow ... + +- Spooling ideas taken from Volker Sauer's and other's emails: + > IMHO job spooling should be turned on + > + > 1) by job + > 2) by schedule + > 3) by sd + > + > where and 2) overrides 1) and 3) is independent. + + Yes, this is the minimum that I think is necessary. + + > + > Reason(s): + > It should be switched by job, because the job that backs up the machine + > with the bacula-sd on doesn't need spooling. + > It should be switched by schedule, because for full-backups I don't need + > spooling, so I can switch it off (because the network faster then the + > tapedrive) + + True, with the exception that if you have enough disk spool space, + and you want to run concurrent jobs, spooling can eliminate the block + interleaving restore inefficiencies. + + > And you should be able to turn it of by sd for sd-machines with low disk + > capacity or if you just don't need or want this feature. + > + > There should be: + > - definitly the possibility for multipe spool direcories + + Having multiple directories is no problem -- having different maximum + sizes creates specification problems. At some point, I will probably + have a common SD pool of spool directories as well as a set of + private spool directories for each device. The first implementation + will be a set of private spool directories for each device since + managing a global pool with a bunch of threads writing into the same + directory is *much* more complicated and prone to error. + + > - the ability to spool parts of a backup (not the whole client) + + This may change in the future, but for the moment, it will spool + either to a job high water mark, or until the directory is full + (reaches max spool size or I/O error). It will then write to tape, + truncate the spool file, and begin spooling again. + + > - spooling while writing to tape + + Not within a job, but yes, if you run concurrent jobs -- each is a + different thread. Within a job could be a feature, but *much* later. + + > - parallel spooling (like parallel jobs/ concurrent jobs) of clients + + Yes, this is one of my main motivations for doing it (aside from + eliminating tape "shoe shine" during incremental backups. + + > - flushing a backup that only went to disk (like amflush in amanda) + + This will be a future feature, since spooling is different from backing + up to disk. The future feature will be "migration" which will move a job + from one backup Volume to another. + - New Storage specifications: Passed to SD as a sort of BSR record called Storage Specification Record or SSR. @@ -215,13 +305,6 @@ Ideas from Jerry Scharf: Job report (Volker Sauer). - Client does not show busy during Estimate command. - Implement Console mtx commands. -- Implement 3 Pools for a Job: - Job { -   Name = ... -   Full Backup Pool = xxx -   Incremental Backup Pool = yyy -   Differential Backup Pool = zzz - } - Add a default DB password to MySQL. GRANT all privileges ON bacula.* TO bacula@localhost IDENTIFIED BY 'bacula_password'; @@ -1119,3 +1202,11 @@ Done: (see kernsdone for more) directories, setting them to be restored. - Figure out a way to set restore on a directory without recursively decending. (recurse off?). +- Fix restore to only pull in last Differential and later Incrementals. +- Implement 3 Pools for a Job: + Job { +   Name = ... +   Full Backup Pool = xxx +   Incremental Backup Pool = yyy +   Differential Backup Pool = zzz + } diff --git a/bacula/src/cats/drop_sqlite_database.in b/bacula/src/cats/drop_sqlite_database.in index c10f3ca6ed..ece801c9b6 100644 --- a/bacula/src/cats/drop_sqlite_database.in +++ b/bacula/src/cats/drop_sqlite_database.in @@ -2,10 +2,5 @@ # # shell script to drop Bacula SQLite tables -bindir=@SQL_BINDIR@ cd @working_dir@ - -# how do we drop an sqlite database? -#$bindir/sqlite $* bacula.db <cLastWritten, row[18]!=NULL?row[18]:"", sizeof(mr->cLastWritten)); mr->LastWritten = (time_t)str_to_utime(mr->cLastWritten); bstrncpy(mr->VolStatus, row[19], sizeof(mr->VolStatus)); - sql_free_result(mdb); db_unlock(mdb); diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c index d4469845b8..34dcb299f0 100644 --- a/bacula/src/cats/sql_get.c +++ b/bacula/src/cats/sql_get.c @@ -322,7 +322,7 @@ int db_get_job_volume_names(JCR *jcr, B_DB *mdb, uint32_t JobId, POOLMEM **Volum db_lock(mdb); Mmsg(&mdb->cmd, "SELECT DISTINCT VolumeName FROM JobMedia,Media WHERE " - "JobMedia.JobId=%u AND JobMedia.MediaId=Media.MediaId ", + "JobMedia.JobId=%u AND JobMedia.MediaId=Media.MediaId", JobId); Dmsg1(130, "VolNam=%s\n", mdb->cmd); diff --git a/bacula/src/cats/sql_list.c b/bacula/src/cats/sql_list.c index b084d5890d..6541f3a27f 100644 --- a/bacula/src/cats/sql_list.c +++ b/bacula/src/cats/sql_list.c @@ -139,14 +139,14 @@ db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr, "MediaType,FirstWritten,LastWritten,LabelDate,VolJobs," "VolFiles,VolBlocks,VolMounts,VolBytes,VolErrors,VolWrites," "VolCapacityBytes,VolStatus,Recycle,VolRetention," - "VolUseDuration,MaxVolJobs,MaxVolFiles,MaxVolBytes " + "VolUseDuration,MaxVolJobs,MaxVolFiles,MaxVolBytes,InChanger " "FROM Media WHERE Media.VolumeName='%s'", mdbr->VolumeName); } else { Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,Slot,PoolId," "MediaType,FirstWritten,LastWritten,LabelDate,VolJobs," "VolFiles,VolBlocks,VolMounts,VolBytes,VolErrors,VolWrites," "VolCapacityBytes,VolStatus,Recycle,VolRetention," - "VolUseDuration,MaxVolJobs,MaxVolFiles,MaxVolBytes " + "VolUseDuration,MaxVolJobs,MaxVolFiles,MaxVolBytes,InChanger " "FROM Media WHERE Media.PoolId=%u ORDER BY MediaId", mdbr->PoolId); } } else { diff --git a/bacula/src/dird/backup.c b/bacula/src/dird/backup.c index 0fe51441a9..d570e274ee 100644 --- a/bacula/src/dird/backup.c +++ b/bacula/src/dird/backup.c @@ -120,10 +120,28 @@ int do_backup(JCR *jcr) jcr->JobId, jcr->Job); /* - * Get the Pool record + * Get the Pool record -- first apply any level defined pools */ + switch (jcr->JobLevel) { + case L_FULL: + if (jcr->full_pool) { + jcr->pool = jcr->full_pool; + } + break; + case L_INCREMENTAL: + if (jcr->inc_pool) { + jcr->pool = jcr->inc_pool; + } + break; + case L_DIFFERENTIAL: + if (jcr->dif_pool) { + jcr->pool = jcr->dif_pool; + } + break; + } memset(&pr, 0, sizeof(pr)); 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, POOL_OP_CREATE) < 0) { diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index f41dce96e5..ebea539c10 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -205,6 +205,9 @@ struct res_items job_items[] = { {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0}, {"storage", store_res, ITEM(res_job.storage), R_STORAGE, ITEM_REQUIRED, 0}, {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0}, + {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0}, + {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0}, + {"differentialbackuppool", store_res, ITEM(res_job.dif_pool), R_POOL, 0, 0}, {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0}, {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0}, {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0}, @@ -534,8 +537,18 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ... if (res->res_job.pool) { sendit(sock, " --> "); dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock); - } else { - sendit(sock, "!!! No Pool resource\n"); + } + if (res->res_job.full_pool) { + sendit(sock, " --> "); + dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock); + } + if (res->res_job.inc_pool) { + sendit(sock, " --> "); + dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock); + } + if (res->res_job.dif_pool) { + sendit(sock, " --> "); + dump_resource(-R_POOL, (RES *)res->res_job.dif_pool, sendit, sock); } if (res->res_job.verify_job) { sendit(sock, " --> "); @@ -959,6 +972,9 @@ void save_resource(int type, struct res_items *items, int pass) res->res_job.fileset = res_all.res_job.fileset; res->res_job.storage = res_all.res_job.storage; res->res_job.pool = res_all.res_job.pool; + res->res_job.full_pool = res_all.res_job.full_pool; + res->res_job.inc_pool = res_all.res_job.inc_pool; + res->res_job.dif_pool = res_all.res_job.dif_pool; res->res_job.verify_job = res_all.res_job.verify_job; res->res_job.jobdefs = res_all.res_job.jobdefs; break; diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h index ee2f15847d..6ab7688f3b 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -228,6 +228,9 @@ struct JOB { 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 */ @@ -348,6 +351,9 @@ struct RUN { int Priority; /* priority override */ int job_type; 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; diff --git a/bacula/src/dird/job.c b/bacula/src/dird/job.c index 71d15ff44a..73eff3e13a 100644 --- a/bacula/src/dird/job.c +++ b/bacula/src/dird/job.c @@ -680,6 +680,9 @@ void set_jcr_defaults(JCR *jcr, JOB *job) } pm_strcpy(&jcr->client_name, jcr->client->hdr.name); jcr->pool = job->pool; + jcr->full_pool = job->full_pool; + jcr->inc_pool = job->inc_pool; + jcr->dif_pool = job->dif_pool; jcr->catalog = job->client->catalog; jcr->fileset = job->fileset; jcr->messages = job->messages; diff --git a/bacula/src/dird/protos.h b/bacula/src/dird/protos.h index 87bc67d8e5..cbfe5b7fee 100644 --- a/bacula/src/dird/protos.h +++ b/bacula/src/dird/protos.h @@ -62,7 +62,7 @@ int variable_expansion(JCR *jcr, char *inp, POOLMEM **exp); /* 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 send_bootstrap_file(JCR *jcr); @@ -70,7 +70,7 @@ extern int send_level_command(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); extern void get_level_since_time(JCR *jcr, char *since, int since_len); extern int send_run_before_and_after_commands(JCR *jcr); @@ -94,7 +94,7 @@ extern void mount_request(JCR *jcr, BSOCK *bs, char *buf); /* msgchan.c */ extern int connect_to_storage_daemon(JCR *jcr, int retry_interval, - int max_retry_time, int verbose); + int max_retry_time, int verbose); extern int start_storage_daemon_job(JCR *jcr); extern int start_storage_daemon_message_thread(JCR *jcr); extern int bget_dirmsg(BSOCK *bs); @@ -146,28 +146,28 @@ JCR *create_control_jcr(char *base_name, int job_type); void free_ua_context(UAContext *ua); /* ua_select.c */ -STORE *select_storage_resource(UAContext *ua); -JOB *select_job_resource(UAContext *ua); -JOB *select_restore_job_resource(UAContext *ua); -CLIENT *select_client_resource(UAContext *ua); +STORE *select_storage_resource(UAContext *ua); +JOB *select_job_resource(UAContext *ua); +JOB *select_restore_job_resource(UAContext *ua); +CLIENT *select_client_resource(UAContext *ua); FILESET *select_fileset_resource(UAContext *ua); -int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr); -int select_media_dbr(UAContext *ua, MEDIA_DBR *mr); -int select_pool_dbr(UAContext *ua, POOL_DBR *pr); -int select_client_dbr(UAContext *ua, CLIENT_DBR *cr); - -void start_prompt(UAContext *ua, char *msg); -void add_prompt(UAContext *ua, char *prompt); -int do_prompt(UAContext *ua, char *automsg, char *msg, char *prompt, int max_prompt); -CAT *get_catalog_resource(UAContext *ua); +int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr); +int select_media_dbr(UAContext *ua, MEDIA_DBR *mr); +int select_pool_dbr(UAContext *ua, POOL_DBR *pr); +int select_client_dbr(UAContext *ua, CLIENT_DBR *cr); + +void start_prompt(UAContext *ua, char *msg); +void add_prompt(UAContext *ua, char *prompt); +int do_prompt(UAContext *ua, char *automsg, char *msg, char *prompt, int max_prompt); +CAT *get_catalog_resource(UAContext *ua); STORE *get_storage_resource(UAContext *ua, int use_default); -int get_media_type(UAContext *ua, char *MediaType, int max_media); -int get_pool_dbr(UAContext *ua, POOL_DBR *pr); -int get_client_dbr(UAContext *ua, CLIENT_DBR *cr); +int get_media_type(UAContext *ua, char *MediaType, int max_media); +int get_pool_dbr(UAContext *ua, POOL_DBR *pr); +int get_client_dbr(UAContext *ua, CLIENT_DBR *cr); POOL *get_pool_resource(UAContext *ua); POOL *select_pool_resource(UAContext *ua); CLIENT *get_client_resource(UAContext *ua); -int get_job_dbr(UAContext *ua, JOB_DBR *jr); +int get_job_dbr(UAContext *ua, JOB_DBR *jr); int find_arg_keyword(UAContext *ua, char **list); int find_arg(UAContext *ua, char *keyword); diff --git a/bacula/src/dird/run_conf.c b/bacula/src/dird/run_conf.c index faabf7c9fa..e4a54ae411 100644 --- a/bacula/src/dird/run_conf.c +++ b/bacula/src/dird/run_conf.c @@ -150,12 +150,15 @@ static void set_defaults() /* Keywords (RHS) permitted in Run records */ static struct s_kw RunFields[] = { - {"pool", 'P'}, - {"level", 'L'}, - {"storage", 'S'}, - {"messages", 'M'}, - {"priority", 'p'}, - {NULL, 0} + {"pool", 'P'}, + {"fullpool", 'f'}, + {"incrementalpool", 'i'}, + {"differentialpool", 'd'}, + {"level", 'L'}, + {"storage", 'S'}, + {"messages", 'M'}, + {"priority", 'p'}, + {NULL, 0} }; /* @@ -222,6 +225,9 @@ void store_run(LEX *lc, struct res_items *item, int index, int pass) } break; case 'P': /* Pool */ + case 'f': /* FullPool */ + case 'i': /* IncPool */ + case 'd': /* DifPool */ token = lex_get_token(lc, T_NAME); if (pass == 2) { res = GetResWithName(R_POOL, lc->str); @@ -230,7 +236,20 @@ void store_run(LEX *lc, struct res_items *item, int index, int pass) lc->str); /* NOT REACHED */ } - lrun.pool = (POOL *)res; + switch(RunFields[i].token) { + case 'P': + lrun.pool = (POOL *)res; + break; + case 'f': + lrun.full_pool = (POOL *)res; + break; + case 'i': + lrun.inc_pool = (POOL *)res; + break; + case 'd': + lrun.dif_pool = (POOL *)res; + break; + } } break; case 'S': /* storage */ diff --git a/bacula/src/dird/scheduler.c b/bacula/src/dird/scheduler.c index 9747835567..3c7f52721d 100644 --- a/bacula/src/dird/scheduler.c +++ b/bacula/src/dird/scheduler.c @@ -146,6 +146,15 @@ JCR *wait_for_next_job(char *one_shot_job_to_run) if (run->pool) { jcr->pool = run->pool; /* override pool */ } + if (run->full_pool) { + jcr->pool = run->full_pool; /* override full pool */ + } + if (run->inc_pool) { + jcr->pool = run->inc_pool; /* override inc pool */ + } + if (run->dif_pool) { + jcr->pool = run->dif_pool; /* override dif pool */ + } if (run->storage) { jcr->store = run->storage; /* override storage */ } diff --git a/bacula/src/dird/sql_cmds.c b/bacula/src/dird/sql_cmds.c index 6ba625abec..6ba94f151c 100644 --- a/bacula/src/dird/sql_cmds.c +++ b/bacula/src/dird/sql_cmds.c @@ -243,7 +243,7 @@ char *uar_full = "AND JobMedia.JobId=Job.JobId " "AND JobMedia.MediaId=Media.MediaId"; -char *uar_dec = +char *uar_dif = "INSERT INTO temp SELECT Job.JobId,Job.JobTDate,Job.ClientId," "Job.Level,Job.JobFiles,Job.StartTime,Media.VolumeName,JobMedia.StartFile," "Job.VolSessionId,Job.VolSessionTime " diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index b5ac957074..350631b88d 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -80,6 +80,7 @@ static int mount_cmd(UAContext *ua, char *cmd); static int release_cmd(UAContext *ua, char *cmd); static int update_cmd(UAContext *ua, char *cmd); static int wait_cmd(UAContext *ua, char *cmd); +static int setip_cmd(UAContext *ua, char *cmd); int quit_cmd(UAContext *ua, char *cmd); @@ -110,6 +111,7 @@ static struct cmdstruct commands[] = { { N_("run"), run_cmd, _("run ")}, { N_("status"), status_cmd, _("status [storage | client]=")}, { N_("setdebug"), setdebug_cmd, _("sets debug level")}, + { N_("setip"), setip_cmd, _("sets new client address -- if authorized")}, { N_("show"), show_cmd, _("show (resource records) [jobs | pools | ... | all]")}, { N_("sqlquery"), sqlquerycmd, _("use SQL to query catalog")}, { N_("time"), time_cmd, _("print current time")}, @@ -528,8 +530,8 @@ static int create_cmd(UAContext *ua, char *cmd) 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); + bsendmsg(ua, _("Error: Pool %s already exists.\n" + "Use update to change it.\n"), pool->hdr.name); break; case -1: @@ -544,6 +546,34 @@ Use update to change it.\n"), pool->hdr.name); } +/* + * Set a new address in a Client resource. We do this only + * if the Console name is the same as the Client name + * and the Console can access the client. + */ +static int setip_cmd(UAContext *ua, char *cmd) +{ + CLIENT *client; + if (!ua->cons && acl_access_ok(ua, Client_ACL, ua->cons->hdr.name)) { + bsendmsg(ua, _("Illegal command from this console.\n")); + return 1; + } + client = (CLIENT *)GetResWithName(R_CLIENT, ua->cons->hdr.name); + + if (!client) { + bsendmsg(ua, _("Client \"%s\" not found.\n"), ua->cons->hdr.name); + return 1; + } + LockRes(); + if (client->address) { + free(client->address); + } + client->address = bstrdup(inet_ntoa(ua->UA_sock->client_addr.sin_addr)); + bsendmsg(ua, _("Client \"%s\" address set to %s\n"), + client->hdr.name, client->address); + UnlockRes(); + return 1; +} /* diff --git a/bacula/src/dird/ua_prune.c b/bacula/src/dird/ua_prune.c index 2278405d80..cccd7c8620 100644 --- a/bacula/src/dird/ua_prune.c +++ b/bacula/src/dird/ua_prune.c @@ -501,7 +501,7 @@ int prune_volume(UAContext *ua, MEDIA_DBR *mr) if (cnt.count == 0) { if (ua->verbose) { - bsendmsg(ua, "There are no Jobs associated with Volume %s. Marking it purged.\n", + bsendmsg(ua, "There are no Jobs associated with Volume \"%s\". Marking it purged.\n", mr->VolumeName); } stat = mark_media_purged(ua, mr); @@ -558,7 +558,7 @@ int prune_volume(UAContext *ua, MEDIA_DBR *mr) free(del.JobId); } if (ua->verbose && del.num_del != 0) { - bsendmsg(ua, _("Pruned %d %s on Volume %s from catalog.\n"), del.num_del, + bsendmsg(ua, _("Pruned %d %s on Volume \"%s\" from catalog.\n"), del.num_del, del.num_del == 1 ? "Job" : "Jobs", mr->VolumeName); } diff --git a/bacula/src/dird/ua_restore.c b/bacula/src/dird/ua_restore.c index dc4e15b279..137bd84883 100644 --- a/bacula/src/dird/ua_restore.c +++ b/bacula/src/dird/ua_restore.c @@ -47,7 +47,7 @@ extern char *uar_del_temp, *uar_del_temp1, *uar_create_temp; extern char *uar_create_temp1, *uar_last_full, *uar_full; extern char *uar_inc, *uar_list_temp, *uar_sel_jobid_temp; extern char *uar_sel_all_temp1, *uar_sel_fileset, *uar_mediatype; -extern char *uar_jobid_fileindex, *uar_dec, *uar_sel_all_temp; +extern char *uar_jobid_fileindex, *uar_dif, *uar_sel_all_temp; struct NAME_LIST { @@ -115,11 +115,10 @@ static int get_date(UAContext *ua, char *date, int date_len); int restore_cmd(UAContext *ua, char *cmd) { RESTORE_CTX rx; /* restore context */ - JOB *job = NULL; + JOB *job; int i; memset(&rx, 0, sizeof(rx)); - rx.path = get_pool_memory(PM_FNAME); rx.fname = get_pool_memory(PM_FNAME); rx.JobIds = get_pool_memory(PM_FNAME); @@ -137,7 +136,7 @@ int restore_cmd(UAContext *ua, char *cmd) /* Ensure there is at least one Restore Job */ LockRes(); - while ( (job = (JOB *)GetNextRes(R_JOB, (RES *)job)) ) { + foreach_res(job, R_JOB) { if (job->JobType == JT_RESTORE) { if (!rx.restore_job) { rx.restore_job = job; @@ -368,7 +367,7 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx) break; case 5: /* pool specified */ i = find_arg_with_value(ua, "pool"); - if (i >= 0) { + if (i >= 0 && acl_access_ok(ua, Pool_ACL, ua->argv[i])) { rx->pool = (POOL *)GetResWithName(R_POOL, ua->argv[i]); } else { bsendmsg(ua, _("Error: Pool resource \"%s\" does not exist.\n"), ua->argv[i]); @@ -520,6 +519,11 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx) JobId, db_strerror(ua->db)); return 0; } + if (!acl_access_ok(ua, Job_ACL, jr.Name)) { + bsendmsg(ua, _("No authorization. Job \"%s\" not selected.\n"), + jr.Name); + continue; + } rx->TotalFiles += jr.JobFiles; } return 1; @@ -839,13 +843,13 @@ static int select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *date goto bail_out; } - /* Now find most recent Decremental Job after Full save, if any */ - Mmsg(&rx->query, uar_dec, edit_uint64(rx->JobTDate, ed1), date, + /* Now find most recent Differental Job after Full save, if any */ + Mmsg(&rx->query, uar_dif, edit_uint64(rx->JobTDate, ed1), date, cr.ClientId, fsr.FileSet, pool_select); if (!db_sql_query(ua->db, rx->query, NULL, NULL)) { bsendmsg(ua, "%s\n", db_strerror(ua->db)); } - /* Now update JobTDate to lock onto Decremental, if any */ + /* Now update JobTDate to lock onto Differental, if any */ rx->JobTDate = 0; if (!db_sql_query(ua->db, uar_sel_all_temp, last_full_handler, (void *)rx)) { bsendmsg(ua, "%s\n", db_strerror(ua->db)); @@ -855,7 +859,7 @@ static int select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *date goto bail_out; } - /* Now find all Incremental Jobs after Full/Dec save */ + /* Now find all Incremental Jobs after Full/dif save */ Mmsg(&rx->query, uar_inc, edit_uint64(rx->JobTDate, ed1), date, cr.ClientId, fsr.FileSet, pool_select); if (!db_sql_query(ua->db, rx->query, NULL, NULL)) { diff --git a/bacula/src/dird/ua_select.c b/bacula/src/dird/ua_select.c index c667a8f7d0..99df0d3a73 100644 --- a/bacula/src/dird/ua_select.c +++ b/bacula/src/dird/ua_select.c @@ -495,6 +495,10 @@ int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr) bsendmsg(ua, "%s", db_strerror(ua->db)); return 0; } + if (!acl_access_ok(ua, Pool_ACL, pr->Name)) { + bsendmsg(ua, _("No access to Pool \"%s\"\n"), pr->Name); + return 0; + } return 1; } diff --git a/bacula/src/dird/ua_status.c b/bacula/src/dird/ua_status.c index 766c6cda63..796f9fc506 100644 --- a/bacula/src/dird/ua_status.c +++ b/bacula/src/dird/ua_status.c @@ -136,6 +136,9 @@ static void do_all_status(UAContext *ua, char *cmd) i = 0; foreach_res(store, R_STORAGE) { found = false; + if (!acl_access_ok(ua, Storage_ACL, store->hdr.name)) { + continue; + } for (j=0; jaddress, store->address) == 0 && unique_store[j]->SDport == store->SDport) { @@ -167,6 +170,9 @@ static void do_all_status(UAContext *ua, char *cmd) i = 0; foreach_res(client, R_CLIENT) { found = false; + if (!acl_access_ok(ua, Client_ACL, client->hdr.name)) { + continue; + } for (j=0; jaddress, client->address) == 0 && unique_client[j]->FDport == client->FDport) { @@ -348,6 +354,9 @@ static void list_scheduled_jobs(UAContext *ua) /* Loop through all jobs */ LockRes(); foreach_res(job, R_JOB) { + if (!acl_access_ok(ua, Job_ACL, job->hdr.name)) { + continue; + } for (run=NULL; (run = find_next_run(run, job, runtime)); ) { level = job->level; if (run->level) { @@ -404,6 +413,9 @@ static void list_running_jobs(UAContext *ua) bsendmsg(ua, _("Level JobId Job Status\n")); bsendmsg(ua, _("====================================================================\n")); for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) { + if (!acl_access_ok(ua, Job_ACL, jcr->job->hdr.name)) { + continue; + } if (jcr->JobId == 0) { /* this is us */ njobs--; free_locked_jcr(jcr); diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index 3cd1702fe5..74518b63d1 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -141,6 +141,9 @@ struct JCR { STORE *store; /* Storage resource */ CLIENT *client; /* Client resource */ POOL *pool; /* Pool resource */ + POOL *full_pool; /* Full backup pool resource */ + POOL *inc_pool; /* Incremental backup pool resource */ + POOL *dif_pool; /* Differential backup pool resource */ FILESET *fileset; /* FileSet resource */ CAT *catalog; /* Catalog resource */ MSGS *messages; /* Default message handler */ diff --git a/bacula/src/lib/parse_conf.c b/bacula/src/lib/parse_conf.c index 692ec0d219..b403d8294a 100755 --- a/bacula/src/lib/parse_conf.c +++ b/bacula/src/lib/parse_conf.c @@ -69,7 +69,7 @@ extern struct s_res resources[]; extern CURES res_all; extern int res_all_size; -static int res_locked = 0; /* set when resource chains locked */ +static bool res_locked = false; /* set when resource chains locked */ /* Forward referenced subroutines */ static void scan_types(LEX *lc, MSGS *msg, int dest, char *where, char *cmd); @@ -579,12 +579,12 @@ void store_yesno(LEX *lc, struct res_items *item, int index, int pass) void LockRes() { P(res_mutex); - res_locked = 1; + res_locked = true; } void UnlockRes() { - res_locked = 0; + res_locked = false; V(res_mutex); } diff --git a/bacula/src/stored/askdir.c b/bacula/src/stored/askdir.c index 5ab474a756..7573f56a93 100644 --- a/bacula/src/stored/askdir.c +++ b/bacula/src/stored/askdir.c @@ -262,7 +262,6 @@ int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) } - /* * Request the sysop to create an appendable volume * @@ -285,6 +284,7 @@ int dir_ask_sysop_to_create_appendable_volume(JCR *jcr, DEVICE *dev) { int stat = 0, jstat; bool unmounted; + bool first = true; Dmsg0(130, "enter dir_ask_sysop_to_create_appendable_volume\n"); ASSERT(dev->dev_blocked); @@ -296,7 +296,8 @@ int dir_ask_sysop_to_create_appendable_volume(JCR *jcr, DEVICE *dev) Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg); return 0; } - if (dir_find_next_appendable_volume(jcr)) { /* get suggested volume */ + /* First pass, we *know* there are no appendable volumes, so no need to call */ + if (!first && dir_find_next_appendable_volume(jcr)) { /* get suggested volume */ jstat = JS_WaitMount; unmounted = (dev->dev_blocked == BST_UNMOUNTED) || (dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP); @@ -312,12 +313,14 @@ int dir_ask_sysop_to_create_appendable_volume(JCR *jcr, DEVICE *dev) Dmsg0(100, "Return 1 from mount without wait.\n"); return 1; } - Jmsg(jcr, M_MOUNT, 0, _( + if (!dev->poll) { + Jmsg(jcr, M_MOUNT, 0, _( "Please mount Volume \"%s\" on Storage Device \"%s\" for Job %s\n" "Use \"mount\" command to release Job.\n"), jcr->VolumeName, jcr->dev_name, jcr->Job); - Dmsg3(190, "Mount %s on %s for Job %s\n", - jcr->VolumeName, jcr->dev_name, jcr->Job); + Dmsg3(190, "Mount %s on %s for Job %s\n", + jcr->VolumeName, jcr->dev_name, jcr->Job); + } } else { jstat = JS_WaitMedia; if (!dev->poll) { @@ -333,6 +336,7 @@ Please use the \"label\" command to create a new Volume for:\n\ jcr->pool_name); } } + first = false; jcr->JobStatus = jstat; dir_send_job_status(jcr); diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index c1ffd58668..b41fa72c28 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -31,9 +31,9 @@ /* #define NEW_LOCK 1 */ -#define new_lock_device(dev) _new_lock_device(__FILE__, __LINE__, (dev)) +#define new_lock_device(dev) _new_lock_device(__FILE__, __LINE__, (dev)) #define new_lock_device_state(dev,state) _new_lock_device(__FILE__, __LINE__, (dev), (state)) -#define new_unlock_device(dev) _new_unlock_device(__FILE__, __LINE__, (dev)) +#define new_unlock_device(dev) _new_unlock_device(__FILE__, __LINE__, (dev)) #define lock_device(d) _lock_device(__FILE__, __LINE__, (d)) #define unlock_device(d) _unlock_device(__FILE__, __LINE__, (d)) @@ -43,155 +43,156 @@ #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 READ_WRITE 0 +#define READ_ONLY 1 #define OPEN_READ_WRITE 0 -#define OPEN_READ_ONLY 1 +#define OPEN_READ_ONLY 1 #define OPEN_WRITE_ONLY 2 /* Generic status bits returned from status_dev() */ -#define BMT_TAPE (1<<0) /* is tape device */ -#define BMT_EOF (1<<1) /* just read EOF */ -#define BMT_BOT (1<<2) /* at beginning of tape */ -#define BMT_EOT (1<<3) /* end of tape reached */ -#define BMT_SM (1<<4) /* DDS setmark */ -#define BMT_EOD (1<<5) /* DDS at end of data */ -#define BMT_WR_PROT (1<<6) /* tape write protected */ -#define BMT_ONLINE (1<<7) /* tape online */ -#define BMT_DR_OPEN (1<<8) /* tape door open */ -#define BMT_IM_REP_EN (1<<9) /* immediate report enabled */ +#define BMT_TAPE (1<<0) /* is tape device */ +#define BMT_EOF (1<<1) /* just read EOF */ +#define BMT_BOT (1<<2) /* at beginning of tape */ +#define BMT_EOT (1<<3) /* end of tape reached */ +#define BMT_SM (1<<4) /* DDS setmark */ +#define BMT_EOD (1<<5) /* DDS at end of data */ +#define BMT_WR_PROT (1<<6) /* tape write protected */ +#define BMT_ONLINE (1<<7) /* tape online */ +#define BMT_DR_OPEN (1<<8) /* tape door open */ +#define BMT_IM_REP_EN (1<<9) /* immediate report enabled */ /* Test capabilities */ #define dev_cap(dev, cap) ((dev)->capabilities & (cap)) /* Bits for device capabilities */ -#define CAP_EOF (1<<0) /* has MTWEOF */ -#define CAP_BSR (1<<1) /* has MTBSR */ -#define CAP_BSF (1<<2) /* has MTBSF */ -#define CAP_FSR (1<<3) /* has MTFSR */ -#define CAP_FSF (1<<4) /* has MTFSF */ -#define CAP_EOM (1<<5) /* has MTEOM */ -#define CAP_REM (1<<6) /* is removable media */ -#define CAP_RACCESS (1<<7) /* is random access device */ -#define CAP_AUTOMOUNT (1<<8) /* Read device at start to see what is there */ -#define CAP_LABEL (1<<9) /* Label blank tapes */ -#define CAP_ANONVOLS (1<<10) /* Mount without knowing volume name */ -#define CAP_ALWAYSOPEN (1<<11) /* always keep device open */ +#define CAP_EOF (1<<0) /* has MTWEOF */ +#define CAP_BSR (1<<1) /* has MTBSR */ +#define CAP_BSF (1<<2) /* has MTBSF */ +#define CAP_FSR (1<<3) /* has MTFSR */ +#define CAP_FSF (1<<4) /* has MTFSF */ +#define CAP_EOM (1<<5) /* has MTEOM */ +#define CAP_REM (1<<6) /* is removable media */ +#define CAP_RACCESS (1<<7) /* is random access device */ +#define CAP_AUTOMOUNT (1<<8) /* Read device at start to see what is there */ +#define CAP_LABEL (1<<9) /* Label blank tapes */ +#define CAP_ANONVOLS (1<<10) /* Mount without knowing volume name */ +#define CAP_ALWAYSOPEN (1<<11) /* always keep device open */ #define CAP_AUTOCHANGER (1<<12) /* AutoChanger */ #define CAP_OFFLINEUNMOUNT (1<<13) /* Offline before unmount */ -#define CAP_STREAM (1<<14) /* Stream device */ -#define CAP_BSFATEOM (1<<15) /* Backspace file at EOM */ -#define CAP_FASTFSF (1<<16) /* Fast forward space file */ -#define CAP_TWOEOF (1<<17) /* Write two eofs for EOM */ +#define CAP_STREAM (1<<14) /* Stream device */ +#define CAP_BSFATEOM (1<<15) /* Backspace file at EOM */ +#define CAP_FASTFSF (1<<16) /* Fast forward space file */ +#define CAP_TWOEOF (1<<17) /* Write two eofs for EOM */ +#define CAP_CLOSEONPOLL (1<<18) /* Close device on polling */ /* Test state */ #define dev_state(dev, st_state) ((dev)->state & (st_state)) /* Device state bits */ -#define ST_OPENED (1<<0) /* set when device opened */ -#define ST_TAPE (1<<1) /* is a tape device */ -#define ST_FILE (1<<2) /* is a file device */ -#define ST_FIFO (1<<3) /* is a fifo device */ -#define ST_PROG (1<<4) /* is a program device */ -#define ST_LABEL (1<<5) /* label found */ +#define ST_OPENED (1<<0) /* set when device opened */ +#define ST_TAPE (1<<1) /* is a tape device */ +#define ST_FILE (1<<2) /* is a file device */ +#define ST_FIFO (1<<3) /* is a fifo device */ +#define ST_PROG (1<<4) /* is a program device */ +#define ST_LABEL (1<<5) /* label found */ #define ST_MALLOC (1<<6) /* dev packet malloc'ed in init_dev() */ -#define ST_APPEND (1<<7) /* ready for Bacula append */ -#define ST_READ (1<<8) /* ready for Bacula read */ -#define ST_EOT (1<<9) /* at end of tape */ -#define ST_WEOT (1<<10) /* Got EOT on write */ -#define ST_EOF (1<<11) /* Read EOF i.e. zero bytes */ -#define ST_NEXTVOL (1<<12) /* Start writing on next volume */ -#define ST_SHORT (1<<13) /* Short block read */ +#define ST_APPEND (1<<7) /* ready for Bacula append */ +#define ST_READ (1<<8) /* ready for Bacula read */ +#define ST_EOT (1<<9) /* at end of tape */ +#define ST_WEOT (1<<10) /* Got EOT on write */ +#define ST_EOF (1<<11) /* Read EOF i.e. zero bytes */ +#define ST_NEXTVOL (1<<12) /* Start writing on next volume */ +#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_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 */ +#define BST_MOUNT 6 /* Mount request */ /* Volume Catalog Information structure definition */ struct VOLUME_CAT_INFO { /* Media info for the current Volume */ - uint32_t VolCatJobs; /* number of jobs on this Volume */ - uint32_t VolCatFiles; /* Number of files */ - uint32_t VolCatBlocks; /* Number of blocks */ - uint64_t VolCatBytes; /* Number of bytes written */ - uint32_t VolCatMounts; /* Number of mounts this volume */ - uint32_t VolCatErrors; /* Number of errors this volume */ - uint32_t VolCatWrites; /* Number of writes this volume */ - uint32_t VolCatReads; /* Number of reads this volume */ - uint64_t VolCatRBytes; /* Number of bytes read */ - uint32_t VolCatRecycles; /* Number of recycles this volume */ - int32_t Slot; /* Slot in changer */ - bool InChanger; /* Set if vol in current magazine */ - uint32_t VolCatMaxJobs; /* Maximum Jobs to write to volume */ - uint32_t VolCatMaxFiles; /* Maximum files to write to volume */ - uint64_t VolCatMaxBytes; /* Max bytes to write to volume */ + uint32_t VolCatJobs; /* number of jobs on this Volume */ + uint32_t VolCatFiles; /* Number of files */ + uint32_t VolCatBlocks; /* Number of blocks */ + uint64_t VolCatBytes; /* Number of bytes written */ + uint32_t VolCatMounts; /* Number of mounts this volume */ + uint32_t VolCatErrors; /* Number of errors this volume */ + uint32_t VolCatWrites; /* Number of writes this volume */ + uint32_t VolCatReads; /* Number of reads this volume */ + uint64_t VolCatRBytes; /* Number of bytes read */ + uint32_t VolCatRecycles; /* Number of recycles this volume */ + int32_t Slot; /* Slot in changer */ + bool InChanger; /* Set if vol in current magazine */ + uint32_t VolCatMaxJobs; /* Maximum Jobs to write to volume */ + uint32_t VolCatMaxFiles; /* Maximum files to write to volume */ + uint64_t VolCatMaxBytes; /* Max bytes to write to volume */ uint64_t VolCatCapacityBytes; /* capacity estimate */ - uint64_t VolReadTime; /* time spent reading */ - uint64_t VolWriteTime; /* time spent writing this Volume */ - char VolCatStatus[20]; /* Volume status */ + uint64_t VolReadTime; /* time spent reading */ + uint64_t VolWriteTime; /* time spent writing this Volume */ + char VolCatStatus[20]; /* Volume status */ char VolCatName[MAX_NAME_LENGTH]; /* Desired volume to mount */ -}; +}; 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 */ +struct DEVRES; /* Device resource defined in stored_conf.h */ /* Device structure definition */ struct DEVICE { public: - DEVICE *next; /* pointer to next open device */ - DEVICE *prev; /* pointer to prev open device */ - JCR *attached_jcrs; /* attached JCR list */ - pthread_mutex_t mutex; /* access control */ - pthread_cond_t wait; /* thread wait variable */ + DEVICE *next; /* pointer to next open device */ + DEVICE *prev; /* pointer to prev open device */ + JCR *attached_jcrs; /* attached JCR list */ + pthread_mutex_t mutex; /* access control */ + 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 */ - int dev_blocked; /* set if we must wait (i.e. change tape) */ - int dev_prev_blocked; /* previous blocked state */ - int num_waiting; /* number of threads waiting */ - int num_writers; /* number of writing threads */ - int use_count; /* usage count on this device */ - int fd; /* file descriptor */ - int capabilities; /* capabilities mask */ - int state; /* state mask */ - int dev_errno; /* Our own errno */ - int mode; /* read/write modes */ - char *dev_name; /* device name */ - char *errmsg; /* nicely edited error message */ - uint32_t block_num; /* current block number base 0 */ - uint32_t file; /* current file number base 0 */ - uint64_t file_addr; /* Current file read/write address */ - uint32_t EndBlock; /* last block written */ - uint32_t EndFile; /* last file written */ - uint32_t min_block_size; /* min block size */ - uint32_t max_block_size; /* max block size */ - 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 */ - 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 */ - utime_t vol_poll_interval; /* interval between polling Vol mount */ - DEVRES *device; /* pointer to Device Resource */ - btimer_id tid; /* timer id */ - - VOLUME_CAT_INFO VolCatInfo; /* Volume Catalog Information */ - VOLUME_LABEL VolHdr; /* Actual volume label */ + pthread_t no_wait_id; /* this thread must not wait */ + int dev_blocked; /* set if we must wait (i.e. change tape) */ + int dev_prev_blocked; /* previous blocked state */ + int num_waiting; /* number of threads waiting */ + int num_writers; /* number of writing threads */ + int use_count; /* usage count on this device */ + int fd; /* file descriptor */ + int capabilities; /* capabilities mask */ + int state; /* state mask */ + int dev_errno; /* Our own errno */ + int mode; /* read/write modes */ + char *dev_name; /* device name */ + char *errmsg; /* nicely edited error message */ + uint32_t block_num; /* current block number base 0 */ + uint32_t file; /* current file number base 0 */ + uint64_t file_addr; /* Current file read/write address */ + uint32_t EndBlock; /* last block written */ + uint32_t EndFile; /* last file written */ + uint32_t min_block_size; /* min block size */ + uint32_t max_block_size; /* max block size */ + 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 */ + 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 */ + utime_t vol_poll_interval; /* interval between polling Vol mount */ + DEVRES *device; /* pointer to Device Resource */ + btimer_id tid; /* timer id */ + + VOLUME_CAT_INFO VolCatInfo; /* Volume Catalog Information */ + VOLUME_LABEL VolHdr; /* Actual volume label */ /* Device wait times ***FIXME*** look at durations */ char BadVolName[MAX_NAME_LENGTH]; /* Last wrong Volume mounted */ - bool poll; /* set to poll Volume */ + bool poll; /* set to poll Volume */ int min_wait; int max_wait; int max_num_wait; @@ -206,7 +207,7 @@ public: * dependent. Arrgggg! */ #ifndef MTEOM -#ifdef MTSEOD +#ifdef MTSEOD #define MTEOM MTSEOD #endif #ifdef MTEOD diff --git a/bacula/src/stored/mount.c b/bacula/src/stored/mount.c index 90c96bdd59..3f70d8d174 100644 --- a/bacula/src/stored/mount.c +++ b/bacula/src/stored/mount.c @@ -80,12 +80,13 @@ mount_next_vol: * Get Director's idea of what tape we should have mounted. * in jcr->VolCatInfo */ - Dmsg0(100, "Before dir_find_next\n"); + Dmsg0(200, "Before dir_find_next_appendable_volume.\n"); while (!dir_find_next_appendable_volume(jcr)) { - Dmsg0(100, "not dir_find_next\n"); + Dmsg0(200, "not dir_find_next\n"); if (!dir_ask_sysop_to_create_appendable_volume(jcr, dev)) { return 0; } + Dmsg0(200, "Again dir_find_next_append...\n"); } if (job_canceled(jcr)) { return 0; @@ -131,6 +132,10 @@ mount_next_vol: } Dmsg1(100, "want vol=%s\n", jcr->VolumeName); + if (dev->poll && dev_cap(dev, CAP_CLOSEONPOLL)) { + force_close_dev(dev); + } + /* Open device */ if (!(dev_state(dev, ST_OPENED))) { int mode; diff --git a/bacula/src/stored/stored_conf.c b/bacula/src/stored/stored_conf.c index eb2ede2a41..206b0cb441 100644 --- a/bacula/src/stored/stored_conf.c +++ b/bacula/src/stored/stored_conf.c @@ -100,6 +100,7 @@ static struct res_items dev_items[] = { {"labelmedia", store_yesno, ITEM(res_dev.cap_bits), CAP_LABEL, ITEM_DEFAULT, 0}, {"alwaysopen", store_yesno, ITEM(res_dev.cap_bits), CAP_ALWAYSOPEN, ITEM_DEFAULT, 1}, {"autochanger", store_yesno, ITEM(res_dev.cap_bits), CAP_AUTOCHANGER, ITEM_DEFAULT, 0}, + {"closeonpoll", store_yesno, ITEM(res_dev.cap_bits), CAP_CLOSEONPOLL, ITEM_DEFAULT, 0}, {"changerdevice", store_strname,ITEM(res_dev.changer_name), 0, 0, 0}, {"changercommand", store_strname,ITEM(res_dev.changer_command), 0, 0, 0}, {"maximumchangerwait", store_pint, ITEM(res_dev.max_changer_wait), 0, ITEM_DEFAULT, 5 * 60}, diff --git a/bacula/src/version.h b/bacula/src/version.h index 54ae8eb9b1..1718eaff35 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -2,8 +2,8 @@ #undef VERSION #define VERSION "1.33" #define VSTRING "1" -#define BDATE "16 Jan 2004" -#define LSMDATE "16Jan04" +#define BDATE "22 Jan 2004" +#define LSMDATE "22Jan04" /* Debug flags */ #undef DEBUG