]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/read.c
35e2abe6266ad201e3035fe6d27f97c88f070b22
[bacula/bacula] / bacula / src / stored / read.c
1 /*
2  * Read code for Storage daemon
3  *
4  *     Kern Sibbald, November MM
5  *
6  *   Version $Id$
7  */
8 /*
9    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
10
11    This program is free software; you can redistribute it and/or
12    modify it under the terms of the GNU General Public License as
13    published by the Free Software Foundation; either version 2 of
14    the License, or (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19    General Public License for more details.
20
21    You should have received a copy of the GNU General Public
22    License along with this program; if not, write to the Free
23    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
24    MA 02111-1307, USA.
25
26  */
27
28 #include "bacula.h"
29 #include "stored.h"
30
31 /* Forward referenced subroutines */
32
33 /* Variables used by Child process */
34 /* Global statistics */
35 /* Note, these probably should be in shared memory so that 
36  * they are truly global for all processes
37  */
38 extern struct s_shm *shm;             /* shared memory structure */
39 extern int  FiledDataChan;            /* File daemon data channel (port) */
40
41
42 /* Responses sent to the File daemon */
43 static char OK_data[]    = "3000 OK data\n";
44 static char rec_header[] = "rechdr %ld %ld %ld %ld %ld";
45
46
47 /* 
48  *  Read Data and send to File Daemon
49  *   Returns: 0 on failure
50  *            1 on success
51  */
52 int do_read_data(JCR *jcr) 
53 {
54    BSOCK *ds;
55    BSOCK *fd_sock = jcr->file_bsock;
56    int ok = TRUE;
57    DEVICE *dev;
58    DEV_RECORD *rec;
59    DEV_BLOCK *block;
60    POOLMEM *hdr; 
61    SESSION_LABEL sessrec;              /* session record */
62    
63    Dmsg0(20, "Start read data.\n");
64
65    dev = jcr->device->dev;
66    memset(&sessrec, 0, sizeof(sessrec));
67
68    /* Tell File daemon we will send data */
69    bnet_fsend(fd_sock, OK_data);
70    Dmsg1(10, "bstored>filed: %s\n", fd_sock->msg);
71
72    ds = fd_sock;
73
74    if (!bnet_set_buffer_size(ds, MAX_NETWORK_BUFFER_SIZE, BNET_SETBUF_READ)) {
75       return 0;
76    }
77
78
79    Dmsg1(20, "Begin read device=%s\n", dev_name(dev));
80
81    block = new_block(dev);
82
83    create_vol_list(jcr);
84
85    Dmsg1(20, "Found %d volumes names to restore.\n", jcr->NumVolumes);
86
87    /* 
88     * Ready device for reading, and read records
89     */
90    if (!acquire_device_for_read(jcr, dev, block)) {
91       free_block(block);
92       free_vol_list(jcr);
93       return 0;
94    }
95
96    rec = new_record();
97    free_pool_memory(rec->data);
98    rec->data = ds->msg;                /* use socket message buffer */
99    hdr = get_pool_memory(PM_MESSAGE);
100
101    /*
102     *   Read records, apply BSR filtering, and return any that are 
103     *    matched.
104     */
105    for ( ;ok; ) {
106       if (job_cancelled(jcr)) {
107          ok = FALSE;
108          break;
109       }
110       /* Read Record */
111       Dmsg1(500, "Main read_record. rem=%d\n", rec->remainder);
112
113       if (!read_block_from_device(dev, block)) {
114          Dmsg1(500, "Main read record failed. rem=%d\n", rec->remainder);
115          if (dev->state & ST_EOT) {
116             if (!mount_next_read_volume(jcr, dev, block)) {
117                break;
118             }
119             continue;
120          }
121          if (dev->state & ST_EOF) {
122             Dmsg0(90, "Got End of File. Trying again ...\n");
123             continue;                 /* End of File */
124          }
125          if (dev->state & ST_SHORT) {
126             continue;
127          }
128       }
129
130       for (rec->state=0; !is_block_empty(rec); ) {
131
132          if (!read_record_from_block(block, rec)) {
133             break;
134          }
135          /*
136           * At this point, we have at least a record header.
137           *  Now decide if we want this record or not, but remember
138           *  before accessing the record, we may need to read again to
139           *  get all the data.
140           */
141
142          /* Some sort of label? */ 
143          if (rec->FileIndex < 0) {
144             char *rtype;
145             memset(&sessrec, 0, sizeof(sessrec));
146             switch (rec->FileIndex) {
147                case PRE_LABEL:
148                   rtype = "Fresh Volume Label";   
149                   break;
150                case VOL_LABEL:
151                   rtype = "Volume Label";
152                   unser_volume_label(dev, rec);
153                   break;
154                case SOS_LABEL:
155                   rtype = "Begin Session";
156                   unser_session_label(&sessrec, rec);
157                   break;
158                case EOS_LABEL:
159                   rtype = "End Session";
160                   break;
161                case EOM_LABEL:
162                   rtype = "End of Media";
163                   break;
164                default:
165                   rtype = "Unknown";
166                   break;
167             }
168             Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n",
169                   rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
170
171             Dmsg1(40, "Got label = %d\n", rec->FileIndex);
172             if (rec->FileIndex == EOM_LABEL) { /* end of tape? */
173                Dmsg0(40, "Get EOM LABEL\n");
174                rec->remainder = 0;
175                break;                         /* yes, get out */
176             }
177             rec->remainder = 0;
178             continue;                         /* ignore other labels */
179          } /* end if label record */
180
181          /* Match BSR against current record */
182          if (jcr->bsr) {
183             if (!match_bsr(jcr->bsr, rec, &dev->VolHdr, &sessrec)) {
184                Dmsg0(50, "BSR rejected record\n");
185                rec->remainder = 0;
186                continue;
187             }
188          } else { 
189             /* Old way, deprecated */
190             if (rec->VolSessionId != jcr->read_VolSessionId ||
191                 rec->VolSessionTime != jcr->read_VolSessionTime) {
192                Dmsg0(50, "Ignore record ids not equal\n");
193                rec->remainder = 0;
194                continue;                    /* ignore */
195             }
196          }
197
198          if (is_partial_record(rec)) {
199             break;                    /* Go read full record */
200          }
201           
202          /* Generate Header parameters and send to File daemon
203           * Note, we build header in hdr buffer to avoid wiping
204           * out the data record
205           */
206          ds->msg = hdr;
207          if (!bnet_fsend(ds, rec_header, rec->VolSessionId, rec->VolSessionTime,
208                 rec->FileIndex, rec->Stream, rec->data_len)) {
209             Dmsg1(30, ">filed: Error Hdr=%s\n", ds->msg);
210             hdr = ds->msg;
211             ds->msg = rec->data;
212             ok = FALSE;
213             break;
214          } else {
215             Dmsg1(30, ">filed: Hdr=%s\n", ds->msg);
216          }
217
218          hdr = ds->msg;               /* restore hdr buffer */
219          ds->msg = rec->data;         /* restore data record address */
220
221          /* Send data record to File daemon */
222          ds->msglen = rec->data_len;
223          Dmsg1(40, ">filed: send %d bytes data.\n", ds->msglen);
224          if (!bnet_send(ds)) {
225             Dmsg1(000, "Error sending to FD. ERR=%s\n", bnet_strerror(ds));
226             Dmsg1(100, "Hdr=%s\n", hdr);
227             Dmsg1(100, "data=%s\n", ds->msg);
228             Jmsg1(jcr, M_FATAL, 0, _("Error sending to File daemon. ERR=%s\n"),
229                bnet_strerror(ds));
230             ok = FALSE;
231             break;
232          }
233       }
234    }
235    /* Send end of data to FD */
236    bnet_sig(ds, BNET_EOD);
237
238    if (!release_device(jcr, dev, block)) {
239       ok = FALSE;
240    }
241    free_pool_memory(hdr);
242    free_block(block);
243    rec->data = NULL;                  /* previously released */
244    free_record(rec);
245    free_vol_list(jcr);
246    Dmsg0(30, "Done reading.\n");
247    return ok ? 1 : 0;
248 }