]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/mac.c
kes Another try at fixing Vbackup. It looks much better this time.
[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    jcr->JobFiles = 0;
117    ok = read_records(jcr->read_dcr, record_cb, mount_next_read_volume);
118    goto ok_out;
119
120 bail_out:
121    ok = false;
122
123 ok_out:
124    if (jcr->dcr) {
125       dev = jcr->dcr->dev;
126       Dmsg1(100, "ok=%d\n", ok);
127       if (ok || dev->can_write()) {
128          /* Flush out final partial block of this session */
129          if (!write_block_to_device(jcr->dcr)) {
130             Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
131                   dev->print_name(), dev->bstrerror());
132             Dmsg0(100, _("Set ok=FALSE after write_block_to_device.\n"));
133             ok = false;
134          }
135          Dmsg2(200, "Flush block to device pos %u:%u\n", dev->file, dev->block_num);
136       }  
137
138       if (!ok) {
139          discard_data_spool(jcr->dcr);
140       } else {
141          /* Note: if commit is OK, the device will remain locked */
142          commit_data_spool(jcr->dcr);
143       }
144
145       if (ok && dev->is_dvd()) {
146          ok = dvd_close_job(jcr->dcr);   /* do DVD cleanup if any */
147       }
148       /* Release the device -- and send final Vol info to DIR */
149       release_device(jcr->dcr);
150
151       if (!ok || job_canceled(jcr)) {
152          discard_attribute_spool(jcr);
153       } else {
154          commit_attribute_spool(jcr);
155       }
156    }
157
158    if (jcr->read_dcr) {
159       if (!release_device(jcr->read_dcr)) {
160          ok = false;
161       }
162    }
163
164    free_restore_volume_list(jcr);
165
166    dir_send_job_status(jcr);          /* update director */
167
168
169    Dmsg0(30, "Done reading.\n");
170    jcr->end_time = time(NULL);
171    dequeue_messages(jcr);             /* send any queued messages */
172    if (ok) {
173       set_jcr_job_status(jcr, JS_Terminated);
174    }
175    generate_daemon_event(jcr, "JobEnd");
176    dir->fsend(Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles,
177       edit_uint64(jcr->JobBytes, ec1));
178    Dmsg4(100, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles, ec1); 
179        
180    dir->signal(BNET_EOD);             /* send EOD to Director daemon */
181
182    return ok;
183 }
184
185 /*
186  * Called here for each record from read_records()
187  *  Returns: true if OK
188  *           false if error
189  */
190 static bool record_cb(DCR *dcr, DEV_RECORD *rec)
191 {
192    JCR *jcr = dcr->jcr;
193    DEVICE *dev = jcr->dcr->dev;
194    char buf1[100], buf2[100];
195    int32_t stream;   
196    
197 #ifdef xxx
198    Dmsg5(000, "on entry     JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
199       jcr->JobId,
200       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
201       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
202 #endif
203    /* If label and not for us, discard it */
204    if (rec->FileIndex < 0 && rec->match_stat <= 0) {
205       return true;
206    }
207    /* We want to write SOS_LABEL and EOS_LABEL discard all others */
208    switch (rec->FileIndex) {                        
209    case PRE_LABEL:
210    case VOL_LABEL:
211    case EOT_LABEL:
212    case EOM_LABEL:
213       return true;                    /* don't write vol labels */
214    }
215    if (jcr->get_JobType() == JT_BACKUP) {
216       /*
217        * For normal migration jobs, FileIndex values are sequential because
218        *  we are dealing with one job.  However, for Vbackup (consolidation),
219        *  we will be getting records from multiple jobs and writing them back
220        *  out, so we need to ensure that the output FileIndex is sequential.
221        *  We do so by detecting a FileIndex change and incrementing the
222        *  JobFiles, which we then use as the output FileIndex.
223        */
224       if (rec->FileIndex > 0) { 
225          /* If something changed, increment FileIndex */
226          if (rec->VolSessionId != rec->last_VolSessionId || 
227              rec->VolSessionTime != rec->last_VolSessionTime ||
228              rec->FileIndex != rec->last_FileIndex) {
229             jcr->JobFiles++;
230             rec->last_VolSessionId = rec->VolSessionId;
231             rec->last_VolSessionTime = rec->VolSessionTime;
232             rec->last_FileIndex = rec->FileIndex;
233          }
234          rec->FileIndex = jcr->JobFiles;     /* set sequential output FileIndex */
235       }
236    }
237    /*
238     * Modify record SessionId and SessionTime to correspond to
239     * output.
240     */
241    rec->VolSessionId = jcr->VolSessionId;
242    rec->VolSessionTime = jcr->VolSessionTime;
243    Dmsg5(200, "before write JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
244       jcr->JobId,
245       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
246       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
247    while (!write_record_to_block(jcr->dcr->block, rec)) {
248       Dmsg4(200, "!write_record_to_block blkpos=%u:%u len=%d rem=%d\n", 
249             dev->file, dev->block_num, rec->data_len, rec->remainder);
250       if (!write_block_to_device(jcr->dcr)) {
251          Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n",
252             dev->print_name(), dev->bstrerror());
253          Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
254                dev->print_name(), dev->bstrerror());
255          return false;
256       }
257       Dmsg2(200, "===== Wrote block new pos %u:%u\n", dev->file, dev->block_num);
258    }
259    jcr->JobBytes += rec->data_len;   /* increment bytes this job */
260    if (rec->FileIndex <= 0) {
261       return true;                    /* don't send LABELs to Dir */
262    }
263    Dmsg5(500, "wrote_record JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
264       jcr->JobId,
265       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
266       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
267
268    /* Send attributes and digest to Director for Catalog */
269    stream = rec->Stream;
270    if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_UNIX_ATTRIBUTES_EX ||
271        crypto_digest_stream_type(stream) != CRYPTO_DIGEST_NONE) {
272       if (!jcr->no_attributes) {
273          BSOCK *dir = jcr->dir_bsock;
274          if (are_attributes_spooled(jcr)) {
275             dir->set_spooling();
276          }
277          Dmsg0(850, "Send attributes to dir.\n");
278          if (!dir_update_file_attributes(jcr->dcr, rec)) {
279             dir->clear_spooling();
280             Jmsg(jcr, M_FATAL, 0, _("Error updating file attributes. ERR=%s\n"),
281                dir->bstrerror());
282             return false;
283          }
284          dir->clear_spooling();
285       }
286    }
287
288    return true;
289 }