diff options
author | Wayne Davison <wayne@opencoder.net> | 2020-06-26 16:51:30 -0700 |
---|---|---|
committer | Wayne Davison <wayne@opencoder.net> | 2020-06-26 17:56:57 -0700 |
commit | ab29ee9c44ef8d58bd2a2bf1cf0e911c71a92104 (patch) | |
tree | 05ea55a36f4e1ae2972f201f2ffad03836238e4a | |
parent | d07c2992d1b672ac8524e462fcb5f4bf223de768 (diff) | |
download | rsync-ab29ee9c44ef8d58bd2a2bf1cf0e911c71a92104.tar.gz |
Negotation env lists can specify "client & server"
-rw-r--r-- | NEWS.md | 3 | ||||
-rw-r--r-- | batch.c | 8 | ||||
-rw-r--r-- | compat.c | 76 | ||||
-rw-r--r-- | rsync.1.md | 19 |
4 files changed, 69 insertions, 37 deletions
@@ -17,7 +17,8 @@ Protocol: 31 (unchanged) ### ENHANCEMENTS: - Allow the server side to restrict checksum & compression choices via - the same environment variables the client uses. + the same environment variables the client uses. Allow the env vars + to be divided into "client list & server list" by the "`&`" char. - Simplify how the negotiation environment variables apply to older rsync versions. @@ -269,14 +269,6 @@ void write_batch_shell_file(void) err |= write_opt("--exclude-from", "-"); } - /* We need to make sure that any protocol-based or negotiated choices get accurately - * reflected in the options we save AND that we avoid any need for --read-batch to - * do a string-based negotiation (since we don't write them into the file). */ - if (do_compression) - err |= write_opt("--compress-choice", compress_choice); - if (strchr(checksum_choice, ',') || xfersum_type != parse_csum_name(NULL, -1)) - err |= write_opt("--checksum-choice", checksum_choice); - /* Elide the filename args from the option list, but scan for them in reverse. */ for (i = raw_argc-1, j = cooked_argc-1; i > 0 && j >= 0; i--) { if (strcmp(raw_argv[i], cooked_argv[j]) == 0) { @@ -20,6 +20,7 @@ */ #include "rsync.h" +#include "itypes.h" extern int am_server; extern int am_sender; @@ -109,6 +110,9 @@ struct name_num_obj valid_compressions = { #define CF_INPLACE_PARTIAL_DIR (1<<6) #define CF_VARINT_FLIST_FLAGS (1<<7) +#define ENV_CHECKSUM 0 +#define ENV_COMPRESS 1 + static const char *client_info; /* The server makes sure that if either side only supports a pre-release @@ -262,10 +266,14 @@ static void init_nno_saw(struct name_num_obj *nno, int val) static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf, int tobuf_len) { char *to = tobuf, *tok = NULL; - int cnt = 0; + int saw_tok = 0, cnt = 0; while (1) { - if (*from == ' ' || !*from) { + int at_space = isSpace(from); + char ch = *from++; + if (ch == '&') + ch = '\0'; + if (!ch || at_space) { if (tok) { struct name_num_item *nni = get_nni_by_name(nno, tok, to - tok); if (nni && !nno->saw[nni->num]) { @@ -279,9 +287,10 @@ static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf } } else to = tok - (tok != tobuf); + saw_tok = 1; tok = NULL; } - if (!*from++) + if (!ch) break; continue; } @@ -294,10 +303,13 @@ static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf to = tok - (tok != tobuf); break; } - *to++ = *from++; + *to++ = ch; } *to = '\0'; + if (saw_tok && to == tobuf) + return strlcpy(tobuf, "INVALID", MAX_NSTR_STRLEN); + return to - tobuf; } @@ -349,14 +361,36 @@ static void recv_negotiate_str(int f_in, struct name_num_obj *nno, char *tmpbuf, exit_cleanup(RERR_UNSUPPORTED); } +static const char *getenv_nstr(int etype) +{ + const char *env_str = getenv(etype == ENV_COMPRESS ? "RSYNC_COMPRESS_LIST" : "RSYNC_CHECKSUM_LIST"); + + /* When writing a batch file, we always negotiate an old-style choice. */ + if (write_batch) + env_str = etype == ENV_COMPRESS ? "zlib" : protocol_version >= 30 ? "md5" : "md4"; + + if (am_server && env_str) { + char *cp = strchr(env_str, '&'); + if (cp) + env_str = cp + 1; + } + + return env_str; +} + /* If num2 < 0 then the caller is checking compress values, otherwise checksum values. */ void validate_choice_vs_env(int num1, int num2) { struct name_num_obj *nno = num2 < 0 ? &valid_compressions : &valid_checksums; - const char *list_str = getenv(num2 < 0 ? "RSYNC_COMPRESS_LIST" : "RSYNC_CHECKSUM_LIST"); + const char *list_str = getenv_nstr(num2 < 0 ? ENV_COMPRESS : ENV_CHECKSUM); char tmpbuf[MAX_NSTR_STRLEN]; - if (!list_str || !*list_str) + if (!list_str) + return; + + while (isSpace(list_str)) list_str++; + + if (!*list_str) return; init_nno_saw(nno, 0); @@ -422,17 +456,15 @@ int get_default_nno_list(struct name_num_obj *nno, char *to_buf, int to_buf_len, return len; } -static void send_negotiate_str(int f_out, struct name_num_obj *nno, const char *env_name) +static void send_negotiate_str(int f_out, struct name_num_obj *nno, int etype) { char tmpbuf[MAX_NSTR_STRLEN]; - const char *list_str = getenv(env_name); + const char *list_str = getenv_nstr(etype); int len; if (list_str && *list_str) { init_nno_saw(nno, 0); len = parse_nni_str(nno, list_str, tmpbuf, MAX_NSTR_STRLEN); - if (!len) - len = strlcpy(tmpbuf, "FAIL", MAX_NSTR_STRLEN); list_str = tmpbuf; } else list_str = NULL; @@ -447,15 +479,10 @@ static void send_negotiate_str(int f_out, struct name_num_obj *nno, const char * rprintf(FINFO, "Client %s list (on client): %s\n", nno->type, tmpbuf); } - if (local_server) { - /* A local server doesn't bother to send/recv the strings, it just constructs - * and parses the same string on both sides. */ - recv_negotiate_str(-1, nno, tmpbuf, len); - } else if (do_negotiated_strings) { - /* Each side sends their list of valid names to the other side and then both sides - * pick the first name in the client's list that is also in the server's list. */ + /* Each side sends their list of valid names to the other side and then both sides + * pick the first name in the client's list that is also in the server's list. */ + if (do_negotiated_strings) write_vstring(f_out, tmpbuf, len); - } } static void negotiate_the_strings(int f_in, int f_out) @@ -463,10 +490,10 @@ static void negotiate_the_strings(int f_in, int f_out) /* We send all the negotiation strings before we start to read them to help avoid a slow startup. */ if (!checksum_choice) - send_negotiate_str(f_out, &valid_checksums, "RSYNC_CHECKSUM_LIST"); + send_negotiate_str(f_out, &valid_checksums, ENV_CHECKSUM); if (do_compression && !compress_choice) - send_negotiate_str(f_out, &valid_compressions, "RSYNC_COMPRESS_LIST"); + send_negotiate_str(f_out, &valid_compressions, ENV_COMPRESS); if (valid_checksums.saw) { char tmpbuf[MAX_NSTR_STRLEN]; @@ -645,10 +672,8 @@ void setup_protocol(int f_out,int f_in) if (local_server || strchr(client_info, 'I') != NULL) compat_flags |= CF_INPLACE_PARTIAL_DIR; if (local_server || strchr(client_info, 'v') != NULL) { - if (!write_batch || protocol_version >= 30) { - do_negotiated_strings = 1; - compat_flags |= CF_VARINT_FLIST_FLAGS; - } + do_negotiated_strings = 1; + compat_flags |= CF_VARINT_FLIST_FLAGS; } if (strchr(client_info, 'V') != NULL) { /* Support a pre-release 'V' that got superseded */ if (!write_batch) @@ -697,6 +722,9 @@ void setup_protocol(int f_out,int f_in) #endif } + if (read_batch) + do_negotiated_strings = 0; + if (need_unsorted_flist && (!am_sender || inc_recurse)) unsort_ndx = ++file_extra_cnt; @@ -1506,7 +1506,10 @@ your home directory (remove the '=' for that). transfer checksum separately from the pre-transfer checksum, and it ignores "auto" and all unknown checksum names. If the remote rsync is not new enough to handle a checksum negotiation list, its list is assumed to - consist of a single "md5" or "md4" item based on the protocol version. + consist of a single "md5" or "md4" item based on the protocol version. If + the environment variable contains a "`&`" character, the string is + separated into the client list & server list, either one of which can be + empty (giving that side the default list). The use of the `--checksum-choice` option overrides this environment list. @@ -2295,11 +2298,14 @@ your home directory (remove the '=' for that). When both sides of the transfer are at least 3.2.0, rsync chooses the first algorithm in the client's list of choices that is also in the server's list - of choices. Your default order can be customized by setting the environment + of choices. The default order can be customized by setting the environment variable RSYNC_COMPRESS_LIST to a space-separated list of acceptable compression names. If no common compress choice is found, the client exits - with an error. If the remote rsync is too old to support checksum negotiation, - its list is assumed to be "zlib". + with an error. If the remote rsync is too old to support checksum + negotiation, its list is assumed to be "zlib". If the environment variable + contains a "`&`" character, the string is separated into the client list & + server list, either one of which can be empty (giving that side the default + list). There are some older rsync versions that were configured to reject a `-z` option and require the use of `-zz` because their compression library was @@ -3104,6 +3110,11 @@ your home directory (remove the '=' for that). with `--read-batch`. See the "BATCH MODE" section for details, and also the `--only-write-batch` option. + This option overrides the negotiated checksum & compress lists and always + negotiates a choice based on old-school md5/md4/zlib choices. If you want + a more modern choice, use the `--checksum-choice` (`--cc`) and/or + `--compress-choice` (`--zc`) options. + 0. `--only-write-batch=FILE` Works like `--write-batch`, except that no updates are made on the |