File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / batch.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:32:36 2021 UTC (3 years, 7 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_2_3, HEAD
rsync 3.2.3

    1: /*
    2:  * Support for the batch-file options.
    3:  *
    4:  * Copyright (C) 1999 Weiss
    5:  * Copyright (C) 2004 Chris Shoemaker
    6:  * Copyright (C) 2004-2020 Wayne Davison
    7:  *
    8:  * This program is free software; you can redistribute it and/or modify
    9:  * it under the terms of the GNU General Public License as published by
   10:  * the Free Software Foundation; either version 3 of the License, or
   11:  * (at your option) any later version.
   12:  *
   13:  * This program is distributed in the hope that it will be useful,
   14:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   15:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16:  * GNU General Public License for more details.
   17:  *
   18:  * You should have received a copy of the GNU General Public License along
   19:  * with this program; if not, visit the http://fsf.org website.
   20:  */
   21: 
   22: #include "rsync.h"
   23: #include <zlib.h>
   24: #include <time.h>
   25: 
   26: extern int eol_nulls;
   27: extern int recurse;
   28: extern int xfer_dirs;
   29: extern int preserve_links;
   30: extern int preserve_hard_links;
   31: extern int preserve_devices;
   32: extern int preserve_uid;
   33: extern int preserve_gid;
   34: extern int preserve_acls;
   35: extern int preserve_xattrs;
   36: extern int always_checksum;
   37: extern int do_compression;
   38: extern int inplace;
   39: extern int append_mode;
   40: extern int write_batch;
   41: extern int protocol_version;
   42: extern int raw_argc, cooked_argc;
   43: extern char **raw_argv, **cooked_argv;
   44: extern char *batch_name;
   45: #ifdef ICONV_OPTION
   46: extern char *iconv_opt;
   47: #endif
   48: 
   49: extern filter_rule_list filter_list;
   50: 
   51: int batch_fd = -1;
   52: int batch_sh_fd = -1;
   53: int batch_stream_flags;
   54: 
   55: static int tweaked_append;
   56: static int tweaked_append_verify;
   57: static int tweaked_iconv;
   58: 
   59: static int *flag_ptr[] = {
   60: 	&recurse,		/* 0 */
   61: 	&preserve_uid,		/* 1 */
   62: 	&preserve_gid,		/* 2 */
   63: 	&preserve_links,	/* 3 */
   64: 	&preserve_devices,	/* 4 */
   65: 	&preserve_hard_links,	/* 5 */
   66: 	&always_checksum,	/* 6 */
   67: 	&xfer_dirs,		/* 7 (protocol 29) */
   68: 	&do_compression,	/* 8 (protocol 29) */
   69: 	&tweaked_iconv,		/* 9  (protocol 30) */
   70: 	&preserve_acls,		/* 10 (protocol 30) */
   71: 	&preserve_xattrs,	/* 11 (protocol 30) */
   72: 	&inplace,		/* 12 (protocol 30) */
   73: 	&tweaked_append,	/* 13 (protocol 30) */
   74: 	&tweaked_append_verify,	/* 14 (protocol 30) */
   75: 	NULL
   76: };
   77: 
   78: static char *flag_name[] = {
   79: 	"--recurse (-r)",
   80: 	"--owner (-o)",
   81: 	"--group (-g)",
   82: 	"--links (-l)",
   83: 	"--devices (-D)",
   84: 	"--hard-links (-H)",
   85: 	"--checksum (-c)",
   86: 	"--dirs (-d)",
   87: 	"--compress (-z)",
   88: 	"--iconv",
   89: 	"--acls (-A)",
   90: 	"--xattrs (-X)",
   91: 	"--inplace",
   92: 	"--append",
   93: 	"--append-verify",
   94: 	NULL
   95: };
   96: 
   97: void write_stream_flags(int fd)
   98: {
   99: 	int i, flags;
  100: 
  101: 	tweaked_append = append_mode == 1;
  102: 	tweaked_append_verify = append_mode == 2;
  103: #ifdef ICONV_OPTION
  104: 	tweaked_iconv = iconv_opt != NULL;
  105: #endif
  106: 
  107: 	/* Start the batch file with a bitmap of data-stream-affecting
  108: 	 * flags. */
  109: 	for (i = 0, flags = 0; flag_ptr[i]; i++) {
  110: 		if (*flag_ptr[i])
  111: 			flags |= 1 << i;
  112: 	}
  113: 	write_int(fd, flags);
  114: }
  115: 
  116: void read_stream_flags(int fd)
  117: {
  118: 	batch_stream_flags = read_int(fd);
  119: }
  120: 
  121: void check_batch_flags(void)
  122: {
  123: 	int i;
  124: 
  125: 	if (protocol_version < 29)
  126: 		flag_ptr[7] = NULL;
  127: 	else if (protocol_version < 30)
  128: 		flag_ptr[9] = NULL;
  129: 	tweaked_append = append_mode == 1;
  130: 	tweaked_append_verify = append_mode == 2;
  131: #ifdef ICONV_OPTION
  132: 	tweaked_iconv = iconv_opt != NULL;
  133: #endif
  134: 	for (i = 0; flag_ptr[i]; i++) {
  135: 		int set = batch_stream_flags & (1 << i) ? 1 : 0;
  136: 		if (*flag_ptr[i] != set) {
  137: 			if (i == 9) {
  138: 				rprintf(FERROR,
  139: 					"%s specify the --iconv option to use this batch file.\n",
  140: 					set ? "Please" : "Do not");
  141: 				exit_cleanup(RERR_SYNTAX);
  142: 			}
  143: 			if (INFO_GTE(MISC, 1)) {
  144: 				rprintf(FINFO,
  145: 					"%sing the %s option to match the batchfile.\n",
  146: 					set ? "Sett" : "Clear", flag_name[i]);
  147: 			}
  148: 			*flag_ptr[i] = set;
  149: 		}
  150: 	}
  151: 	if (protocol_version < 29) {
  152: 		if (recurse)
  153: 			xfer_dirs |= 1;
  154: 		else if (xfer_dirs < 2)
  155: 			xfer_dirs = 0;
  156: 	}
  157: 
  158: 	if (tweaked_append)
  159: 		append_mode = 1;
  160: 	else if (tweaked_append_verify)
  161: 		append_mode = 2;
  162: }
  163: 
  164: static int write_arg(const char *arg)
  165: {
  166: 	const char *x, *s;
  167: 	int len, err = 0;
  168: 
  169: 	if (*arg == '-' && (x = strchr(arg, '=')) != NULL) {
  170: 		err |= write(batch_sh_fd, arg, x - arg + 1) != x - arg + 1;
  171: 		arg += x - arg + 1;
  172: 	}
  173: 
  174: 	if (strpbrk(arg, " \"'&;|[]()$#!*?^\\") != NULL) {
  175: 		err |= write(batch_sh_fd, "'", 1) != 1;
  176: 		for (s = arg; (x = strchr(s, '\'')) != NULL; s = x + 1) {
  177: 			err |= write(batch_sh_fd, s, x - s + 1) != x - s + 1;
  178: 			err |= write(batch_sh_fd, "'", 1) != 1;
  179: 		}
  180: 		len = strlen(s);
  181: 		err |= write(batch_sh_fd, s, len) != len;
  182: 		err |= write(batch_sh_fd, "'", 1) != 1;
  183: 		return err;
  184: 	}
  185: 
  186: 	len = strlen(arg);
  187: 	err |= write(batch_sh_fd, arg, len) != len;
  188: 
  189: 	return err;
  190: }
  191: 
  192: /* Writes out a space and then an option (or other string) with an optional "=" + arg suffix. */
  193: static int write_opt(const char *opt, const char *arg)
  194: {
  195: 	int len = strlen(opt);
  196: 	int err = write(batch_sh_fd, " ", 1) != 1;
  197: 	err = write(batch_sh_fd, opt, len) != len ? 1 : 0; 
  198: 	if (arg) {
  199: 		err |= write(batch_sh_fd, "=", 1) != 1;
  200: 		err |= write_arg(arg);
  201: 	}
  202: 	return err;
  203: }
  204: 
  205: static void write_filter_rules(int fd)
  206: {
  207: 	filter_rule *ent;
  208: 
  209: 	write_sbuf(fd, " <<'#E#'\n");
  210: 	for (ent = filter_list.head; ent; ent = ent->next) {
  211: 		unsigned int plen;
  212: 		char *p = get_rule_prefix(ent, "- ", 0, &plen);
  213: 		write_buf(fd, p, plen);
  214: 		write_sbuf(fd, ent->pattern);
  215: 		if (ent->rflags & FILTRULE_DIRECTORY)
  216: 			write_byte(fd, '/');
  217: 		write_byte(fd, eol_nulls ? 0 : '\n');
  218: 	}
  219: 	if (eol_nulls)
  220: 		write_sbuf(fd, ";\n");
  221: 	write_sbuf(fd, "#E#");
  222: }
  223: 
  224: /* This sets batch_fd and (for --write-batch) batch_sh_fd. */
  225: void open_batch_files(void)
  226: {
  227: 	if (write_batch) {
  228: 		char filename[MAXPATHLEN];
  229: 
  230: 		stringjoin(filename, sizeof filename, batch_name, ".sh", NULL);
  231: 
  232: 		batch_sh_fd = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IXUSR);
  233: 		if (batch_sh_fd < 0) {
  234: 			rsyserr(FERROR, errno, "Batch file %s open error", full_fname(filename));
  235: 			exit_cleanup(RERR_FILESELECT);
  236: 		}
  237: 
  238: 		batch_fd = do_open(batch_name, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
  239: 	} else if (strcmp(batch_name, "-") == 0)
  240: 		batch_fd = STDIN_FILENO;
  241: 	else
  242: 		batch_fd = do_open(batch_name, O_RDONLY, S_IRUSR | S_IWUSR);
  243: 
  244: 	if (batch_fd < 0) {
  245: 		rsyserr(FERROR, errno, "Batch file %s open error", full_fname(batch_name));
  246: 		exit_cleanup(RERR_FILEIO);
  247: 	}
  248: }
  249: 
  250: /* This routine tries to write out an equivalent --read-batch command
  251:  * given the user's --write-batch args.  However, it doesn't really
  252:  * understand most of the options, so it uses some overly simple
  253:  * heuristics to munge the command line into something that will
  254:  * (hopefully) work. */
  255: void write_batch_shell_file(void)
  256: {
  257: 	int i, j, len, err = 0;
  258: 	char *p, *p2;
  259: 
  260: 	/* Write argvs info to BATCH.sh file */
  261: 	err |= write_arg(raw_argv[0]);
  262: 	if (filter_list.head) {
  263: 		if (protocol_version >= 29)
  264: 			err |= write_opt("--filter", "._-");
  265: 		else
  266: 			err |= write_opt("--exclude-from", "-");
  267: 	}
  268: 
  269: 	/* Elide the filename args from the option list, but scan for them in reverse. */
  270: 	for (i = raw_argc-1, j = cooked_argc-1; i > 0 && j >= 0; i--) {
  271: 		if (strcmp(raw_argv[i], cooked_argv[j]) == 0) {
  272: 			raw_argv[i] = NULL;
  273: 			j--;
  274: 		}
  275: 	}
  276: 
  277: 	for (i = 1; i < raw_argc; i++) {
  278: 		if (!(p = raw_argv[i]))
  279: 			continue;
  280: 		if (strncmp(p, "--files-from", 12) == 0
  281: 		 || strncmp(p, "--filter", 8) == 0
  282: 		 || strncmp(p, "--include", 9) == 0
  283: 		 || strncmp(p, "--exclude", 9) == 0) {
  284: 			if (strchr(p, '=') == NULL)
  285: 				i++;
  286: 			continue;
  287: 		}
  288: 		if (strcmp(p, "-f") == 0) {
  289: 			i++;
  290: 			continue;
  291: 		}
  292: 		if (strncmp(p, "--write-batch", len = 13) == 0
  293: 		 || strncmp(p, "--only-write-batch", len = 18) == 0)
  294: 			err |= write_opt("--read-batch", p[len] == '=' ? p + len + 1 : NULL);
  295: 		else {
  296: 			err |= write(batch_sh_fd, " ", 1) != 1;
  297: 			err |= write_arg(p);
  298: 		}
  299: 	}
  300: 	if (!(p = check_for_hostspec(cooked_argv[cooked_argc - 1], &p2, &i)))
  301: 		p = cooked_argv[cooked_argc - 1];
  302: 	err |= write_opt("${1:-", NULL);
  303: 	err |= write_arg(p);
  304: 	err |= write(batch_sh_fd, "}", 1) != 1;
  305: 	if (filter_list.head)
  306: 		write_filter_rules(batch_sh_fd);
  307: 	if (write(batch_sh_fd, "\n", 1) != 1 || close(batch_sh_fd) < 0 || err) {
  308: 		rsyserr(FERROR, errno, "Batch file %s.sh write error", batch_name);
  309: 		exit_cleanup(RERR_FILEIO);
  310: 	}
  311: 	batch_sh_fd = -1;
  312: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>