]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/restore.c
This commit was manufactured by cvs2svn to create tag
[bacula/bacula] / bacula / src / dird / restore.c
1 /*
2  *
3  *   Bacula Director -- restore.c -- responsible for restoring files
4  *
5  *     Kern Sibbald, November MM
6  *
7  *    This routine is run as a separate thread.  There may be more
8  *    work to be done to make it totally reentrant!!!!
9  * 
10  * Current implementation is Catalog verification only (i.e. no
11  *  verification versus tape).
12  *
13  *  Basic tasks done here:
14  *     Open DB
15  *     Open Message Channel with Storage daemon to tell him a job will be starting.
16  *     Open connection with File daemon and pass him commands
17  *       to do the restore.
18  *     Update the DB according to what files where restored????
19  *
20  */
21
22 /*
23    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
24
25    This program is free software; you can redistribute it and/or
26    modify it under the terms of the GNU General Public License as
27    published by the Free Software Foundation; either version 2 of
28    the License, or (at your option) any later version.
29
30    This program is distributed in the hope that it will be useful,
31    but WITHOUT ANY WARRANTY; without even the implied warranty of
32    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
33    General Public License for more details.
34
35    You should have received a copy of the GNU General Public
36    License along with this program; if not, write to the Free
37    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
38    MA 02111-1307, USA.
39
40  */
41
42 #include "bacula.h"
43 #include "dird.h"
44
45 /* Commands sent to File daemon */
46 static char restorecmd[]   = "restore where=%s\n";
47 static char storaddr[]     = "storage address=%s port=%d\n";
48 static char sessioncmd[]   = "session %s %ld %ld %ld %ld %ld %ld\n";  
49
50 /* Responses received from File daemon */
51 static char OKrestore[]   = "2000 OK restore\n";
52 static char OKstore[]     = "2000 OK storage\n";
53 static char OKsession[]   = "2000 OK session\n";
54
55 /* Forward referenced functions */
56 static void restore_cleanup(JCR *jcr, int status);
57
58 /* External functions */
59
60 /* 
61  * Do a restore of the specified files
62  *    
63  *  Returns:  0 on failure
64  *            1 on success
65  */
66 int do_restore(JCR *jcr) 
67 {
68    char dt[MAX_TIME_LENGTH];
69    BSOCK   *fd;
70    JOB_DBR rjr;                       /* restore job record */
71    CLIENT_DBR cr;
72
73    /*
74     * Get or Create a client record
75     */
76    memset(&cr, 0, sizeof(cr));
77    strcpy(cr.Name, jcr->client->hdr.name);
78    cr.AutoPrune = jcr->client->AutoPrune;
79    cr.FileRetention = jcr->client->FileRetention;
80    cr.JobRetention = jcr->client->JobRetention;
81    if (jcr->client_name) {
82       free(jcr->client_name);
83    }
84    jcr->client_name = bstrdup(jcr->client->hdr.name);
85    if (!db_create_client_record(jcr->db, &cr)) {
86       Jmsg(jcr, M_ERROR, 0, _("Could not create Client record. %s"), 
87          db_strerror(jcr->db));
88       restore_cleanup(jcr, JS_ErrorTerminated);
89       return 0;
90    }
91    jcr->jr.ClientId = cr.ClientId;
92
93    memset(&rjr, 0, sizeof(rjr));
94    jcr->jr.Level = 'F';            /* Full restore */
95    jcr->jr.StartTime = jcr->start_time;
96    if (!db_update_job_start_record(jcr->db, &jcr->jr)) {
97       Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
98       restore_cleanup(jcr, JS_ErrorTerminated);
99       return 0;
100    }
101    Dmsg0(20, "Updated job start record\n");
102    jcr->fname = (char *) get_pool_memory(PM_FNAME);
103
104    Dmsg1(20, "RestoreJobId=%d\n", jcr->job->RestoreJobId);
105
106    /*
107     * Find Job Record for Files to be restored
108     */
109    if (jcr->RestoreJobId != 0) {
110       rjr.JobId = jcr->RestoreJobId;     /* specified by UA */
111    } else {
112       rjr.JobId = jcr->job->RestoreJobId; /* specified by Job Resource */
113    }
114    if (!db_get_job_record(jcr->db, &rjr)) {
115       Jmsg2(jcr, M_FATAL, 0, _("Cannot get job record id=%d %s"), rjr.JobId,
116          db_strerror(jcr->db));
117       restore_cleanup(jcr, JS_ErrorTerminated);
118       return 0;
119    }
120    Dmsg3(20, "Got JobId=%d VolSessId=%ld, VolSesTime=%ld\n", 
121              rjr.JobId, rjr.VolSessionId, rjr.VolSessionTime);
122    Dmsg4(20, "StartFile=%ld, EndFile=%ld StartBlock=%ld EndBlock=%ld\n", 
123              rjr.StartFile, rjr.EndFile, rjr.StartBlock, rjr.EndBlock);
124
125    /*
126     * Now find the Volumes we will need for the Restore
127     */
128    jcr->VolumeName[0] = 0;
129    if (!db_get_job_volume_names(jcr->db, rjr.JobId, jcr->VolumeName) ||
130         jcr->VolumeName[0] == 0) {
131       Jmsg(jcr, M_FATAL, 0, _("Cannot find Volume Name for restore Job %d. %s"), 
132          rjr.JobId, db_strerror(jcr->db));
133       restore_cleanup(jcr, JS_ErrorTerminated);
134       return 0;
135    }
136    Dmsg1(20, "Got job Volume Names: %s\n", jcr->VolumeName);
137       
138
139    /* Print Job Start message */
140    bstrftime(dt, sizeof(dt), jcr->start_time);
141    Jmsg(jcr, M_INFO, 0, _("%s Start Restore Job %s Name=%s, Client=%s, FileSet=%s\n"), 
142       dt, jcr->Job, jcr->job->hdr.name, jcr->client->hdr.name, 
143       jcr->fileset->hdr.name);
144
145    /*
146     * Open a message channel connection with the Storage
147     * daemon. This is to let him know that our client
148     * will be contacting him for a backup  session.
149     *
150     */
151    Dmsg0(10, "Open connection with storage daemon\n");
152    jcr->JobStatus = JS_Blocked;
153    /*
154     * Start conversation with Storage daemon  
155     */
156    if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
157       restore_cleanup(jcr, JS_ErrorTerminated);
158       return 0;
159    }
160    /*
161     * Now start a job with the Storage daemon
162     */
163    if (!start_storage_daemon_job(jcr)) {
164       restore_cleanup(jcr, JS_ErrorTerminated);
165       return 0;
166    }
167    /*
168     * Now start a Storage daemon message thread
169     */
170    if (!start_storage_daemon_message_thread(jcr)) {
171       restore_cleanup(jcr, JS_ErrorTerminated);
172       return 0;
173    }
174    Dmsg0(50, "Storage daemon connection OK\n");
175
176    /* 
177     * Start conversation with File daemon  
178     */
179    if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
180       restore_cleanup(jcr, JS_ErrorTerminated);
181       return 0;
182    }
183
184    fd = jcr->file_bsock;
185    jcr->JobStatus = JS_Running;
186
187    if (!send_include_list(jcr)) {
188       restore_cleanup(jcr, JS_ErrorTerminated);
189       return 0;
190    }
191
192    if (!send_exclude_list(jcr)) {
193       restore_cleanup(jcr, JS_ErrorTerminated);
194       return 0;
195    }
196
197    /* 
198     * send Storage daemon address to the File daemon,
199     *   then wait for File daemon to make connection
200     *   with Storage daemon.
201     */
202    jcr->JobStatus = JS_Blocked;
203    if (jcr->store->SDDport == 0) {
204       jcr->store->SDDport = jcr->store->SDport;
205    }
206    bnet_fsend(fd, storaddr, jcr->store->address, jcr->store->SDDport);
207    Dmsg1(6, "dird>filed: %s\n", fd->msg);
208    if (!response(fd, OKstore, "Storage")) {
209       restore_cleanup(jcr, JS_ErrorTerminated);
210       return 0;
211    }
212    jcr->JobStatus = JS_Running;
213
214    /*
215     * Pass the VolSessionId, VolSessionTime, Start and
216     * end File and Blocks on the session command.
217     */
218    bnet_fsend(fd, sessioncmd, 
219              jcr->VolumeName,
220              rjr.VolSessionId, rjr.VolSessionTime, 
221              rjr.StartFile, rjr.EndFile, rjr.StartBlock, 
222              rjr.EndBlock);
223    if (!response(fd, OKsession, "Session")) {
224       restore_cleanup(jcr, JS_ErrorTerminated);
225       return 0;
226    }
227
228    /* Send restore command */
229    if (jcr->RestoreWhere) {
230       bnet_fsend(fd, restorecmd, jcr->RestoreWhere);
231    } else {
232       bnet_fsend(fd, restorecmd,                               
233          jcr->job->RestoreWhere==NULL ? "" : jcr->job->RestoreWhere);
234    }
235    if (!response(fd, OKrestore, "Restore")) {
236       restore_cleanup(jcr, JS_ErrorTerminated);
237       return 0;
238    }
239
240    /* Wait for Job Termination */
241    /*** ****FIXME**** get job termination data */
242    Dmsg0(20, "wait for job termination\n");
243    while (bget_msg(fd, 0) >  0) {
244       Dmsg1(0, "dird<filed: %s\n", fd->msg);
245    }
246
247    restore_cleanup(jcr, JS_Terminated);
248
249    return 1;
250 }
251
252 /*
253  * Release resources allocated during restore.
254  *
255  */
256 static void restore_cleanup(JCR *jcr, int status) 
257 {
258    char dt[MAX_TIME_LENGTH];
259
260    Dmsg0(20, "In restore_cleanup\n");
261    if (jcr->jr.EndTime == 0) {
262       jcr->jr.EndTime = time(NULL);
263    }
264    jcr->jr.JobStatus = jcr->JobStatus = status;
265    if (!db_update_job_end_record(jcr->db, &jcr->jr)) {
266       Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"), 
267          db_strerror(jcr->db));
268    }
269
270    bstrftime(dt, sizeof(dt), jcr->jr.EndTime);
271    Jmsg(jcr, M_INFO, 0, _("%s End Restore Job %s.\n"),
272       dt, jcr->Job);
273
274    Dmsg0(20, "Leaving restore_cleanup\n");
275 }