]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/mac.c
Make cd accept wildcards
[bacula/bacula] / bacula / src / stored / mac.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2006-2011 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 three of the GNU Affero 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 Affero 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       jcr->setJobStatus(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    jcr->sendJobStatus(JS_Running);
104
105    begin_data_spool(jcr->dcr);
106    begin_attribute_spool(jcr);
107
108    jcr->dcr->VolFirstIndex = jcr->dcr->VolLastIndex = 0;
109    jcr->run_time = time(NULL);
110    set_start_vol_position(jcr->dcr);
111
112    jcr->JobFiles = 0;
113    ok = read_records(jcr->read_dcr, record_cb, mount_next_read_volume);
114    goto ok_out;
115
116 bail_out:
117    ok = false;
118
119 ok_out:
120    if (jcr->dcr) {
121       dev = jcr->dcr->dev;
122       Dmsg1(100, "ok=%d\n", ok);
123       if (ok || dev->can_write()) {
124          /* Flush out final partial block of this session */
125          if (!write_block_to_device(jcr->dcr)) {
126             Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
127                   dev->print_name(), dev->bstrerror());
128             Dmsg0(100, _("Set ok=FALSE after write_block_to_device.\n"));
129             ok = false;
130          }
131          Dmsg2(200, "Flush block to device pos %u:%u\n", dev->file, dev->block_num);
132       }  
133
134       if (!ok) {
135          discard_data_spool(jcr->dcr);
136       } else {
137          /* Note: if commit is OK, the device will remain blocked */
138          commit_data_spool(jcr->dcr);
139       }
140
141       if (ok && dev->is_dvd()) {
142          ok = dvd_close_job(jcr->dcr);   /* do DVD cleanup if any */
143       }
144       /* Release the device -- and send final Vol info to DIR */
145       release_device(jcr->dcr);
146
147       if (!ok || job_canceled(jcr)) {
148          discard_attribute_spool(jcr);
149       } else {
150          commit_attribute_spool(jcr);
151       }
152    }
153
154    if (jcr->read_dcr) {
155       if (!release_device(jcr->read_dcr)) {
156          ok = false;
157       }
158    }
159
160    jcr->sendJobStatus();              /* update director */
161
162    Dmsg0(30, "Done reading.\n");
163    jcr->end_time = time(NULL);
164    dequeue_messages(jcr);             /* send any queued messages */
165    if (ok) {
166       jcr->setJobStatus(JS_Terminated);
167    }
168    generate_daemon_event(jcr, "JobEnd");
169    generate_plugin_event(jcr, bsdEventJobEnd);
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    free_plugins(jcr);                 /* release instantiated plugins */
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    
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_attrs_to_dir(jcr, rec);
266
267    return true;
268 }