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