]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/mac.c
f58ba6380cfc70a01f0b6c544ce27b8fcbc0763f
[bacula/bacula] / bacula / src / stored / mac.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2006-2010 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  */
35
36 #include "bacula.h"
37 #include "stored.h"
38
39 /* Import functions */
40 extern char Job_end[];   
41
42 /* Forward referenced subroutines */
43 static bool record_cb(DCR *dcr, DEV_RECORD *rec);
44
45
46 /*
47  *  Read Data and send to File Daemon
48  *   Returns: false on failure
49  *            true  on success
50  */
51 bool do_mac(JCR *jcr)
52 {
53    bool ok = true;
54    BSOCK *dir = jcr->dir_bsock;
55    const char *Type;
56    char ec1[50];
57    DEVICE *dev;
58
59    switch(jcr->getJobType()) {
60    case JT_MIGRATE:
61       Type = "Migration";
62       break;
63    case JT_ARCHIVE:
64       Type = "Archive";
65       break;
66    case JT_COPY:
67       Type = "Copy";
68       break;
69    case JT_BACKUP:
70       Type = "Virtual Backup";
71       break;
72    default:
73       Type = "Unknown";
74       break;
75    }
76
77
78    Dmsg0(20, "Start read data.\n");
79
80    if (!jcr->read_dcr || !jcr->dcr) {
81       Jmsg(jcr, M_FATAL, 0, _("Read and write devices not properly initialized.\n"));
82       goto bail_out;
83    }
84    Dmsg2(100, "read_dcr=%p write_dcr=%p\n", jcr->read_dcr, jcr->dcr);
85
86    if (jcr->NumReadVolumes == 0) {
87       Jmsg(jcr, M_FATAL, 0, _("No Volume names found for %s.\n"), Type);
88       goto bail_out;
89    }
90
91    Dmsg3(200, "Found %d volumes names for %s. First=%s\n", jcr->NumReadVolumes,
92       jcr->VolList->VolumeName, Type);
93
94    /* Ready devices for reading and writing */
95    if (!acquire_device_for_read(jcr->read_dcr) ||
96        !acquire_device_for_append(jcr->dcr)) {
97       set_jcr_job_status(jcr, JS_ErrorTerminated);
98       goto bail_out;
99    }
100
101    Dmsg2(200, "===== After acquire pos %u:%u\n", jcr->dcr->dev->file, jcr->dcr->dev->block_num);
102      
103    set_jcr_job_status(jcr, JS_Running);
104    dir_send_job_status(jcr);
105
106    begin_data_spool(jcr->dcr);
107    begin_attribute_spool(jcr);
108
109    jcr->dcr->VolFirstIndex = jcr->dcr->VolLastIndex = 0;
110    jcr->run_time = time(NULL);
111    set_start_vol_position(jcr->dcr);
112
113    jcr->JobFiles = 0;
114    ok = read_records(jcr->read_dcr, record_cb, mount_next_read_volume);
115    goto ok_out;
116
117 bail_out:
118    ok = false;
119
120 ok_out:
121    if (jcr->dcr) {
122       dev = jcr->dcr->dev;
123       Dmsg1(100, "ok=%d\n", ok);
124       if (ok || dev->can_write()) {
125          /* Flush out final partial block of this session */
126          if (!write_block_to_device(jcr->dcr)) {
127             Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
128                   dev->print_name(), dev->bstrerror());
129             Dmsg0(100, _("Set ok=FALSE after write_block_to_device.\n"));
130             ok = false;
131          }
132          Dmsg2(200, "Flush block to device pos %u:%u\n", dev->file, dev->block_num);
133       }  
134
135       if (!ok) {
136          discard_data_spool(jcr->dcr);
137       } else {
138          /* Note: if commit is OK, the device will remain blocked */
139          commit_data_spool(jcr->dcr);
140       }
141
142       if (ok && dev->is_dvd()) {
143          ok = dvd_close_job(jcr->dcr);   /* do DVD cleanup if any */
144       }
145       /* Release the device -- and send final Vol info to DIR */
146       release_device(jcr->dcr);
147
148       if (!ok || job_canceled(jcr)) {
149          discard_attribute_spool(jcr);
150       } else {
151          commit_attribute_spool(jcr);
152       }
153    }
154
155    if (jcr->read_dcr) {
156       if (!release_device(jcr->read_dcr)) {
157          ok = false;
158       }
159    }
160
161    dir_send_job_status(jcr);          /* update director */
162
163    Dmsg0(30, "Done reading.\n");
164    jcr->end_time = time(NULL);
165    dequeue_messages(jcr);             /* send any queued messages */
166    if (ok) {
167       set_jcr_job_status(jcr, JS_Terminated);
168    }
169    generate_daemon_event(jcr, "JobEnd");
170    dir->fsend(Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles,
171       edit_uint64(jcr->JobBytes, ec1), jcr->JobErrors);
172    Dmsg4(100, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles, ec1); 
173        
174    dir->signal(BNET_EOD);             /* send EOD to Director daemon */
175
176    return ok;
177 }
178
179 /*
180  * Called here for each record from read_records()
181  *  Returns: true if OK
182  *           false if error
183  */
184 static bool record_cb(DCR *dcr, DEV_RECORD *rec)
185 {
186    JCR *jcr = dcr->jcr;
187    DEVICE *dev = jcr->dcr->dev;
188    char buf1[100], buf2[100];
189    int32_t stream;   
190    
191 #ifdef xxx
192    Dmsg5(000, "on entry     JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
193       jcr->JobId,
194       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
195       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
196 #endif
197    /* If label and not for us, discard it */
198    if (rec->FileIndex < 0 && rec->match_stat <= 0) {
199       return true;
200    }
201    /* We want to write SOS_LABEL and EOS_LABEL discard all others */
202    switch (rec->FileIndex) {                        
203    case PRE_LABEL:
204    case VOL_LABEL:
205    case EOT_LABEL:
206    case EOM_LABEL:
207       return true;                    /* don't write vol labels */
208    }
209 //   if (jcr->getJobType() == JT_BACKUP) {
210       /*
211        * For normal migration jobs, FileIndex values are sequential because
212        *  we are dealing with one job.  However, for Vbackup (consolidation),
213        *  we will be getting records from multiple jobs and writing them back
214        *  out, so we need to ensure that the output FileIndex is sequential.
215        *  We do so by detecting a FileIndex change and incrementing the
216        *  JobFiles, which we then use as the output FileIndex.
217        */
218       if (rec->FileIndex >= 0) { 
219          /* If something changed, increment FileIndex */
220          if (rec->VolSessionId != rec->last_VolSessionId || 
221              rec->VolSessionTime != rec->last_VolSessionTime ||
222              rec->FileIndex != rec->last_FileIndex) {
223             jcr->JobFiles++;
224             rec->last_VolSessionId = rec->VolSessionId;
225             rec->last_VolSessionTime = rec->VolSessionTime;
226             rec->last_FileIndex = rec->FileIndex;
227          }
228          rec->FileIndex = jcr->JobFiles;     /* set sequential output FileIndex */
229       }
230 //   }
231    /*
232     * Modify record SessionId and SessionTime to correspond to
233     * output.
234     */
235    rec->VolSessionId = jcr->VolSessionId;
236    rec->VolSessionTime = jcr->VolSessionTime;
237    Dmsg5(200, "before write JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
238       jcr->JobId,
239       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
240       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
241    while (!write_record_to_block(jcr->dcr->block, rec)) {
242       Dmsg4(200, "!write_record_to_block blkpos=%u:%u len=%d rem=%d\n", 
243             dev->file, dev->block_num, rec->data_len, rec->remainder);
244       if (!write_block_to_device(jcr->dcr)) {
245          Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n",
246             dev->print_name(), dev->bstrerror());
247          Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
248                dev->print_name(), dev->bstrerror());
249          return false;
250       }
251       Dmsg2(200, "===== Wrote block new pos %u:%u\n", dev->file, dev->block_num);
252    }
253    /* Restore packet */
254    rec->VolSessionId = rec->last_VolSessionId;
255    rec->VolSessionTime = rec->last_VolSessionTime;
256    if (rec->FileIndex < 0) {
257       return true;                    /* don't send LABELs to Dir */
258    }
259    jcr->JobBytes += rec->data_len;   /* increment bytes this job */
260    Dmsg5(500, "wrote_record JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
261       jcr->JobId,
262       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
263       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
264
265    /* Send attributes and digest to Director for Catalog */
266    stream = rec->Stream;
267    if (stream == STREAM_UNIX_ATTRIBUTES    || 
268        stream == STREAM_UNIX_ATTRIBUTES_EX ||
269        crypto_digest_stream_type(stream) != CRYPTO_DIGEST_NONE) {
270       if (!jcr->no_attributes) {
271          BSOCK *dir = jcr->dir_bsock;
272          if (are_attributes_spooled(jcr)) {
273             dir->set_spooling();
274          }
275          Dmsg0(850, "Send attributes to dir.\n");
276          if (!dir_update_file_attributes(jcr->dcr, rec)) {
277             dir->clear_spooling();
278             Jmsg(jcr, M_FATAL, 0, _("Error updating file attributes. ERR=%s\n"),
279                dir->bstrerror());
280             return false;
281          }
282          dir->clear_spooling();
283       }
284    }
285
286    return true;
287 }