1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1999 University of Maryland at College Park
4  * Copyright (c) 2007-2013 Zmanda, Inc.  All Rights Reserved.
5  * All Rights Reserved.
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and its
8  * documentation for any purpose is hereby granted without fee, provided that
9  * the above copyright notice appear in all copies and that both that
10  * copyright notice and this permission notice appear in supporting
11  * documentation, and that the name of U.M. not be used in advertising or
12  * publicity pertaining to distribution of the software without specific,
13  * written prior permission.  U.M. makes no representations about the
14  * suitability of this software for any purpose.  It is provided "as is"
15  * without express or implied warranty.
16  *
17  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23  *
24  * Authors: the Amanda Development Team.  Its members are listed in a
25  * file named AUTHORS, in the root directory of this distribution.
26  */
27 /*
28  * $Id: sendbackup-dump.c,v 1.90 2006/07/25 18:10:07 martinea Exp $
29  *
30  * send backup data using BSD dump
31  */
32 
33 #include "amanda.h"
34 #include "sendbackup.h"
35 #include "getfsent.h"
36 #include "clock.h"
37 
38 #define LEAF_AND_DIRS "sed -e \'\ns/^leaf[ \t]*[0-9]*[ \t]*\\.//\nt\n/^dir[ \t]/ {\ns/^dir[ \t]*[0-9]*[ \t]*\\.//\ns%$%/%\nt\n}\nd\n\'"
39 
40 static amregex_t re_table[] = {
41   /* the various encodings of dump size */
42   /* this should also match BSDI pre-3.0's buggy dump program, that
43      produced doubled DUMP: DUMP: messages */
44   AM_SIZE_RE("DUMP: [0-9][0-9]* tape blocks", 1024, 1),
45   AM_SIZE_RE("dump: Actual: [0-9][0-9]* tape blocks", 1024, 1),
46   AM_SIZE_RE("backup: There are [0-9][0-9]* tape blocks on [0-9][0-9]* tapes",
47 	     1024, 1),
48   AM_SIZE_RE("backup: [0-9][0-9]* tape blocks on [0-9][0-9]* tape\\(s\\)",
49 	     1024, 1),
50   AM_SIZE_RE("backup: [0-9][0-9]* 1k blocks on [0-9][0-9]* volume\\(s\\)",
51 	     1024, 1),
52   AM_SIZE_RE("DUMP: [0-9][0-9]* blocks \\([0-9][0-9]*KB\\) on [0-9][0-9]* volume",
53 	     512, 1),
54   AM_SIZE_RE("DUMP: [0-9][0-9]* blocks \\([0-9][0-9]*\\.[0-9][0-9]*MB\\) on [0-9][0-9]* volume",
55 	     512, 1),
56   AM_SIZE_RE("DUMP: [0-9][0-9]* blocks \\([0-9][0-9]*KB\\)",
57 	     1024, 2),
58   AM_SIZE_RE("DUMP: [0-9][0-9]* blocks \\([0-9][0-9]*\\.[0-9][0-9]*MB\\)",
59 	     1048576, 2),
60   AM_SIZE_RE("DUMP: [0-9][0-9]* blocks", 512, 1),
61   AM_SIZE_RE("DUMP: [0-9][0-9]* bytes were dumped", 1, 1),
62   /* OSF's vdump */
63   AM_SIZE_RE("vdump: Dumped  [0-9][0-9]* of [0-9][0-9]* bytes", 1, 1),
64   /* DU 4.0a dump */
65   AM_SIZE_RE("dump: Actual: [0-9][0-9]* blocks output to pipe", 1024, 1),
66   /* DU 4.0 vdump */
67   AM_SIZE_RE("dump: Dumped  [0-9][0-9]* of [0-9][0-9]* bytes", 1, 1),
68   /* HPUX dump */
69   AM_SIZE_RE("DUMP: [0-9][0-9]* KB actual output", 1024, 1),
70   /* HPUX 10.20 and above vxdump */
71   AM_SIZE_RE("vxdump: [0-9][0-9]* tape blocks", 1024, 1),
72   /* UnixWare vxdump */
73   AM_SIZE_RE("vxdump: [0-9][0-9]* blocks", 1024, 1),
74   /* SINIX vxdump */
75   AM_SIZE_RE("   VXDUMP: [0-9][0-9]* blocks", 512, 1),
76   /* SINIX ufsdump */
77   AM_SIZE_RE("   UFSDUMP: [0-9][0-9]* blocks", 512, 1),
78   /* Irix 6.2 xfs dump */
79   AM_SIZE_RE("xfsdump: media file size [0-9][0-9]* bytes", 1, 1),
80   /* NetApp dump */
81   AM_SIZE_RE("DUMP: [0-9][0-9]* KB", 1024, 1),
82 
83   /* strange dump lines */
84   AM_STRANGE_RE("should not happen"),
85   AM_STRANGE_RE("Cannot open"),
86   AM_STRANGE_RE("[Ee]rror"),
87   AM_STRANGE_RE("[Ff]ail"),
88   /* XXX add more ERROR entries here by scanning dump sources? */
89 
90   /* any blank or non-strange DUMP: lines are marked as normal */
91   AM_NORMAL_RE("^ *DUMP:"),
92   AM_NORMAL_RE("^dump:"),					/* OSF/1 */
93   AM_NORMAL_RE("^vdump:"),					/* OSF/1 */
94   AM_NORMAL_RE("^ *vxdump:"),					/* HPUX10 */
95   AM_NORMAL_RE("^ *vxfs *vxdump:"),				/* Solaris */
96   AM_NORMAL_RE("^Dumping .* to stdout"),			/* Sol vxdump */
97   AM_NORMAL_RE("^xfsdump:"),					/* IRIX xfs */
98   AM_NORMAL_RE("^ *VXDUMP:"),					/* Sinix */
99   AM_NORMAL_RE("^ *UFSDUMP:"),					/* Sinix */
100 
101 #ifdef VDUMP	/* this is for OSF/1 3.2's vdump for advfs */
102   AM_NORMAL_RE("^The -s option is ignored"),			/* OSF/1 */
103   AM_NORMAL_RE("^path"),					/* OSF/1 */
104   AM_NORMAL_RE("^dev/fset"),					/* OSF/1 */
105   AM_NORMAL_RE("^type"),					/* OSF/1 */
106   AM_NORMAL_RE("^advfs id"),					/* OSF/1 */
107   AM_NORMAL_RE("^[A-Z][a-z][a-z] [A-Z][a-z][a-z] .[0-9] [0-9]"), /* OSF/1 */
108 #endif
109 
110   AM_NORMAL_RE("^backup:"),					/* AIX */
111   AM_NORMAL_RE("^        Use the umount command to unmount the filesystem"),
112 
113   AM_NORMAL_RE("^[ \t]*$"),
114 
115   /* catch-all; DMP_STRANGE is returned for all other lines */
116   AM_STRANGE_RE(NULL)
117 };
118 
119 static void start_backup(dle_t *dle, char *host,
120 			 int dataf, int mesgf, int indexf);
121 static void end_backup(dle_t *dle, int status);
122 
123 /*
124  *  doing similar to $ dump | compression | encryption
125  */
126 
127 static void
start_backup(dle_t * dle,char * host,int dataf,int mesgf,int indexf)128 start_backup(
129     dle_t      *dle,
130     char       *host,
131     int		dataf,
132     int		mesgf,
133     int		indexf)
134 {
135     int dumpin, dumpout, compout;
136     char *dumpkeys = NULL;
137     char *device = NULL;
138     char *fstype = NULL;
139     char *cmd = NULL;
140     char *cmdX = NULL;
141     char *indexcmd = NULL;
142     char level_str[NUM_STR_SIZE];
143     char *compopt  = NULL;
144     char *encryptopt = skip_argument;
145     char *qdisk;
146     char *config;
147     am_level_t *alevel = (am_level_t *)dle->levellist->data;
148     int      level  = alevel->level;
149 
150     g_snprintf(level_str, SIZEOF(level_str), "%d", level);
151 
152     qdisk = quote_string(dle->disk);
153     dbprintf(_("start: %s:%s lev %d\n"), host, qdisk, level);
154 
155     g_fprintf(stderr, _("%s: start [%s:%s level %d]\n"),
156 	    get_pname(), host, qdisk, level);
157     amfree(qdisk);
158 
159     /*  apply client-side encryption here */
160     if (dle->encrypt == ENCRYPT_CUST ) {
161         encpid = pipespawn(dle->clnt_encrypt, STDIN_PIPE, 0,
162 	                   &compout, &dataf, &mesgf,
163 	                   dle->clnt_encrypt, encryptopt, NULL);
164         dbprintf(_("gnutar: pid %ld: %s\n"), (long)encpid, dle->clnt_encrypt);
165     } else {
166         compout = dataf;
167         encpid = -1;
168     }
169     /*  now do the client-side compression */
170 
171 
172     if(dle->compress == COMP_FAST || dle->compress == COMP_BEST) {
173 	compopt = skip_argument;
174 
175 #if defined(COMPRESS_BEST_OPT) && defined(COMPRESS_FAST_OPT)
176 	if(dle->compress == COMP_BEST) {
177 	    compopt = COMPRESS_BEST_OPT;
178 	} else {
179 	    compopt = COMPRESS_FAST_OPT;
180 	}
181 #endif
182 	comppid = pipespawn(COMPRESS_PATH, STDIN_PIPE, 0,
183 			    &dumpout, &compout, &mesgf,
184 			    COMPRESS_PATH, compopt, NULL);
185 	dbprintf(_("dump: pid %ld: %s"), (long)comppid, COMPRESS_PATH);
186 	if(compopt != skip_argument) {
187 	    dbprintf(" %s", compopt);
188 	}
189 	dbprintf("\n");
190      } else if (dle->compress == COMP_CUST) {
191         compopt = skip_argument;
192 	comppid = pipespawn(dle->compprog, STDIN_PIPE, 0,
193 			    &dumpout, &compout, &mesgf,
194 			    dle->compprog, compopt, NULL);
195 	dbprintf(_("gnutar-cust: pid %ld: %s"),
196 		(long)comppid, dle->compprog);
197 	if(compopt != skip_argument) {
198 	    dbprintf(" %s", compopt);
199 	}
200 	dbprintf("\n");
201     } else {
202 	dumpout = compout;
203 	comppid = -1;
204     }
205 
206     /* invoke dump */
207     device = amname_to_devname(dle->device);
208     fstype = amname_to_fstype(dle->device);
209 
210     dbprintf(_("dumping device '%s' with '%s'\n"), device, fstype);
211 
212 #if defined(USE_RUNDUMP) || !defined(DUMP)
213     cmd = vstralloc(amlibexecdir, "/", "rundump", NULL);
214     cmdX = cmd;
215     if (g_options->config)
216 	config = g_options->config;
217     else
218 	config = "NOCONFIG";
219 #else
220     cmd = stralloc(DUMP);
221     cmdX = skip_argument;
222     config = skip_argument;
223 #endif
224 
225 #ifndef AIX_BACKUP					/* { */
226     /* normal dump */
227 #ifdef XFSDUMP						/* { */
228 #ifdef DUMP						/* { */
229     if (strcmp(amname_to_fstype(dle->device), "xfs") == 0)
230 #else							/* } { */
231     if (1)
232 #endif							/* } */
233     {
234         char *progname = cmd = newvstralloc(cmd, amlibexecdir, "/", "rundump",
235 					    NULL);
236 	cmdX = cmd;
237 	if (g_options->config)
238 	    config = g_options->config;
239 	else
240 	    config = "NOCONFIG";
241 
242 	program->backup_name  = XFSDUMP;
243 	program->restore_name = XFSRESTORE;
244 
245 	indexcmd = vstralloc(XFSRESTORE,
246 			     " -t",
247 			     " -v", " silent",
248 			     " -",
249 			     " 2>/dev/null",
250 			     " | sed",
251 			     " -e", " \'s/^/\\//\'",
252 			     NULL);
253 	info_tapeheader(dle);
254 
255 	start_index(dle->create_index, dumpout, mesgf, indexf, indexcmd);
256 
257 	dumpkeys = stralloc(level_str);
258 	dumppid = pipespawn(progname, STDIN_PIPE, 0,
259 			    &dumpin, &dumpout, &mesgf,
260 			    cmdX, config,
261 			    "xfsdump",
262 			    !dle->record ? "-J" : skip_argument,
263 			    "-F",
264 			    "-l", dumpkeys,
265 			    "-",
266 			    device,
267 			    NULL);
268     }
269     else
270 #endif							/* } */
271 #ifdef VXDUMP						/* { */
272 #ifdef DUMP
273     if (strcmp(amname_to_fstype(dle->device), "vxfs") == 0)
274 #else
275     if (1)
276 #endif
277     {
278 #ifdef USE_RUNDUMP
279         char *progname = cmd = newvstralloc(cmd, amlibexecdir, "/", "rundump",
280 					    NULL);
281 	cmdX = cmd;
282 	if (g_options->config)
283 	    config = g_options->config;
284 	else
285 	    config = "NOCONFIG";
286 #else
287 	char *progname = cmd = newvstralloc(cmd, VXDUMP, NULL);
288 	cmdX = skip_argument;
289 	config = skip_argument;
290 #endif
291 	program->backup_name  = VXDUMP;
292 	program->restore_name = VXRESTORE;
293 
294 	dumpkeys = vstralloc(level_str,
295 			     !dle->record ? "" : "u",
296 			     "s",
297 			     "f",
298 			     NULL);
299 
300 	indexcmd = vstralloc(VXRESTORE,
301 			     " -tvf", " -",
302 			     " 2>/dev/null",
303 			     " | ",
304 			     LEAF_AND_DIRS,
305 			     NULL);
306 	info_tapeheader(dle);
307 
308 	start_index(dle->create_index, dumpout, mesgf, indexf, indexcmd);
309 
310 	dumppid = pipespawn(progname, STDIN_PIPE, 0,
311 			    &dumpin, &dumpout, &mesgf,
312 			    cmdX, config,
313 			    "vxdump",
314 			    dumpkeys,
315 			    "1048576",
316 			    "-",
317 			    device,
318 			    NULL);
319     }
320     else
321 #endif							/* } */
322 
323 #ifdef VDUMP						/* { */
324 #ifdef DUMP
325     if (strcmp(amname_to_fstype(dle->device), "advfs") == 0)
326 #else
327     if (1)
328 #endif
329     {
330         cmd = newvstralloc(cmd, amlibexecdir, "/", "rundump", NULL);
331 	cmdX = cmd;
332 	if (g_options->config)
333 	    config = g_options->config;
334 	else
335 	    config = "NOCONFIG";
336 	device = newstralloc(device, amname_to_dirname(dle->device));
337 	program->backup_name  = VDUMP;
338 	program->restore_name = VRESTORE;
339 
340 	dumpkeys = vstralloc(level_str,
341 			     !dle->record ? "" : "u",
342 			     "b",
343 			     "f",
344 			     NULL);
345 
346 	indexcmd = vstralloc(VRESTORE,
347 			     " -tvf", " -",
348 			     " 2>/dev/null",
349 			     " | ",
350 			     "sed -e \'\n/^\\./ {\ns/^\\.//\ns/, [0-9]*$//\ns/^\\.//\ns/ @-> .*$//\nt\n}\nd\n\'",
351 			     NULL);
352 	info_tapeheader(dle);
353 
354 	start_index(dle->create_index, dumpout, mesgf, indexf, indexcmd);
355 
356 	dumppid = pipespawn(cmd, STDIN_PIPE, 0,
357 			    &dumpin, &dumpout, &mesgf,
358 			    cmdX, config,
359 			    "vdump",
360 			    dumpkeys,
361 			    "60",
362 			    "-",
363 			    device,
364 			    NULL);
365     }
366     else
367 #endif							/* } */
368 
369     {
370 #ifndef RESTORE
371 #define RESTORE "restore"
372 #endif
373 
374 #ifdef HAVE_HONOR_NODUMP
375 #  define PARAM_HONOR_NODUMP "h"
376 #else
377 #  define PARAM_HONOR_NODUMP ""
378 #endif
379 
380 #ifdef __FreeBSD__
381 # if defined(__FreeBSD_version) && (__FreeBSD_version >= 500043) && !defined(FreeBSD_NO_SNAPSHOT_DUMP)
382 #  define FREEBSD_EXTRA_KEYS "bL"
383 # else
384 #  define FREEBSD_EXTRA_KEYS "b"
385 # endif
386 #else
387 # define FREEBSD_EXTRA_KEYS ""
388 #endif
389 
390 	dumpkeys = vstralloc(level_str,
391 			     !dle->record ? "" : "u",
392 			     FREEBSD_EXTRA_KEYS,
393 			     "s",
394 			     PARAM_HONOR_NODUMP,
395 			     "f",
396 			     NULL);
397 
398 	indexcmd = vstralloc(RESTORE,
399 			     " -tvf", " -",
400 			     " 2>&1",
401 			     /* not to /dev/null because of DU's dump */
402 			     " | ",
403 			     LEAF_AND_DIRS,
404 			     NULL);
405 	info_tapeheader(dle);
406 
407 	start_index(dle->create_index, dumpout, mesgf, indexf, indexcmd);
408 
409 	dumppid = pipespawn(cmd, STDIN_PIPE, 0,
410 			    &dumpin, &dumpout, &mesgf,
411 			    cmdX, config,
412 			    "dump",
413 			    dumpkeys,
414 #ifdef __FreeBSD__
415 			    "64",
416 #endif
417 			    "1048576",
418 #ifdef HAVE_HONOR_NODUMP
419 			    "0",
420 #endif
421 			    "-",
422 			    device,
423 			    NULL);
424     }
425 #else							/* } { */
426     /* AIX backup program */
427     dumpkeys = vstralloc("-",
428 			 level_str,
429 			 !dle->record ? "" : "u",
430 			 "f",
431 			 NULL);
432 
433     indexcmd = vstralloc(RESTORE,
434 			 " -B",
435 			 " -tvf", " -",
436 			 " 2>/dev/null",
437 			 " | ",
438 			 LEAF_AND_DIRS,
439 			 NULL);
440     info_tapeheader(dle);
441 
442     start_index(dle->create_index, dumpout, mesgf, indexf, indexcmd);
443 
444     dumppid = pipespawn(cmd, STDIN_PIPE, 0,
445 			&dumpin, &dumpout, &mesgf,
446 			cmdX, config,
447 			"backup",
448 			dumpkeys,
449 			"-",
450 			device,
451 			NULL);
452 #endif							/* } */
453 
454     amfree(dumpkeys);
455     amfree(fstype);
456     amfree(device);
457     amfree(cmd);
458     amfree(indexcmd);
459 
460     /* close the write ends of the pipes */
461 
462     aclose(dumpin);
463     aclose(dumpout);
464     aclose(compout);
465     aclose(dataf);
466     aclose(mesgf);
467     if (dle->create_index)
468 	aclose(indexf);
469 }
470 
471 static void
end_backup(dle_t * dle,int status)472 end_backup(
473     dle_t      *dle,
474     int		status)
475 {
476     (void)dle;
477     (void)status;	/* Quiet unused parameter warning */
478 
479     /* don't need to do anything for dump */
480 }
481 
482 backup_program_t dump_program = {
483   "DUMP",
484 #ifdef DUMP
485   DUMP
486 #else
487   "dump"
488 #endif
489   ,
490   RESTORE
491   ,
492   re_table, start_backup, end_backup
493 };
494