]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/mac.c
Reverted the change of TRU64 to OSF1 for the OS detection rules. Although Compaq...
[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 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       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    
190 #ifdef xxx
191    Dmsg5(000, "on entry     JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
192       jcr->JobId,
193       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
194       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
195 #endif
196    /* If label and not for us, discard it */
197    if (rec->FileIndex < 0 && rec->match_stat <= 0) {
198       return true;
199    }
200    /* We want to write SOS_LABEL and EOS_LABEL discard all others */
201    switch (rec->FileIndex) {                        
202    case PRE_LABEL:
203    case VOL_LABEL:
204    case EOT_LABEL:
205    case EOM_LABEL:
206       return true;                    /* don't write vol labels */
207    }
208 //   if (jcr->getJobType() == JT_BACKUP) {
209       /*
210        * For normal migration jobs, FileIndex values are sequential because
211        *  we are dealing with one job.  However, for Vbackup (consolidation),
212        *  we will be getting records from multiple jobs and writing them back
213        *  out, so we need to ensure that the output FileIndex is sequential.
214        *  We do so by detecting a FileIndex change and incrementing the
215        *  JobFiles, which we then use as the output FileIndex.
216        */
217       if (rec->FileIndex >= 0) { 
218          /* If something changed, increment FileIndex */
219          if (rec->VolSessionId != rec->last_VolSessionId || 
220              rec->VolSessionTime != rec->last_VolSessionTime ||
221              rec->FileIndex != rec->last_FileIndex) {
222             jcr->JobFiles++;
223             rec->last_VolSessionId = rec->VolSessionId;
224             rec->last_VolSessionTime = rec->VolSessionTime;
225             rec->last_FileIndex = rec->FileIndex;
226          }
227          rec->FileIndex = jcr->JobFiles;     /* set sequential output FileIndex */
228       }
229 //   }
230    /*
231     * Modify record SessionId and SessionTime to correspond to
232     * output.
233     */
234    rec->VolSessionId = jcr->VolSessionId;
235    rec->VolSessionTime = jcr->VolSessionTime;
236    Dmsg5(200, "before write JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
237       jcr->JobId,
238       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
239       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
240    while (!write_record_to_block(jcr->dcr->block, rec)) {
241       Dmsg4(200, "!write_record_to_block blkpos=%u:%u len=%d rem=%d\n", 
242             dev->file, dev->block_num, rec->data_len, rec->remainder);
243       if (!write_block_to_device(jcr->dcr)) {
244          Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n",
245             dev->print_name(), dev->bstrerror());
246          Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
247                dev->print_name(), dev->bstrerror());
248          return false;
249       }
250       Dmsg2(200, "===== Wrote block new pos %u:%u\n", dev->file, dev->block_num);
251    }
252    /* Restore packet */
253    rec->VolSessionId = rec->last_VolSessionId;
254    rec->VolSessionTime = rec->last_VolSessionTime;
255    if (rec->FileIndex < 0) {
256       return true;                    /* don't send LABELs to Dir */
257    }
258    jcr->JobBytes += rec->data_len;   /* increment bytes this job */
259    Dmsg5(500, "wrote_record JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
260       jcr->JobId,
261       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
262       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
263
264    send_attrs_to_dir(jcr, rec);
265
266    return true;
267 }