From 48700f0dbd29635e70ca1dcf1dbf95fb40f3ecea Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Fri, 6 Jun 2003 17:22:33 +0000 Subject: [PATCH] New query.sql, JobMedia VolIndex, add Release command git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@566 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/kernstodo | 50 +++++++++++++- bacula/src/cats/sql_create.c | 15 ++++- bacula/src/cats/sql_find.c | 2 +- bacula/src/cats/sql_get.c | 2 +- bacula/src/dird/bacula-dir.conf.in | 8 +-- bacula/src/dird/dird.c | 4 +- bacula/src/dird/query.sql | 30 +++++++-- bacula/src/dird/ua_cmds.c | 105 +++++++++++++++-------------- bacula/src/dird/ua_dotcmds.c | 6 +- bacula/src/findlib/create_file.c | 14 ++-- bacula/src/stored/block.c | 4 -- bacula/src/stored/block.h | 14 ++-- bacula/src/stored/btape.c | 95 +++++++++++++++++--------- bacula/src/stored/dev.c | 8 +-- bacula/src/stored/dircmd.c | 84 +++++++++++++++++++++++ bacula/src/stored/mount.c | 44 ++++++------ bacula/src/stored/protos.h | 1 + bacula/src/stored/status.c | 14 ++-- 18 files changed, 350 insertions(+), 150 deletions(-) diff --git a/bacula/kernstodo b/bacula/kernstodo index 27cb30d5b8..224b413688 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -1,5 +1,5 @@ Kern's ToDo List - 31 May 2003 + 06 June 2003 Documentation to do: (any release a little bit at a time) - Document running a test version. @@ -26,19 +26,48 @@ Testing to do: (painful) - Test cancel at EOM. - Test not zeroing Autochanger slot when it is wrong. - Test multiple simultaneous Volumes +- That restoring a hard link that already exists works correctly. + Same for soft link. +- Test of last block is correct in JobMedia when splitting file + over two volumes. - Figure out how to use ssh or stunnel to protect Bacula communications. For 1.31 release: +- Something is not right in last block of fill command. +- Check this below from Phil. + > When the job was done, Bacula reported 11084 files restored: + > + > JobId: 527 + > Job: Zocalo_Restore.2003-06-05_16.42.01 + > Client: Zocalo + > Start time: 05-Jun-2003 16:42 + > End time: 06-Jun-2003 01:21 + > Files Restored: 11,084 + > Bytes Restored: 65,474,772 + > Rate: 2.1 KB/s + > FD termination status: OK + > Termination: Restore OK + > + > when it should probably have reported 11084 files scanned, 250 restored. + > The bytes restored count looks about right. + > +- If during a restore, a hard linked file already exists (on option), delete + the file and re-link it. This is to avoid the possibility that the + user had re-linked the file between the backup and the restore. + Do lstat() to see if it is already properly linked. + Same for symlinked file. +- Remove the Jmsg() in sql_find.c:102 or only print on hard error. +- Implement List Volume Job=xxx or List scheduled volumes or + Status Director - Instrument use_count on DEVICE packets and ensure that the device is being close()ed at the appropriate time. - Check if Incremental is working correctly when it looks for the previous Job (Phil's problem). - Add next Volume to be used to status output. - Add a recycle command. -- Command to determine next volume needed for a particular job. - Make bootstrap filename unique. -- Implement FileSet VolIndex. +- Implement FileSet VolIndex -- done, but must update old records. - Sort JobIds entered into recover tree. - The bsr for Dan's job has file indexes covering the whole range rather than only the range contained on the volume. @@ -82,6 +111,8 @@ For 1.31 release: After 1.31: +- When doing a Backup send all attributes back to the Director, who + would then figure out what files have been deleted. - Currently in mount.c:236 the SD simply creates a Volume. It should have explicit permission to do so. It should also mark the tape in error if there is an error. @@ -255,6 +286,18 @@ After 1.31: - Make bcopy copy with a single tape drive. - Permit changing ownership during restore. +- From Phil: + > My suggestion: Add a feature on the systray menu-icon menu to request + > an immediate backup now. This would be useful for laptop users who may + > not be on the network when the regular scheduled backup is run. + > + > My wife's suggestion: Add a setting to the win32 client to allow it to + > shut down the machine after backup is complete (after, of course, + > displaying a "System will shut down in one minute, click here to cancel" + > warning dialog). This would be useful for sites that want user + > woorkstations to be shut down overnight to save power. + > + - Autolabel should be specified by DIR instead of SD. - Storage daemon - Add media capacity @@ -923,3 +966,4 @@ Done: (see kernsdone for more) - The "List last 20 Jobs run" doesnt work correctly in restore. It doesnt show the last 20 jobs , but some older ones. - Fix Verify VolumeToCatalog to use BSRs -- it is broken. +- Implement Release Storage=xxx diff --git a/bacula/src/cats/sql_create.c b/bacula/src/cats/sql_create.c index 0cc5deb0e2..670570c009 100644 --- a/bacula/src/cats/sql_create.c +++ b/bacula/src/cats/sql_create.c @@ -114,6 +114,7 @@ int db_create_jobmedia_record(JCR *jcr, B_DB *mdb, JOBMEDIA_DBR *jm) { int stat; + int count; db_lock(mdb); Mmsg(&mdb->cmd, "SELECT JobId, MediaId FROM JobMedia WHERE \ @@ -132,13 +133,21 @@ JobId=%d AND MediaId=%d", jm->JobId, jm->MediaId); sql_free_result(mdb); } + /* Now get count for VolIndex */ + Mmsg(&mdb->cmd, "SELECT count(*) from JobMedia"); + count = get_sql_record_max(jcr, mdb); + if (count < 0) { + count = 0; + } + count++; + /* Must create it */ Mmsg(&mdb->cmd, "INSERT INTO JobMedia (JobId,MediaId,FirstIndex,LastIndex,\ -StartFile,EndFile,StartBlock,EndBlock) \ -VALUES (%u,%u,%u,%u,%u,%u,%u,%u)", +StartFile,EndFile,StartBlock,EndBlock,VolIndex) \ +VALUES (%u,%u,%u,%u,%u,%u,%u,%u,%u)", jm->JobId, jm->MediaId, jm->FirstIndex, jm->LastIndex, - jm->StartFile, jm->EndFile, jm->StartBlock, jm->EndBlock); + jm->StartFile, jm->EndFile, jm->StartBlock, jm->EndBlock,count); Dmsg0(30, mdb->cmd); if (!INSERT_DB(jcr, mdb, mdb->cmd)) { diff --git a/bacula/src/cats/sql_find.c b/bacula/src/cats/sql_find.c index 0dab06bcce..ec5815010a 100644 --- a/bacula/src/cats/sql_find.c +++ b/bacula/src/cats/sql_find.c @@ -99,7 +99,7 @@ db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime) } if ((row = sql_fetch_row(mdb)) == NULL) { sql_free_result(mdb); - Mmsg0(&mdb->errmsg, _("No Job Found.\n")); + Mmsg(&mdb->errmsg, _("No prior Job record found.\n")); db_unlock(mdb); return 0; } diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c index 1adaa39e2e..7369abbcc9 100644 --- a/bacula/src/cats/sql_get.c +++ b/bacula/src/cats/sql_get.c @@ -363,7 +363,7 @@ int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, uint32_t JobId, VOL_PARAMS Mmsg(&mdb->cmd, "SELECT VolumeName,FirstIndex,LastIndex,StartFile,EndFile,StartBlock,EndBlock" " FROM JobMedia,Media WHERE JobMedia.JobId=%u" -" AND JobMedia.MediaId=Media.MediaId ORDER BY JobMediaId", JobId); +" AND JobMedia.MediaId=Media.MediaId ORDER BY VolIndex,JobMediaId", JobId); Dmsg1(130, "VolNam=%s\n", mdb->cmd); if (QUERY_DB(jcr, mdb, mdb->cmd)) { diff --git a/bacula/src/dird/bacula-dir.conf.in b/bacula/src/dird/bacula-dir.conf.in index fc07bc837d..a51ab2b870 100644 --- a/bacula/src/dird/bacula-dir.conf.in +++ b/bacula/src/dird/bacula-dir.conf.in @@ -27,15 +27,15 @@ Director { # define myself # Define the main nightly save backup job # By default, this job will back up to disk in /tmp Job { - Name = "NightlySave" + Name = "Client1" Type = Backup - Client=@hostname@-fd - FileSet="Full Set" + Client = @hostname@-fd + FileSet = "Full Set" Schedule = "WeeklyCycle" Storage = File Messages = Standard Pool = Default - Write Bootstrap = "@working_dir@/NightlySave.bsr" + Write Bootstrap = "@working_dir@/Client1.bsr" } # Backup the catalog database (after the nightly save) diff --git a/bacula/src/dird/dird.c b/bacula/src/dird/dird.c index 0df270545d..c5e1f5ef0a 100644 --- a/bacula/src/dird/dird.c +++ b/bacula/src/dird/dird.c @@ -370,7 +370,9 @@ Without that I don't know who I am :-(\n"), configfile); catalog->db_password, catalog->db_address, catalog->db_port, catalog->db_socket); if (!db_open_database(NULL, db)) { - OK = FALSE; /* Error message already printed */ + Jmsg(NULL, M_FATAL, 0, _("Could not open database \"%s\".\n"), + catalog->db_name); + OK = FALSE; } else { /* If a pool is defined for this job, create the pool DB * record if it is not already created. diff --git a/bacula/src/dird/query.sql b/bacula/src/dird/query.sql index 0cecb5b45f..9cbd51f0fa 100644 --- a/bacula/src/dird/query.sql +++ b/bacula/src/dird/query.sql @@ -8,7 +8,7 @@ SELECT max(JobId) AS Jobs,sum(JobFiles) AS Files, *Enter path with trailing slash: *Enter filename: *Enter Client name: -SELECT Job.JobId, StartTime AS JobStartTime, VolumeName, Client.Name AS ClientName +SELECT Job.JobId,StartTime AS JobStartTime,VolumeName,Client.Name AS ClientName FROM Job,File,Path,Filename,Media,JobMedia,Client WHERE File.JobId=Job.JobId AND Path.Path='%1' @@ -25,7 +25,7 @@ SELECT Job.JobId, StartTime AS JobStartTime, VolumeName, Client.Name AS ClientNa *Enter path with trailing slash: *Enter filename: *Enter Client name: -SELECT Job.JobId, StartTime AS JobStartTime, VolumeName, Client.Name AS ClientName +SELECT Job.JobId,StartTime AS JobStartTime,VolumeName,Client.Name AS ClientName FROM Job,File,Path,Filename,Media,JobMedia,Client WHERE File.JobId=Job.JobId AND Path.Path='%1' @@ -47,7 +47,29 @@ JobMedia.StartFile as VolFile,VolumeName AND Client.ClientId=Job.ClientId AND Level='F' AND JobStatus='T' AND JobMedia.JobId=Job.JobId AND JobMedia.MediaId=Media.MediaId - ORDER BY JobId DESC LIMIT 20; + ORDER BY Job.StartTime DESC LIMIT 20; +# +:List all backups for a Client after a specified time +*Enter Client Name: +*Enter time in YYYY-MM-DD HH:MM:SS format: +Select Job.JobId,Client.Name as Client,Level,StartTime,JobFiles,JobBytes,VolumeName + FROM Client,Job,JobMedia,Media + WHERE Client.Name='%1' + AND Client.ClientId=Job.ClientId + AND JobStatus='T' + AND JobMedia.JobId=Job.JobId AND JobMedia.MediaId=Media.MediaId + AND Job.StartTime >= '%2' + ORDER BY Job.StartTime; +# +:List all backups for a Client +*Enter Client Name: +Select Job.JobId,Client.Name as Client,Level,StartTime,JobFiles,JobBytes,VolumeName + FROM Client,Job,JobMedia,Media + WHERE Client.Name='%1' + AND Client.ClientId=Job.ClientId + AND JobStatus='T' + AND JobMedia.JobId=Job.JobId AND JobMedia.MediaId=Media.MediaId + ORDER BY Job.StartTime; # :List Volume Attributes for a selected Volume: *Enter Volume name: @@ -126,7 +148,7 @@ SELECT Job.JobId as JobId, Client.Name as Client, FROM Client,Job,File,Filename,Path WHERE Client.ClientId=Job.ClientId AND JobStatus='T' AND Job.JobId=File.JobId AND Path.PathId=File.PathId AND Filename.FilenameId=File.FilenameId - AND Filename.Name='%1' ORDER BY Job.JobId LIMIT 20; + AND Filename.Name='%1' ORDER BY Job.StartTime LIMIT 20; # :List total files/bytes by Job: SELECT count(*) AS Jobs, sum(JobFiles) AS Files, diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index 44eaf6935a..d5133b2361 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -63,56 +63,58 @@ extern int relabelcmd(UAContext *ua, char *cmd); extern int update_slots(UAContext *ua); /* ua_label.c */ /* Forward referenced functions */ -static int addcmd(UAContext *ua, char *cmd), createcmd(UAContext *ua, char *cmd), cancelcmd(UAContext *ua, char *cmd); -static int setdebugcmd(UAContext *ua, char *cmd); -static int helpcmd(UAContext *ua, char *cmd); -static int deletecmd(UAContext *ua, char *cmd); -static int usecmd(UAContext *ua, char *cmd), unmountcmd(UAContext *ua, char *cmd); -static int versioncmd(UAContext *ua, char *cmd), automountcmd(UAContext *ua, char *cmd); -static int timecmd(UAContext *ua, char *cmd); +static int add_cmd(UAContext *ua, char *cmd), createcmd(UAContext *ua, char *cmd), cancelcmd(UAContext *ua, char *cmd); +static int setdebug_cmd(UAContext *ua, char *cmd); +static int help_cmd(UAContext *ua, char *cmd); +static int delete_cmd(UAContext *ua, char *cmd); +static int use_cmd(UAContext *ua, char *cmd), unmount_cmd(UAContext *ua, char *cmd); +static int version_cmd(UAContext *ua, char *cmd), automount_cmd(UAContext *ua, char *cmd); +static int time_cmd(UAContext *ua, char *cmd); static int update_volume(UAContext *ua); static int update_pool(UAContext *ua); static int delete_volume(UAContext *ua); static int delete_pool(UAContext *ua); -static int mountcmd(UAContext *ua, char *cmd); -static int updatecmd(UAContext *ua, char *cmd); -static int waitcmd(UAContext *ua, char *cmd); +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); -int quitcmd(UAContext *ua, char *cmd); +int quit_cmd(UAContext *ua, char *cmd); struct cmdstruct { char *key; int (*func)(UAContext *ua, char *cmd); char *help; }; static struct cmdstruct commands[] = { - { N_("add"), addcmd, _("add media to a pool")}, + { N_("add"), add_cmd, _("add media to a pool")}, { N_("autodisplay"), autodisplaycmd, _("autodisplay [on/off] -- console messages")}, - { N_("automount"), automountcmd, _("automount [on/off] -- after label")}, + { N_("automount"), automount_cmd, _("automount [on/off] -- after label")}, { N_("cancel"), cancelcmd, _("cancel job=nnn -- cancel a job")}, { N_("create"), createcmd, _("create DB Pool from resource")}, - { N_("delete"), deletecmd, _("delete [pool= | media volume=]")}, - { N_("help"), helpcmd, _("print this command")}, + { N_("delete"), delete_cmd, _("delete [pool= | media volume=]")}, + { N_("help"), help_cmd, _("print this command")}, { N_("label"), labelcmd, _("label a tape")}, { N_("relabel"), relabelcmd, _("relabel a tape")}, { N_("list"), listcmd, _("list [pools | jobs | jobtotals | media | files job=]; from catalog")}, { N_("llist"), llistcmd, _("full or long list like list command")}, { N_("messages"), messagescmd, _("messages")}, - { N_("mount"), mountcmd, _("mount ")}, + { N_("mount"), mount_cmd, _("mount ")}, { N_("restore"), restorecmd, _("restore files")}, { N_("prune"), prunecmd, _("prune expired records from catalog")}, { N_("purge"), purgecmd, _("purge records from catalog")}, { N_("run"), runcmd, _("run ")}, - { N_("setdebug"), setdebugcmd, _("sets debug level")}, + { N_("setdebug"), setdebug_cmd, _("sets debug level")}, { N_("show"), showcmd, _("show (resource records) [jobs | pools | ... | all]")}, { N_("sqlquery"), sqlquerycmd, _("use SQL to query catalog")}, { N_("status"), statuscmd, _("status [storage | client]=")}, - { N_("unmount"), unmountcmd, _("unmount ")}, - { N_("update"), updatecmd, _("update Volume or Pool")}, - { N_("use"), usecmd, _("use catalog xxx")}, - { N_("version"), versioncmd, _("print Director version")}, - { N_("quit"), quitcmd, _("quit")}, + { N_("unmount"), unmount_cmd, _("unmount ")}, + { N_("update"), update_cmd, _("update Volume or Pool")}, + { N_("use"), use_cmd, _("use catalog xxx")}, + { N_("version"), version_cmd, _("print Director version")}, + { N_("quit"), quit_cmd, _("quit")}, { N_("query"), querycmd, _("query catalog")}, - { N_("time"), timecmd, _("print current time")}, - { N_("exit"), quitcmd, _("exit = quit")}, - { N_("wait"), waitcmd, _("wait until no jobs are running")}, + { N_("release"), release_cmd, _("release ")}, + { N_("time"), time_cmd, _("print current time")}, + { N_("exit"), quit_cmd, _("exit = quit")}, + { N_("wait"), wait_cmd, _("wait until no jobs are running")}, }; #define comsize (sizeof(commands)/sizeof(struct cmdstruct)) @@ -170,7 +172,7 @@ void set_pool_dbr_defaults_in_media_dbr(MEDIA_DBR *mr, POOL_DBR *pr) /* * Add Volumes to an existing Pool */ -static int addcmd(UAContext *ua, char *cmd) +static int add_cmd(UAContext *ua, char *cmd) { POOL_DBR pr; MEDIA_DBR mr; @@ -314,7 +316,7 @@ getVolName: * automount on * automount off */ -int automountcmd(UAContext *ua, char *cmd) +int automount_cmd(UAContext *ua, char *cmd) { char *onoff; @@ -598,7 +600,7 @@ Use update to change it.\n"), pool->hdr.name); * update media pool= volume= * changes pool info for volume */ -static int updatecmd(UAContext *ua, char *cmd) +static int update_cmd(UAContext *ua, char *cmd) { static char *kw[] = { N_("media"), /* 0 */ @@ -1058,7 +1060,7 @@ static void do_all_setdebug(UAContext *ua, int level) /* * setdebug level=nn all */ -static int setdebugcmd(UAContext *ua, char *cmd) +static int setdebug_cmd(UAContext *ua, char *cmd) { STORE *store; CLIENT *client; @@ -1163,7 +1165,7 @@ static int setdebugcmd(UAContext *ua, char *cmd) /* * print time */ -static int timecmd(UAContext *ua, char *cmd) +static int time_cmd(UAContext *ua, char *cmd) { char sdt[50]; time_t ttime = time(NULL); @@ -1182,7 +1184,7 @@ static int timecmd(UAContext *ua, char *cmd) * delete pool= * delete media pool= volume= */ -static int deletecmd(UAContext *ua, char *cmd) +static int delete_cmd(UAContext *ua, char *cmd) { static char *keywords[] = { N_("volume"), @@ -1266,7 +1268,7 @@ static int delete_pool(UAContext *ua) } -static void do_mount_cmd(int mount, UAContext *ua, char *cmd) +static void do_mount_cmd(UAContext *ua, char *command) { STORE *store; BSOCK *sd; @@ -1276,7 +1278,7 @@ static void do_mount_cmd(int mount, UAContext *ua, char *cmd) if (!open_db(ua)) { return; } - Dmsg1(120, "mount: %s\n", ua->UA_sock->msg); + Dmsg2(120, "%s: %s\n", command, ua->UA_sock->msg); store = get_storage_resource(ua, 1); if (!store) { @@ -1294,16 +1296,9 @@ static void do_mount_cmd(int mount, UAContext *ua, char *cmd) sd = ua->jcr->store_bsock; strcpy(dev_name, store->dev_name); bash_spaces(dev_name); - if (mount) { - bnet_fsend(sd, "mount %s", dev_name); - } else { - bnet_fsend(sd, "unmount %s", dev_name); - } + bnet_fsend(sd, "%s %s", command, dev_name); while (bnet_recv(sd) >= 0) { bsendmsg(ua, "%s", sd->msg); - if (strncmp(sd->msg, "3001 OK mount.", 14) == 0) { - /***** ****FIXME**** fix JobStatus */ - } } bnet_sig(sd, BNET_TERMINATE); bnet_close(sd); @@ -1313,9 +1308,9 @@ static void do_mount_cmd(int mount, UAContext *ua, char *cmd) /* * mount [storage | device] */ -static int mountcmd(UAContext *ua, char *cmd) +static int mount_cmd(UAContext *ua, char *cmd) { - do_mount_cmd(1, ua, cmd); /* mount */ + do_mount_cmd(ua, "mount"); /* mount */ return 1; } @@ -1323,9 +1318,19 @@ static int mountcmd(UAContext *ua, char *cmd) /* * unmount [storage | device] */ -static int unmountcmd(UAContext *ua, char *cmd) +static int unmount_cmd(UAContext *ua, char *cmd) +{ + do_mount_cmd(ua, "unmount"); /* unmount */ + return 1; +} + + +/* + * release [storage | device] + */ +static int release_cmd(UAContext *ua, char *cmd) { - do_mount_cmd(0, ua, cmd); /* unmount */ + do_mount_cmd(ua, "release"); /* release */ return 1; } @@ -1334,7 +1339,7 @@ static int unmountcmd(UAContext *ua, char *cmd) * Switch databases * use catalog= */ -static int usecmd(UAContext *ua, char *cmd) +static int use_cmd(UAContext *ua, char *cmd) { CAT *oldcatalog, *catalog; @@ -1354,7 +1359,7 @@ static int usecmd(UAContext *ua, char *cmd) return 1; } -int quitcmd(UAContext *ua, char *cmd) +int quit_cmd(UAContext *ua, char *cmd) { ua->quit = TRUE; return 1; @@ -1363,7 +1368,7 @@ int quitcmd(UAContext *ua, char *cmd) /* * Wait until no job is running */ -int waitcmd(UAContext *ua, char *cmd) +int wait_cmd(UAContext *ua, char *cmd) { bmicrosleep(0, 200000); /* let job actually start */ for (int running=1; running; ) { @@ -1386,7 +1391,7 @@ int waitcmd(UAContext *ua, char *cmd) } -static int helpcmd(UAContext *ua, char *cmd) +static int help_cmd(UAContext *ua, char *cmd) { unsigned int i; @@ -1399,7 +1404,7 @@ static int helpcmd(UAContext *ua, char *cmd) return 1; } -static int versioncmd(UAContext *ua, char *cmd) +static int version_cmd(UAContext *ua, char *cmd) { bsendmsg(ua, "%s Version: " VERSION " (" BDATE ")\n", my_name); return 1; diff --git a/bacula/src/dird/ua_dotcmds.c b/bacula/src/dird/ua_dotcmds.c index 4f85e6e2ef..698ec67f0a 100644 --- a/bacula/src/dird/ua_dotcmds.c +++ b/bacula/src/dird/ua_dotcmds.c @@ -42,7 +42,7 @@ extern char my_name[]; /* Imported functions */ extern int qmessagescmd(UAContext *ua, char *cmd); -extern int quitcmd(UAContext *ua, char *cmd); +extern int quit_cmd(UAContext *ua, char *cmd); /* Forward referenced functions */ static int diecmd(UAContext *ua, char *cmd); @@ -69,8 +69,8 @@ static struct cmdstruct commands[] = { { N_(".storage"), storagecmd, NULL}, { N_(".defaults"), defaultscmd, NULL}, { N_(".messages"), qmessagescmd, NULL}, - { N_(".quit"), quitcmd, NULL}, - { N_(".exit"), quitcmd, NULL} + { N_(".quit"), quit_cmd, NULL}, + { N_(".exit"), quit_cmd, NULL} }; #define comsize (sizeof(commands)/sizeof(struct cmdstruct)) diff --git a/bacula/src/findlib/create_file.c b/bacula/src/findlib/create_file.c index f231553c36..37e7c3e84b 100644 --- a/bacula/src/findlib/create_file.c +++ b/bacula/src/findlib/create_file.c @@ -211,13 +211,13 @@ int create_file(JCR *jcr, char *fname, char *ofile, char *lname, return CF_CREATED; case FT_LNKSAVED: /* Hard linked, file already saved */ - Dmsg2(130, "Hard link %s => %s\n", ofile, lname); - if (link(lname, ofile) != 0) { - Jmsg3(jcr, M_ERROR, 0, _("Could not hard link %s -> %s: ERR=%s\n"), - ofile, lname, strerror(errno)); - return CF_ERROR; - } - return CF_CREATED; + Dmsg2(130, "Hard link %s => %s\n", ofile, lname); + if (link(lname, ofile) != 0) { + Jmsg3(jcr, M_ERROR, 0, _("Could not hard link %s -> %s: ERR=%s\n"), + ofile, lname, strerror(errno)); + return CF_ERROR; + } + return CF_CREATED; } /* End inner switch */ diff --git a/bacula/src/stored/block.c b/bacula/src/stored/block.c index a9dac57009..ed20383c11 100644 --- a/bacula/src/stored/block.c +++ b/bacula/src/stored/block.c @@ -357,8 +357,6 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) Jmsg(jcr, M_INFO, 0, _("User defined maximum volume capacity %s exceeded on device %s.\n"), edit_uint64(max_cap, ed1), dev->dev_name); block->write_failed = true; - dev->EndBlock = dev->block_num; - dev->EndFile = dev->file; weof_dev(dev, 1); /* end the tape */ weof_dev(dev, 1); /* write second eof */ dev->state |= (ST_EOF | ST_EOT | ST_WEOT); @@ -403,8 +401,6 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) wlen, stat, dev->dev_errno, strerror(dev->dev_errno)); block->write_failed = true; - dev->EndBlock = dev->block_num; - dev->EndFile = dev->file; weof_dev(dev, 1); /* end the tape */ weof_dev(dev, 1); /* write second eof */ dev->state |= (ST_EOF | ST_EOT | ST_WEOT); diff --git a/bacula/src/stored/block.h b/bacula/src/stored/block.h index 551804c20d..1f76241524 100644 --- a/bacula/src/stored/block.h +++ b/bacula/src/stored/block.h @@ -85,24 +85,22 @@ struct DEV_BLOCK { DEV_BLOCK *next; /* pointer to next one */ void *dev; /* pointer to device (DEVICE not defined yet) */ - /* binbuf is the number of bytes remaining - * in the buffer. For writes, it is bytes not yet written. - * For reads, it is remaining bytes not yet read. + /* binbuf is the number of bytes remaining in the buffer. + * For writes, it is bytes not yet written. + * For reads, it is remaining bytes not yet read. */ uint32_t binbuf; /* bytes in buffer */ uint32_t block_len; /* length of current block read */ uint32_t buf_len; /* max/default block length */ - uint32_t BlockNumber; /* sequential block number */ + uint32_t BlockNumber; /* sequential Bacula block number */ uint32_t read_len; /* bytes read into buffer, if zero, block empty */ uint32_t VolSessionId; /* */ uint32_t VolSessionTime; /* */ int BlockVer; /* block version 1 or 2 */ bool write_failed; /* set if write failed */ bool block_read; /* set when block read */ - char *bufp; /* pointer into buffer */ - POOLMEM *buf; /* actual data buffer. This is a - * Pool buffer! - */ + char *bufp; /* pointer into buffer */ + POOLMEM *buf; /* actual data buffer */ }; #define block_is_empty(block) !((block)->read_len) diff --git a/bacula/src/stored/btape.c b/bacula/src/stored/btape.c index 868d66a93b..ff325d8cb0 100644 --- a/bacula/src/stored/btape.c +++ b/bacula/src/stored/btape.c @@ -68,6 +68,7 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec); static int my_mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); static void scan_blocks(); static void set_volume_name(char *VolName, int volnum); +static void rawfill_cmd(); /* Static variables */ @@ -108,19 +109,6 @@ static void terminate_btape(int sig); int get_cmd(char *prompt); -int write_dev(DEVICE *dev, char *buf, size_t len) -{ - Emsg0(M_ABORT, 0, "write_dev not implemented.\n"); - return 0; -} - -int read_dev(DEVICE *dev, char *buf, size_t len) -{ - Emsg0(M_ABORT, 0, "read_dev not implemented.\n"); - return 0; -} - - /********************************************************************* * * Main Bacula Pool Creation Program @@ -918,6 +906,7 @@ static void scancmd() } update_pos_dev(dev); tot_files = dev->file; + Pmsg1(0, _("Starting scan at file %u\n"), dev->file); for (;;) { if ((stat = read(dev->fd, buf, sizeof(buf))) < 0) { clrerror_dev(dev, -1); @@ -1227,7 +1216,7 @@ This may take a long time -- hours! ...\n\n"); /* Get out after writing 10 blocks to the second tape */ if (BlockNumber > 10 && stop != 0) { /* get out */ - Pmsg0(-1, "Done writing 10 blocks to second tape.\n"); + Pmsg0(-1, "Done writing ...\n"); break; } } @@ -1286,22 +1275,24 @@ static void unfillcmd() end_of_tape = 0; - /* Close device so user can use autochanger if desired */ - if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) { - offline_dev(dev); - } - force_close_dev(dev); - get_cmd(_("Mount first tape. Press enter when ready: ")); + if (!simple) { + /* Close device so user can use autochanger if desired */ + if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) { + offline_dev(dev); + } + force_close_dev(dev); + get_cmd(_("Mount first tape. Press enter when ready: ")); - free_vol_list(jcr); - set_volume_name("TestVolume1", 1); - jcr->bsr = NULL; - create_vol_list(jcr); - close_dev(dev); - dev->state &= ~ST_READ; - if (!acquire_device_for_read(jcr, dev, block)) { - Pmsg1(-1, "%s", dev->errmsg); - return; + free_vol_list(jcr); + set_volume_name("TestVolume1", 1); + jcr->bsr = NULL; + create_vol_list(jcr); + close_dev(dev); + dev->state &= ~ST_READ; + if (!acquire_device_for_read(jcr, dev, block)) { + Pmsg1(-1, "%s", dev->errmsg); + return; + } } time(&jcr->run_time); /* start counting time for rates */ @@ -1330,7 +1321,7 @@ static void unfillcmd() Pmsg1(-1, _("Forward space to file %u complete. Reading blocks ...\n"), last_file); Pmsg1(-1, _("Now reading to block %u.\n"), last_block_num); - for (uint32_t i= 0; i < last_block_num; i++) { + for (uint32_t i=0; i <= last_block_num; i++) { if (!read_block_from_device(jcr, dev, block, NO_BLOCK_NUMBER_CHECK)) { Pmsg1(-1, _("Error reading blocks: ERR=%s\n"), strerror_dev(dev)); Pmsg2(-1, _("Wanted block %u error at block %u\n"), last_block_num, i); @@ -1487,6 +1478,8 @@ static int flush_block(DEV_BLOCK *block, int dump) Pmsg0(000, strerror_dev(dev)); Pmsg3(000, "Block not written: FileIndex=%u Block=%u Size=%u\n", (unsigned)file_index, block->BlockNumber, block->block_len); + Pmsg2(000, "last_block_num=%u this_block_num=%d\n", last_block_num, + this_block_num); if (dump) { dump_block(block, "Block not written"); } @@ -1595,7 +1588,45 @@ bail_out: } +static void rawfill_cmd() +{ + DEV_BLOCK *block; + int stat; + int fd; + uint32_t block_num = 0; + uint32_t *p; + int my_errno; + block = new_block(dev); + fd = open("/dev/urandom", O_RDONLY); + if (fd) { + read(fd, block->buf, block->buf_len); + } else { + Pmsg0(0, "Cannot open /dev/urandom.\n"); + free_block(block); + return; + } + p = (uint32_t *)block->buf; + Pmsg1(0, "Begin writing blocks of %u bytes.\n", block->buf_len); + for ( ;; ) { + *p = block_num; + stat = write(dev->fd, block->buf, block->buf_len); + if (stat == (int)block->buf_len) { + if ((block_num++ % 100) == 0) { + printf("+"); + } + continue; + } + break; + } + my_errno = errno; + printf("\n"); + weofcmd(); + printf("Write failed at block %u. stat=%d ERR=%s\n", block_num, stat, + strerror(my_errno)); + free_block(block); + +} struct cmdstruct { char *key; void (*func)(); char *help; }; static struct cmdstruct commands[] = { @@ -1613,10 +1644,12 @@ static struct cmdstruct commands[] = { {"label", labelcmd, "write a Bacula label to the tape"}, {"load", loadcmd, "load a tape"}, {"quit", quitcmd, "quit btape"}, + {"rawfill", rawfill_cmd, "use write() to fill tape"}, {"readlabel", readlabelcmd, "read and print the Bacula tape label"}, {"rectest", rectestcmd, "test record handling functions"}, {"rewind", rewindcmd, "rewind the tape"}, - {"scan", scancmd, "read tape block by block to EOT and report"}, + {"scan", scancmd, "read() tape block by block to EOT and report"}, + {"scanblocks", scan_blocks, "Bacula read block by block to EOT and report"}, {"status", statcmd, "print tape status"}, {"test", testcmd, "General test Bacula tape functions"}, {"weof", weofcmd, "write an EOF on the tape"}, diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index b97a1bc3f0..8eb7acb577 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -83,11 +83,6 @@ #include "stored.h" /* Forward referenced functions */ -int dev_is_tape(DEVICE *dev); -void clrerror_dev(DEVICE *dev, int func); -int fsr_dev(DEVICE *dev, int num); - -extern int debug_level; /* * Allocate and initialize the DEVICE structure @@ -344,7 +339,7 @@ int rewind_dev(DEVICE *dev) Emsg0(M_FATAL, 0, dev->errmsg); return 0; } - dev->state &= ~(ST_APPEND|ST_READ|ST_EOT | ST_EOF | ST_WEOT); /* remove EOF/EOT flags */ + dev->state &= ~(ST_APPEND|ST_READ|ST_EOT|ST_EOF|ST_WEOT); /* remove EOF/EOT flags */ dev->block_num = dev->file = 0; dev->file_addr = 0; if (dev->state & ST_TAPE) { @@ -651,6 +646,7 @@ int offline_dev(DEVICE *dev) return 1; } + dev->state &= ~(ST_APPEND|ST_READ|ST_EOT|ST_EOF|ST_WEOT); /* remove EOF/EOT flags */ dev->block_num = dev->file = 0; dev->file_addr = 0; #ifdef MTUNLOCK diff --git a/bacula/src/stored/dircmd.c b/bacula/src/stored/dircmd.c index 9f3d8d9d54..d712b3208c 100644 --- a/bacula/src/stored/dircmd.c +++ b/bacula/src/stored/dircmd.c @@ -64,6 +64,7 @@ extern int status_cmd(JCR *sjcr); /* Forward referenced functions */ static int label_cmd(JCR *jcr); static int relabel_cmd(JCR *jcr); +static int release_cmd(JCR *jcr); static int setdebug_cmd(JCR *jcr); static int cancel_cmd(JCR *cjcr); static int mount_cmd(JCR *jcr); @@ -92,6 +93,7 @@ static struct s_cmds cmds[] = { {"unmount", unmount_cmd}, {"status", status_cmd}, {"autochanger", autochanger_cmd}, + {"release", release_cmd}, {NULL, NULL} /* list terminator */ }; @@ -672,6 +674,88 @@ static int unmount_cmd(JCR *jcr) return 1; } +/* + * Release command from Director. This rewinds the device and if + * configured does a offline and ensures that Bacula will + * re-read the label of the tape before continuing. This gives + * the operator the chance to change the tape anytime before the + * next job starts. + */ +static int release_cmd(JCR *jcr) +{ + POOLMEM *dname; + BSOCK *dir = jcr->dir_bsock; + DEVRES *device; + DEVICE *dev; + int found = 0; + + dname = get_memory(dir->msglen+1); + if (sscanf(dir->msg, "release %s", dname) == 1) { + unbash_spaces(dname); + device = NULL; + LockRes(); + while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) { + /* Find resource, and make sure we were able to open it */ + if (strcmp(device->hdr.name, dname) == 0 && device->dev) { + Dmsg1(20, "Found device %s\n", device->hdr.name); + found = 1; + break; + } + } + UnlockRes(); + if (found) { + jcr->device = device; + dev = device->dev; + P(dev->mutex); /* Use P to avoid indefinite block */ + if (!(dev->state & ST_OPENED)) { + Dmsg0(90, "Device already released\n"); + bnet_fsend(dir, _("3911 Device %s already released.\n"), dev_name(dev)); + + } else if (dev->dev_blocked == BST_WAITING_FOR_SYSOP || + dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP) { + Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting, + dev->dev_blocked); + bnet_fsend(dir, _("3912 Device %s waiting for mount.\n"), dev_name(dev)); + + } else if (dev->dev_blocked == BST_DOING_ACQUIRE) { + bnet_fsend(dir, _("3913 Device %s is busy in acquire.\n"), + dev_name(dev)); + + } else if (dev->dev_blocked == BST_WRITING_LABEL) { + bnet_fsend(dir, _("3914 Device %s is being labeled.\n"), + dev_name(dev)); + + } else if (dev->state & ST_READ || dev->num_writers) { + if (dev->state & ST_READ) { + Dmsg0(90, "Device in read mode\n"); + bnet_fsend(dir, _("3915 Device %s is busy with 1 reader.\n"), + dev_name(dev)); + } else { + Dmsg1(90, "Device busy with %d writers\n", dev->num_writers); + bnet_fsend(dir, _("3916 Device %s is busy with %d writer(s).\n"), + dev_name(dev), dev->num_writers); + } + + } else { /* device not being used */ + Dmsg0(90, "Device not in use, unmounting\n"); + release_volume(jcr, dev); + bnet_fsend(dir, _("3012 Device %s released.\n"), dev_name(dev)); + } + V(dev->mutex); + } else { + bnet_fsend(dir, _("3999 Device %s not found\n"), dname); + } + } else { + /* NB dir->msg gets clobbered in bnet_fsend, so save command */ + pm_strcpy(&jcr->errmsg, dir->msg); + bnet_fsend(dir, _("3917 Error scanning release command: %s\n"), jcr->errmsg); + } + free_memory(dname); + bnet_sig(dir, BNET_EOD); + return 1; +} + + /* * Autochanger command from Director diff --git a/bacula/src/stored/mount.c b/bacula/src/stored/mount.c index f47f53c347..2ff25f96f1 100644 --- a/bacula/src/stored/mount.c +++ b/bacula/src/stored/mount.c @@ -63,26 +63,8 @@ mount_next_vol: recycle = ask = autochanger = 0; if (release) { Dmsg0(100, "mount_next_volume release=1\n"); - /* - * First erase all memory of the current volume - */ - dev->block_num = dev->file = 0; - dev->EndBlock = dev->EndFile = 0; - memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo)); - memset(&jcr->VolCatInfo, 0, sizeof(jcr->VolCatInfo)); - memset(&dev->VolHdr, 0, sizeof(dev->VolHdr)); - dev->state &= ~ST_LABEL; /* label not yet read */ - jcr->VolumeName[0] = 0; - - if (!dev_is_tape(dev) || !dev_cap(dev, CAP_ALWAYSOPEN)) { - offline_or_rewind_dev(dev); - close_dev(dev); - } - /* If we have not closed the device, then at least rewind the tape */ - if (dev->state & ST_OPENED) { - offline_or_rewind_dev(dev); - } + release_volume(jcr, dev); ask = 1; /* ask operator to mount tape */ } @@ -378,3 +360,27 @@ int mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) Dmsg0(90, "End of Device reached.\n"); return 0; } + +void release_volume(JCR *jcr, DEVICE *dev) +{ + /* + * First erase all memory of the current volume + */ + dev->block_num = dev->file = 0; + dev->EndBlock = dev->EndFile = 0; + memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo)); + memset(&jcr->VolCatInfo, 0, sizeof(jcr->VolCatInfo)); + memset(&dev->VolHdr, 0, sizeof(dev->VolHdr)); + dev->state &= ~ST_LABEL; /* label not yet read */ + jcr->VolumeName[0] = 0; + + if (!dev_is_tape(dev) || !dev_cap(dev, CAP_ALWAYSOPEN)) { + offline_or_rewind_dev(dev); + close_dev(dev); + } + + /* If we have not closed the device, then at least rewind the tape */ + if (dev->state & ST_OPENED) { + offline_or_rewind_dev(dev); + } +} diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h index 89361d0dfb..8ef17a840a 100644 --- a/bacula/src/stored/protos.h +++ b/bacula/src/stored/protos.h @@ -147,6 +147,7 @@ int match_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, /* From mount.c */ int mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release); int mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); +void release_volume(JCR *jcr, DEVICE *dev); /* From autochanger.c */ int autoload_device(JCR *jcr, DEVICE *dev, int writing, BSOCK *dir); diff --git a/bacula/src/stored/status.c b/bacula/src/stored/status.c index 53401ed411..0b1d1a9565 100644 --- a/bacula/src/stored/status.c +++ b/bacula/src/stored/status.c @@ -101,7 +101,11 @@ int status_cmd(JCR *jcr) if (bpb <= 0) { bpb = 1; } - bpb = dev->VolCatInfo.VolCatRBytes / bpb; + if (dev->VolCatInfo.VolCatRBytes > 0) { + bpb = dev->VolCatInfo.VolCatRBytes / bpb; + } else { + bpb = 0; + } bnet_fsend(user, _(" Total Bytes Read=%s Blocks Read=%s Bytes/block=%s\n"), edit_uint64_with_commas(dev->VolCatInfo.VolCatRBytes, b1), edit_uint64_with_commas(dev->VolCatInfo.VolCatReads, b2), @@ -128,11 +132,11 @@ int status_cmd(JCR *jcr) job_type_to_str(jcr->JobType), jcr->Job); } if (jcr->device) { - bnet_fsend(user, _("%s %s job %s is using device %s volume %s\n"), + bnet_fsend(user, _("%s %s job %s using Volume \"%s\" on device %s\n"), job_level_to_str(jcr->JobLevel), job_type_to_str(jcr->JobType), - jcr->Job, jcr->device->device_name, - jcr->VolumeName); + jcr->VolumeName, + jcr->Job, jcr->device->device_name); sec = time(NULL) - jcr->run_time; if (sec <= 0) { sec = 1; @@ -197,5 +201,5 @@ static void send_blocked_status(JCR *jcr, DEVICE *dev) break; default: break; -} + } } -- 2.39.5