1/* 2 * Support for the batch-file options. 3 * 4 * Copyright (C) 1999 Weiss 5 * Copyright (C) 2004 Chris Shoemaker 6 * Copyright (C) 2004, 2005, 2006 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 2 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, write to the Free Software Foundation, Inc., 20 * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 21 */ 22 23#include "rsync.h" 24#include "zlib/zlib.h" 25#include <time.h> 26 27extern int eol_nulls; 28extern int recurse; 29extern int xfer_dirs; 30extern int preserve_links; 31extern int preserve_hard_links; 32extern int preserve_devices; 33extern int preserve_uid; 34extern int preserve_gid; 35extern int always_checksum; 36extern int do_compression; 37extern int def_compress_level; 38extern int protocol_version; 39extern char *batch_name; 40 41extern struct filter_list_struct filter_list; 42 43static int tweaked_compress_level; 44 45static int *flag_ptr[] = { 46 &recurse, /* 0 */ 47 &preserve_uid, /* 1 */ 48 &preserve_gid, /* 2 */ 49 &preserve_links, /* 3 */ 50 &preserve_devices, /* 4 */ 51 &preserve_hard_links, /* 5 */ 52 &always_checksum, /* 6 */ 53 &xfer_dirs, /* 7 (protocol 29) */ 54 &tweaked_compress_level,/* 8 (protocol 29) */ 55 NULL 56}; 57 58static char *flag_name[] = { 59 "--recurse (-r)", 60 "--owner (-o)", 61 "--group (-g)", 62 "--links (-l)", 63 "--devices (-D)", 64 "--hard-links (-H)", 65 "--checksum (-c)", 66 "--dirs (-d)", 67 "--compress (-z)", 68 NULL 69}; 70 71void write_stream_flags(int fd) 72{ 73 int i, flags; 74 75#if Z_DEFAULT_COMPRESSION == -1 76 tweaked_compress_level = do_compression ? def_compress_level + 2 : 0; 77#else 78#error internal logic error! Fix def_compress_level logic above and below too! 79#endif 80 81 /* Start the batch file with a bitmap of data-stream-affecting 82 * flags. */ 83 if (protocol_version < 29) 84 flag_ptr[7] = NULL; 85 for (i = 0, flags = 0; flag_ptr[i]; i++) { 86 if (*flag_ptr[i]) 87 flags |= 1 << i; 88 } 89 write_int(fd, flags); 90} 91 92void read_stream_flags(int fd) 93{ 94 int i, flags; 95 96 if (protocol_version < 29) 97 flag_ptr[7] = NULL; 98 for (i = 0, flags = read_int(fd); flag_ptr[i]; i++) { 99 int set = flags & (1 << i) ? 1 : 0; 100 if (*flag_ptr[i] != set) { 101 if (verbose) { 102 rprintf(FINFO, 103 "%sing the %s option to match the batchfile.\n", 104 set ? "Sett" : "Clear", flag_name[i]); 105 } 106 *flag_ptr[i] = set; 107 } 108 } 109 if (protocol_version < 29) { 110 if (recurse) 111 xfer_dirs |= 1; 112 else if (xfer_dirs < 2) 113 xfer_dirs = 0; 114 } 115 116 if (tweaked_compress_level == 0 || tweaked_compress_level == 2) 117 do_compression = 0; 118 else { 119 do_compression = 1; 120 def_compress_level = tweaked_compress_level - 2; 121 } 122} 123 124static void write_arg(int fd, char *arg) 125{ 126 char *x, *s; 127 128 if (*arg == '-' && (x = strchr(arg, '=')) != NULL) { 129 write(fd, arg, x - arg + 1); 130 arg += x - arg + 1; 131 } 132 133 if (strpbrk(arg, " \"'&;|[]()$#!*?^\\") != NULL) { 134 write(fd, "'", 1); 135 for (s = arg; (x = strchr(s, '\'')) != NULL; s = x + 1) { 136 write(fd, s, x - s + 1); 137 write(fd, "'", 1); 138 } 139 write(fd, s, strlen(s)); 140 write(fd, "'", 1); 141 return; 142 } 143 144 write(fd, arg, strlen(arg)); 145} 146 147static void write_filter_rules(int fd) 148{ 149 struct filter_struct *ent; 150 151 write_sbuf(fd, " <<'#E#'\n"); 152 for (ent = filter_list.head; ent; ent = ent->next) { 153 unsigned int plen; 154 char *p = get_rule_prefix(ent->match_flags, "- ", 0, &plen); 155 write_buf(fd, p, plen); 156 write_sbuf(fd, ent->pattern); 157 if (ent->match_flags & MATCHFLG_DIRECTORY) 158 write_byte(fd, '/'); 159 write_byte(fd, eol_nulls ? 0 : '\n'); 160 } 161 if (eol_nulls) 162 write_sbuf(fd, ";\n"); 163 write_sbuf(fd, "#E#"); 164} 165 166/* This routine tries to write out an equivalent --read-batch command 167 * given the user's --write-batch args. However, it doesn't really 168 * understand most of the options, so it uses some overly simple 169 * heuristics to munge the command line into something that will 170 * (hopefully) work. */ 171void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt) 172{ 173 int fd, i, len; 174 char *p, filename[MAXPATHLEN]; 175 176 stringjoin(filename, sizeof filename, 177 batch_name, ".sh", NULL); 178 fd = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC, 179 S_IRUSR | S_IWUSR | S_IEXEC); 180 if (fd < 0) { 181 rsyserr(FERROR, errno, "Batch file %s open error", 182 filename); 183 exit_cleanup(1); 184 } 185 186 /* Write argvs info to BATCH.sh file */ 187 write_arg(fd, argv[0]); 188 if (filter_list.head) { 189 if (protocol_version >= 29) 190 write_sbuf(fd, " --filter=._-"); 191 else 192 write_sbuf(fd, " --exclude-from=-"); 193 } 194 for (i = 1; i < argc - file_arg_cnt; i++) { 195 p = argv[i]; 196 if (strncmp(p, "--files-from", 12) == 0 197 || strncmp(p, "--filter", 8) == 0 198 || strncmp(p, "--include", 9) == 0 199 || strncmp(p, "--exclude", 9) == 0) { 200 if (strchr(p, '=') == NULL) 201 i++; 202 continue; 203 } 204 if (strcmp(p, "-f") == 0) { 205 i++; 206 continue; 207 } 208 write(fd, " ", 1); 209 if (strncmp(p, "--write-batch", len = 13) == 0 210 || strncmp(p, "--only-write-batch", len = 18) == 0) { 211 write(fd, "--read-batch", 12); 212 if (p[len] == '=') { 213 write(fd, "=", 1); 214 write_arg(fd, p + len + 1); 215 } 216 } else 217 write_arg(fd, p); 218 } 219 if (!(p = check_for_hostspec(argv[argc - 1], &p, &i))) 220 p = argv[argc - 1]; 221 write(fd, " ${1:-", 6); 222 write_arg(fd, p); 223 write_byte(fd, '}'); 224 if (filter_list.head) 225 write_filter_rules(fd); 226 if (write(fd, "\n", 1) != 1 || close(fd) < 0) { 227 rsyserr(FERROR, errno, "Batch file %s write error", 228 filename); 229 exit_cleanup(1); 230 } 231} 232