1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2011-2015 Planets Communications B.V.
5 Copyright (C) 2013-2019 Bareos GmbH & Co. KG
6
7 This program is Free Software; you can redistribute it and/or
8 modify it under the terms of version three of the GNU Affero General Public
9 License as published by the Free Software Foundation and included
10 in the file LICENSE.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Affero General Public License for more details.
16
17 You should have received a copy of the GNU Affero General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301, USA.
21 */
22 /*
23 * Restore specific NDMP Data Management Application (DMA) routines
24 * common for NDMP_BAREOS and NDMP_NATIVE restores
25 *
26 * extracted and reorganized from ndmp_dma_restore.c
27 *
28 * Philipp Storz, April 2017
29 */
30
31 #include "include/bareos.h"
32 #include "dird.h"
33 #include "dird/jcr_private.h"
34 #include "dird/job.h"
35 #include "dird/restore.h"
36
37 #if HAVE_NDMP
38 # include "ndmp/ndmagents.h"
39 # include "ndmp_dma_priv.h"
40 #endif /* HAVE_NDMP */
41
42 namespace directordaemon {
43
44 #if HAVE_NDMP
45 /*
46 * Add a filename to the files we want to restore.
47 *
48 * The RFC says this:
49 *
50 * original_path - The original path name of the data to be recovered,
51 * relative to the backup root. If original_path is the null
52 * string, the server shall recover all data contained in the
53 * backup image.
54 *
55 * destination_path, name, other_name
56 * - Together, these identify the absolute path name to which
57 * data are to be recovered.
58 *
59 * If name is the null string:
60 * - destination_path identifies the name to which the data
61 * identified by original_path are to be recovered.
62 * - other_name must be the null string.
63 *
64 * If name is not the null string:
65 * - destination_path, when concatenated with the server-
66 * specific path name delimiter and name, identifies the
67 * name to which the data identified by original_path are
68 * to be recovered.
69 *
70 * If other_name is not the null string:
71 * - destination_path, when concatenated with the server-
72 * specific path name delimiter and other_name,
73 * identifies the alternate name-space name of the data
74 * to be recovered. The definition of such alternate
75 * name-space is server-specific.
76 *
77 * Neither name nor other_name may contain a path name delimiter.
78 *
79 * Under no circumstance may destination_path be the null string.
80 *
81 * If intermediate directories that lead to the path name to
82 * recover do not exist, the server should create them.
83 */
AddToNamelist(struct ndm_job_param * job,char * filename,const char * restore_prefix,char * name,char * other_name,uint64_t node,uint64_t fhinfo)84 void AddToNamelist(struct ndm_job_param* job,
85 char* filename,
86 const char* restore_prefix,
87 char* name,
88 char* other_name,
89 uint64_t node,
90 uint64_t fhinfo)
91 {
92 ndmp9_name nl;
93 PoolMem destination_path;
94
95 memset(&nl, 0, sizeof(ndmp9_name));
96
97 /*
98 * See if the filename is an absolute pathname.
99 */
100 if (*filename == '\0') {
101 PmStrcpy(destination_path, restore_prefix);
102 } else if (*filename == '/') {
103 Mmsg(destination_path, "%s%s", restore_prefix, filename);
104 } else {
105 Mmsg(destination_path, "%s/%s", restore_prefix, filename);
106 }
107
108 nl.original_path = filename;
109 nl.destination_path = destination_path.c_str();
110 nl.name = name;
111 nl.other_name = other_name;
112
113
114 /*
115 * add fh_node and fh_info for DAR for native NDMP backup
116 */
117 nl.node = node;
118
119 if (fhinfo) {
120 nl.fh_info.value = fhinfo;
121 nl.fh_info.valid = NDMP9_VALIDITY_VALID;
122 }
123
124 ndma_store_nlist(&job->nlist_tab, &nl);
125 }
126
127 /*
128 * Database handler that handles the returned environment data for a given
129 * JobId.
130 */
NdmpEnvHandler(void * ctx,int num_fields,char ** row)131 int NdmpEnvHandler(void* ctx, int num_fields, char** row)
132 {
133 struct ndm_env_table* envtab;
134 ndmp9_pval pv;
135
136 if (row[0] && row[1]) {
137 envtab = (struct ndm_env_table*)ctx;
138 pv.name = row[0];
139 pv.value = row[1];
140
141 ndma_store_env_list(envtab, &pv);
142 }
143
144 return 0;
145 }
146
147 /*
148 * Extract any post backup statistics.
149 */
ExtractPostRestoreStats(JobControlRecord * jcr,struct ndm_session * sess)150 bool ExtractPostRestoreStats(JobControlRecord* jcr, struct ndm_session* sess)
151 {
152 bool retval = true;
153 struct ndmmedia* media;
154
155 /*
156 * See if an error was raised during the backup session.
157 */
158 if (sess->error_raised) { return false; }
159
160 /*
161 * See if there is any media error.
162 */
163 for (media = sess->control_acb->job.result_media_tab.head; media;
164 media = media->next) {
165 if (media->media_open_error || media->media_io_error
166 || media->label_io_error || media->label_mismatch
167 || media->fmark_error) {
168 retval = false;
169 }
170 }
171
172 /*
173 * Update the Job statistics from the NDMP statistics.
174 */
175 jcr->JobBytes += sess->control_acb->job.bytes_read;
176 jcr->JobFiles++;
177
178 return retval;
179 }
180
181 /**
182 * Cleanup a NDMP restore session.
183 */
NdmpRestoreCleanup(JobControlRecord * jcr,int TermCode)184 void NdmpRestoreCleanup(JobControlRecord* jcr, int TermCode)
185 {
186 char term_code[100];
187 const char* TermMsg;
188 int msg_type = M_INFO;
189
190 Dmsg0(20, "In NdmpRestoreCleanup\n");
191 UpdateJobEnd(jcr, TermCode);
192
193 if (jcr->impl->unlink_bsr && jcr->RestoreBootstrap) {
194 SecureErase(jcr, jcr->RestoreBootstrap);
195 jcr->impl->unlink_bsr = false;
196 }
197
198 if (JobCanceled(jcr)) { CancelStorageDaemonJob(jcr); }
199
200 switch (TermCode) {
201 case JS_Terminated:
202 if (jcr->impl->ExpectedFiles > jcr->impl->jr.JobFiles) {
203 TermMsg = _("Restore OK -- warning file count mismatch");
204 } else {
205 TermMsg = _("Restore OK");
206 }
207 break;
208 case JS_Warnings:
209 TermMsg = _("Restore OK -- with warnings");
210 break;
211 case JS_FatalError:
212 case JS_ErrorTerminated:
213 TermMsg = _("*** Restore Error ***");
214 msg_type = M_ERROR; /* Generate error message */
215 if (jcr->store_bsock) {
216 jcr->store_bsock->signal(BNET_TERMINATE);
217 if (jcr->impl->SD_msg_chan_started) {
218 pthread_cancel(jcr->impl->SD_msg_chan);
219 }
220 }
221 break;
222 case JS_Canceled:
223 TermMsg = _("Restore Canceled");
224 if (jcr->store_bsock) {
225 jcr->store_bsock->signal(BNET_TERMINATE);
226 if (jcr->impl->SD_msg_chan_started) {
227 pthread_cancel(jcr->impl->SD_msg_chan);
228 }
229 }
230 break;
231 default:
232 TermMsg = term_code;
233 sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode);
234 break;
235 }
236
237 GenerateRestoreSummary(jcr, msg_type, TermMsg);
238
239 Dmsg0(20, "Leaving NdmpRestoreCleanup\n");
240 }
241
242 #else /* HAVE_NDMP */
243
244 void NdmpRestoreCleanup(JobControlRecord* jcr, int TermCode)
245 {
246 Jmsg(jcr, M_FATAL, 0, _("NDMP protocol not supported\n"));
247 }
248
249 #endif /* HAVE_NDMP */
250 } /* namespace directordaemon */
251