]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/mac.c
Fix migration code broken by previous virtual backup fix
[bacula/bacula] / bacula / src / stored / mac.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2006-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * SD -- mac.c --  responsible for doing
30  *     migration, archive, copy, and virtual backup jobs.
31  *
32  *     Kern Sibbald, January MMVI
33  *
34  *   Version $Id$
35  */
36
37 #include "bacula.h"
38 #include "stored.h"
39
40 /* Import functions */
41 extern char Job_end[];   
42
43 /* Forward referenced subroutines */
44 static bool record_cb(DCR *dcr, DEV_RECORD *rec);
45
46
47 /*
48  *  Read Data and send to File Daemon
49  *   Returns: false on failure
50  *            true  on success
51  */
52 bool do_mac(JCR *jcr)
53 {
54    bool ok = true;
55    BSOCK *dir = jcr->dir_bsock;
56    const char *Type;
57    char ec1[50];
58    DEVICE *dev;
59
60    switch(jcr->get_JobType()) {
61    case JT_MIGRATE:
62       Type = "Migration";
63       break;
64    case JT_ARCHIVE:
65       Type = "Archive";
66       break;
67    case JT_COPY:
68       Type = "Copy";
69       break;
70    case JT_BACKUP:
71       Type = "Virtual Backup";
72       break;
73    default:
74       Type = "Unknown";
75       break;
76    }
77
78
79    Dmsg0(20, "Start read data.\n");
80
81    if (!jcr->read_dcr || !jcr->dcr) {
82       Jmsg(jcr, M_FATAL, 0, _("Read and write devices not properly initialized.\n"));
83       goto bail_out;
84    }
85    Dmsg2(100, "read_dcr=%p write_dcr=%p\n", jcr->read_dcr, jcr->dcr);
86
87
88    create_restore_volume_list(jcr);
89    if (jcr->NumReadVolumes == 0) {
90       Jmsg(jcr, M_FATAL, 0, _("No Volume names found for %s.\n"), Type);
91       goto bail_out;
92    }
93
94    Dmsg3(200, "Found %d volumes names for %s. First=%s\n", jcr->NumReadVolumes,
95       jcr->VolList->VolumeName, Type);
96
97    /* Ready devices for reading and writing */
98    if (!acquire_device_for_read(jcr->read_dcr) ||
99        !acquire_device_for_append(jcr->dcr)) {
100       set_jcr_job_status(jcr, JS_ErrorTerminated);
101       goto bail_out;
102    }
103
104    Dmsg2(200, "===== After acquire pos %u:%u\n", jcr->dcr->dev->file, jcr->dcr->dev->block_num);
105      
106    set_jcr_job_status(jcr, JS_Running);
107    dir_send_job_status(jcr);
108
109    begin_data_spool(jcr->dcr);
110    begin_attribute_spool(jcr);
111
112    jcr->dcr->VolFirstIndex = jcr->dcr->VolLastIndex = 0;
113    jcr->run_time = time(NULL);
114    set_start_vol_position(jcr->dcr);
115
116    ok = read_records(jcr->read_dcr, record_cb, mount_next_read_volume);
117    goto ok_out;
118
119 bail_out:
120    ok = false;
121
122 ok_out:
123    if (jcr->dcr) {
124       dev = jcr->dcr->dev;
125       Dmsg1(100, "ok=%d\n", ok);
126       if (ok || dev->can_write()) {
127          /* Flush out final partial block of this session */
128          if (!write_block_to_device(jcr->dcr)) {
129             Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
130                   dev->print_name(), dev->bstrerror());
131             Dmsg0(100, _("Set ok=FALSE after write_block_to_device.\n"));
132             ok = false;
133          }
134          Dmsg2(200, "Flush block to device pos %u:%u\n", dev->file, dev->block_num);
135       }  
136
137       if (!ok) {
138          discard_data_spool(jcr->dcr);
139       } else {
140          /* Note: if commit is OK, the device will remain locked */
141          commit_data_spool(jcr->dcr);
142       }
143
144       if (ok && dev->is_dvd()) {
145          ok = dvd_close_job(jcr->dcr);   /* do DVD cleanup if any */
146       }
147       /* Release the device -- and send final Vol info to DIR */
148       release_device(jcr->dcr);
149
150       if (!ok || job_canceled(jcr)) {
151          discard_attribute_spool(jcr);
152       } else {
153          commit_attribute_spool(jcr);
154       }
155    }
156
157    if (jcr->read_dcr) {
158       if (!release_device(jcr->read_dcr)) {
159          ok = false;
160       }
161    }
162
163    free_restore_volume_list(jcr);
164
165    dir_send_job_status(jcr);          /* update director */
166
167
168    Dmsg0(30, "Done reading.\n");
169    jcr->end_time = time(NULL);
170    dequeue_messages(jcr);             /* send any queued messages */
171    if (ok) {
172       set_jcr_job_status(jcr, JS_Terminated);
173    }
174    generate_daemon_event(jcr, "JobEnd");
175    dir->fsend(Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles,
176       edit_uint64(jcr->JobBytes, ec1));
177    Dmsg4(100, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles, ec1); 
178        
179    dir->signal(BNET_EOD);             /* send EOD to Director daemon */
180
181    return ok;
182 }
183
184 /*
185  * Called here for each record from read_records()
186  *  Returns: true if OK
187  *           false if error
188  */
189 static bool record_cb(DCR *dcr, DEV_RECORD *rec)
190 {
191    JCR *jcr = dcr->jcr;
192    DEVICE *dev = jcr->dcr->dev;
193    char buf1[100], buf2[100];
194    int32_t stream;   
195    uint32_t last_VolSessionId = 0;
196    uint32_t last_VolSessionTime = 0;
197    int32_t  last_FileIndex = 0;
198    
199    /* If label and not for us, discard it */
200    if (rec->FileIndex < 0 && rec->match_stat <= 0) {
201       return true;
202    }
203    /* We want to write SOS_LABEL and EOS_LABEL discard all others */
204    switch (rec->FileIndex) {                        
205    case PRE_LABEL:
206    case VOL_LABEL:
207    case EOT_LABEL:
208    case EOM_LABEL:
209       return true;                    /* don't write vol labels */
210    }
211    if (jcr->get_JobType() == JT_BACKUP) {
212       /*
213        * For normal migration jobs, FileIndex values are sequential because
214        *  we are dealing with one job.  However, for Vbackup (consolidation),
215        *  we will be getting records from multiple jobs and writing them back
216        *  out, so we need to ensure that the output FileIndex is sequential.
217        *  We do so by detecting a FileIndex change and incrementing the
218        *  JobFiles, which we then use as the output FileIndex.
219        */
220       if (rec->VolSessionId != last_VolSessionId || 
221           rec->VolSessionTime != last_VolSessionTime ||
222           (rec->FileIndex > 0 && rec->FileIndex != last_FileIndex)) {
223          jcr->JobFiles++;
224          last_VolSessionId = rec->VolSessionId;
225          last_VolSessionTime = rec->VolSessionTime;
226          last_FileIndex = rec->FileIndex;
227       }
228       if (rec->FileIndex > 0) {
229          rec->FileIndex = jcr->JobFiles;     /* set sequential output FileIndex */
230       }
231    }
232    /*
233     * Modify record SessionId and SessionTime to correspond to
234     * output.
235     */
236    rec->VolSessionId = jcr->VolSessionId;
237    rec->VolSessionTime = jcr->VolSessionTime;
238    Dmsg5(200, "before write_rec JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
239       jcr->JobId,
240       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
241       stream_to_ascii(buf1, rec->Stream,rec->FileIndex), rec->data_len);
242
243    while (!write_record_to_block(jcr->dcr->block, rec)) {
244       Dmsg4(200, "!write_record_to_block blkpos=%u:%u len=%d rem=%d\n", 
245             dev->file, dev->block_num, rec->data_len, rec->remainder);
246       if (!write_block_to_device(jcr->dcr)) {
247          Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n",
248             dev->print_name(), dev->bstrerror());
249          Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
250                dev->print_name(), dev->bstrerror());
251          return false;
252       }
253       Dmsg2(200, "===== Wrote block new pos %u:%u\n", dev->file, dev->block_num);
254    }
255    jcr->JobBytes += rec->data_len;   /* increment bytes this job */
256    if (rec->FileIndex <= 0) {
257       return true;                    /* don't send LABELs to Dir */
258    }
259    Dmsg5(500, "wrote_record JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
260       jcr->JobId,
261       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
262       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
263
264    /* Send attributes and digest to Director for Catalog */
265    stream = rec->Stream;
266    if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_UNIX_ATTRIBUTES_EX ||
267        crypto_digest_stream_type(stream) != CRYPTO_DIGEST_NONE) {
268       if (!jcr->no_attributes) {
269          BSOCK *dir = jcr->dir_bsock;
270          if (are_attributes_spooled(jcr)) {
271             dir->set_spooling();
272          }
273          Dmsg0(850, "Send attributes to dir.\n");
274          if (!dir_update_file_attributes(jcr->dcr, rec)) {
275             dir->clear_spooling();
276             Jmsg(jcr, M_FATAL, 0, _("Error updating file attributes. ERR=%s\n"),
277                dir->bstrerror());
278             return false;
279          }
280          dir->clear_spooling();
281       }
282    }
283
284    return true;
285 }