1 /*
2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 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: client_util.c,v 1.34 2006/05/25 01:47:11 johnfranks Exp $
29 *
30 */
31
32 #include "amanda.h"
33 #include "conffile.h"
34 #include "client_util.h"
35 #include "getfsent.h"
36 #include "util.h"
37 #include "glib-util.h"
38 #include "timestamp.h"
39 #include "pipespawn.h"
40 #include "amxml.h"
41 #include "glob.h"
42 #include "clock.h"
43 #include "amandates.h"
44 #include "security-file.h"
45
46 #define MAXMAXDUMPS 16
47
48 static int add_exclude(FILE *file_exclude, char *aexc, int verbose);
49 static int add_include(char *disk, char *device, FILE *file_include, char *ainc, int verbose);
50 static char *build_name(char *disk, char *exin, int verbose);
51 static char *get_name(char *diskname, char *exin, time_t t, int n);
52
53
54 char *
fixup_relative(char * name,char * device)55 fixup_relative(
56 char * name,
57 char * device)
58 {
59 char *newname;
60 if(*name != '/') {
61 char *dirname = amname_to_dirname(device);
62 newname = vstralloc(dirname, "/", name , NULL);
63 amfree(dirname);
64 }
65 else {
66 newname = stralloc(name);
67 }
68 return newname;
69 }
70
71 /* GDestroyFunc for a hash table whose values are GSLists contianing malloc'd
72 * strings */
73 static void
destroy_slist_free_full(gpointer list)74 destroy_slist_free_full(gpointer list) {
75 slist_free_full((GSList *)list, g_free);
76 }
77
78
79 static char *
get_name(char * diskname,char * exin,time_t t,int n)80 get_name(
81 char * diskname,
82 char * exin,
83 time_t t,
84 int n)
85 {
86 char number[NUM_STR_SIZE];
87 char *filename;
88 char *ts;
89
90 ts = get_timestamp_from_time(t);
91 if(n == 0)
92 number[0] = '\0';
93 else
94 g_snprintf(number, SIZEOF(number), "%03d", n - 1);
95
96 filename = vstralloc(get_pname(), ".", diskname, ".", ts, number, ".",
97 exin, NULL);
98 amfree(ts);
99 return filename;
100 }
101
102
103 static char *
build_name(char * disk,char * exin,int verbose)104 build_name(
105 char * disk,
106 char * exin,
107 int verbose)
108 {
109 int n;
110 int fd;
111 char *filename = NULL;
112 char *afilename = NULL;
113 char *diskname;
114 time_t curtime;
115 char *dbgdir;
116 char *e = NULL;
117 DIR *d;
118 struct dirent *entry;
119 char *test_name;
120 size_t match_len, d_name_len;
121 char *quoted;
122
123 time(&curtime);
124 diskname = sanitise_filename(disk);
125
126 dbgdir = stralloc2(AMANDA_TMPDIR, "/");
127 if((d = opendir(AMANDA_TMPDIR)) == NULL) {
128 error(_("open debug directory \"%s\": %s"),
129 AMANDA_TMPDIR, strerror(errno));
130 /*NOTREACHED*/
131 }
132 test_name = get_name(diskname, exin,
133 curtime - (getconf_int(CNF_DEBUG_DAYS) * 24 * 60 * 60), 0);
134 match_len = strlen(get_pname()) + strlen(diskname) + 2;
135 while((entry = readdir(d)) != NULL) {
136 if(is_dot_or_dotdot(entry->d_name)) {
137 continue;
138 }
139 d_name_len = strlen(entry->d_name);
140 if(strncmp(test_name, entry->d_name, match_len) != 0
141 || d_name_len < match_len + 14 + 8
142 || strcmp(entry->d_name+ d_name_len - 7, exin) != 0) {
143 continue; /* not one of our files */
144 }
145 if(strcmp(entry->d_name, test_name) < 0) {
146 e = newvstralloc(e, dbgdir, entry->d_name, NULL);
147 (void) unlink(e); /* get rid of old file */
148 }
149 }
150 amfree(test_name);
151 amfree(e);
152 closedir(d);
153
154 n=0;
155 do {
156 filename = get_name(diskname, exin, curtime, n);
157 afilename = newvstralloc(afilename, dbgdir, filename, NULL);
158 if((fd=open(afilename, O_WRONLY|O_CREAT|O_APPEND, 0600)) < 0){
159 amfree(afilename);
160 n++;
161 }
162 else {
163 close(fd);
164 }
165 amfree(filename);
166 } while(!afilename && n < 1000);
167
168 if(afilename == NULL) {
169 filename = get_name(diskname, exin, curtime, 0);
170 afilename = newvstralloc(afilename, dbgdir, filename, NULL);
171 quoted = quote_string(afilename);
172 dbprintf(_("Cannot create %s (%s)\n"), quoted, strerror(errno));
173 if(verbose) {
174 g_printf(_("ERROR [cannot create %s (%s)]\n"),
175 quoted, strerror(errno));
176 }
177 amfree(quoted);
178 amfree(afilename);
179 amfree(filename);
180 }
181
182 amfree(dbgdir);
183 amfree(diskname);
184
185 return afilename;
186 }
187
188
189 static int
add_exclude(FILE * file_exclude,char * aexc,int verbose)190 add_exclude(
191 FILE * file_exclude,
192 char * aexc,
193 int verbose)
194 {
195 size_t l;
196 char *quoted, *file;
197
198 (void)verbose; /* Quiet unused parameter warning */
199
200 l = strlen(aexc);
201 if(aexc[l-1] == '\n') {
202 aexc[l-1] = '\0';
203 l--;
204 }
205 file = quoted = quote_string(aexc);
206 if (*file == '"') {
207 file[strlen(file) - 1] = '\0';
208 file++;
209 }
210 g_fprintf(file_exclude, "%s\n", file);
211 amfree(quoted);
212 return 1;
213 }
214
215 static int
add_include(char * disk,char * device,FILE * file_include,char * ainc,int verbose)216 add_include(
217 char * disk,
218 char * device,
219 FILE * file_include,
220 char * ainc,
221 int verbose)
222 {
223 size_t l;
224 int nb_exp=0;
225 char *quoted, *file;
226
227 (void)disk; /* Quiet unused parameter warning */
228 (void)device; /* Quiet unused parameter warning */
229
230 l = strlen(ainc);
231 if(ainc[l-1] == '\n') {
232 ainc[l-1] = '\0';
233 l--;
234 }
235 if (strncmp(ainc, "./", 2) != 0) {
236 quoted = quote_string(ainc);
237 dbprintf(_("include must start with './' (%s)\n"), quoted);
238 if(verbose) {
239 g_printf(_("ERROR [include must start with './' (%s)]\n"), quoted);
240 }
241 amfree(quoted);
242 }
243 else {
244 char *incname = ainc+2;
245 int set_root;
246
247 set_root = set_root_privs(1);
248 /* Take as is if not root && many '/' */
249 if(!set_root && strchr(incname, '/')) {
250 file = quoted = quote_string(ainc);
251 if (*file == '"') {
252 file[strlen(file) - 1] = '\0';
253 file++;
254 }
255 g_fprintf(file_include, "%s\n", file);
256 amfree(quoted);
257 nb_exp++;
258 }
259 else {
260 int nb;
261 glob_t globbuf;
262 char *cwd;
263
264 globbuf.gl_offs = 0;
265
266 cwd = g_get_current_dir();
267 if (chdir(device) != 0) {
268 error(_("Failed to chdir(%s): %s\n"), device, strerror(errno));
269 }
270 glob(incname, 0, NULL, &globbuf);
271 if (chdir(cwd) != 0) {
272 error(_("Failed to chdir(%s): %s\n"), cwd, strerror(errno));
273 }
274 if (set_root)
275 set_root_privs(0);
276 nb_exp = globbuf.gl_pathc;
277 for (nb=0; nb < nb_exp; nb++) {
278 file = stralloc2("./", globbuf.gl_pathv[nb]);
279 quoted = quote_string(file);
280 if (*file == '"') {
281 file[strlen(file) - 1] = '\0';
282 file++;
283 }
284 g_fprintf(file_include, "%s\n", file);
285 amfree(quoted);
286 amfree(file);
287 }
288 }
289 }
290 return nb_exp;
291 }
292
293 char *
build_exclude(dle_t * dle,int verbose)294 build_exclude(
295 dle_t *dle,
296 int verbose)
297 {
298 char *filename;
299 FILE *file_exclude;
300 FILE *exclude;
301 char *aexc;
302 sle_t *excl;
303 int nb_exclude = 0;
304 char *quoted;
305
306 if (dle->exclude_file) nb_exclude += dle->exclude_file->nb_element;
307 if (dle->exclude_list) nb_exclude += dle->exclude_list->nb_element;
308
309 if (nb_exclude == 0) return NULL;
310
311 if ((filename = build_name(dle->disk, "exclude", verbose)) != NULL) {
312 if ((file_exclude = fopen(filename,"w")) != NULL) {
313
314 if (dle->exclude_file) {
315 for(excl = dle->exclude_file->first; excl != NULL;
316 excl = excl->next) {
317 add_exclude(file_exclude, excl->name,
318 verbose && dle->exclude_optional == 0);
319 }
320 }
321
322 if (dle->exclude_list) {
323 for(excl = dle->exclude_list->first; excl != NULL;
324 excl = excl->next) {
325 char *exclname = fixup_relative(excl->name, dle->device);
326 if((exclude = fopen(exclname, "r")) != NULL) {
327 while ((aexc = agets(exclude)) != NULL) {
328 if (aexc[0] == '\0') {
329 amfree(aexc);
330 continue;
331 }
332 add_exclude(file_exclude, aexc,
333 verbose && dle->exclude_optional == 0);
334 amfree(aexc);
335 }
336 fclose(exclude);
337 }
338 else {
339 quoted = quote_string(exclname);
340 dbprintf(_("Can't open exclude file %s (%s)\n"),
341 quoted, strerror(errno));
342 if(verbose && (dle->exclude_optional == 0 ||
343 errno != ENOENT)) {
344 g_printf(_("ERROR [Can't open exclude file %s (%s)]\n"),
345 quoted, strerror(errno));
346 }
347 amfree(quoted);
348 }
349 amfree(exclname);
350 }
351 }
352 fclose(file_exclude);
353 } else {
354 quoted = quote_string(filename);
355 dbprintf(_("Can't create exclude file %s (%s)\n"),
356 quoted, strerror(errno));
357 if (verbose) {
358 g_printf(_("ERROR [Can't create exclude file %s (%s)]\n"),
359 quoted, strerror(errno));
360 }
361 amfree(quoted);
362 }
363 }
364
365 return filename;
366 }
367
368 char *
build_include(dle_t * dle,int verbose)369 build_include(
370 dle_t *dle,
371 int verbose)
372 {
373 char *filename;
374 FILE *file_include;
375 FILE *include;
376 char *ainc = NULL;
377 sle_t *incl;
378 int nb_include = 0;
379 int nb_exp = 0;
380 char *quoted;
381
382 if (dle->include_file) nb_include += dle->include_file->nb_element;
383 if (dle->include_list) nb_include += dle->include_list->nb_element;
384
385 if (nb_include == 0) return NULL;
386
387 if ((filename = build_name(dle->disk, "include", verbose)) != NULL) {
388 if ((file_include = fopen(filename,"w")) != NULL) {
389
390 if (dle->include_file) {
391 for (incl = dle->include_file->first; incl != NULL;
392 incl = incl->next) {
393 nb_exp += add_include(dle->disk, dle->device, file_include,
394 incl->name,
395 verbose && dle->include_optional == 0);
396 }
397 }
398
399 if (dle->include_list) {
400 for (incl = dle->include_list->first; incl != NULL;
401 incl = incl->next) {
402 char *inclname = fixup_relative(incl->name, dle->device);
403 if ((include = fopen(inclname, "r")) != NULL) {
404 while ((ainc = agets(include)) != NULL) {
405 if (ainc[0] == '\0') {
406 amfree(ainc);
407 continue;
408 }
409 nb_exp += add_include(dle->disk, dle->device,
410 file_include, ainc,
411 verbose && dle->include_optional == 0);
412 amfree(ainc);
413 }
414 fclose(include);
415 }
416 else {
417 quoted = quote_string(inclname);
418 dbprintf(_("Can't open include file %s (%s)\n"),
419 quoted, strerror(errno));
420 if (verbose && (dle->include_optional == 0 ||
421 errno != ENOENT)) {
422 g_printf(_("ERROR [Can't open include file %s (%s)]\n"),
423 quoted, strerror(errno));
424 }
425 amfree(quoted);
426 }
427 amfree(inclname);
428 }
429 }
430 fclose(file_include);
431 } else {
432 quoted = quote_string(filename);
433 dbprintf(_("Can't create include file %s (%s)\n"),
434 quoted, strerror(errno));
435 if (verbose) {
436 g_printf(_("ERROR [Can't create include file %s (%s)]\n"),
437 quoted, strerror(errno));
438 }
439 amfree(quoted);
440 }
441 }
442
443 if (nb_exp == 0) {
444 quoted = quote_string(dle->disk);
445 dbprintf(_("Nothing found to include for disk %s\n"), quoted);
446 if (verbose && dle->include_optional == 0) {
447 g_printf(_("ERROR [Nothing found to include for disk %s]\n"), quoted);
448 }
449 amfree(quoted);
450 }
451
452 return filename;
453 }
454
455
456 void
parse_options(char * str,dle_t * dle,am_feature_t * fs,int verbose)457 parse_options(
458 char *str,
459 dle_t *dle,
460 am_feature_t *fs,
461 int verbose)
462 {
463 char *exc;
464 char *inc;
465 char *p, *tok;
466 char *quoted;
467
468 p = stralloc(str);
469 tok = strtok(p,";");
470
471 while (tok != NULL) {
472 if(am_has_feature(fs, fe_options_auth)
473 && BSTRNCMP(tok,"auth=") == 0) {
474 if (dle->auth != NULL) {
475 quoted = quote_string(tok + 5);
476 dbprintf(_("multiple auth option %s\n"), quoted);
477 if(verbose) {
478 g_printf(_("ERROR [multiple auth option %s]\n"), quoted);
479 }
480 amfree(quoted);
481 }
482 dle->auth = stralloc(&tok[5]);
483 }
484 else if(am_has_feature(fs, fe_options_bsd_auth)
485 && BSTRNCMP(tok, "bsd-auth") == 0) {
486 if (dle->auth != NULL) {
487 dbprintf(_("multiple auth option\n"));
488 if (verbose) {
489 g_printf(_("ERROR [multiple auth option]\n"));
490 }
491 }
492 dle->auth = stralloc("bsd");
493 }
494 else if (BSTRNCMP(tok, "compress-fast") == 0) {
495 if (dle->compress != COMP_NONE) {
496 dbprintf(_("multiple compress option\n"));
497 if (verbose) {
498 g_printf(_("ERROR [multiple compress option]\n"));
499 }
500 }
501 dle->compress = COMP_FAST;
502 }
503 else if (BSTRNCMP(tok, "compress-best") == 0) {
504 if (dle->compress != COMP_NONE) {
505 dbprintf(_("multiple compress option\n"));
506 if (verbose) {
507 g_printf(_("ERROR [multiple compress option]\n"));
508 }
509 }
510 dle->compress = COMP_BEST;
511 }
512 else if (BSTRNCMP(tok, "srvcomp-fast") == 0) {
513 if (dle->compress != COMP_NONE) {
514 dbprintf(_("multiple compress option\n"));
515 if (verbose) {
516 g_printf(_("ERROR [multiple compress option]\n"));
517 }
518 }
519 dle->compress = COMP_SERVER_FAST;
520 }
521 else if (BSTRNCMP(tok, "srvcomp-best") == 0) {
522 if (dle->compress != COMP_NONE) {
523 dbprintf(_("multiple compress option\n"));
524 if (verbose) {
525 g_printf(_("ERROR [multiple compress option]\n"));
526 }
527 }
528 dle->compress = COMP_SERVER_BEST;
529 }
530 else if (BSTRNCMP(tok, "srvcomp-cust=") == 0) {
531 if (dle->compress != COMP_NONE) {
532 dbprintf(_("multiple compress option\n"));
533 if (verbose) {
534 g_printf(_("ERROR [multiple compress option]\n"));
535 }
536 }
537 dle->compprog = stralloc(tok + SIZEOF("srvcomp-cust=") -1);
538 dle->compress = COMP_SERVER_CUST;
539 }
540 else if (BSTRNCMP(tok, "comp-cust=") == 0) {
541 if (dle->compress != COMP_NONE) {
542 dbprintf(_("multiple compress option\n"));
543 if (verbose) {
544 g_printf(_("ERROR [multiple compress option]\n"));
545 }
546 }
547 dle->compprog = stralloc(tok + SIZEOF("comp-cust=") -1);
548 dle->compress = COMP_CUST;
549 /* parse encryption options */
550 }
551 else if (BSTRNCMP(tok, "encrypt-serv-cust=") == 0) {
552 if (dle->encrypt != ENCRYPT_NONE) {
553 dbprintf(_("multiple encrypt option\n"));
554 if (verbose) {
555 g_printf(_("ERROR [multiple encrypt option]\n"));
556 }
557 }
558 dle->srv_encrypt = stralloc(tok + SIZEOF("encrypt-serv-cust=") -1);
559 dle->encrypt = ENCRYPT_SERV_CUST;
560 }
561 else if (BSTRNCMP(tok, "encrypt-cust=") == 0) {
562 if (dle->encrypt != ENCRYPT_NONE) {
563 dbprintf(_("multiple encrypt option\n"));
564 if (verbose) {
565 g_printf(_("ERROR [multiple encrypt option]\n"));
566 }
567 }
568 dle->clnt_encrypt= stralloc(tok + SIZEOF("encrypt-cust=") -1);
569 dle->encrypt = ENCRYPT_CUST;
570 }
571 else if (BSTRNCMP(tok, "server-decrypt-option=") == 0) {
572 dle->srv_decrypt_opt = stralloc(tok + SIZEOF("server-decrypt-option=") -1);
573 }
574 else if (BSTRNCMP(tok, "client-decrypt-option=") == 0) {
575 dle->clnt_decrypt_opt = stralloc(tok + SIZEOF("client-decrypt-option=") -1);
576 }
577 else if (BSTRNCMP(tok, "no-record") == 0) {
578 if (dle->record != 1) {
579 dbprintf(_("multiple no-record option\n"));
580 if (verbose) {
581 g_printf(_("ERROR [multiple no-record option]\n"));
582 }
583 }
584 dle->record = 0;
585 }
586 else if (BSTRNCMP(tok, "index") == 0) {
587 if (dle->create_index != 0) {
588 dbprintf(_("multiple index option\n"));
589 if (verbose) {
590 g_printf(_("ERROR [multiple index option]\n"));
591 }
592 }
593 dle->create_index = 1;
594 }
595 else if (BSTRNCMP(tok, "exclude-optional") == 0) {
596 if (dle->exclude_optional != 0) {
597 dbprintf(_("multiple exclude-optional option\n"));
598 if (verbose) {
599 g_printf(_("ERROR [multiple exclude-optional option]\n"));
600 }
601 }
602 dle->exclude_optional = 1;
603 }
604 else if (strcmp(tok, "include-optional") == 0) {
605 if (dle->include_optional != 0) {
606 dbprintf(_("multiple include-optional option\n"));
607 if (verbose) {
608 g_printf(_("ERROR [multiple include-optional option]\n"));
609 }
610 }
611 dle->include_optional = 1;
612 }
613 else if (BSTRNCMP(tok,"exclude-file=") == 0) {
614 exc = unquote_string(&tok[13]);
615 dle->exclude_file = append_sl(dle->exclude_file, exc);
616 amfree(exc);
617 }
618 else if (BSTRNCMP(tok,"exclude-list=") == 0) {
619 exc = unquote_string(&tok[13]);
620 dle->exclude_list = append_sl(dle->exclude_list, exc);
621 amfree(exc);
622 }
623 else if (BSTRNCMP(tok,"include-file=") == 0) {
624 inc = unquote_string(&tok[13]);
625 dle->include_file = append_sl(dle->include_file, inc);
626 amfree(inc);
627 }
628 else if (BSTRNCMP(tok,"include-list=") == 0) {
629 inc = unquote_string(&tok[13]);
630 dle->include_list = append_sl(dle->include_list, inc);
631 amfree(inc);
632 }
633 else if (BSTRNCMP(tok,"kencrypt") == 0) {
634 dle->kencrypt = 1;
635 }
636 else if (strcmp(tok,"|") != 0) {
637 quoted = quote_string(tok);
638 dbprintf(_("unknown option %s\n"), quoted);
639 if (verbose) {
640 g_printf(_("ERROR [unknown option: %s]\n"), quoted);
641 }
642 amfree(quoted);
643 }
644 tok = strtok(NULL, ";");
645 }
646 amfree(p);
647 }
648
649 void
application_property_add_to_argv(GPtrArray * argv_ptr,dle_t * dle,backup_support_option_t * bsu,am_feature_t * amfeatures)650 application_property_add_to_argv(
651 GPtrArray *argv_ptr,
652 dle_t *dle,
653 backup_support_option_t *bsu,
654 am_feature_t *amfeatures)
655 {
656 sle_t *incl, *excl;
657
658 if (bsu) {
659 if (bsu->include_file && dle->include_file) {
660 for (incl = dle->include_file->first; incl != NULL;
661 incl = incl->next) {
662 g_ptr_array_add(argv_ptr, stralloc("--include-file"));
663 g_ptr_array_add(argv_ptr, stralloc(incl->name));
664 }
665 }
666 if (bsu->include_list && dle->include_list) {
667 for (incl = dle->include_list->first; incl != NULL;
668 incl = incl->next) {
669 g_ptr_array_add(argv_ptr, stralloc("--include-list"));
670 g_ptr_array_add(argv_ptr, stralloc(incl->name));
671 }
672 }
673 if (bsu->include_optional && dle->include_optional) {
674 g_ptr_array_add(argv_ptr, stralloc("--include-optional"));
675 g_ptr_array_add(argv_ptr, stralloc("yes"));
676 }
677
678 if (bsu->exclude_file && dle->exclude_file) {
679 for (excl = dle->exclude_file->first; excl != NULL;
680 excl = excl->next) {
681 g_ptr_array_add(argv_ptr, stralloc("--exclude-file"));
682 g_ptr_array_add(argv_ptr, stralloc(excl->name));
683 }
684 }
685 if (bsu->exclude_list && dle->exclude_list) {
686 for (excl = dle->exclude_list->first; excl != NULL;
687 excl = excl->next) {
688 g_ptr_array_add(argv_ptr, stralloc("--exclude-list"));
689 g_ptr_array_add(argv_ptr, stralloc(excl->name));
690 }
691 }
692 if (bsu->exclude_optional && dle->exclude_optional) {
693 g_ptr_array_add(argv_ptr, stralloc("--exclude-optional"));
694 g_ptr_array_add(argv_ptr, stralloc("yes"));
695 }
696
697 if (bsu->features && amfeatures) {
698 char *feature_string = am_feature_to_string(amfeatures);
699 g_ptr_array_add(argv_ptr, stralloc("--amfeatures"));
700 g_ptr_array_add(argv_ptr, feature_string);
701 }
702
703 if (dle->data_path == DATA_PATH_DIRECTTCP &&
704 bsu->data_path_set & DATA_PATH_DIRECTTCP) {
705 GSList *directtcp;
706
707 g_ptr_array_add(argv_ptr, stralloc("--data-path"));
708 g_ptr_array_add(argv_ptr, stralloc("directtcp"));
709 for (directtcp = dle->directtcp_list; directtcp != NULL;
710 directtcp = directtcp->next) {
711 g_ptr_array_add(argv_ptr, stralloc("--direct-tcp"));
712 g_ptr_array_add(argv_ptr, stralloc(directtcp->data));
713 break; /* XXX temporary; apps only support one ip:port pair */
714 }
715 }
716 }
717
718 property_add_to_argv(argv_ptr, dle->application_property);
719 return;
720 }
721
722 typedef struct {
723 dle_t *dle;
724 char *name;
725 proplist_t dle_proplist;
726 int verbose;
727 int good;
728 } merge_property_t;
729
730 static void
merge_property(gpointer key_p,gpointer value_p,gpointer user_data_p)731 merge_property(
732 gpointer key_p,
733 gpointer value_p,
734 gpointer user_data_p)
735 {
736 char *property_s = key_p;
737 property_t *conf_property = value_p;
738 merge_property_t *merge_p = user_data_p;
739 property_t *dle_property = g_hash_table_lookup(merge_p->dle_proplist,
740 property_s);
741 GSList *value;
742 char *qdisk = quote_string(merge_p->dle->disk);
743
744 if (dle_property) {
745 if (dle_property->priority && conf_property->priority) {
746 if (merge_p->verbose) {
747 g_fprintf(stdout,
748 _("ERROR %s (%s) Both server client have priority for property '%s'.\n"),
749 qdisk, merge_p->name, property_s);
750 }
751 g_debug("ERROR %s (%s) Both server client have priority for property '%s'.", qdisk, merge_p->name, property_s);
752 merge_p->good = 0;
753 /* Use client property */
754 g_hash_table_remove(merge_p->dle_proplist, key_p);
755 g_hash_table_insert(merge_p->dle_proplist, key_p, conf_property);
756 } else if (dle_property->priority) {
757 if (merge_p->verbose) {
758 g_fprintf(stdout,
759 _("ERROR %s (%s) Server set priority for property '%s' but client set the property.\n"),
760 qdisk, merge_p->name, property_s);
761 }
762 g_debug("%s (%s) Server set priority for property '%s' but client set the property.", qdisk, merge_p->name, property_s);
763 /* use server property */
764 } else if (conf_property->priority) {
765 if (merge_p->verbose) {
766 g_fprintf(stdout,
767 _("ERROR %s (%s) Client set priority for property '%s' but server set the property.\n"),
768 qdisk, merge_p->name, property_s);
769 }
770 g_debug("%s (%s) Client set priority for property '%s' but server set the property.", qdisk, merge_p->name, property_s);
771 /* Use client property */
772 g_hash_table_remove(merge_p->dle_proplist, key_p);
773 g_hash_table_insert(merge_p->dle_proplist, key_p, conf_property);
774 } else if (!conf_property->append) {
775 if (merge_p->verbose) {
776 g_fprintf(stdout,
777 _("ERROR %s (%s) Both server and client set property '%s', using client value.\n"),
778 qdisk, merge_p->name, property_s);
779 }
780 g_debug("%s (%s) Both server and client set property '%s', using client value.", qdisk, merge_p->name, property_s);
781 /* Use client property */
782 g_hash_table_remove(merge_p->dle_proplist, key_p);
783 g_hash_table_insert(merge_p->dle_proplist, key_p, conf_property);
784 } else { /* merge */
785 for (value = conf_property->values; value != NULL;
786 value = value->next) {
787 dle_property->values = g_slist_append(dle_property->values,
788 value->data);
789 }
790 }
791 } else { /* take value from conf */
792 g_hash_table_insert(merge_p->dle_proplist, key_p, conf_property);
793 }
794 }
795
796 int
merge_properties(dle_t * dle,char * name,proplist_t dle_proplist,proplist_t conf_proplist,int verbose)797 merge_properties(
798 dle_t *dle,
799 char *name,
800 proplist_t dle_proplist,
801 proplist_t conf_proplist,
802 int verbose)
803 {
804 merge_property_t merge_p = {dle, name, dle_proplist, verbose, 1};
805
806 if (conf_proplist != NULL) {
807 g_hash_table_foreach(conf_proplist,
808 &merge_property,
809 &merge_p);
810 }
811
812 return merge_p.good;
813 }
814
815 int
merge_dles_properties(dle_t * dles,int verbose)816 merge_dles_properties(
817 dle_t *dles,
818 int verbose)
819 {
820 dle_t *dle;
821 application_t *app;
822 GSList *scriptlist;
823 pp_script_t *pp_script;
824 int good = 1;
825
826 for (dle=dles; dle != NULL; dle=dle->next) {
827 if (dle->program_is_application_api) {
828 app = NULL;
829 if (dle->application_client_name &&
830 strlen(dle->application_client_name) > 0) {
831 app = lookup_application(dle->application_client_name);
832 if (!app) {
833 char *qamname = quote_string(dle->disk);
834 char *errmsg = vstrallocf("Application '%s' not found on client",
835 dle->application_client_name);
836 char *qerrmsg = quote_string(errmsg);
837 good = 0;
838 if (verbose) {
839 g_fprintf(stdout, _("ERROR %s %s\n"), qamname, qerrmsg);
840 }
841 g_debug("%s: %s", qamname, qerrmsg);
842 amfree(qamname);
843 amfree(errmsg);
844 amfree(qerrmsg);
845 }
846 } else {
847 app = lookup_application(dle->program);
848 }
849 if (app) {
850 merge_properties(dle, dle->program,
851 dle->application_property,
852 application_get_property(app),
853 verbose);
854 }
855 }
856 for (scriptlist = dle->scriptlist; scriptlist != NULL;
857 scriptlist = scriptlist->next) {
858 script_t *script = scriptlist->data;
859 pp_script = NULL;
860 if (script->client_name && strlen(script->client_name) > 0) {
861 pp_script = lookup_pp_script(script->client_name);
862 if (!pp_script) {
863 char *qamname = quote_string(dle->disk);
864 char *errmsg = vstrallocf("Script '%s' not found on client",
865 script->client_name);
866 char *qerrmsg = quote_string(errmsg);
867 good = 0;
868 if (verbose) {
869 g_fprintf(stderr, _("ERROR %s %s\n"), qamname, qerrmsg);
870 }
871 g_debug("%s: %s", qamname, qerrmsg);
872 amfree(qamname);
873 amfree(errmsg);
874 amfree(qerrmsg);
875 }
876 } else {
877 pp_script = lookup_pp_script(script->plugin);
878 }
879 if (pp_script) {
880 merge_properties(dle, script->plugin,
881 script->property,
882 pp_script_get_property(pp_script),
883 verbose);
884 }
885 }
886 }
887 return good;
888 }
889
890 backup_support_option_t *
backup_support_option(char * program,g_option_t * g_options,char * disk,char * amdevice,GPtrArray ** errarray)891 backup_support_option(
892 char *program,
893 g_option_t *g_options,
894 char *disk,
895 char *amdevice,
896 GPtrArray **errarray)
897 {
898 pid_t supportpid;
899 int supportin, supportout, supporterr;
900 char *cmd;
901 GPtrArray *argv_ptr = g_ptr_array_new();
902 FILE *streamout;
903 FILE *streamerr;
904 char *line;
905 int status;
906 char *err = NULL;
907 backup_support_option_t *bsu;
908
909 *errarray = g_ptr_array_new();
910 cmd = vstralloc(APPLICATION_DIR, "/", program, NULL);
911 g_ptr_array_add(argv_ptr, stralloc(program));
912 g_ptr_array_add(argv_ptr, stralloc("support"));
913 if (g_options->config) {
914 g_ptr_array_add(argv_ptr, stralloc("--config"));
915 g_ptr_array_add(argv_ptr, stralloc(g_options->config));
916 }
917 if (g_options->hostname) {
918 g_ptr_array_add(argv_ptr, stralloc("--host"));
919 g_ptr_array_add(argv_ptr, stralloc(g_options->hostname));
920 }
921 if (disk) {
922 g_ptr_array_add(argv_ptr, stralloc("--disk"));
923 g_ptr_array_add(argv_ptr, stralloc(disk));
924 }
925 if (amdevice) {
926 g_ptr_array_add(argv_ptr, stralloc("--device"));
927 g_ptr_array_add(argv_ptr, stralloc(amdevice));
928 }
929 g_ptr_array_add(argv_ptr, NULL);
930
931 supporterr = fileno(stderr);
932 supportpid = pipespawnv(cmd, STDIN_PIPE|STDOUT_PIPE|STDERR_PIPE, 0,
933 &supportin, &supportout, &supporterr,
934 (char **)argv_ptr->pdata);
935
936 aclose(supportin);
937
938 bsu = g_new0(backup_support_option_t, 1);
939 bsu->config = 1;
940 bsu->host = 1;
941 bsu->disk = 1;
942 streamout = fdopen(supportout, "r");
943 if (!streamout) {
944 error(_("Error opening pipe to child: %s"), strerror(errno));
945 /* NOTREACHED */
946 }
947 while((line = agets(streamout)) != NULL) {
948 dbprintf(_("support line: %s\n"), line);
949 if (strncmp(line,"CONFIG ", 7) == 0) {
950 if (strcmp(line+7, "YES") == 0)
951 bsu->config = 1;
952 } else if (strncmp(line,"HOST ", 5) == 0) {
953 if (strcmp(line+5, "YES") == 0)
954 bsu->host = 1;
955 } else if (strncmp(line,"DISK ", 5) == 0) {
956 if (strcmp(line+5, "YES") == 0)
957 bsu->disk = 1;
958 } else if (strncmp(line,"INDEX-LINE ", 11) == 0) {
959 if (strcmp(line+11, "YES") == 0)
960 bsu->index_line = 1;
961 } else if (strncmp(line,"INDEX-XML ", 10) == 0) {
962 if (strcmp(line+10, "YES") == 0)
963 bsu->index_xml = 1;
964 } else if (strncmp(line,"MESSAGE-LINE ", 13) == 0) {
965 if (strcmp(line+13, "YES") == 0)
966 bsu->message_line = 1;
967 } else if (strncmp(line,"MESSAGE-XML ", 12) == 0) {
968 if (strcmp(line+12, "YES") == 0)
969 bsu->message_xml = 1;
970 } else if (strncmp(line,"RECORD ", 7) == 0) {
971 if (strcmp(line+7, "YES") == 0)
972 bsu->record = 1;
973 } else if (strncmp(line,"INCLUDE-FILE ", 13) == 0) {
974 if (strcmp(line+13, "YES") == 0)
975 bsu->include_file = 1;
976 } else if (strncmp(line,"INCLUDE-LIST ", 13) == 0) {
977 if (strcmp(line+13, "YES") == 0)
978 bsu->include_list = 1;
979 } else if (strncmp(line,"INCLUDE-LIST-GLOB ", 17) == 0) {
980 if (strcmp(line+17, "YES") == 0)
981 bsu->include_list_glob = 1;
982 } else if (strncmp(line,"INCLUDE-OPTIONAL ", 17) == 0) {
983 if (strcmp(line+17, "YES") == 0)
984 bsu->include_optional = 1;
985 } else if (strncmp(line,"EXCLUDE-FILE ", 13) == 0) {
986 if (strcmp(line+13, "YES") == 0)
987 bsu->exclude_file = 1;
988 } else if (strncmp(line,"EXCLUDE-LIST ", 13) == 0) {
989 if (strcmp(line+13, "YES") == 0)
990 bsu->exclude_list = 1;
991 } else if (strncmp(line,"EXCLUDE-LIST-GLOB ", 17) == 0) {
992 if (strcmp(line+17, "YES") == 0)
993 bsu->exclude_list_glob = 1;
994 } else if (strncmp(line,"EXCLUDE-OPTIONAL ", 17) == 0) {
995 if (strcmp(line+17, "YES") == 0)
996 bsu->exclude_optional = 1;
997 } else if (strncmp(line,"COLLECTION ", 11) == 0) {
998 if (strcmp(line+11, "YES") == 0)
999 bsu->collection = 1;
1000 } else if (strncmp(line,"CALCSIZE ", 9) == 0) {
1001 if (strcmp(line+9, "YES") == 0)
1002 bsu->calcsize = 1;
1003 } else if (strncmp(line,"CLIENT-ESTIMATE ", 16) == 0) {
1004 if (strcmp(line+16, "YES") == 0)
1005 bsu->client_estimate = 1;
1006 } else if (strncmp(line,"MULTI-ESTIMATE ", 15) == 0) {
1007 if (strcmp(line+15, "YES") == 0)
1008 bsu->multi_estimate = 1;
1009 } else if (strncmp(line,"MAX-LEVEL ", 10) == 0) {
1010 bsu->max_level = atoi(line+10);
1011 } else if (strncmp(line,"RECOVER-MODE ", 13) == 0) {
1012 if (strcasecmp(line+13, "SMB") == 0)
1013 bsu->smb_recover_mode = 1;
1014 } else if (strncmp(line,"DATA-PATH ", 10) == 0) {
1015 if (strcasecmp(line+10, "AMANDA") == 0)
1016 bsu->data_path_set |= DATA_PATH_AMANDA;
1017 else if (strcasecmp(line+10, "DIRECTTCP") == 0)
1018 bsu->data_path_set |= DATA_PATH_DIRECTTCP;
1019 } else if (strncmp(line,"RECOVER-PATH ", 13) == 0) {
1020 if (strcasecmp(line+13, "CWD") == 0)
1021 bsu->recover_path = RECOVER_PATH_CWD;
1022 else if (strcasecmp(line+13, "REMOTE") == 0)
1023 bsu->recover_path = RECOVER_PATH_REMOTE;
1024 } else if (strncmp(line,"AMFEATURES ", 11) == 0) {
1025 if (strcmp(line+11, "YES") == 0)
1026 bsu->features = 1;
1027 } else if (g_str_has_prefix(line, "RECOVER-DUMP-STATE-FILE ")) {
1028 if (g_str_equal(line + 19, "YES"))
1029 bsu->features = 1;
1030 } else {
1031 dbprintf(_("Invalid support line: %s\n"), line);
1032 }
1033 amfree(line);
1034 }
1035 fclose(streamout);
1036
1037 if (bsu->data_path_set == 0)
1038 bsu->data_path_set = DATA_PATH_AMANDA;
1039
1040 streamerr = fdopen(supporterr, "r");
1041 if (!streamerr) {
1042 error(_("Error opening pipe to child: %s"), strerror(errno));
1043 /* NOTREACHED */
1044 }
1045 while((line = agets(streamerr)) != NULL) {
1046 if (strlen(line) > 0) {
1047 g_ptr_array_add(*errarray, line);
1048 dbprintf("Application '%s': %s\n", program, line);
1049 }
1050 amfree(bsu);
1051 }
1052 fclose(streamerr);
1053
1054 if (waitpid(supportpid, &status, 0) < 0) {
1055 err = vstrallocf(_("waitpid failed: %s"), strerror(errno));
1056 } else if (!WIFEXITED(status)) {
1057 err = vstrallocf(_("exited with signal %d"), WTERMSIG(status));
1058 } else if (WEXITSTATUS(status) != 0) {
1059 err = vstrallocf(_("exited with status %d"), WEXITSTATUS(status));
1060 }
1061
1062 if (err) {
1063 g_ptr_array_add(*errarray, err);
1064 dbprintf("Application '%s': %s\n", program, err);
1065 amfree(bsu);
1066 }
1067 g_ptr_array_free_full(argv_ptr);
1068 amfree(cmd);
1069 return bsu;
1070 }
1071
1072 void
run_client_script(script_t * script,execute_on_t execute_on,g_option_t * g_options,dle_t * dle)1073 run_client_script(
1074 script_t *script,
1075 execute_on_t execute_on,
1076 g_option_t *g_options,
1077 dle_t *dle)
1078 {
1079 pid_t scriptpid;
1080 int scriptin, scriptout, scripterr;
1081 char *cmd;
1082 GPtrArray *argv_ptr = g_ptr_array_new();
1083 FILE *streamout;
1084 FILE *streamerr;
1085 char *line;
1086 amwait_t wait_status;
1087 char *command = NULL;
1088
1089 if ((script->execute_on & execute_on) == 0)
1090 return;
1091 if (script->execute_where != ES_CLIENT)
1092 return;
1093
1094 cmd = vstralloc(APPLICATION_DIR, "/", script->plugin, NULL);
1095 g_ptr_array_add(argv_ptr, stralloc(script->plugin));
1096
1097 switch (execute_on) {
1098 case EXECUTE_ON_PRE_DLE_AMCHECK:
1099 command = "PRE-DLE-AMCHECK";
1100 break;
1101 case EXECUTE_ON_PRE_HOST_AMCHECK:
1102 command = "PRE-HOST-AMCHECK";
1103 break;
1104 case EXECUTE_ON_POST_DLE_AMCHECK:
1105 command = "POST-DLE-AMCHECK";
1106 break;
1107 case EXECUTE_ON_POST_HOST_AMCHECK:
1108 command = "POST-HOST-AMCHECK";
1109 break;
1110 case EXECUTE_ON_PRE_DLE_ESTIMATE:
1111 command = "PRE-DLE-ESTIMATE";
1112 break;
1113 case EXECUTE_ON_PRE_HOST_ESTIMATE:
1114 command = "PRE-HOST-ESTIMATE";
1115 break;
1116 case EXECUTE_ON_POST_DLE_ESTIMATE:
1117 command = "POST-DLE-ESTIMATE";
1118 break;
1119 case EXECUTE_ON_POST_HOST_ESTIMATE:
1120 command = "POST-HOST-ESTIMATE";
1121 break;
1122 case EXECUTE_ON_PRE_DLE_BACKUP:
1123 command = "PRE-DLE-BACKUP";
1124 break;
1125 case EXECUTE_ON_PRE_HOST_BACKUP:
1126 command = "PRE-HOST-BACKUP";
1127 break;
1128 case EXECUTE_ON_POST_DLE_BACKUP:
1129 command = "POST-DLE-BACKUP";
1130 break;
1131 case EXECUTE_ON_POST_HOST_BACKUP:
1132 command = "POST-HOST-BACKUP";
1133 break;
1134 case EXECUTE_ON_PRE_RECOVER:
1135 command = "PRE-RECOVER";
1136 break;
1137 case EXECUTE_ON_POST_RECOVER:
1138 command = "POST-RECOVER";
1139 break;
1140 case EXECUTE_ON_PRE_LEVEL_RECOVER:
1141 command = "PRE-LEVEL-RECOVER";
1142 break;
1143 case EXECUTE_ON_POST_LEVEL_RECOVER:
1144 command = "POST-LEVEL-RECOVER";
1145 break;
1146 case EXECUTE_ON_INTER_LEVEL_RECOVER:
1147 command = "INTER-LEVEL-RECOVER";
1148 break;
1149 }
1150 g_ptr_array_add(argv_ptr, stralloc(command));
1151 g_ptr_array_add(argv_ptr, stralloc("--execute-where"));
1152 g_ptr_array_add(argv_ptr, stralloc("client"));
1153
1154 if (g_options->config) {
1155 g_ptr_array_add(argv_ptr, stralloc("--config"));
1156 g_ptr_array_add(argv_ptr, stralloc(g_options->config));
1157 }
1158 if (g_options->hostname) {
1159 g_ptr_array_add(argv_ptr, stralloc("--host"));
1160 g_ptr_array_add(argv_ptr, stralloc(g_options->hostname));
1161 }
1162 if (dle->disk) {
1163 g_ptr_array_add(argv_ptr, stralloc("--disk"));
1164 g_ptr_array_add(argv_ptr, stralloc(dle->disk));
1165 }
1166 if (dle->device) {
1167 g_ptr_array_add(argv_ptr, stralloc("--device"));
1168 g_ptr_array_add(argv_ptr, stralloc(dle->device));
1169 }
1170 if (dle->levellist) {
1171 levellist_t levellist;
1172 char number[NUM_STR_SIZE];
1173 for (levellist=dle->levellist; levellist; levellist=levellist->next) {
1174 am_level_t *alevel = (am_level_t *)levellist->data;
1175 g_ptr_array_add(argv_ptr, stralloc("--level"));
1176 g_snprintf(number, SIZEOF(number), "%d", alevel->level);
1177 g_ptr_array_add(argv_ptr, stralloc(number));
1178 }
1179 }
1180 property_add_to_argv(argv_ptr, script->property);
1181 g_ptr_array_add(argv_ptr, NULL);
1182
1183 scriptpid = pipespawnv(cmd, STDIN_PIPE|STDOUT_PIPE|STDERR_PIPE, 0,
1184 &scriptin, &scriptout, &scripterr,
1185 (char **)argv_ptr->pdata);
1186
1187 close(scriptin);
1188
1189 script->result = g_new0(client_script_result_t, 1);
1190 script->result->proplist =
1191 g_hash_table_new_full(g_str_hash, g_str_equal,
1192 &g_free, &destroy_slist_free_full);
1193 script->result->output = g_ptr_array_new();
1194 script->result->err = g_ptr_array_new();
1195
1196 streamout = fdopen(scriptout, "r");
1197 if (streamout) {
1198 while((line = agets(streamout)) != NULL) {
1199 dbprintf("script: %s\n", line);
1200 if (BSTRNCMP(line, "PROPERTY ") == 0) {
1201 char *property_name, *property_value;
1202 property_name = line + 9;
1203 property_value = strchr(property_name,' ');
1204 if (property_value == NULL) {
1205 char *msg = g_strdup_printf(
1206 "ERROR %s: Bad output property: %s",
1207 script->plugin, line);
1208 g_ptr_array_add(script->result->output, msg);
1209 } else {
1210 property_t *property;
1211
1212 *property_value++ = '\0';
1213 property_name = stralloc(property_name);
1214 property_value = stralloc(property_value);
1215 property = g_hash_table_lookup(script->result->proplist,
1216 property_name);
1217 if (!property) {
1218 property = g_new0(property_t, 1);
1219 g_hash_table_insert(script->result->proplist,
1220 property_name, property);
1221 }
1222 property->values = g_slist_append(property->values,
1223 property_value);
1224 }
1225 amfree(line);
1226 } else {
1227 g_ptr_array_add(script->result->output, line);
1228 }
1229 }
1230 }
1231 fclose(streamout);
1232
1233 streamerr = fdopen(scripterr, "r");
1234 if (streamerr) {
1235 while((line = agets(streamerr)) != NULL) {
1236 g_ptr_array_add(script->result->err,
1237 g_strdup_printf(_("Script '%s' command '%s': %s"),
1238 script->plugin, command, line));
1239 amfree(line);
1240 }
1241 }
1242
1243 waitpid(scriptpid, &wait_status, 0);
1244 if (WIFSIGNALED(wait_status)) {
1245 g_ptr_array_add(script->result->err,
1246 g_strdup_printf(_("Script '%s' command '%s' terminated with signal %d: see %s"),
1247 script->plugin, command,
1248 WTERMSIG(wait_status),
1249 dbfn()));
1250 } else if (WIFEXITED(wait_status)) {
1251 if (WEXITSTATUS(wait_status) != 0) {
1252 g_ptr_array_add(script->result->err,
1253 g_strdup_printf(_("Script '%s' command '%s' exited with status %d: see %s"),
1254 script->plugin, command,
1255 WEXITSTATUS(wait_status),
1256 dbfn()));
1257 } else {
1258 /* Normal exit */
1259 }
1260 }
1261 amfree(cmd);
1262 g_ptr_array_free_full(argv_ptr);
1263 }
1264
1265 void run_client_script_output(gpointer data, gpointer user_data);
1266 void run_client_script_output_backup(gpointer data, gpointer user_data);
1267 void run_client_script_err_amcheck(gpointer data, gpointer user_data);
1268 void run_client_script_err_estimate(gpointer data, gpointer user_data);
1269 void run_client_script_err_backup(gpointer data, gpointer user_data);
1270 void run_client_script_err_recover(gpointer data, gpointer user_data);
1271
1272 typedef struct script_output_s {
1273 FILE *stream;
1274 dle_t *dle;
1275 } script_output_t;
1276
1277 void
run_client_script_output(gpointer data,gpointer user_data)1278 run_client_script_output(
1279 gpointer data,
1280 gpointer user_data)
1281 {
1282 char *line = data;
1283 script_output_t *so = user_data;
1284
1285 if (line && so->stream) {
1286 g_fprintf(so->stream, "%s\n", line);
1287 }
1288 }
1289
1290 void
run_client_script_output_backup(gpointer data,gpointer user_data)1291 run_client_script_output_backup(
1292 gpointer data,
1293 gpointer user_data)
1294 {
1295 char *line = data;
1296 script_output_t *so = user_data;
1297
1298 if (line && so->stream) {
1299 g_fprintf(so->stream, "| %s\n", line);
1300 }
1301 }
1302
1303 void
run_client_script_err_amcheck(gpointer data,gpointer user_data)1304 run_client_script_err_amcheck(
1305 gpointer data,
1306 gpointer user_data)
1307 {
1308 char *line = data;
1309 script_output_t *so = user_data;
1310
1311 if (line && so->stream) {
1312 g_fprintf(so->stream, "ERROR %s\n", line);
1313 }
1314 }
1315
1316 void
run_client_script_err_estimate(gpointer data,gpointer user_data)1317 run_client_script_err_estimate(
1318 gpointer data,
1319 gpointer user_data)
1320 {
1321 char *line = data;
1322 script_output_t *so = user_data;
1323
1324 if (line && so->stream) {
1325 char *qdisk = quote_string(so->dle->disk);
1326 g_fprintf(so->stream, "%s 0 WARNING \"%s\"\n", qdisk, line);
1327 amfree(qdisk);
1328 }
1329 }
1330
1331 void
run_client_script_err_backup(gpointer data,gpointer user_data)1332 run_client_script_err_backup(
1333 gpointer data,
1334 gpointer user_data)
1335 {
1336 char *line = data;
1337 script_output_t *so = user_data;
1338
1339 if (line && so->stream) {
1340 g_fprintf(so->stream, "? %s\n", line);
1341 }
1342 }
1343
1344 void
run_client_script_err_recover(gpointer data,gpointer user_data)1345 run_client_script_err_recover(
1346 gpointer data,
1347 gpointer user_data)
1348 {
1349 char *line = data;
1350 script_output_t *so = user_data;
1351
1352 if (line && so->stream) {
1353 g_fprintf(so->stream, "%s\n", line);
1354 }
1355 }
1356
1357 void
run_client_scripts(execute_on_t execute_on,g_option_t * g_options,dle_t * dle,FILE * streamout)1358 run_client_scripts(
1359 execute_on_t execute_on,
1360 g_option_t *g_options,
1361 dle_t *dle,
1362 FILE *streamout)
1363 {
1364 GSList *scriptlist;
1365 script_t *script;
1366 GFunc client_script_err = NULL;
1367 GFunc client_script_out = NULL;
1368 script_output_t so = { streamout, dle };
1369
1370 for (scriptlist = dle->scriptlist; scriptlist != NULL;
1371 scriptlist = scriptlist->next) {
1372 script = (script_t *)scriptlist->data;
1373 run_client_script(script, execute_on, g_options, dle);
1374 if (script->result) {
1375 switch (execute_on) {
1376 case EXECUTE_ON_PRE_DLE_AMCHECK:
1377 case EXECUTE_ON_PRE_HOST_AMCHECK:
1378 case EXECUTE_ON_POST_DLE_AMCHECK:
1379 case EXECUTE_ON_POST_HOST_AMCHECK:
1380 client_script_out = run_client_script_output;
1381 client_script_err = run_client_script_err_amcheck;
1382 break;
1383 case EXECUTE_ON_PRE_DLE_ESTIMATE:
1384 case EXECUTE_ON_PRE_HOST_ESTIMATE:
1385 case EXECUTE_ON_POST_DLE_ESTIMATE:
1386 case EXECUTE_ON_POST_HOST_ESTIMATE:
1387 client_script_out = run_client_script_output;
1388 if (am_has_feature(g_options->features,
1389 fe_sendsize_rep_warning)) {
1390 client_script_err = run_client_script_err_estimate;
1391 }
1392 break;
1393 case EXECUTE_ON_PRE_DLE_BACKUP:
1394 case EXECUTE_ON_PRE_HOST_BACKUP:
1395 case EXECUTE_ON_POST_DLE_BACKUP:
1396 case EXECUTE_ON_POST_HOST_BACKUP:
1397 client_script_out = run_client_script_output_backup;
1398 client_script_err = run_client_script_err_backup;
1399 break;
1400 case EXECUTE_ON_PRE_RECOVER:
1401 case EXECUTE_ON_POST_RECOVER:
1402 case EXECUTE_ON_PRE_LEVEL_RECOVER:
1403 case EXECUTE_ON_POST_LEVEL_RECOVER:
1404 case EXECUTE_ON_INTER_LEVEL_RECOVER:
1405 client_script_out = run_client_script_output;
1406 client_script_err = run_client_script_err_recover;
1407 }
1408 if (script->result->output) {
1409 if (client_script_out) {
1410 g_ptr_array_foreach(script->result->output,
1411 client_script_out,
1412 &so);
1413 }
1414 g_ptr_array_free(script->result->output, TRUE);
1415 script->result->output = NULL;
1416 }
1417 if (script->result->err) {
1418 if (client_script_err != NULL) {
1419 g_ptr_array_foreach(script->result->err,
1420 client_script_err,
1421 &so);
1422 }
1423 g_ptr_array_free(script->result->err, TRUE);
1424 script->result->err = NULL;
1425 }
1426 }
1427 }
1428 }
1429
1430
1431 void
run_calcsize(char * config,char * program,char * disk,char * dirname,GSList * levels,char * file_exclude,char * file_include)1432 run_calcsize(
1433 char *config,
1434 char *program,
1435 char *disk,
1436 char *dirname,
1437 GSList *levels,
1438 char *file_exclude,
1439 char *file_include)
1440 {
1441 char *cmd, *cmdline;
1442 char *command;
1443 GPtrArray *argv_ptr = g_ptr_array_new();
1444 char tmppath[PATH_MAX];
1445 char number[NUM_STR_SIZE];
1446 GSList *alevel;
1447 guint level;
1448 guint i;
1449 char *match_expr;
1450 int pipefd = -1, nullfd = -1;
1451 pid_t calcpid;
1452 times_t start_time;
1453 FILE *dumpout = NULL;
1454 int dumpsince;
1455 char *errmsg = NULL;
1456 char *line = NULL;
1457 amwait_t wait_status;
1458 int len;
1459 char *qdisk;
1460 amandates_t *amdp;
1461 char *amandates_file;
1462
1463 qdisk = quote_string(disk);
1464
1465 amandates_file = getconf_str(CNF_AMANDATES);
1466 if(!start_amandates(amandates_file, 0)) {
1467 char *errstr = strerror(errno);
1468 char *errmsg = vstrallocf(_("could not open %s: %s"), amandates_file, errstr);
1469 char *qerrmsg = quote_string(errmsg);
1470 g_printf(_("ERROR %s\n"), qerrmsg);
1471 amfree(qdisk);
1472 amfree(errmsg);
1473 amfree(qerrmsg);
1474 return;
1475 }
1476
1477 startclock();
1478 cmd = vstralloc(amlibexecdir, "/", "calcsize", NULL);
1479
1480
1481 g_ptr_array_add(argv_ptr, stralloc("calcsize"));
1482 if (config)
1483 g_ptr_array_add(argv_ptr, stralloc(config));
1484 else
1485 g_ptr_array_add(argv_ptr, stralloc("NOCONFIG"));
1486
1487 g_ptr_array_add(argv_ptr, stralloc(program));
1488
1489 canonicalize_pathname(disk, tmppath);
1490 g_ptr_array_add(argv_ptr, stralloc(tmppath));
1491 canonicalize_pathname(dirname, tmppath);
1492 g_ptr_array_add(argv_ptr, stralloc(tmppath));
1493
1494 if (file_exclude) {
1495 g_ptr_array_add(argv_ptr, stralloc("-X"));
1496 g_ptr_array_add(argv_ptr, stralloc(file_exclude));
1497 }
1498
1499 if (file_include) {
1500 g_ptr_array_add(argv_ptr, stralloc("-I"));
1501 g_ptr_array_add(argv_ptr, stralloc(file_include));
1502 }
1503
1504 for (alevel = levels; alevel != NULL; alevel = alevel->next) {
1505 amdp = amandates_lookup(disk);
1506 level = GPOINTER_TO_INT(alevel->data);
1507 dbprintf("level: %d\n", level);
1508 dumpsince = 0;
1509 for (i=0; i < level; i++) {
1510 if (dumpsince < amdp->dates[i])
1511 dumpsince = amdp->dates[i];
1512 }
1513 g_snprintf(number, SIZEOF(number), "%d", level);
1514 g_ptr_array_add(argv_ptr, stralloc(number));
1515 g_snprintf(number, SIZEOF(number), "%d", dumpsince);
1516 g_ptr_array_add(argv_ptr, stralloc(number));
1517 }
1518
1519 g_ptr_array_add(argv_ptr, NULL);
1520 command = (char *)g_ptr_array_index(argv_ptr, 0);
1521 cmdline = stralloc(command);
1522 for(i = 1; i < argv_ptr->len - 1; i++)
1523 cmdline = vstrextend(&cmdline, " ",
1524 (char *)g_ptr_array_index(argv_ptr,i), NULL);
1525 dbprintf(_("running: \"%s\"\n"), cmdline);
1526 amfree(cmdline);
1527
1528 start_time = curclock();
1529
1530 fflush(stderr); fflush(stdout);
1531
1532 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
1533 errmsg = vstrallocf(_("Cannot access /dev/null : %s"),
1534 strerror(errno));
1535 dbprintf("%s\n", errmsg);
1536 goto common_exit;
1537 }
1538
1539 calcpid = pipespawnv(cmd, STDERR_PIPE, 0,
1540 &nullfd, &nullfd, &pipefd, (char **)argv_ptr->pdata);
1541 amfree(cmd);
1542
1543 dumpout = fdopen(pipefd,"r");
1544 if (!dumpout) {
1545 error(_("Can't fdopen: %s"), strerror(errno));
1546 /*NOTREACHED*/
1547 }
1548
1549 match_expr = vstralloc(" %d SIZE %lld", NULL);
1550 len = strlen(qdisk);
1551 for(; (line = agets(dumpout)) != NULL; free(line)) {
1552 long long size_ = (long long)0;
1553 if (line[0] == '\0' || (int)strlen(line) <= len)
1554 continue;
1555 /* Don't use sscanf for qdisk because it can have a '%'. */
1556 if (strncmp(line, qdisk, len) == 0 &&
1557 sscanf(line+len, match_expr, &level, &size_) == 2) {
1558 g_printf("%d %lld %d\n", level, size_, 1); /* write to sendsize */
1559 dbprintf(_("estimate size for %s level %d: %lld KB\n"),
1560 qdisk, level, size_);
1561 }
1562 }
1563 amfree(match_expr);
1564
1565 dbprintf(_("waiting for %s %s child (pid=%d)\n"),
1566 command, qdisk, (int)calcpid);
1567 waitpid(calcpid, &wait_status, 0);
1568 if (WIFSIGNALED(wait_status)) {
1569 errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
1570 "calcsize", WTERMSIG(wait_status),
1571 dbfn());
1572 } else if (WIFEXITED(wait_status)) {
1573 if (WEXITSTATUS(wait_status) != 0) {
1574 errmsg = vstrallocf(_("%s exited with status %d: see %s"),
1575 "calcsize", WEXITSTATUS(wait_status),
1576 dbfn());
1577 } else {
1578 /* Normal exit */
1579 }
1580 } else {
1581 errmsg = vstrallocf(_("%s got bad exit: see %s"),
1582 "calcsize", dbfn());
1583 }
1584
1585 dbprintf(_("after %s %s wait: child pid=%d status=%d\n"),
1586 command, qdisk,
1587 (int)calcpid, WEXITSTATUS(wait_status));
1588
1589 dbprintf(_(".....\n"));
1590 dbprintf(_("estimate time for %s: %s\n"),
1591 qdisk,
1592 walltime_str(timessub(curclock(), start_time)));
1593
1594 common_exit:
1595 if (errmsg && errmsg[0] != '\0') {
1596 char *qerrmsg = quote_string(errmsg);
1597 dbprintf(_("errmsg is %s\n"), errmsg);
1598 g_printf("ERROR %s\n", qerrmsg);
1599 amfree(qerrmsg);
1600 }
1601 amfree(qdisk);
1602 amfree(errmsg);
1603 g_ptr_array_free_full(argv_ptr);
1604 amfree(cmd);
1605 }
1606
1607
1608 gboolean
check_access(char * filename,int mode)1609 check_access(
1610 char * filename,
1611 int mode)
1612 {
1613 char *noun, *adjective;
1614 char *quoted = quote_string(filename);
1615 gboolean result;
1616
1617 if(mode == F_OK)
1618 noun = "find", adjective = "exists";
1619 else if((mode & X_OK) == X_OK)
1620 noun = "execute", adjective = "executable";
1621 else if((mode & (W_OK|R_OK)) == (W_OK|R_OK))
1622 noun = "read/write", adjective = "read/writable";
1623 else
1624 noun = "access", adjective = "accessible";
1625
1626 if(EUIDACCESS(filename, mode) == -1) {
1627 g_printf(_("ERROR [can not %s %s: %s (ruid:%d euid:%d)\n"), noun, quoted, strerror(errno),
1628 (int)getuid(), (int)geteuid());
1629 result = FALSE;
1630 } else {
1631 g_printf(_("OK %s %s (ruid:%d euid:%d)\n"), quoted, adjective,
1632 (int)getuid(), (int)geteuid());
1633 result = TRUE;
1634 }
1635 amfree(quoted);
1636 return result;
1637 }
1638
1639 gboolean
check_file(char * filename,int mode)1640 check_file(
1641 char * filename,
1642 int mode)
1643 {
1644 struct stat stat_buf;
1645 char *quoted;
1646
1647 if(!stat(filename, &stat_buf)) {
1648 if(!S_ISREG(stat_buf.st_mode)) {
1649 quoted = quote_string(filename);
1650 g_printf(_("ERROR [%s is not a file]\n"), quoted);
1651 amfree(quoted);
1652 return FALSE;
1653 }
1654 } else {
1655 int save_errno = errno;
1656 quoted = quote_string(filename);
1657 g_printf(_("ERROR [can not stat %s: %s]\n"), quoted,
1658 strerror(save_errno));
1659 amfree(quoted);
1660 return FALSE;
1661 }
1662
1663 return check_access(filename, mode);
1664 }
1665
1666 gboolean
check_dir(char * dirname,int mode)1667 check_dir(
1668 char * dirname,
1669 int mode)
1670 {
1671 struct stat stat_buf;
1672 char *quoted;
1673 char *dir;
1674 gboolean result;
1675
1676 if(!stat(dirname, &stat_buf)) {
1677 if(!S_ISDIR(stat_buf.st_mode)) {
1678 quoted = quote_string(dirname);
1679 g_printf(_("ERROR [%s is not a directory]\n"), quoted);
1680 amfree(quoted);
1681 return FALSE;
1682 }
1683 } else {
1684 int save_errno = errno;
1685 quoted = quote_string(dirname);
1686 g_printf(_("ERROR [can not stat %s: %s]\n"), quoted,
1687 strerror(save_errno));
1688 amfree(quoted);
1689 return FALSE;
1690 }
1691
1692 dir = g_strconcat(dirname, "/.", NULL);
1693 result = check_access(dir, mode);
1694 amfree(dir);
1695 return result;
1696 }
1697
1698 gboolean
check_suid(char * filename)1699 check_suid(
1700 char * filename)
1701 {
1702 #ifndef SINGLE_USERID
1703 struct stat stat_buf;
1704 char *quoted = quote_string(filename);
1705
1706 if(!stat(filename, &stat_buf)) {
1707 if(stat_buf.st_uid != 0 ) {
1708 g_printf(_("ERROR [%s is not owned by root]\n"), quoted);
1709 amfree(quoted);
1710 return FALSE;
1711 }
1712 if((stat_buf.st_mode & S_ISUID) != S_ISUID) {
1713 g_printf(_("ERROR [%s is not SUID root]\n"), quoted);
1714 amfree(quoted);
1715 return FALSE;
1716 }
1717 }
1718 else {
1719 g_printf(_("ERROR [can not stat %s: %s]\n"), quoted, strerror(errno));
1720 amfree(quoted);
1721 return FALSE;
1722 }
1723 amfree(quoted);
1724 #else
1725 (void)filename; /* Quiet unused parameter warning */
1726 #endif
1727 return TRUE;
1728 }
1729
1730 #ifndef SINGLE_USERID
1731 gboolean check_exec_for_suid_recursive(char *filename, FILE *verbose);
1732 #endif
1733
1734 gboolean
check_exec_for_suid(char * type,char * filename,FILE * verbose,char ** my_realpath)1735 check_exec_for_suid(
1736 char *type,
1737 char *filename,
1738 FILE *verbose,
1739 char **my_realpath)
1740 {
1741
1742 #ifndef SINGLE_USERID
1743 char tmp_realpath[PATH_MAX];
1744 *my_realpath = realpath(filename, tmp_realpath);
1745 if (!*my_realpath) {
1746 int saved_errno = errno;
1747 char *quoted = quote_string(filename);
1748 if (verbose)
1749 g_fprintf(verbose, "ERROR [Can't find realpath for '%s': %s\n", quoted, strerror(saved_errno));
1750 g_debug("ERROR [Can't find realpath for '%s': %s", quoted, strerror(saved_errno));
1751 amfree(quoted);
1752 return FALSE;
1753 }
1754 *my_realpath = g_strdup(tmp_realpath);
1755 if (!security_allow_program_as_root(type, *my_realpath, verbose)) {
1756 return FALSE;
1757 }
1758 return check_exec_for_suid_recursive(*my_realpath, verbose);
1759 #else
1760 (void)type;
1761 *my_realpath = g_strdup(filename);
1762 (void)verbose;
1763 return TRUE;
1764 #endif
1765 }
1766
1767 #ifndef SINGLE_USERID
1768 gboolean
check_exec_for_suid_recursive(char * filename,FILE * verbose)1769 check_exec_for_suid_recursive(
1770 char *filename,
1771 FILE *verbose)
1772 {
1773 struct stat stat_buf;
1774 char *quoted = quote_string(filename);
1775
1776 if (lstat(filename, &stat_buf) == 0) {
1777 char *copy_filename;
1778 char *s;
1779
1780 if (stat_buf.st_uid != 0 ) {
1781 if (verbose)
1782 g_fprintf(verbose, "ERROR [%s is not owned by root]\n", quoted);
1783 g_debug("Error: %s is not owned by root", quoted);
1784 amfree(quoted);
1785 return FALSE;
1786 }
1787 if (stat_buf.st_mode & S_IWOTH) {
1788 if (verbose)
1789 g_fprintf(verbose, "ERROR [%s is writable by everyone]\n", quoted);
1790 g_debug("Error: %s is writable by everyone", quoted);
1791 amfree(quoted);
1792 return FALSE;
1793 }
1794 if (stat_buf.st_mode & S_IWGRP) {
1795 if (verbose)
1796 g_fprintf(verbose, "ERROR [%s is writable by the group]\n", quoted);
1797 g_debug("Error: %s is writable by the group", quoted);
1798 amfree(quoted);
1799 return FALSE;
1800 }
1801 copy_filename = g_strdup(filename);
1802 if ((s = strchr(copy_filename, '/'))) {
1803 *s = '\0';
1804 if (*copy_filename && !check_exec_for_suid_recursive(copy_filename, verbose)) {
1805 amfree(quoted);
1806 amfree(copy_filename);
1807 return FALSE;
1808 }
1809 }
1810 amfree(copy_filename);
1811 }
1812 else {
1813 if (verbose)
1814 g_fprintf(verbose, "ERROR [can not stat %s: %s]\n", quoted, strerror(errno));
1815 g_debug("Error: can not stat %s: %s", quoted, strerror(errno));
1816 amfree(quoted);
1817 return FALSE;
1818 }
1819 amfree(quoted);
1820 return TRUE;
1821 }
1822 #endif
1823
1824 /*
1825 * Returns the value of the first integer in a string.
1826 */
1827
1828 double
the_num(char * str,int pos)1829 the_num(
1830 char * str,
1831 int pos)
1832 {
1833 char *num;
1834 int ch;
1835 double d;
1836
1837 do {
1838 ch = *str++;
1839 while(ch && !isdigit(ch)) ch = *str++;
1840 if (pos == 1) break;
1841 pos--;
1842 while(ch && (isdigit(ch) || ch == '.')) ch = *str++;
1843 } while (ch);
1844 num = str - 1;
1845 while(isdigit(ch) || ch == '.') ch = *str++;
1846 str[-1] = '\0';
1847 d = atof(num);
1848 str[-1] = (char)ch;
1849 return d;
1850 }
1851
1852 char *
config_errors_to_error_string(GSList * errlist)1853 config_errors_to_error_string(
1854 GSList *errlist)
1855 {
1856 char *errmsg;
1857 gboolean multiple_errors = FALSE;
1858
1859 if (errlist) {
1860 errmsg = (char *)errlist->data;
1861 if (errlist->next)
1862 multiple_errors = TRUE;
1863 } else {
1864 errmsg = _("(no error message)");
1865 }
1866
1867 return vstrallocf("ERROR %s%s", errmsg,
1868 multiple_errors? _(" (additional errors not displayed)"):"");
1869 }
1870
1871
1872 void
add_type_table(dmpline_t typ,amregex_t ** re_table,amregex_t * orig_re_table,GSList * normal_message,GSList * ignore_message,GSList * strange_message)1873 add_type_table(
1874 dmpline_t typ,
1875 amregex_t **re_table,
1876 amregex_t *orig_re_table,
1877 GSList *normal_message,
1878 GSList *ignore_message,
1879 GSList *strange_message)
1880 {
1881 amregex_t *rp;
1882
1883 for(rp = orig_re_table; rp->regex != NULL; rp++) {
1884 if (rp->typ == typ) {
1885 int found = 0;
1886 GSList *mes;
1887
1888 for (mes = normal_message; mes != NULL; mes = mes->next) {
1889 if (strcmp(rp->regex, (char *)mes->data) == 0)
1890 found = 1;
1891 }
1892 for (mes = ignore_message; mes != NULL; mes = mes->next) {
1893 if (strcmp(rp->regex, (char *)mes->data) == 0)
1894 found = 1;
1895 }
1896 for (mes = strange_message; mes != NULL; mes = mes->next) {
1897 if (strcmp(rp->regex, (char *)mes->data) == 0)
1898 found = 1;
1899 }
1900 if (found == 0) {
1901 (*re_table)->regex = rp->regex;
1902 (*re_table)->srcline = rp->srcline;
1903 (*re_table)->scale = rp->scale;
1904 (*re_table)->field = rp->field;
1905 (*re_table)->typ = rp->typ;
1906 (*re_table)++;
1907 }
1908 }
1909 }
1910 }
1911
1912 void
add_list_table(dmpline_t typ,amregex_t ** re_table,GSList * message)1913 add_list_table(
1914 dmpline_t typ,
1915 amregex_t **re_table,
1916 GSList *message)
1917 {
1918 GSList *mes;
1919
1920 for (mes = message; mes != NULL; mes = mes->next) {
1921 (*re_table)->regex = (char *)mes->data;
1922 (*re_table)->srcline = 0;
1923 (*re_table)->scale = 0;
1924 (*re_table)->field = 0;
1925 (*re_table)->typ = typ;
1926 (*re_table)++;
1927 }
1928 }
1929
1930 amregex_t *
build_re_table(amregex_t * orig_re_table,GSList * normal_message,GSList * ignore_message,GSList * strange_message)1931 build_re_table(
1932 amregex_t *orig_re_table,
1933 GSList *normal_message,
1934 GSList *ignore_message,
1935 GSList *strange_message)
1936 {
1937 int nb = 0;
1938 amregex_t *rp;
1939 amregex_t *re_table, *new_re_table;
1940
1941 for(rp = orig_re_table; rp->regex != NULL; rp++) {
1942 nb++;
1943 }
1944 nb += g_slist_length(normal_message);
1945 nb += g_slist_length(ignore_message);
1946 nb += g_slist_length(strange_message);
1947 nb ++;
1948
1949 re_table = new_re_table = malloc(nb * sizeof(amregex_t));
1950
1951 /* add SIZE from orig_re_table */
1952 add_type_table(DMP_SIZE, &re_table, orig_re_table,
1953 normal_message, ignore_message, strange_message);
1954
1955 /* add ignore_message */
1956 add_list_table(DMP_IGNORE, &re_table, ignore_message);
1957
1958 /* add IGNORE from orig_re_table */
1959 add_type_table(DMP_IGNORE, &re_table, orig_re_table,
1960 normal_message, ignore_message, strange_message);
1961
1962 /* add normal_message */
1963 add_list_table(DMP_NORMAL, &re_table, normal_message);
1964
1965 /* add NORMAL from orig_re_table */
1966 add_type_table(DMP_NORMAL, &re_table, orig_re_table,
1967 normal_message, ignore_message, strange_message);
1968
1969 /* add strange_message */
1970 add_list_table(DMP_STRANGE, &re_table, strange_message);
1971
1972 /* add STRANGE from orig_re_table */
1973 add_type_table(DMP_STRANGE, &re_table, orig_re_table,
1974 normal_message, ignore_message, strange_message);
1975
1976 /* Add DMP_STRANGE with NULL regex, */
1977 /* it is not copied by previous statement */
1978 re_table->regex = NULL;
1979 re_table->srcline = 0;
1980 re_table->scale = 0;
1981 re_table->field = 0;
1982 re_table->typ = DMP_STRANGE;
1983
1984 return new_re_table;
1985 }
1986
1987