]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/mac.c
Small tweaks to locking code no substantial change
[bacula/bacula] / bacula / src / stored / mac.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2006-2009 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->getJobType()) {
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    if (jcr->NumReadVolumes == 0) {
88       Jmsg(jcr, M_FATAL, 0, _("No Volume names found for %s.\n"), Type);
89       goto bail_out;
90    }
91
92    Dmsg3(200, "Found %d volumes names for %s. First=%s\n", jcr->NumReadVolumes,
93       jcr->VolList->VolumeName, Type);
94
95    /* Ready devices for reading and writing */
96    if (!acquire_device_for_read(jcr->read_dcr) ||
97        !acquire_device_for_append(jcr->dcr)) {
98       set_jcr_job_status(jcr, JS_ErrorTerminated);
99       goto bail_out;
100    }
101
102    Dmsg2(200, "===== After acquire pos %u:%u\n", jcr->dcr->dev->file, jcr->dcr->dev->block_num);
103      
104    set_jcr_job_status(jcr, JS_Running);
105    dir_send_job_status(jcr);
106
107    begin_data_spool(jcr->dcr);
108    begin_attribute_spool(jcr);
109
110    jcr->dcr->VolFirstIndex = jcr->dcr->VolLastIndex = 0;
111    jcr->run_time = time(NULL);
112    set_start_vol_position(jcr->dcr);
113
114    jcr->JobFiles = 0;
115    ok = read_records(jcr->read_dcr, record_cb, mount_next_read_volume);
116    goto ok_out;
117
118 bail_out:
119    ok = false;
120
121 ok_out:
122    if (jcr->dcr) {
123       dev = jcr->dcr->dev;
124       Dmsg1(100, "ok=%d\n", ok);
125       if (ok || dev->can_write()) {
126          /* Flush out final partial block of this session */
127          if (!write_block_to_device(jcr->dcr)) {
128             Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
129                   dev->print_name(), dev->bstrerror());
130             Dmsg0(100, _("Set ok=FALSE after write_block_to_device.\n"));
131             ok = false;
132          }
133          Dmsg2(200, "Flush block to device pos %u:%u\n", dev->file, dev->block_num);
134       }  
135
136       if (!ok) {
137          discard_data_spool(jcr->dcr);
138       } else {
139          /* Note: if commit is OK, the device will remain locked */
140          commit_data_spool(jcr->dcr);
141       }
142
143       if (ok && dev->is_dvd()) {
144          ok = dvd_close_job(jcr->dcr);   /* do DVD cleanup if any */
145       }
146       /* Release the device -- and send final Vol info to DIR */
147       release_device(jcr->dcr);
148
149       if (!ok || job_canceled(jcr)) {
150          discard_attribute_spool(jcr);
151       } else {
152          commit_attribute_spool(jcr);
153       }
154    }
155
156    if (jcr->read_dcr) {
157       if (!release_device(jcr->read_dcr)) {
158          ok = false;
159       }
160    }
161
162    dir_send_job_status(jcr);          /* update director */
163
164    Dmsg0(30, "Done reading.\n");
165    jcr->end_time = time(NULL);
166    dequeue_messages(jcr);             /* send any queued messages */
167    if (ok) {
168       set_jcr_job_status(jcr, JS_Terminated);
169    }
170    generate_daemon_event(jcr, "JobEnd");
171    dir->fsend(Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles,
172       edit_uint64(jcr->JobBytes, ec1), jcr->JobErrors);
173    Dmsg4(100, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles, ec1); 
174        
175    dir->signal(BNET_EOD);             /* send EOD to Director daemon */
176
177    return ok;
178 }
179
180 /*
181  * Called here for each record from read_records()
182  *  Returns: true if OK
183  *           false if error
184  */
185 static bool record_cb(DCR *dcr, DEV_RECORD *rec)
186 {
187    JCR *jcr = dcr->jcr;
188    DEVICE *dev = jcr->dcr->dev;
189    char buf1[100], buf2[100];
190    int32_t stream;   
191    
192 #ifdef xxx
193    Dmsg5(000, "on entry     JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
194       jcr->JobId,
195       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
196       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
197 #endif
198    /* If label and not for us, discard it */
199    if (rec->FileIndex < 0 && rec->match_stat <= 0) {
200       return true;
201    }
202    /* We want to write SOS_LABEL and EOS_LABEL discard all others */
203    switch (rec->FileIndex) {                        
204    case PRE_LABEL:
205    case VOL_LABEL:
206    case EOT_LABEL:
207    case EOM_LABEL:
208       return true;                    /* don't write vol labels */
209    }
210 //   if (jcr->getJobType() == JT_BACKUP) {
211       /*
212        * For normal migration jobs, FileIndex values are sequential because
213        *  we are dealing with one job.  However, for Vbackup (consolidation),
214        *  we will be getting records from multiple jobs and writing them back
215        *  out, so we need to ensure that the output FileIndex is sequential.
216        *  We do so by detecting a FileIndex change and incrementing the
217        *  JobFiles, which we then use as the output FileIndex.
218        */
219       if (rec->FileIndex >= 0) { 
220          /* If something changed, increment FileIndex */
221          if (rec->VolSessionId != rec->last_VolSessionId || 
222              rec->VolSessionTime != rec->last_VolSessionTime ||
223              rec->FileIndex != rec->last_FileIndex) {
224             jcr->JobFiles++;
225             rec->last_VolSessionId = rec->VolSessionId;
226             rec->last_VolSessionTime = rec->VolSessionTime;
227             rec->last_FileIndex = rec->FileIndex;
228          }
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 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(buf2, rec->Stream, rec->FileIndex), rec->data_len);
242    while (!write_record_to_block(jcr->dcr->block, rec)) {
243       Dmsg4(200, "!write_record_to_block blkpos=%u:%u len=%d rem=%d\n", 
244             dev->file, dev->block_num, rec->data_len, rec->remainder);
245       if (!write_block_to_device(jcr->dcr)) {
246          Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n",
247             dev->print_name(), dev->bstrerror());
248          Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
249                dev->print_name(), dev->bstrerror());
250          return false;
251       }
252       Dmsg2(200, "===== Wrote block new pos %u:%u\n", dev->file, dev->block_num);
253    }
254    /* Restore packet */
255    rec->VolSessionId = rec->last_VolSessionId;
256    rec->VolSessionTime = rec->last_VolSessionTime;
257    if (rec->FileIndex < 0) {
258       return true;                    /* don't send LABELs to Dir */
259    }
260    jcr->JobBytes += rec->data_len;   /* increment bytes this job */
261    Dmsg5(500, "wrote_record JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
262       jcr->JobId,
263       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
264       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
265
266    /* Send attributes and digest to Director for Catalog */
267    stream = rec->Stream;
268    if (stream == STREAM_UNIX_ATTRIBUTES || 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 }