]> git.sur5r.net Git - bacula/bacula/commitdiff
New query.sql, JobMedia VolIndex, add Release command
authorKern Sibbald <kern@sibbald.com>
Fri, 6 Jun 2003 17:22:33 +0000 (17:22 +0000)
committerKern Sibbald <kern@sibbald.com>
Fri, 6 Jun 2003 17:22:33 +0000 (17:22 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@566 91ce42f0-d328-0410-95d8-f526ca767f89

18 files changed:
bacula/kernstodo
bacula/src/cats/sql_create.c
bacula/src/cats/sql_find.c
bacula/src/cats/sql_get.c
bacula/src/dird/bacula-dir.conf.in
bacula/src/dird/dird.c
bacula/src/dird/query.sql
bacula/src/dird/ua_cmds.c
bacula/src/dird/ua_dotcmds.c
bacula/src/findlib/create_file.c
bacula/src/stored/block.c
bacula/src/stored/block.h
bacula/src/stored/btape.c
bacula/src/stored/dev.c
bacula/src/stored/dircmd.c
bacula/src/stored/mount.c
bacula/src/stored/protos.h
bacula/src/stored/status.c

index 27cb30d5b820a0d029793f400a7db9f3d165514b..224b4136885623ee8148288dd4d9582db091f230 100644 (file)
@@ -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
index 0cc5deb0e2a8ae4858926264b584b03338fdbcd3..670570c0098bb70fa96c3a0b769131794c0f6588 100644 (file)
@@ -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)) {
index 0dab06bccee983d987b0145316f091c0662ee274..ec5815010a429e8536c912b6dcfbf5fe784deda1 100644 (file)
@@ -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;
       }
index 1adaa39e2e9bfff1b97d7053d25cdf9198af43bd..7369abbcc9d5cc5cd88e433c9cd70c22d4c5fad9 100644 (file)
@@ -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)) {
index fc07bc837dc1f39d608c165f27e6dbc2af84e940..a51ab2b870aa05161fab19aa12cc8342d0933d1c 100644 (file)
@@ -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)
index 0df270545d8ec17f8706ef3b3c6979807cb7cb7c..c5e1f5ef0a345a3a9b93745c2b31aeac9e796980 100644 (file)
@@ -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. 
index 0cecb5b45f19d41042293bd9836ae8fc3f9cbda8..9cbd51f0fa8d35b4ea4dabf054343816722c5e33 100644 (file)
@@ -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,
index 44eaf6935a3876e0148832414bbf1082ccb65d75..d5133b2361f94c88b40628b52e4863cd63caa0cf 100644 (file)
@@ -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=<pool-name> | media volume=<volume-name>]")},    
- { N_("help"),       helpcmd,      _("print this command")},
+ { N_("delete"),     delete_cmd,    _("delete [pool=<pool-name> | media volume=<volume-name>]")},    
+ { 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 <pool> | files job=<nn>]; from catalog")},
  { N_("llist"),      llistcmd,     _("full or long list like list command")},
  { N_("messages"),   messagescmd,  _("messages")},
- { N_("mount"),      mountcmd,     _("mount <storage-name>")},
+ { N_("mount"),      mount_cmd,     _("mount <storage-name>")},
  { N_("restore"),    restorecmd,   _("restore files")},
  { N_("prune"),      prunecmd,     _("prune expired records from catalog")},
  { N_("purge"),      purgecmd,     _("purge records from catalog")},
  { N_("run"),        runcmd,       _("run <job-name>")},
- { 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]=<name>")},
- { N_("unmount"),    unmountcmd,   _("unmount <storage-name>")},
- { 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 <storage-name>")},
+ { 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 <storage-name>")},
+ { 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=<pool-name> volume=<volume-name>
  *        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=<pool-name>
  *  delete media pool=<pool-name> volume=<name>
  */
-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] <name>
  */
-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] <name>
  */
-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] <name>
+ */
+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=<name>
  */
-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;
index 4f85e6e2efb8df3ade32f38512a0ef06a0524ee4..698ec67f0a776a91950886b636fab1fb0a9361cd 100644 (file)
@@ -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))
 
index f231553c361274cd7edbdb54c724ea0052dc4d3a..37e7c3e84b74694873579c91665488df68a89723 100644 (file)
@@ -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 */
 
index a9dac5700909041bcf5b3bbaaf4c638f2a0fc906..ed20383c1152f4a93856b828ed989540e08558a7 100644 (file)
@@ -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);
index 551804c20d68e4453935dbc41587f6f6cf9d042c..1f762415249f3311bd23732316703b7dcb668bc4 100644 (file)
 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)
index 868d66a93b99b3fb1311ce756e6e04ee23e846ce..ff325d8cb0614aa2ab39be529412b0e634d128a3 100644 (file)
@@ -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"},
index b97a1bc3f0444051cf076e7155b2cf9d56deb2ef..8eb7acb5776cafe73903e984986c6b4b42d81581 100644 (file)
 #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
index 9f3d8d9d546513ccaa51856e7f7a66d8d296db3b..d712b3208c771e0d3a88315e6540fb784679d8fc 100644 (file)
@@ -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
index f47f53c347c3671db4657cb2c5b14e1c9e085f3b..2ff25f96f145203e766f8ade6827dccc56b67487 100644 (file)
@@ -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);
+   }
+}
index 89361d0dfbfb0e4c0fd72f1136fe34c03c479f0d..8ef17a840abc8546b04578ab4bcb935a7eb9cb6f 100644 (file)
@@ -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);
index 53401ed4114af10c4645b0b346a0079b5fa73e9f..0b1d1a956590b2bae0d9ffdd8a0269b3dba09649 100644 (file)
@@ -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;
-}
+   }
 }