2 * SD -- mac.c -- responsible for doing
3 * migration, archive, and copy jobs.
5 * Kern Sibbald, January MMVI
10 Bacula® - The Network Backup Solution
12 Copyright (C) 2006-2006 Free Software Foundation Europe e.V.
14 The main author of Bacula is Kern Sibbald, with contributions from
15 many others, a complete list can be found in the file AUTHORS.
16 This program is Free Software; you can redistribute it and/or
17 modify it under the terms of version two of the GNU General Public
18 License as published by the Free Software Foundation and included
21 This program is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31 Bacula® is a registered trademark of John Walker.
32 The licensor of Bacula is the Free Software Foundation Europe
33 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
34 Switzerland, email:ftf@fsfeurope.org.
40 /* Import functions */
41 extern char Job_end[];
43 /* Forward referenced subroutines */
44 static bool record_cb(DCR *dcr, DEV_RECORD *rec);
48 * Read Data and send to File Daemon
49 * Returns: false on failure
55 BSOCK *dir = jcr->dir_bsock;
60 switch(jcr->JobType) {
76 Dmsg0(20, "Start read data.\n");
78 if (!jcr->read_dcr || !jcr->dcr) {
79 Jmsg(jcr, M_FATAL, 0, _("Read and write devices not properly initialized.\n"));
82 Dmsg2(100, "read_dcr=%p write_dcr=%p\n", jcr->read_dcr, jcr->dcr);
85 create_restore_volume_list(jcr);
86 if (jcr->NumReadVolumes == 0) {
87 Jmsg(jcr, M_FATAL, 0, _("No Volume names found for %s.\n"), Type);
91 Dmsg3(200, "Found %d volumes names for %s. First=%s\n", jcr->NumReadVolumes,
92 jcr->VolList->VolumeName, Type);
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);
101 Dmsg2(200, "===== After acquire pos %u:%u\n", jcr->dcr->dev->file, jcr->dcr->dev->block_num);
103 set_jcr_job_status(jcr, JS_Running);
104 dir_send_job_status(jcr);
106 begin_data_spool(jcr->dcr);
107 begin_attribute_spool(jcr);
109 jcr->dcr->VolFirstIndex = jcr->dcr->VolLastIndex = 0;
110 jcr->run_time = time(NULL);
112 ok = read_records(jcr->read_dcr, record_cb, mount_next_read_volume);
121 if (ok || dev->can_write()) {
122 /* Flush out final partial block of this session */
123 if (!write_block_to_device(jcr->dcr)) {
124 Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
125 dev->print_name(), dev->bstrerror());
126 Dmsg0(100, _("Set ok=FALSE after write_block_to_device.\n"));
129 Dmsg2(200, "Flush block to device pos %u:%u\n", dev->file, dev->block_num);
133 discard_data_spool(jcr->dcr);
135 /* Note: if commit is OK, the device will remain locked */
136 commit_data_spool(jcr->dcr);
139 if (ok && dev->is_dvd()) {
140 ok = dvd_close_job(jcr->dcr); /* do DVD cleanup if any */
142 /* Release the device -- and send final Vol info to DIR */
143 release_device(jcr->dcr);
145 if (!ok || job_canceled(jcr)) {
146 discard_attribute_spool(jcr);
148 commit_attribute_spool(jcr);
153 if (!release_device(jcr->read_dcr)) {
158 free_restore_volume_list(jcr);
160 dir_send_job_status(jcr); /* update director */
163 Dmsg0(30, "Done reading.\n");
164 jcr->end_time = time(NULL);
165 dequeue_messages(jcr); /* send any queued messages */
167 set_jcr_job_status(jcr, JS_Terminated);
169 generate_daemon_event(jcr, "JobEnd");
170 bnet_fsend(dir, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles,
171 edit_uint64(jcr->JobBytes, ec1));
172 Dmsg4(200, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles, ec1);
174 dir->signal(BNET_EOD); /* send EOD to Director daemon */
180 * Called here for each record from read_records()
181 * Returns: true if OK
184 static bool record_cb(DCR *dcr, DEV_RECORD *rec)
187 DEVICE *dev = jcr->dcr->dev;
188 char buf1[100], buf2[100];
191 /* If label and not for us, discard it */
192 if (rec->FileIndex < 0 && rec->match_stat <= 0) {
195 /* We want to write SOS_LABEL and EOS_LABEL discard all others */
196 switch (rec->FileIndex) {
201 return true; /* don't write vol labels */
204 * Modify record SessionId and SessionTime to correspond to
207 rec->VolSessionId = jcr->VolSessionId;
208 rec->VolSessionTime = jcr->VolSessionTime;
209 Dmsg5(200, "before write_rec JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
211 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
212 stream_to_ascii(buf1, rec->Stream,rec->FileIndex), rec->data_len);
214 while (!write_record_to_block(jcr->dcr->block, rec)) {
215 Dmsg4(200, "!write_record_to_block blkpos=%u:%u len=%d rem=%d\n",
216 dev->file, dev->block_num, rec->data_len, rec->remainder);
217 if (!write_block_to_device(jcr->dcr)) {
218 Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n",
219 dev->print_name(), dev->bstrerror());
220 Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
221 dev->print_name(), dev->bstrerror());
224 Dmsg2(200, "===== Wrote block new pos %u:%u\n", dev->file, dev->block_num);
226 jcr->JobBytes += rec->data_len; /* increment bytes this job */
227 if (rec->FileIndex > 0) {
228 jcr->JobFiles = rec->FileIndex;
230 return true; /* don't send LABELs to Dir */
232 Dmsg5(500, "wrote_record JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
234 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
235 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
237 /* Send attributes and digest to Director for Catalog */
238 stream = rec->Stream;
239 if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_UNIX_ATTRIBUTES_EX ||
240 crypto_digest_stream_type(stream) != CRYPTO_DIGEST_NONE) {
241 if (!jcr->no_attributes) {
242 if (are_attributes_spooled(jcr)) {
243 jcr->dir_bsock->set_spooling();
245 Dmsg0(850, "Send attributes to dir.\n");
246 if (!dir_update_file_attributes(jcr->dcr, rec)) {
247 jcr->dir_bsock->clear_spooling();
248 Jmsg(jcr, M_FATAL, 0, _("Error updating file attributes. ERR=%s\n"),
249 bnet_strerror(jcr->dir_bsock));
252 jcr->dir_bsock->clear_spooling();