Line data Source code
1 : #include "../burp.h"
2 : #include "../alloc.h"
3 : #include "../asfd.h"
4 : #include "../async.h"
5 : #include "../bu.h"
6 : #include "../cmd.h"
7 : #include "../cntr.h"
8 : #include "../handy.h"
9 : #include "../linkhash.h"
10 : #include "../log.h"
11 : #include "../pathcmp.h"
12 : #include "../prepend.h"
13 : #include "../protocol2/blk.h"
14 : #include "../regexp.h"
15 : #include "../slist.h"
16 : #include "../strlist.h"
17 : #include "bu_get.h"
18 : #include "child.h"
19 : #include "compress.h"
20 : #include "manio.h"
21 : #include "protocol1/restore.h"
22 : #include "protocol2/dpth.h"
23 : #include "protocol2/restore.h"
24 : #include "protocol2/restore_spool.h"
25 : #include "sdirs.h"
26 :
27 0 : static enum asl_ret restore_end_func(struct asfd *asfd,
28 : struct conf **confs, void *param)
29 : {
30 0 : if(!strcmp(asfd->rbuf->buf, "restoreend_ok"))
31 0 : return ASL_END_OK;
32 0 : iobuf_log_unexpected(asfd->rbuf, __func__);
33 0 : return ASL_END_ERROR;
34 : }
35 :
36 0 : static int restore_end(struct asfd *asfd, struct conf **confs)
37 : {
38 0 : if(asfd->write_str(asfd, CMD_GEN, "restoreend")) return -1;
39 0 : return asfd->simple_loop(asfd, confs, NULL, __func__, restore_end_func);
40 : }
41 :
42 0 : static int srestore_matches(struct strlist *s, const char *path)
43 : {
44 0 : int r=0;
45 0 : if(!s->flag) return 0; // Do not know how to do excludes yet.
46 0 : if((r=strncmp_w(path, s->path))) return 0; // no match
47 0 : if(!r) return 1; // exact match
48 0 : if(*(path+strlen(s->path)+1)=='/')
49 0 : return 1; // matched directory contents
50 0 : return 0; // no match
51 : }
52 :
53 : // Used when restore is initiated from the server.
54 0 : static int check_srestore(struct conf **confs, const char *path)
55 : {
56 0 : struct strlist *l=get_strlist(confs[OPT_INCEXCDIR]);
57 :
58 : // If no includes specified, restore everything.
59 0 : if(!l) return 1;
60 :
61 0 : for(; l; l=l->next)
62 0 : if(srestore_matches(l, path))
63 0 : return 1;
64 0 : return 0;
65 : }
66 :
67 0 : int want_to_restore(int srestore, struct sbuf *sb,
68 : regex_t *regex, struct conf **cconfs)
69 : {
70 0 : return (!srestore || check_srestore(cconfs, sb->path.buf))
71 0 : && (!regex || regex_check(regex, sb->path.buf));
72 : }
73 :
74 0 : static int setup_cntr(struct asfd *asfd, const char *manifest,
75 : regex_t *regex, int srestore,
76 : enum action act, char status, struct conf **cconfs)
77 : {
78 0 : int ars=0;
79 0 : int ret=-1;
80 0 : struct fzp *fzp=NULL;
81 0 : struct sbuf *sb=NULL;
82 0 : struct cntr *cntr=get_cntr(cconfs);
83 :
84 : // FIX THIS: this is only trying to work for protocol1.
85 0 : if(get_protocol(cconfs)!=PROTO_1) return 0;
86 :
87 0 : if(!(sb=sbuf_alloc(PROTO_1))) goto end;
88 0 : if(!(fzp=fzp_gzopen(manifest, "rb")))
89 : {
90 0 : log_and_send(asfd, "could not open manifest");
91 0 : goto end;
92 : }
93 : while(1)
94 : {
95 0 : if((ars=sbuf_fill_from_file(sb, fzp, NULL, NULL)))
96 : {
97 0 : if(ars<0) goto end;
98 : // ars==1 means end ok
99 0 : break;
100 : }
101 : else
102 : {
103 0 : if(want_to_restore(srestore, sb, regex, cconfs))
104 : {
105 0 : cntr_add_phase1(cntr, sb->path.cmd, 0);
106 0 : if(sb->endfile.buf)
107 : cntr_add_val(cntr,
108 : CMD_BYTES_ESTIMATED,
109 : strtoull(sb->endfile.buf,
110 0 : NULL, 10), 0);
111 : }
112 : }
113 0 : sbuf_free_content(sb);
114 : }
115 0 : ret=0;
116 : end:
117 0 : sbuf_free(&sb);
118 0 : fzp_close(&fzp);
119 0 : return ret;
120 : }
121 :
122 : static int restore_sbuf(struct asfd *asfd, struct sbuf *sb, struct bu *bu,
123 : enum action act, struct sdirs *sdirs, enum cntr_status cntr_status,
124 : struct conf **cconfs, struct sbuf *need_data, const char *manifest,
125 : struct slist *slist);
126 :
127 : // Used when restoring a hard link that we have not restored the destination
128 : // for. Read through the manifest from the beginning and substitute the path
129 : // and data to the new location.
130 0 : static int hard_link_substitution(struct asfd *asfd,
131 : struct sbuf *sb, struct f_link *lp,
132 : struct bu *bu, enum action act, struct sdirs *sdirs,
133 : enum cntr_status cntr_status, struct conf **cconfs,
134 : const char *manifest, struct slist *slist)
135 : {
136 0 : int ret=-1;
137 0 : struct sbuf *need_data=NULL;
138 0 : int last_ent_was_dir=0;
139 0 : struct sbuf *hb=NULL;
140 0 : struct manio *manio=NULL;
141 0 : struct blk *blk=NULL;
142 : int pcmp;
143 0 : enum protocol protocol=get_protocol(cconfs);
144 0 : struct cntr *cntr=get_cntr(cconfs);
145 :
146 0 : if(!(manio=manio_open(manifest, "rb", protocol))
147 0 : || !(need_data=sbuf_alloc(protocol))
148 0 : || !(hb=sbuf_alloc(protocol)))
149 0 : goto end;
150 :
151 0 : if(protocol==PROTO_2)
152 : {
153 0 : if(!(blk=blk_alloc()))
154 0 : goto end;
155 : }
156 :
157 : while(1)
158 : {
159 0 : switch(manio_read_with_blk(manio,
160 0 : hb, need_data->path.buf?blk:NULL, sdirs))
161 : {
162 0 : case 0: break; // Keep going.
163 0 : case 1: ret=0; goto end; // Finished OK.
164 0 : default: goto end; // Error;
165 : }
166 :
167 0 : if(protocol==PROTO_2)
168 : {
169 0 : if(hb->endfile.buf)
170 : {
171 0 : sbuf_free_content(hb);
172 0 : continue;
173 : }
174 0 : if(blk->data)
175 : {
176 0 : if(protocol2_extra_restore_stream_bits(asfd,
177 : blk, slist, act, need_data,
178 0 : last_ent_was_dir, cntr)) goto end;
179 0 : continue;
180 : }
181 0 : sbuf_free_content(need_data);
182 : }
183 :
184 0 : pcmp=pathcmp(lp->name, hb->path.buf);
185 :
186 0 : if(!pcmp && (sbuf_is_filedata(hb) || sbuf_is_vssdata(hb)))
187 : {
188 : // Copy the path from sb to hb.
189 0 : free_w(&hb->path.buf);
190 0 : if(!(hb->path.buf=strdup_w(sb->path.buf, __func__)))
191 0 : goto end;
192 : // Should now be able to restore the original data
193 : // to the new location.
194 : ret=restore_sbuf(asfd, hb, bu, act, sdirs,
195 0 : cntr_status, cconfs, need_data, manifest, slist);
196 : // May still need to get protocol2 data.
197 0 : if(!ret && need_data->path.buf) continue;
198 0 : break;
199 : }
200 :
201 0 : sbuf_free_content(hb);
202 : // Break out once we have gone past the entry that we are
203 : // interested in.
204 0 : if(pcmp<0) break;
205 : }
206 : end:
207 0 : blk_free(&blk);
208 0 : sbuf_free(&hb);
209 0 : manio_close(&manio);
210 0 : return ret;
211 : }
212 :
213 0 : static int restore_sbuf(struct asfd *asfd, struct sbuf *sb, struct bu *bu,
214 : enum action act, struct sdirs *sdirs, enum cntr_status cntr_status,
215 : struct conf **cconfs, struct sbuf *need_data, const char *manifest,
216 : struct slist *slist)
217 : {
218 : //printf("%s: %s\n", act==ACTION_RESTORE?"restore":"verify", sb->path.buf);
219 0 : if(write_status(cntr_status, sb->path.buf, get_cntr(cconfs)))
220 0 : return -1;
221 :
222 0 : if(sb->path.cmd==CMD_HARD_LINK)
223 : {
224 0 : struct f_link *lp=NULL;
225 0 : struct f_link **bucket=NULL;
226 0 : if((lp=linkhash_search(&sb->statp, &bucket)))
227 : {
228 : // It is in the list of stuff that is in the manifest,
229 : // but was skipped on this restore.
230 : // Need to go through the manifest from the beginning,
231 : // and substitute in the data to restore to this
232 : // location.
233 : return hard_link_substitution(asfd, sb, lp,
234 : bu, act, sdirs,
235 0 : cntr_status, cconfs, manifest, slist);
236 : // FIX THIS: Would be nice to remember the new link
237 : // location so that further hard links would link to
238 : // it instead of doing the hard_link_substitution
239 : // business over again.
240 : }
241 : }
242 :
243 0 : if(get_protocol(cconfs)==PROTO_1)
244 : {
245 : return restore_sbuf_protocol1(asfd, sb, bu,
246 0 : act, sdirs, cntr_status, cconfs);
247 : }
248 : else
249 : {
250 : return restore_sbuf_protocol2(asfd, sb,
251 0 : act, cntr_status, get_cntr(cconfs), need_data);
252 : }
253 : }
254 :
255 0 : int restore_ent(struct asfd *asfd,
256 : struct sbuf **sb,
257 : struct slist *slist,
258 : struct bu *bu,
259 : enum action act,
260 : struct sdirs *sdirs,
261 : enum cntr_status cntr_status,
262 : struct conf **cconfs,
263 : struct sbuf *need_data,
264 : int *last_ent_was_dir,
265 : const char *manifest)
266 : {
267 0 : int ret=-1;
268 : struct sbuf *xb;
269 :
270 0 : if(!(*sb)->path.buf)
271 : {
272 0 : logp("Got NULL path!\n");
273 0 : return -1;
274 : }
275 :
276 : // Check if we have any directories waiting to be restored.
277 0 : while((xb=slist->head))
278 : {
279 0 : if(is_subdir(xb->path.buf, (*sb)->path.buf))
280 : {
281 : // We are still in a subdir.
282 0 : break;
283 : }
284 : else
285 : {
286 : // Can now restore xb because nothing else is fiddling
287 : // in a subdirectory.
288 0 : if(restore_sbuf(asfd, xb, bu,
289 : act, sdirs, cntr_status, cconfs, need_data, manifest,
290 0 : slist))
291 0 : goto end;
292 0 : slist->head=xb->next;
293 0 : sbuf_free(&xb);
294 : }
295 : }
296 :
297 : /* If it is a directory, need to remember it and restore it later, so
298 : that the permissions come out right. */
299 : /* Meta data of directories will also have the stat stuff set to be a
300 : directory, so will also come out at the end. */
301 : /* FIX THIS: for Windows, need to read and remember the blocks that
302 : go with the directories. Probably have to do the same for metadata
303 : that goes with directories. */
304 0 : if(S_ISDIR((*sb)->statp.st_mode))
305 : {
306 : // Add to the head of the list instead of the tail.
307 0 : (*sb)->next=slist->head;
308 0 : slist->head=*sb;
309 :
310 0 : *last_ent_was_dir=1;
311 :
312 : // Allocate a new sb.
313 0 : if(!(*sb=sbuf_alloc(get_protocol(cconfs)))) goto end;
314 : }
315 : else
316 : {
317 0 : *last_ent_was_dir=0;
318 0 : if(restore_sbuf(asfd, *sb, bu,
319 : act, sdirs, cntr_status, cconfs, need_data, manifest,
320 0 : slist))
321 0 : goto end;
322 : }
323 0 : ret=0;
324 : end:
325 0 : return ret;
326 : }
327 :
328 0 : static int restore_remaining_dirs(struct asfd *asfd, struct bu *bu,
329 : struct slist *slist, enum action act, struct sdirs *sdirs,
330 : enum cntr_status cntr_status, struct conf **cconfs)
331 : {
332 0 : int ret=-1;
333 : struct sbuf *sb;
334 0 : struct sbuf *need_data=NULL;
335 0 : if(!(need_data=sbuf_alloc(get_protocol(cconfs)))) goto end;
336 : // Restore any directories that are left in the list.
337 0 : for(sb=slist->head; sb; sb=sb->next)
338 : {
339 0 : if(get_protocol(cconfs)==PROTO_1)
340 : {
341 0 : if(restore_sbuf_protocol1(asfd, sb, bu, act,
342 0 : sdirs, cntr_status, cconfs))
343 0 : goto end;
344 : }
345 : else
346 : {
347 0 : if(restore_sbuf_protocol2(asfd, sb, act,
348 0 : cntr_status, get_cntr(cconfs), need_data))
349 0 : goto end;
350 : }
351 : }
352 0 : ret=0;
353 : end:
354 0 : sbuf_free(&need_data);
355 0 : return ret;
356 : }
357 :
358 0 : static int restore_stream(struct asfd *asfd, struct sdirs *sdirs,
359 : struct slist *slist, struct bu *bu, const char *manifest,
360 : regex_t *regex, int srestore, struct conf **cconfs, enum action act,
361 : enum cntr_status cntr_status)
362 : {
363 0 : int ret=-1;
364 0 : int last_ent_was_dir=0;
365 0 : struct sbuf *sb=NULL;
366 0 : struct iobuf *rbuf=asfd->rbuf;
367 0 : struct manio *manio=NULL;
368 0 : struct blk *blk=NULL;
369 0 : struct sbuf *need_data=NULL;
370 0 : enum protocol protocol=get_protocol(cconfs);
371 0 : struct cntr *cntr=get_cntr(cconfs);
372 :
373 0 : if(protocol==PROTO_2)
374 : {
375 : static int rs_sent=0;
376 0 : if(!(blk=blk_alloc()))
377 0 : goto end;
378 0 : if(!rs_sent)
379 : {
380 0 : rs_sent=1;
381 0 : if(asfd->write_str(asfd,
382 0 : CMD_GEN, "restore_stream")
383 0 : || asfd->read_expect(asfd,
384 0 : CMD_GEN, "restore_stream_ok"))
385 0 : goto end;
386 : }
387 : }
388 :
389 0 : if(!(manio=manio_open(manifest, "rb", protocol))
390 0 : || !(need_data=sbuf_alloc(protocol))
391 0 : || !(sb=sbuf_alloc(protocol)))
392 0 : goto end;
393 :
394 : while(1)
395 : {
396 0 : iobuf_free_content(rbuf);
397 0 : if(asfd->as->read_quick(asfd->as))
398 : {
399 0 : logp("read quick error\n");
400 0 : goto end;
401 : }
402 0 : if(rbuf->buf) switch(rbuf->cmd)
403 : {
404 : case CMD_MESSAGE:
405 : case CMD_WARNING:
406 : {
407 0 : log_recvd(rbuf, cntr, 0);
408 0 : continue;
409 : }
410 : case CMD_INTERRUPT:
411 : // Client wanted to interrupt the
412 : // sending of a file. But if we are
413 : // here, we have already moved on.
414 : // Ignore.
415 : if(protocol==PROTO_2)
416 : {
417 : // FIX THIS:
418 : // Suspect the case is different for
419 : // PROTO_2.
420 : }
421 0 : continue;
422 : default:
423 0 : iobuf_log_unexpected(rbuf, __func__);
424 0 : goto end;
425 : }
426 :
427 0 : switch(manio_read_with_blk(manio,
428 0 : sb, need_data->path.buf?blk:NULL, sdirs))
429 : {
430 0 : case 0: break; // Keep going.
431 0 : case 1: ret=0; goto end; // Finished OK.
432 0 : default: goto end; // Error;
433 : }
434 :
435 0 : if(protocol==PROTO_2)
436 : {
437 0 : if(sb->endfile.buf)
438 : {
439 0 : sbuf_free_content(sb);
440 0 : continue;
441 : }
442 0 : if(blk->data)
443 : {
444 0 : if(protocol2_extra_restore_stream_bits(asfd,
445 : blk, slist, act, need_data,
446 0 : last_ent_was_dir, cntr)) goto end;
447 0 : continue;
448 : }
449 0 : sbuf_free_content(need_data);
450 : }
451 :
452 0 : if(want_to_restore(srestore, sb, regex, cconfs))
453 : {
454 0 : if(restore_ent(asfd, &sb, slist,
455 : bu, act, sdirs, cntr_status, cconfs,
456 0 : need_data, &last_ent_was_dir, manifest))
457 0 : goto end;
458 : }
459 0 : else if(sbuf_is_filedata(sb) || sbuf_is_vssdata(sb))
460 : {
461 : // Add it to the list of filedata that was not
462 : // restored.
463 0 : struct f_link **bucket=NULL;
464 0 : if(!linkhash_search(&sb->statp, &bucket)
465 0 : && linkhash_add(sb->path.buf, &sb->statp, bucket))
466 0 : goto end;
467 : }
468 :
469 0 : sbuf_free_content(sb);
470 : }
471 : end:
472 0 : blk_free(&blk);
473 0 : sbuf_free(&sb);
474 0 : sbuf_free(&need_data);
475 0 : iobuf_free_content(rbuf);
476 0 : manio_close(&manio);
477 0 : return ret;
478 : }
479 :
480 0 : static int actual_restore(struct asfd *asfd, struct bu *bu,
481 : const char *manifest, regex_t *regex, int srestore, enum action act,
482 : struct sdirs *sdirs, enum cntr_status cntr_status, struct conf **cconfs)
483 : {
484 0 : int ret=-1;
485 0 : int do_restore_stream=1;
486 : // For out-of-sequence directory restoring so that the
487 : // timestamps come out right:
488 0 : struct slist *slist=NULL;
489 :
490 0 : if(linkhash_init()
491 0 : || !(slist=slist_alloc()))
492 0 : goto end;
493 :
494 0 : if(get_protocol(cconfs)==PROTO_2)
495 : {
496 0 : switch(maybe_restore_spool(asfd, manifest, sdirs, bu,
497 0 : srestore, regex, cconfs, slist, act, cntr_status))
498 : {
499 0 : case 1: do_restore_stream=0; break;
500 0 : case 0: do_restore_stream=1; break;
501 0 : default: goto end; // Error;
502 : }
503 : }
504 0 : if(do_restore_stream && restore_stream(asfd, sdirs, slist,
505 : bu, manifest, regex,
506 0 : srestore, cconfs, act, cntr_status))
507 0 : goto end;
508 :
509 0 : if(restore_remaining_dirs(asfd, bu, slist,
510 0 : act, sdirs, cntr_status, cconfs)) goto end;
511 :
512 0 : cntr_print(get_cntr(cconfs), act);
513 0 : cntr_stats_to_file(get_cntr(cconfs), bu->path, act, cconfs);
514 : end:
515 0 : slist_free(&slist);
516 0 : linkhash_free();
517 0 : return ret;
518 : }
519 :
520 0 : static int get_logpaths(struct bu *bu, const char *file,
521 : char **logpath, char **logpathz)
522 : {
523 0 : if(!(*logpath=prepend_s(bu->path, file))
524 0 : || !(*logpathz=prepend(*logpath, ".gz")))
525 0 : return -1;
526 0 : return 0;
527 : }
528 :
529 0 : static int restore_manifest(struct asfd *asfd, struct bu *bu,
530 : regex_t *regex, int srestore, enum action act, struct sdirs *sdirs,
531 : char **dir_for_notify, struct conf **cconfs)
532 : {
533 0 : int ret=-1;
534 0 : char *manifest=NULL;
535 0 : char *logpath=NULL;
536 0 : char *logpathz=NULL;
537 : // For sending status information up to the server.
538 0 : enum cntr_status cntr_status=CNTR_STATUS_RESTORING;
539 :
540 0 : if(act==ACTION_RESTORE) cntr_status=CNTR_STATUS_RESTORING;
541 0 : else if(act==ACTION_VERIFY) cntr_status=CNTR_STATUS_VERIFYING;
542 :
543 0 : if((act==ACTION_RESTORE && get_logpaths(bu, "restorelog",
544 0 : &logpath, &logpathz))
545 0 : || (act==ACTION_VERIFY && get_logpaths(bu, "verifylog",
546 0 : &logpath, &logpathz))
547 0 : || !(manifest=prepend_s(bu->path,
548 0 : get_protocol(cconfs)==PROTO_1?
549 0 : "manifest.gz":"manifest")))
550 : {
551 0 : log_and_send_oom(asfd, __func__);
552 0 : goto end;
553 : }
554 :
555 0 : if(log_fzp_set(logpath, cconfs))
556 : {
557 0 : char msg[256]="";
558 : snprintf(msg, sizeof(msg),
559 0 : "could not open log file: %s", logpath);
560 0 : log_and_send(asfd, msg);
561 0 : goto end;
562 : }
563 :
564 0 : *dir_for_notify=strdup_w(bu->path, __func__);
565 :
566 0 : log_restore_settings(cconfs, srestore);
567 :
568 : // First, do a pass through the manifest to set up cntr.
569 : // This is the equivalent of a phase1 scan during backup.
570 :
571 0 : if(setup_cntr(asfd, manifest,
572 0 : regex, srestore, act, cntr_status, cconfs))
573 0 : goto end;
574 :
575 0 : if(get_int(cconfs[OPT_SEND_CLIENT_CNTR])
576 0 : && cntr_send(get_cntr(cconfs)))
577 0 : goto end;
578 :
579 : // Now, do the actual restore.
580 : ret=actual_restore(asfd, bu, manifest,
581 0 : regex, srestore, act, sdirs, cntr_status, cconfs);
582 : end:
583 0 : log_fzp_set(NULL, cconfs);
584 0 : compress_file(logpath, logpathz, get_int(cconfs[OPT_COMPRESSION]));
585 0 : if(manifest) free(manifest);
586 0 : if(logpath) free(logpath);
587 0 : if(logpathz) free(logpathz);
588 0 : return ret;
589 : }
590 :
591 1 : int do_restore_server(struct asfd *asfd, struct sdirs *sdirs,
592 : enum action act, int srestore,
593 : char **dir_for_notify, struct conf **confs)
594 : {
595 1 : int ret=-1;
596 1 : uint8_t found=0;
597 1 : struct bu *bu=NULL;
598 1 : struct bu *bu_list=NULL;
599 1 : unsigned long bno=0;
600 1 : regex_t *regex=NULL;
601 1 : const char *regexstr=get_string(confs[OPT_REGEX]);
602 1 : const char *backup=get_string(confs[OPT_BACKUP]);
603 :
604 1 : logp("in do_restore\n");
605 :
606 1 : if(regexstr
607 1 : && *regexstr
608 2 : && !(regex=regex_compile(regexstr)))
609 : {
610 1 : char msg[256]="";
611 : snprintf(msg, sizeof(msg), "unable to compile regex: %s\n",
612 1 : regexstr);
613 1 : log_and_send(asfd, msg);
614 1 : goto end;
615 : }
616 :
617 0 : if(bu_get_list(sdirs, &bu_list))
618 0 : goto end;
619 :
620 0 : if(bu_list &&
621 : (!backup
622 0 : || !*backup
623 0 : || (!(bno=strtoul(backup, NULL, 10)) && *backup!='a')))
624 : {
625 0 : found=1;
626 : // No backup specified, do the most recent.
627 0 : for(bu=bu_list; bu && bu->next; bu=bu->next) { }
628 : ret=restore_manifest(asfd, bu, regex, srestore,
629 0 : act, sdirs, dir_for_notify, confs);
630 : }
631 :
632 0 : if(!found) for(bu=bu_list; bu; bu=bu->next)
633 : {
634 0 : if(!strcmp(bu->timestamp, backup)
635 0 : || bu->bno==bno || (backup && *backup=='a'))
636 : {
637 0 : found=1;
638 : //logp("got: %s\n", bu->path);
639 : ret|=restore_manifest(asfd, bu, regex, srestore,
640 0 : act, sdirs, dir_for_notify, confs);
641 0 : if(backup && *backup=='a')
642 0 : continue;
643 0 : break;
644 : }
645 : }
646 :
647 0 : bu_list_free(&bu_list);
648 :
649 :
650 0 : if(found)
651 : {
652 : // Restore has nearly completed OK.
653 0 : ret=restore_end(asfd, confs);
654 : }
655 : else
656 : {
657 0 : logp("backup not found\n");
658 0 : asfd->write_str(asfd, CMD_ERROR, "backup not found");
659 0 : ret=-1;
660 : }
661 : end:
662 1 : regex_free(®ex);
663 1 : return ret;
664 : }
|