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 plus additions
19 that are listed in the file LICENSE.
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);
104 set_jcr_job_status(jcr, JS_Running);
105 dir_send_job_status(jcr);
107 jcr->dcr->VolFirstIndex = jcr->dcr->VolLastIndex = 0;
108 jcr->run_time = time(NULL);
110 ok = read_records(jcr->read_dcr, record_cb, mount_next_read_volume);
119 if (ok || dev->can_write()) {
120 /* Flush out final partial block of this session */
121 if (!write_block_to_device(jcr->dcr)) {
122 Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
123 dev->print_name(), dev->bstrerror());
124 Dmsg0(100, _("Set ok=FALSE after write_block_to_device.\n"));
127 Dmsg2(200, "Flush block to device pos %u:%u\n", dev->file, dev->block_num);
131 if (ok && dev->is_dvd()) {
132 ok = dvd_close_job(jcr->dcr); /* do DVD cleanup if any */
134 /* Release the device -- and send final Vol info to DIR */
135 release_device(jcr->dcr);
139 if (!release_device(jcr->read_dcr)) {
144 free_restore_volume_list(jcr);
147 if (!ok || job_canceled(jcr)) {
148 discard_attribute_spool(jcr);
150 commit_attribute_spool(jcr);
153 dir_send_job_status(jcr); /* update director */
156 Dmsg0(30, "Done reading.\n");
157 jcr->end_time = time(NULL);
158 dequeue_messages(jcr); /* send any queued messages */
160 set_jcr_job_status(jcr, JS_Terminated);
162 generate_daemon_event(jcr, "JobEnd");
163 bnet_fsend(dir, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles,
164 edit_uint64(jcr->JobBytes, ec1));
165 Dmsg4(200, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles, ec1);
167 dir->signal(BNET_EOD); /* send EOD to Director daemon */
173 * Called here for each record from read_records()
174 * Returns: true if OK
177 static bool record_cb(DCR *dcr, DEV_RECORD *rec)
180 DEVICE *dev = jcr->dcr->dev;
181 char buf1[100], buf2[100];
184 /* If label and not for us, discard it */
185 if (rec->FileIndex < 0 && rec->match_stat <= 0) {
188 /* We want to write SOS_LABEL and EOS_LABEL discard all others */
189 switch (rec->FileIndex) {
194 return true; /* don't write vol labels */
197 * Modify record SessionId and SessionTime to correspond to
200 rec->VolSessionId = jcr->VolSessionId;
201 rec->VolSessionTime = jcr->VolSessionTime;
202 Dmsg5(200, "before write_rec JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
204 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
205 stream_to_ascii(buf1, rec->Stream,rec->FileIndex), rec->data_len);
207 while (!write_record_to_block(jcr->dcr->block, rec)) {
208 Dmsg4(200, "!write_record_to_block blkpos=%u:%u len=%d rem=%d\n",
209 dev->file, dev->block_num, rec->data_len, rec->remainder);
210 if (!write_block_to_device(jcr->dcr)) {
211 Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n",
212 dev->print_name(), dev->bstrerror());
213 Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
214 dev->print_name(), dev->bstrerror());
217 Dmsg2(200, "===== Wrote block new pos %u:%u\n", dev->file, dev->block_num);
219 jcr->JobBytes += rec->data_len; /* increment bytes this job */
220 if (rec->FileIndex > 0) {
221 jcr->JobFiles = rec->FileIndex;
223 return true; /* don't send LABELs to Dir */
225 Dmsg5(500, "wrote_record JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
227 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
228 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
230 /* Send attributes and digest to Director for Catalog */
231 stream = rec->Stream;
232 if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_UNIX_ATTRIBUTES_EX ||
233 crypto_digest_stream_type(stream) != CRYPTO_DIGEST_NONE) {
234 if (!jcr->no_attributes) {
235 if (are_attributes_spooled(jcr)) {
236 jcr->dir_bsock->spool = true;
238 Dmsg0(850, "Send attributes to dir.\n");
239 if (!dir_update_file_attributes(jcr->dcr, rec)) {
240 jcr->dir_bsock->spool = false;
241 Jmsg(jcr, M_FATAL, 0, _("Error updating file attributes. ERR=%s\n"),
242 bnet_strerror(jcr->dir_bsock));
245 jcr->dir_bsock->spool = false;