2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
4 * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
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.
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.
24 * Authors: the Amanda Development Team. Its members are listed in a
25 * file named AUTHORS, in the root directory of this distribution.
28 * $Id: amstar.c 8888 2007-10-02 13:40:42Z martineau $
30 * send estimated backup sizes using dump
35 * STAR-PATH (default STAR)
43 * INCLUDE-LIST (for restore only)
51 #include "pipespawn.h"
52 #include "amfeatures.h"
53 #include "amandates.h"
57 #include "client_util.h"
60 #include "sendbackup.h"
62 int debug_application = 1;
63 #define application_debug(i, ...) do { \
64 if ((i) <= debug_application) { \
65 dbprintf(__VA_ARGS__); \
69 static amregex_t init_re_table[] = {
70 /* tar prints the size in bytes */
71 AM_SIZE_RE("star: [0-9][0-9]* blocks", 10240, 1),
72 AM_NORMAL_RE("^could not open conf file"),
73 AM_NORMAL_RE("^Type of this level "),
74 AM_NORMAL_RE("^Date of this level "),
75 AM_NORMAL_RE("^Date of last level "),
76 AM_NORMAL_RE("^Dump record level "),
77 AM_NORMAL_RE("^Throughput"),
78 AM_NORMAL_RE("^.*is sparse$"),
80 #ifdef IGNORE_TAR_ERRORS
81 AM_NORMAL_RE("^.*shrunk*$"),
82 AM_NORMAL_RE("^.*changed size.*$"),
83 AM_NORMAL_RE("^.*Cannot listxattr for.*$"),
84 AM_NORMAL_RE("^.Cannot: stat .*$"),
85 AM_NORMAL_RE("^.Missing links .*$"),
86 AM_NORMAL_RE("^.Cannot get xattr.*$"),
87 AM_NORMAL_RE("^.Cannot.*acl.*$"),
90 AM_NORMAL_RE("^star: dumped [0-9][0-9]* (tar )?files"),
91 AM_NORMAL_RE("^.*The following problems occurred during .* processing.*$"),
92 AM_NORMAL_RE("^.*Processed all possible files, despite earlier errors.*$"),
93 AM_NORMAL_RE("^.*not written due to problems during backup.*$"),
95 AM_STRANGE_RE("^Perform a level 0 dump first.*$"),
97 /* catch-all: DMP_STRANGE is returned for all other lines */
100 static amregex_t *re_table;
102 /* local functions */
103 int main(int argc, char **argv);
105 typedef struct application_argument_s {
112 GSList *command_options;
116 } application_argument_t;
118 enum { CMD_ESTIMATE, CMD_BACKUP };
120 static void amstar_support(application_argument_t *argument);
121 static void amstar_selfcheck(application_argument_t *argument);
122 static void amstar_estimate(application_argument_t *argument);
123 static void amstar_backup(application_argument_t *argument);
124 static void amstar_restore(application_argument_t *argument);
125 static void amstar_validate(application_argument_t *argument);
126 static GPtrArray *amstar_build_argv(application_argument_t *argument,
129 static int check_device(application_argument_t *argument);
131 static char *star_path;
132 static char *star_tardumps;
133 static int star_dle_tardumps;
134 static int star_onefilesystem;
135 static int star_sparse;
137 static char *star_directory;
138 static GSList *normal_message = NULL;
139 static GSList *ignore_message = NULL;
140 static GSList *strange_message = NULL;
142 static struct option long_options[] = {
143 {"config" , 1, NULL, 1},
144 {"host" , 1, NULL, 2},
145 {"disk" , 1, NULL, 3},
146 {"device" , 1, NULL, 4},
147 {"level" , 1, NULL, 5},
148 {"index" , 1, NULL, 6},
149 {"message" , 1, NULL, 7},
150 {"collection" , 0, NULL, 8},
151 {"record" , 0, NULL, 9},
152 {"star-path" , 1, NULL, 10},
153 {"star-tardump" , 1, NULL, 11},
154 {"star-dle-tardump", 1, NULL, 12},
155 {"one-file-system" , 1, NULL, 13},
156 {"sparse" , 1, NULL, 14},
157 {"calcsize" , 0, NULL, 15},
158 {"normal" , 1, NULL, 16},
159 {"ignore" , 1, NULL, 17},
160 {"strange" , 1, NULL, 18},
161 {"include-list" , 1, NULL, 19},
162 {"exclude-list" , 1, NULL, 20},
163 {"directory" , 1, NULL, 21},
164 {"command-options" , 1, NULL, 22},
165 {"exclude-file" , 1, NULL, 23},
166 {"acl" , 1, NULL, 24},
178 application_argument_t argument;
185 star_tardumps = "/etc/tardumps";
186 star_dle_tardumps = 0;
187 star_onefilesystem = 1;
190 star_directory = NULL;
195 * Configure program for internationalization:
196 * 1) Only set the message locale for now.
197 * 2) Set textdomain for all amanda related programs to "amanda"
198 * We don't want to be forced to support dozens of message catalogs.
200 setlocale(LC_MESSAGES, "C");
201 textdomain("amanda");
204 printf("ERROR no command given to amstar\n");
205 error(_("No command given to amstar"));
208 /* drop root privileges */
209 if (!set_root_privs(0)) {
210 if (strcmp(argv[1], "selfcheck") == 0) {
211 printf("ERROR amstar must be run setuid root\n");
213 error(_("amstar must be run setuid root"));
220 /* Don't die when child closes pipe */
221 signal(SIGPIPE, SIG_IGN);
223 #if defined(USE_DBMALLOC)
224 malloc_size_1 = malloc_inuse(&malloc_hist_1);
227 add_amanda_log_handler(amanda_log_stderr);
228 add_amanda_log_handler(amanda_log_syslog);
229 dbopen(DBG_SUBDIR_CLIENT);
231 dbprintf(_("version %s\n"), VERSION);
233 config_init(CONFIG_INIT_CLIENT, NULL);
235 //check_running_as(RUNNING_AS_DUMPUSER_PREFERRED);
237 //RUNNING_AS_CLIENT_LOGIN from selfcheck, sendsize, sendbackup
242 argument.config = NULL;
243 argument.host = NULL;
244 argument.message = 0;
245 argument.collection = 0;
246 argument.calcsize = 0;
247 argument.level = NULL;
248 argument.command_options = NULL;
249 init_dle(&argument.dle);
250 argument.dle.record = 0;
254 int option_index = 0;
255 c = getopt_long (argc, argv, "", long_options, &option_index);
260 case 1: argument.config = stralloc(optarg);
262 case 2: argument.host = stralloc(optarg);
264 case 3: argument.dle.disk = stralloc(optarg);
266 case 4: argument.dle.device = stralloc(optarg);
268 case 5: argument.level = g_slist_append(argument.level,
269 GINT_TO_POINTER(atoi(optarg)));
271 case 6: argument.dle.create_index = 1;
273 case 7: argument.message = 1;
275 case 8: argument.collection = 1;
277 case 9: argument.dle.record = 1;
279 case 10: star_path = stralloc(optarg);
281 case 11: star_tardumps = stralloc(optarg);
283 case 12: if (optarg && strcasecmp(optarg, "NO") == 0)
284 star_dle_tardumps = 0;
285 else if (optarg && strcasecmp(optarg, "YES") == 0)
286 star_dle_tardumps = 1;
287 else if (strcasecmp(command, "selfcheck") == 0)
288 printf(_("ERROR [%s: bad STAR-DLE-TARDUMP property value (%s)]\n"), get_pname(), optarg);
290 case 13: if (optarg && strcasecmp(optarg, "YES") != 0) {
291 /* This option is required to be YES */
292 /* star_onefilesystem = 0; */
295 case 14: if (optarg && strcasecmp(optarg, "NO") == 0)
297 else if (optarg && strcasecmp(optarg, "YES") == 0)
299 else if (strcasecmp(command, "selfcheck") == 0)
300 printf(_("ERROR [%s: bad SPARSE property value (%s)]\n"), get_pname(), optarg);
302 case 15: argument.calcsize = 1;
306 g_slist_append(normal_message, optarg);
310 g_slist_append(ignore_message, optarg);
314 g_slist_append(strange_message, optarg);
317 argument.dle.include_list =
318 append_sl(argument.dle.include_list, optarg);
321 argument.dle.exclude_list =
322 append_sl(argument.dle.exclude_list, optarg);
325 star_directory = stralloc(optarg);
327 case 22: argument.command_options =
328 g_slist_append(argument.command_options,
332 argument.dle.exclude_file =
333 append_sl(argument.dle.exclude_file, optarg);
335 case 24: if (optarg && strcasecmp(optarg, "NO") == 0)
337 else if (optarg && strcasecmp(optarg, "YES") == 0)
339 else if (strcasecmp(command, "selfcheck") == 0)
340 printf(_("ERROR [%s: bad ACL property value (%s)]\n"), get_pname(), optarg);
348 if (!argument.dle.disk && argument.dle.device)
349 argument.dle.disk = stralloc(argument.dle.device);
350 if (!argument.dle.device && argument.dle.disk)
351 argument.dle.device = stralloc(argument.dle.disk);
353 argument.argc = argc - optind;
354 argument.argv = argv + optind;
356 if (argument.config) {
357 /* overlay this configuration on the existing (nameless) configuration */
358 config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY,
360 dbrename(get_config_name(), DBG_SUBDIR_CLIENT);
364 if (config_errors(NULL) >= CFGERR_ERRORS) {
365 g_critical(_("errors processing config file"));
368 re_table = build_re_table(init_re_table, normal_message, ignore_message,
371 if (strcmp(command, "support") == 0) {
372 amstar_support(&argument);
373 } else if (strcmp(command, "selfcheck") == 0) {
374 amstar_selfcheck(&argument);
375 } else if (strcmp(command, "estimate") == 0) {
376 amstar_estimate(&argument);
377 } else if (strcmp(command, "backup") == 0) {
378 amstar_backup(&argument);
379 } else if (strcmp(command, "restore") == 0) {
380 amstar_restore(&argument);
381 } else if (strcmp(command, "validate") == 0) {
382 amstar_validate(&argument);
384 fprintf(stderr, "Unknown command `%s'.\n", command);
392 application_argument_t *argument)
395 fprintf(stdout, "CONFIG YES\n");
396 fprintf(stdout, "HOST YES\n");
397 fprintf(stdout, "DISK YES\n");
398 fprintf(stdout, "MAX-LEVEL 9\n");
399 fprintf(stdout, "INDEX-LINE YES\n");
400 fprintf(stdout, "INDEX-XML NO\n");
401 fprintf(stdout, "MESSAGE-LINE YES\n");
402 fprintf(stdout, "MESSAGE-XML NO\n");
403 fprintf(stdout, "RECORD YES\n");
404 fprintf(stdout, "INCLUDE-FILE NO\n");
405 fprintf(stdout, "INCLUDE-LIST YES\n");
406 fprintf(stdout, "EXCLUDE-FILE YES\n");
407 fprintf(stdout, "EXCLUDE-LIST YES\n");
408 fprintf(stdout, "COLLECTION NO\n");
409 fprintf(stdout, "MULTI-ESTIMATE YES\n");
410 fprintf(stdout, "CALCSIZE YES\n");
411 fprintf(stdout, "CLIENT-ESTIMATE YES\n");
416 application_argument_t *argument)
418 if (argument->dle.disk) {
419 char *qdisk = quote_string(argument->dle.disk);
420 fprintf(stdout, "OK disk %s\n", qdisk);
424 fprintf(stdout, "OK amstar version %s\n", VERSION);
425 fprintf(stdout, "OK amstar\n");
427 if (argument->dle.device) {
428 char *qdevice = quote_string(argument->dle.device);
429 fprintf(stdout, "OK %s\n", qdevice);
432 if (star_directory) {
433 char *qdirectory = quote_string(star_directory);
434 fprintf(stdout, "OK %s\n", qdirectory);
438 if (argument->dle.include_list &&
439 argument->dle.include_list->nb_element >= 0) {
440 fprintf(stdout, "ERROR include-list not supported for backup\n");
444 fprintf(stdout, "ERROR STAR-PATH not defined\n");
446 if (check_file(star_path, X_OK)) {
448 GPtrArray *argv_ptr = g_ptr_array_new();
450 g_ptr_array_add(argv_ptr, star_path);
451 g_ptr_array_add(argv_ptr, "--version");
452 g_ptr_array_add(argv_ptr, NULL);
454 star_version = get_first_line(argv_ptr);
458 for (sv = star_version; *sv && !g_ascii_isdigit(*sv); sv++);
459 for (sv1 = sv; *sv1 && *sv1 != ' '; sv1++);
461 printf("OK amstar star-version %s\n", sv);
463 printf(_("ERROR [Can't get %s version]\n"), star_path);
465 g_ptr_array_free(argv_ptr, TRUE);
466 amfree(star_version);
471 if (argument->calcsize) {
472 char *calcsize = vstralloc(amlibexecdir, "/", "calcsize", NULL);
473 check_file(calcsize, X_OK);
474 check_suid(calcsize);
479 char *amandates_file;
480 amandates_file = getconf_str(CNF_AMANDATES);
481 check_file(amandates_file, R_OK|W_OK);
485 if (argument->dle.device) {
486 check_dir(argument->dle.device, R_OK);
493 application_argument_t *argument)
499 FILE *dumpout = NULL;
505 amwait_t wait_status;
510 GSList *levels = NULL;
512 if (!argument->level) {
513 fprintf(stderr, "ERROR No level argument\n");
514 error(_("No level argument"));
516 if (!argument->dle.disk) {
517 fprintf(stderr, "ERROR No disk argument\n");
518 error(_("No disk argument"));
520 if (!argument->dle.device) {
521 fprintf(stderr, "ERROR No device argument\n");
522 error(_("No device argument"));
525 if (argument->dle.include_list &&
526 argument->dle.include_list->nb_element >= 0) {
527 fprintf(stderr, "ERROR include-list not supported for backup\n");
530 if (check_device(argument) == 0) {
534 qdisk = quote_string(argument->dle.disk);
535 if (argument->calcsize) {
538 if (star_directory) {
539 dirname = star_directory;
541 dirname = argument->dle.device;
543 run_calcsize(argument->config, "STAR", argument->dle.disk, dirname,
544 argument->level, NULL, NULL);
549 errmsg = vstrallocf(_("STAR-PATH not defined"));
552 cmd = stralloc(star_path);
554 start_time = curclock();
556 for (levels = argument->level; levels != NULL; levels = levels->next) {
557 level = GPOINTER_TO_INT(levels->data);
558 argv_ptr = amstar_build_argv(argument, level, CMD_ESTIMATE);
560 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
561 errmsg = vstrallocf(_("Cannot access /dev/null : %s"),
566 starpid = pipespawnv(cmd, STDERR_PIPE, 1,
567 &nullfd, &nullfd, &pipefd,
568 (char **)argv_ptr->pdata);
570 dumpout = fdopen(pipefd,"r");
572 errmsg = vstrallocf(_("Can't fdopen: %s"), strerror(errno));
577 while (size < 0 && (fgets(line, sizeof(line), dumpout)) != NULL) {
578 if (line[strlen(line)-1] == '\n') /* remove trailling \n */
579 line[strlen(line)-1] = '\0';
582 dbprintf("%s\n", line);
583 /* check for size match */
585 for(rp = re_table; rp->regex != NULL; rp++) {
586 if(match(rp->regex, line)) {
587 if (rp->typ == DMP_SIZE) {
588 size = ((the_num(line, rp->field)*rp->scale+1023.0)/1024.0);
590 size = 1.0; /* found on NeXT -- sigh */
598 while ((fgets(line, sizeof(line), dumpout)) != NULL) {
599 dbprintf("%s", line);
603 dbprintf(_("estimate time for %s level %d: %s\n"),
606 walltime_str(timessub(curclock(), start_time)));
607 if(size == (off_t)-1) {
608 errmsg = vstrallocf(_("no size line match in %s output"),
610 dbprintf(_("%s for %s\n"), errmsg, qdisk);
612 } else if(size == (off_t)0 && argument->level == 0) {
613 dbprintf(_("possible %s problem -- is \"%s\" really empty?\n"),
614 cmd, argument->dle.disk);
617 dbprintf(_("estimate size for %s level %d: %lld KB\n"),
622 kill(-starpid, SIGTERM);
624 dbprintf(_("waiting for %s \"%s\" child\n"), cmd, qdisk);
625 waitpid(starpid, &wait_status, 0);
626 if (WIFSIGNALED(wait_status)) {
627 errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
628 cmd, WTERMSIG(wait_status), dbfn());
629 } else if (WIFEXITED(wait_status)) {
630 if (WEXITSTATUS(wait_status) != 0) {
631 errmsg = vstrallocf(_("%s exited with status %d: see %s"),
632 cmd, WEXITSTATUS(wait_status), dbfn());
637 errmsg = vstrallocf(_("%s got bad exit: see %s"), cmd, dbfn());
639 dbprintf(_("after %s %s wait\n"), cmd, qdisk);
641 g_ptr_array_free_full(argv_ptr);
646 fprintf(stdout, "%d %lld 1\n", level, (long long)size);
653 dbprintf("%s\n", errmsg);
654 qerrmsg = quote_string(errmsg);
656 dbprintf("%s", errmsg);
657 fprintf(stdout, "ERROR %s\n", qerrmsg);
665 application_argument_t *argument)
672 off_t dump_size = -1;
682 FILE *indexstream = NULL;
688 regex_t regex_special;
689 regex_t regex_symbolic;
692 mesgstream = fdopen(mesgf, "w");
694 error(_("error mesgstream(%d): %s\n"), mesgf, strerror(errno));
697 if (!argument->level) {
698 fprintf(mesgstream, "? No level argument\n");
699 error(_("No level argument"));
701 if (!argument->dle.disk) {
702 fprintf(mesgstream, "? No disk argument\n");
703 error(_("No disk argument"));
705 if (!argument->dle.device) {
706 fprintf(mesgstream, "? No device argument\n");
707 error(_("No device argument"));
710 if (argument->dle.include_list &&
711 argument->dle.include_list->nb_element >= 0) {
712 fprintf(mesgstream, "? include-list not supported for backup\n");
715 level = GPOINTER_TO_INT(argument->level->data);
717 qdisk = quote_string(argument->dle.disk);
719 argv_ptr = amstar_build_argv(argument, level, CMD_BACKUP);
721 cmd = stralloc(star_path);
723 starpid = pipespawnv(cmd, STDIN_PIPE|STDERR_PIPE, 1,
724 &dumpin, &dataf, &outf, (char **)argv_ptr->pdata);
726 g_ptr_array_free_full(argv_ptr);
727 /* close the write ends of the pipes */
730 if (argument->dle.create_index) {
731 indexstream = fdopen(indexf, "w");
733 error(_("error indexstream(%d): %s\n"), indexf, strerror(errno));
736 outstream = fdopen(outf, "r");
738 error(_("error outstream(%d): %s\n"), outf, strerror(errno));
741 regcomp(®ex_root, "^a \\.\\/ directory$", REG_EXTENDED|REG_NEWLINE);
742 regcomp(®ex_dir, "^a (.*) directory$", REG_EXTENDED|REG_NEWLINE);
743 regcomp(®ex_file, "^a (.*) (.*) bytes", REG_EXTENDED|REG_NEWLINE);
744 regcomp(®ex_special, "^a (.*) special", REG_EXTENDED|REG_NEWLINE);
745 regcomp(®ex_symbolic, "^a (.*) symbolic", REG_EXTENDED|REG_NEWLINE);
746 regcomp(®ex_hard, "^a (.*) link to", REG_EXTENDED|REG_NEWLINE);
748 while ((fgets(line, sizeof(line), outstream)) != NULL) {
749 regmatch_t regmatch[3];
751 if (line[strlen(line)-1] == '\n') /* remove trailling \n */
752 line[strlen(line)-1] = '\0';
754 if (regexec(®ex_root, line, 1, regmatch, 0) == 0) {
755 if (argument->dle.create_index)
756 fprintf(indexstream, "%s\n", "/");
760 if (regexec(®ex_dir, line, 3, regmatch, 0) == 0) {
761 if (argument->dle.create_index && regmatch[1].rm_so == 2) {
762 line[regmatch[1].rm_eo]='\0';
763 fprintf(indexstream, "/%s\n", &line[regmatch[1].rm_so]);
768 if (regexec(®ex_file, line, 3, regmatch, 0) == 0 ||
769 regexec(®ex_special, line, 3, regmatch, 0) == 0 ||
770 regexec(®ex_symbolic, line, 3, regmatch, 0) == 0 ||
771 regexec(®ex_hard, line, 3, regmatch, 0) == 0) {
772 if (argument->dle.create_index && regmatch[1].rm_so == 2) {
773 line[regmatch[1].rm_eo]='\0';
774 fprintf(indexstream, "/%s\n", &line[regmatch[1].rm_so]);
779 for (rp = re_table; rp->regex != NULL; rp++) {
780 if (match(rp->regex, line)) {
784 if (rp->typ == DMP_SIZE) {
785 dump_size = (off_t)((the_num(line, rp->field)* rp->scale+1023.0)/1024.0);
811 dbprintf("%3d: %7s(%c): %s\n", rp->srcline, type, startchr, line);
812 fprintf(mesgstream,"%c %s\n", startchr, line);
815 regfree(®ex_root);
817 regfree(®ex_file);
818 regfree(®ex_special);
819 regfree(®ex_symbolic);
820 regfree(®ex_hard);
822 dbprintf(_("gnutar: %s: pid %ld\n"), cmd, (long)starpid);
824 dbprintf("sendbackup: size %lld\n", (long long)dump_size);
825 fprintf(mesgstream, "sendbackup: size %lld\n", (long long)dump_size);
826 dbprintf("sendbackup: end\n");
827 fprintf(mesgstream, "sendbackup: end\n");
830 if (argument->dle.create_index)
839 application_argument_t *argument)
842 GPtrArray *argv_ptr = g_ptr_array_new();
848 error(_("STAR-PATH not defined"));
851 cmd = stralloc(star_path);
853 g_ptr_array_add(argv_ptr, stralloc(star_path));
854 if (star_directory) {
855 struct stat stat_buf;
856 if(stat(star_directory, &stat_buf) != 0) {
857 fprintf(stderr,"can not stat directory %s: %s\n", star_directory, strerror(errno));
860 if (!S_ISDIR(stat_buf.st_mode)) {
861 fprintf(stderr,"%s is not a directory\n", star_directory);
864 if (access(star_directory, W_OK) != 0 ) {
865 fprintf(stderr, "Can't write to %s: %s\n", star_directory, strerror(errno));
869 g_ptr_array_add(argv_ptr, stralloc("-C"));
870 g_ptr_array_add(argv_ptr, stralloc(star_directory));
872 g_ptr_array_add(argv_ptr, stralloc("-x"));
873 g_ptr_array_add(argv_ptr, stralloc("-v"));
874 g_ptr_array_add(argv_ptr, stralloc("-xattr"));
875 g_ptr_array_add(argv_ptr, stralloc("-acl"));
876 g_ptr_array_add(argv_ptr, stralloc("errctl=WARN|SAMEFILE|SETTIME|DIFF|SETACL|SETXATTR|SETMODE|BADACL *"));
877 g_ptr_array_add(argv_ptr, stralloc("-no-fifo"));
878 g_ptr_array_add(argv_ptr, stralloc("-f"));
879 g_ptr_array_add(argv_ptr, stralloc("-"));
881 if (argument->dle.exclude_list &&
882 argument->dle.exclude_list->nb_element == 1) {
883 g_ptr_array_add(argv_ptr, stralloc("-exclude-from"));
884 g_ptr_array_add(argv_ptr,
885 stralloc(argument->dle.exclude_list->first->name));
888 if (argument->dle.include_list &&
889 argument->dle.include_list->nb_element == 1) {
890 FILE *include_list = fopen(argument->dle.include_list->first->name, "r");
891 char line[2*PATH_MAX+2];
892 while (fgets(line, 2*PATH_MAX, include_list)) {
893 line[strlen(line)-1] = '\0'; /* remove '\n' */
894 if (strncmp(line, "./", 2) == 0)
895 g_ptr_array_add(argv_ptr, stralloc(line+2)); /* remove ./ */
896 else if (strcmp(line, ".") != 0)
897 g_ptr_array_add(argv_ptr, stralloc(line));
899 fclose(include_list);
901 for (j=1; j< argument->argc; j++) {
902 if (strncmp(argument->argv[j], "./", 2) == 0)
903 g_ptr_array_add(argv_ptr, stralloc(argument->argv[j]+2));/*remove ./ */
904 else if (strcmp(argument->argv[j], ".") != 0)
905 g_ptr_array_add(argv_ptr, stralloc(argument->argv[j]));
907 g_ptr_array_add(argv_ptr, NULL);
909 debug_executing(argv_ptr);
912 execve(cmd, (char **)argv_ptr->pdata, env);
914 error(_("error [exec %s: %s]"), cmd, e);
920 application_argument_t *argument G_GNUC_UNUSED)
923 GPtrArray *argv_ptr = g_ptr_array_new();
929 dbprintf("STAR-PATH not set; Piping to /dev/null\n");
930 fprintf(stderr,"STAR-PATH not set; Piping to /dev/null\n");
934 cmd = stralloc(star_path);
936 g_ptr_array_add(argv_ptr, stralloc(star_path));
937 g_ptr_array_add(argv_ptr, stralloc("-t"));
938 g_ptr_array_add(argv_ptr, stralloc("-f"));
939 g_ptr_array_add(argv_ptr, stralloc("-"));
940 g_ptr_array_add(argv_ptr, NULL);
942 debug_executing(argv_ptr);
944 execve(cmd, (char **)argv_ptr->pdata, env);
946 dbprintf("failed to execute %s: %s; Piping to /dev/null\n", cmd, e);
947 fprintf(stderr,"failed to execute %s: %s; Piping to /dev/null\n", cmd, e);
949 while (read(0, buf, 32768) > 0) {
954 static GPtrArray *amstar_build_argv(
955 application_argument_t *argument,
961 char levelstr[NUM_STR_SIZE+7];
962 GPtrArray *argv_ptr = g_ptr_array_new();
967 if (star_directory) {
968 dirname = star_directory;
970 dirname = argument->dle.device;
972 fsname = vstralloc("fs-name=", dirname, NULL);
973 for (s = fsname; *s != '\0'; s++) {
974 if (iscntrl((int)*s))
977 snprintf(levelstr, SIZEOF(levelstr), "-level=%d", level);
979 if (star_dle_tardumps) {
980 char *sdisk = sanitise_filename(argument->dle.disk);
981 tardumpfile = vstralloc(star_tardumps, sdisk, NULL);
984 tardumpfile = stralloc(star_tardumps);
987 g_ptr_array_add(argv_ptr, stralloc(star_path));
989 g_ptr_array_add(argv_ptr, stralloc("-c"));
990 g_ptr_array_add(argv_ptr, stralloc("-f"));
991 if (command == CMD_ESTIMATE) {
992 g_ptr_array_add(argv_ptr, stralloc("/dev/null"));
994 g_ptr_array_add(argv_ptr, stralloc("-"));
996 g_ptr_array_add(argv_ptr, stralloc("-C"));
998 #if defined(__CYGWIN__)
1000 char tmppath[PATH_MAX];
1002 cygwin_conv_to_full_posix_path(dirname, tmppath);
1003 g_ptr_array_add(argv_ptr, stralloc(tmppath));
1006 g_ptr_array_add(argv_ptr, stralloc(dirname));
1008 g_ptr_array_add(argv_ptr, stralloc(fsname));
1009 if (star_onefilesystem)
1010 g_ptr_array_add(argv_ptr, stralloc("-xdev"));
1011 g_ptr_array_add(argv_ptr, stralloc("-link-dirs"));
1012 g_ptr_array_add(argv_ptr, stralloc(levelstr));
1013 g_ptr_array_add(argv_ptr, stralloc2("tardumps=", tardumpfile));
1014 if (command == CMD_BACKUP)
1015 g_ptr_array_add(argv_ptr, stralloc("-wtardumps"));
1017 g_ptr_array_add(argv_ptr, stralloc("-xattr"));
1019 g_ptr_array_add(argv_ptr, stralloc("-acl"));
1020 g_ptr_array_add(argv_ptr, stralloc("H=exustar"));
1021 g_ptr_array_add(argv_ptr, stralloc("errctl=WARN|SAMEFILE|DIFF|GROW|SHRINK|SPECIALFILE|GETXATTR|BADACL *"));
1023 g_ptr_array_add(argv_ptr, stralloc("-sparse"));
1024 g_ptr_array_add(argv_ptr, stralloc("-dodesc"));
1026 if (command == CMD_BACKUP && argument->dle.create_index)
1027 g_ptr_array_add(argv_ptr, stralloc("-v"));
1029 if ((argument->dle.exclude_file &&
1030 argument->dle.exclude_file->nb_element >= 1) ||
1031 (argument->dle.exclude_list &&
1032 argument->dle.exclude_list->nb_element >= 1)) {
1033 g_ptr_array_add(argv_ptr, stralloc("-match-tree"));
1034 g_ptr_array_add(argv_ptr, stralloc("-not"));
1036 if (argument->dle.exclude_file &&
1037 argument->dle.exclude_file->nb_element >= 1) {
1039 for (excl = argument->dle.exclude_file->first; excl != NULL;
1040 excl = excl->next) {
1042 if (strcmp(excl->name, "./") == 0) {
1043 ex = g_strdup_printf("pat=%s", excl->name+2);
1045 ex = g_strdup_printf("pat=%s", excl->name);
1047 g_ptr_array_add(argv_ptr, ex);
1050 if (argument->dle.exclude_list &&
1051 argument->dle.exclude_list->nb_element >= 1) {
1053 for (excl = argument->dle.exclude_list->first; excl != NULL;
1054 excl = excl->next) {
1055 char *exclname = fixup_relative(excl->name, argument->dle.device);
1058 if ((exclude = fopen(exclname, "r")) != NULL) {
1059 while ((aexc = agets(exclude)) != NULL) {
1060 if (aexc[0] != '\0') {
1062 if (strcmp(aexc, "./") == 0) {
1063 ex = g_strdup_printf("pat=%s", aexc+2);
1065 ex = g_strdup_printf("pat=%s", aexc);
1067 g_ptr_array_add(argv_ptr, ex);
1077 /* It is best to place command_options at the and of command line.
1078 * For example '-find' option requires that it is the last option used.
1079 * See: http://cdrecord.berlios.de/private/man/star/star.1.html
1081 for (copt = argument->command_options; copt != NULL; copt = copt->next) {
1082 g_ptr_array_add(argv_ptr, stralloc((char *)copt->data));
1085 g_ptr_array_add(argv_ptr, stralloc("."));
1087 g_ptr_array_add(argv_ptr, NULL);
1089 amfree(tardumpfile);
1097 application_argument_t *argument)
1100 struct stat stat_buf;
1102 qdevice = quote_string(argument->dle.device);
1104 if(!stat(argument->dle.device, &stat_buf)) {
1105 if (!S_ISDIR(stat_buf.st_mode)) {
1107 g_fprintf(stderr, _("ERROR %s is not a directory\n"), qdevice);
1113 g_fprintf(stderr, _("ERROR can not stat %s: %s\n"), qdevice,
1118 if (access(argument->dle.device, R_OK|X_OK) == -1) {
1120 g_fprintf(stderr, _("ERROR can not access %s: %s\n"),
1121 argument->dle.device, strerror(errno));