From 5c93dedf4538426982f8832fa9103f09a78a01ad Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Wed, 4 Jan 2023 21:52:48 -0800 Subject: [PATCH 001/101] Add backtick to SHELL_CHARS. --- options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options.c b/options.c index ded0e7a30..c9c825273 100644 --- a/options.c +++ b/options.c @@ -2518,7 +2518,7 @@ static char SPLIT_ARG_WHEN_OLD[1]; **/ char *safe_arg(const char *opt, const char *arg) { -#define SHELL_CHARS "!#$&;|<>(){}\"' \t\\" +#define SHELL_CHARS "!#$&;|<>(){}\"'` \t\\" #define WILD_CHARS "*?[]" /* We don't allow remote brace expansion */ BOOL is_filename_arg = !opt; char *escapes = is_filename_arg ? SHELL_CHARS : WILD_CHARS SHELL_CHARS; From 90df93e446f9ebbfd4ce97d6755c5fe1f45f9fd0 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sun, 8 Jan 2023 21:35:39 -0800 Subject: [PATCH 002/101] Don't call memcmp() on an empty lastdir. --- flist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flist.c b/flist.c index 65b459b17..4eb672f1c 100644 --- a/flist.c +++ b/flist.c @@ -2367,7 +2367,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) } dirlen = dir ? strlen(dir) : 0; - if (dirlen != lastdir_len || memcmp(lastdir, dir, dirlen) != 0) { + if (dirlen != lastdir_len || (dirlen && memcmp(lastdir, dir, dirlen) != 0)) { if (!change_pathname(NULL, dir, -dirlen)) goto bad_path; lastdir = pathname; From 0698ea9aeb4044d615dc0ff2c6da24cea1bcc98e Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sun, 5 Feb 2023 19:46:45 -0800 Subject: [PATCH 003/101] Fix flist string comparison issue in tr_TR.utf-8 locale. --- options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options.c b/options.c index c9c825273..097d7f31d 100644 --- a/options.c +++ b/options.c @@ -2340,7 +2340,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) if (do_progress && !am_server) { if (!log_before_transfer && INFO_EQ(NAME, 0)) parse_output_words(info_words, info_levels, "name", DEFAULT_PRIORITY); - parse_output_words(info_words, info_levels, "flist2,progress", DEFAULT_PRIORITY); + parse_output_words(info_words, info_levels, "FLIST2,PROGRESS", DEFAULT_PRIORITY); } if (dry_run) From 2c82006b1fcddcdfb12aceb838f4dff7531b6a7c Mon Sep 17 00:00:00 2001 From: dogvisor <13217529+dogvisor@users.noreply.github.com> Date: Thu, 30 Mar 2023 21:55:56 +0200 Subject: [PATCH 004/101] add rrsync option to enforce `--ignore-existing` (#461) The `-no-overwrite` rrsync option disallows the updating of existing files for incoming rrsync copies. --- support/rrsync | 4 ++++ support/rrsync.1.md | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/support/rrsync b/support/rrsync index 94c85f597..4b4b87c55 100755 --- a/support/rrsync +++ b/support/rrsync @@ -258,6 +258,9 @@ def main(): if args.munge: rsync_opts.append('--munge-links') + + if args.no_overwrite: + rsync_opts.append('--ignore-existing') if not rsync_args: rsync_args = [ '.' ] @@ -364,6 +367,7 @@ if __name__ == '__main__': arg_parser.add_argument('-munge', action='store_true', help="Enable rsync's --munge-links on the server side.") arg_parser.add_argument('-no-del', action='store_true', help="Disable rsync's --delete* and --remove* options.") arg_parser.add_argument('-no-lock', action='store_true', help="Avoid the single-run (per-user) lock check.") + arg_parser.add_argument('-no-overwrite', action='store_true', help="Prevent overwriting existing files by enforcing --ignore-existing") arg_parser.add_argument('-help', '-h', action='help', help="Output this help message and exit.") arg_parser.add_argument('dir', metavar='DIR', help="The restricted directory to use.") args = arg_parser.parse_args() diff --git a/support/rrsync.1.md b/support/rrsync.1.md index 98f2cab05..24892900d 100644 --- a/support/rrsync.1.md +++ b/support/rrsync.1.md @@ -5,7 +5,7 @@ rrsync - a script to setup restricted rsync users via ssh logins ## SYNOPSIS ``` -rrsync [-ro|-rw] [-munge] [-no-del] [-no-lock] DIR +rrsync [-ro|-rw] [-munge] [-no-del] [-no-lock] [-no-overwrite] DIR ``` The single non-option argument specifies the restricted _DIR_ to use. It can be @@ -85,6 +85,11 @@ The remainder of this manpage is dedicated to using the rrsync script. Avoid the single-run (per-user) lock check. Useful with [`-munge`](#opt). +0. `-no-overwrite` + + Enforce `--ignore-existing` on the server. Prevents overwriting existing + files when the server is the receiver. + 0. `-help`, `-h` Output this help message and exit. From c69dc7a5ab473bb52a575b5803026c2694761084 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Thu, 30 Mar 2023 12:56:33 -0700 Subject: [PATCH 005/101] Tweak shell protection news to mention a few more characters. --- NEWS.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/NEWS.md b/NEWS.md index 555d16f59..f4c748369 100644 --- a/NEWS.md +++ b/NEWS.md @@ -217,9 +217,10 @@ - A new form of arg protection was added that works similarly to the older `--protect-args` ([`-s`](rsync.1#opt)) option but in a way that avoids breaking things like rrsync (the restricted rsync script): rsync now uses - backslash escaping for sending "shell-active" characters to the remote - shell. This includes spaces, so fetching a remote file via a simple quoted - filename value now works by default without any extra quoting: + backslash escaping for sending "shell-active" characters to the remote shell + (such as `$(){}<>#&` and others). This includes spaces, so fetching a remote + file via a quoted filename value now works by default without any extra + quoting: ```shell rsync -aiv host:'a simple file.pdf' . From c3d3b49d722439f18be24a0414aa49b4b035841f Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sat, 22 Apr 2023 08:37:01 -0700 Subject: [PATCH 006/101] Make use of .UR & .UE for links. --- md-convert | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/md-convert b/md-convert index a48689a78..2cd9a72b6 100755 --- a/md-convert +++ b/md-convert @@ -276,7 +276,10 @@ class TransformHtml(HTMLParser): bad_hashtags = set(), latest_targets = [ ], opt_prefix = 'opt', + a_href = None, + a_href_external = False, a_txt_start = None, + after_a_tag = False, target_suf = '', ) @@ -315,6 +318,13 @@ class TransformHtml(HTMLParser): for bad in st.referenced_hashtags - st.created_hashtags: warn('Unknown hashtag link in', self.fn + ':', '#' + bad) + def handle_UE(self): + st = self.state + if st.txt.startswith(('.', ',', '!', '?', ';', ':')): + st.man_out[-1] = ".UE " + st.txt[0] + "\n" + st.txt = st.txt[1:] + st.after_a_tag = False + def handle_starttag(self, tag, attrs_list): st = self.state if args.debug: @@ -387,13 +397,20 @@ class TransformHtml(HTMLParser): for var, val in attrs_list: if var == 'href': if val.startswith(('https://', 'http://', 'mailto:', 'ftp:')): - pass # nothing to check + if st.after_a_tag: + self.handle_UE() + st.man_out.append(manify(st.txt.strip()) + "\n") + st.man_out.append(".UR " + val + "\n") + st.txt = '' + st.a_href = val + st.a_href_external = True elif '#' in val: pg, tgt = val.split('#', 1) if pg and pg not in VALID_PAGES or '#' in tgt: st.bad_hashtags.add(val) elif tgt in ('', 'opt', 'dopt'): st.a_href = val + st.a_href_external = False elif pg == '': st.referenced_hashtags.add(tgt) if tgt in st.latest_targets: @@ -409,6 +426,8 @@ class TransformHtml(HTMLParser): st = self.state if args.debug: self.output_debug('END', (tag,)) + if st.after_a_tag: + self.handle_UE() if tag in CONSUMES_TXT or st.dt_from == tag: txt = st.txt.strip() st.txt = '' @@ -473,7 +492,15 @@ class TransformHtml(HTMLParser): elif tag == 'hr': return elif tag == 'a': - if st.a_href: + if st.a_href_external: + st.txt = st.txt.strip() + if st.a_href != st.txt: + st.man_out.append(manify(st.txt) + "\n") + st.man_out.append(".UE\n") # This might get replaced with a punctuation version in handle_UE() + st.after_a_tag = True + st.a_href_external = False + st.txt = '' + elif st.a_href: atxt = st.txt[st.a_txt_start:] find = 'href="' + st.a_href + '"' for j in range(len(st.html_out)-1, 0, -1): From 0f599d3641bd197ff01f5182fad33169aa46a055 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sat, 22 Apr 2023 08:49:48 -0700 Subject: [PATCH 007/101] Fix overflow of sum2 buffer for sha1 rolling checksums. Fixed #353. --- checksum.c | 1 + generator.c | 2 +- match.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/checksum.c b/checksum.c index c6007f368..cd741d1ba 100644 --- a/checksum.c +++ b/checksum.c @@ -300,6 +300,7 @@ uint32 get_checksum1(char *buf1, int32 len) } #endif +/* The "sum" buffer must be at least MAX_DIGEST_LEN bytes! */ void get_checksum2(char *buf, int32 len, char *sum) { #ifdef USE_OPENSSL diff --git a/generator.c b/generator.c index 21c4a595a..557769e65 100644 --- a/generator.c +++ b/generator.c @@ -783,7 +783,7 @@ static int generate_and_send_sums(int fd, OFF_T len, int f_out, int f_copy) for (i = 0; i < sum.count; i++) { int32 n1 = (int32)MIN(len, (OFF_T)sum.blength); char *map = map_ptr(mapbuf, offset, n1); - char sum2[SUM_LENGTH]; + char sum2[MAX_DIGEST_LEN]; uint32 sum1; len -= n1; diff --git a/match.c b/match.c index 6243994ca..192b154a2 100644 --- a/match.c +++ b/match.c @@ -142,7 +142,7 @@ static void hash_search(int f,struct sum_struct *s, { OFF_T offset, aligned_offset, end; int32 k, want_i, aligned_i, backup; - char sum2[SUM_LENGTH]; + char sum2[MAX_DIGEST_LEN]; uint32 s1, s2, sum; int more; schar *map; From 6ae7f4085a5012038c29ae1c70f626cae7714b69 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sun, 23 Apr 2023 08:26:32 -0700 Subject: [PATCH 008/101] Add --force-link-text to md-convert. --- maybe-make-man | 9 ++++++++- md-convert | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/maybe-make-man b/maybe-make-man index 0dc173059..c7af73934 100755 --- a/maybe-make-man +++ b/maybe-make-man @@ -8,6 +8,7 @@ fi inname="$1" srcdir=`dirname "$0"` flagfile="$srcdir/.md2man-works" +force_flagfile="$srcdir/.md2man-force" if [ ! -f "$flagfile" ]; then # We test our smallest manpage just to see if the python setup works. @@ -32,4 +33,10 @@ if [ ! -f "$flagfile" ]; then fi fi -"$srcdir/md-convert" "$srcdir/$inname" +if [ -f "$force_flagfile" ]; then + opt='--force-link-text' +else + opt='' +fi + +"$srcdir/md-convert" $opt "$srcdir/$inname" diff --git a/md-convert b/md-convert index 2cd9a72b6..5fd63a76d 100755 --- a/md-convert +++ b/md-convert @@ -494,7 +494,7 @@ class TransformHtml(HTMLParser): elif tag == 'a': if st.a_href_external: st.txt = st.txt.strip() - if st.a_href != st.txt: + if args.force_link_text or st.a_href != st.txt: st.man_out.append(manify(st.txt) + "\n") st.man_out.append(".UE\n") # This might get replaced with a punctuation version in handle_UE() st.after_a_tag = True @@ -639,6 +639,7 @@ if __name__ == '__main__': parser = argparse.ArgumentParser(description="Convert markdown into html and (optionally) nroff. Each input filename must have a .md suffix, which is changed to .html for the output filename. If the input filename ends with .num.md (e.g. foo.1.md) then a nroff file is also output with the input filename's .md suffix removed (e.g. foo.1).", add_help=False) parser.add_argument('--test', action='store_true', help="Just test the parsing without outputting any files.") parser.add_argument('--dest', metavar='DIR', help="Create files in DIR instead of the current directory.") + parser.add_argument('--force-link-text', action='store_true', help="Don't remove the link text if it matches the link href. Useful when nroff doesn't understand .UR and .UE.") parser.add_argument('--debug', '-D', action='count', default=0, help='Output copious info on the html parsing. Repeat for even more.') parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.") parser.add_argument("mdfiles", metavar='FILE.md', nargs='+', help="One or more .md files to convert.") From fe95a9369ac7a1d8d47b036094f91946cacccf53 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sat, 29 Apr 2023 07:45:52 -0700 Subject: [PATCH 009/101] Fix issue with trailing --sparse --inplace blocks. Fixes #450. --- fileio.c | 40 ++++++++++++++++++++++------------------ receiver.c | 2 +- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/fileio.c b/fileio.c index f80af19e4..3be5bd15e 100644 --- a/fileio.c +++ b/fileio.c @@ -40,30 +40,34 @@ OFF_T preallocated_len = 0; static OFF_T sparse_seek = 0; static OFF_T sparse_past_write = 0; -int sparse_end(int f, OFF_T size) +int sparse_end(int f, OFF_T size, int updating_basis_or_equiv) { - int ret; - - sparse_past_write = 0; - - if (!sparse_seek) - return 0; + int ret = 0; + if (updating_basis_or_equiv) { + if (sparse_seek && do_punch_hole(f, sparse_past_write, sparse_seek) < 0) + ret = -1; +#ifdef HAVE_FTRUNCATE /* A compilation formality -- in-place requires ftruncate() */ + else /* Just in case the original file was longer */ + ret = do_ftruncate(f, size); +#endif + } else if (sparse_seek) { #ifdef HAVE_FTRUNCATE - ret = do_ftruncate(f, size); + ret = do_ftruncate(f, size); #else - if (do_lseek(f, sparse_seek-1, SEEK_CUR) != size-1) - ret = -1; - else { - do { - ret = write(f, "", 1); - } while (ret < 0 && errno == EINTR); - - ret = ret <= 0 ? -1 : 0; - } + if (do_lseek(f, sparse_seek-1, SEEK_CUR) != size-1) + ret = -1; + else { + do { + ret = write(f, "", 1); + } while (ret < 0 && errno == EINTR); + + ret = ret <= 0 ? -1 : 0; + } #endif + } - sparse_seek = 0; + sparse_past_write = sparse_seek = 0; return ret; } diff --git a/receiver.c b/receiver.c index c9d7e01d7..3061eeb49 100644 --- a/receiver.c +++ b/receiver.c @@ -372,7 +372,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r, if (fd != -1 && offset > 0) { if (sparse_files > 0) { - if (sparse_end(fd, offset) != 0) + if (sparse_end(fd, offset, updating_basis_or_equiv) != 0) goto report_write_error; } else if (flush_write_file(fd) < 0) { report_write_error: From b6e2321973e163f7c7f22fad4db5fd1bc3638710 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sat, 29 Apr 2023 08:20:30 -0700 Subject: [PATCH 010/101] Mention that `--crtimes` support is spotty. --- rsync.1.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rsync.1.md b/rsync.1.md index ee0a4f394..16dbf20c2 100644 --- a/rsync.1.md +++ b/rsync.1.md @@ -1636,7 +1636,9 @@ expand it. 0. `--crtimes`, `-N,` This tells rsync to set the create times (newness) of the destination - files to the same value as the source files. + files to the same value as the source files. Your OS & filesystem must + support the setting of arbitrary creation (birth) times for this option + to be supported. 0. `--omit-dir-times`, `-O` From 273dced284e2bef03ccdf626e44aec4ce6bab6fe Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sat, 29 Apr 2023 08:52:42 -0700 Subject: [PATCH 011/101] Update the NEWS. --- NEWS.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/NEWS.md b/NEWS.md index f4c748369..1d3a158b1 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,53 @@ +# NEWS for rsync 3.3.0 (UNRELEASED) + +## Changes in this version: + +### BUG FIXES: + +- Fixed a bug with `--sparse --inplace` where a trailing gap in the source + file would not clear out the trailing data in the destination file. + +- Fixed an buffer overflow in the checksum2 code if SHA1 is being used for + the checksum2 algorithm. + +- Fixed a string-comparison issue in the internal file-list code that affected + tr_TR.utf-8. + +- Add a backtick to the list of characters that the filename quoting needs to + escape using backslashes. + +- Make sure that a local transfer marks the sender side as trusted. + +- Change the argv handling to work with a newer popt library -- one that likes + to free more data than it used to. + +- Rsync now calls `OpenSSL_add_all_algorithms()` when compiled against an older + openssl library. + +- Fixed a problem in the daemon auth for older protocols (29 and before) if the + openssl library is being used to compute md4 checksums. + +- Fixed `rsync -VV` on Cygwin -- it needed a flush of stdout. + +### ENHANCEMENTS: + +- Enhanced rrsync with the `-no-overwrite` option that allows you to ensure + that existing files on your restricted but writable directory can't be + modified. + +- Enhanced the manpages to mark links with .UR & .UE. If your nroff doesn't + support these idioms, touch the file `.md2man-force` in the source directory + so that `md-convert` gets called with the `--force-link-text` option, and + that should ensure that your manpages are still readable even with the + ignored markup. + +- Some manpage improvements on the handling of [global] modules. + +- Changed the mapfrom & mapto perl scripts (in the support dir) into a single + python script named idmap. Converted a couple more perl scripts into python. + +------------------------------------------------------------------------------ + # NEWS for rsync 3.2.7 (20 Oct 2022) ## Changes in this version: @@ -4697,6 +4747,7 @@ | RELEASE DATE | VER. | DATE OF COMMIT\* | PROTOCOL | |--------------|--------|------------------|-------------| +| ?? May 2023 | 3.3.0 | | 31 | | 20 Oct 2022 | 3.2.7 | | 31 | | 09 Sep 2022 | 3.2.6 | | 31 | | 14 Aug 2022 | 3.2.5 | | 31 | From 9a06b2edb0ea1a226bcc642682c07bacd2ea47d3 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sat, 29 Apr 2023 09:01:43 -0700 Subject: [PATCH 012/101] Preparing for release of 3.3.0pre1 [buildall] --- checksum.c | 2 +- fileio.c | 2 +- flist.c | 2 +- generator.c | 2 +- latest-year.h | 2 +- match.c | 2 +- options.c | 2 +- packaging/lsb/rsync.spec | 12 ++++++------ receiver.c | 2 +- version.h | 2 +- 10 files changed, 15 insertions(+), 15 deletions(-) diff --git a/checksum.c b/checksum.c index cd741d1ba..cb21882c5 100644 --- a/checksum.c +++ b/checksum.c @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras - * Copyright (C) 2004-2022 Wayne Davison + * Copyright (C) 2004-2023 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/fileio.c b/fileio.c index 3be5bd15e..69c9a7b49 100644 --- a/fileio.c +++ b/fileio.c @@ -3,7 +3,7 @@ * * Copyright (C) 1998 Andrew Tridgell * Copyright (C) 2002 Martin Pool - * Copyright (C) 2004-2020 Wayne Davison + * Copyright (C) 2004-2023 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/flist.c b/flist.c index 4eb672f1c..311bbcf1e 100644 --- a/flist.c +++ b/flist.c @@ -4,7 +4,7 @@ * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2001, 2002 Martin Pool - * Copyright (C) 2002-2022 Wayne Davison + * Copyright (C) 2002-2023 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/generator.c b/generator.c index 557769e65..110db28fc 100644 --- a/generator.c +++ b/generator.c @@ -4,7 +4,7 @@ * Copyright (C) 1996-2000 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2002 Martin Pool - * Copyright (C) 2003-2022 Wayne Davison + * Copyright (C) 2003-2023 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/latest-year.h b/latest-year.h index 37e8efbb8..0dcf3464b 100644 --- a/latest-year.h +++ b/latest-year.h @@ -1 +1 @@ -#define LATEST_YEAR "2022" +#define LATEST_YEAR "2023" diff --git a/match.c b/match.c index 192b154a2..cdb30a15e 100644 --- a/match.c +++ b/match.c @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras - * Copyright (C) 2003-2022 Wayne Davison + * Copyright (C) 2003-2023 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/options.c b/options.c index 097d7f31d..93bbe7b06 100644 --- a/options.c +++ b/options.c @@ -3,7 +3,7 @@ * * Copyright (C) 1998-2001 Andrew Tridgell * Copyright (C) 2000, 2001, 2002 Martin Pool - * Copyright (C) 2002-2022 Wayne Davison + * Copyright (C) 2002-2023 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/packaging/lsb/rsync.spec b/packaging/lsb/rsync.spec index f2d7aa44b..5df58b966 100644 --- a/packaging/lsb/rsync.spec +++ b/packaging/lsb/rsync.spec @@ -1,9 +1,9 @@ Summary: A fast, versatile, remote (and local) file-copying tool Name: rsync -Version: 3.2.7 -%define fullversion %{version} -Release: 1 -%define srcdir src +Version: 3.3.0 +%define fullversion %{version}pre1 +Release: 0.1.pre1 +%define srcdir src-previews Group: Applications/Internet License: GPL Source0: https://rsync.samba.org/ftp/rsync/%{srcdir}/rsync-%{fullversion}.tar.gz @@ -79,8 +79,8 @@ rm -rf $RPM_BUILD_ROOT %dir /etc/rsync-ssl/certs %changelog -* Thu Oct 20 2022 Wayne Davison -Released 3.2.7. +* Sat Apr 29 2023 Wayne Davison +Released 3.3.0pre1. * Fri Mar 21 2008 Wayne Davison Added installation of /etc/xinetd.d/rsync file and some commented-out diff --git a/receiver.c b/receiver.c index 3061eeb49..6b4b369ee 100644 --- a/receiver.c +++ b/receiver.c @@ -3,7 +3,7 @@ * * Copyright (C) 1996-2000 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras - * Copyright (C) 2003-2022 Wayne Davison + * Copyright (C) 2003-2023 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/version.h b/version.h index fdfce4c40..da4bb3688 100644 --- a/version.h +++ b/version.h @@ -1,2 +1,2 @@ -#define RSYNC_VERSION "3.2.7" +#define RSYNC_VERSION "3.3.0pre1" #define MAINTAINER_TZ_OFFSET -7.0 From 86f41650fb048fa5857a137f70074d77ebe06e36 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sun, 30 Apr 2023 17:28:50 -0700 Subject: [PATCH 013/101] A couple spelling tweaks; tweak order. --- NEWS.md | 8 ++++---- rsync.1.md | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/NEWS.md b/NEWS.md index 1d3a158b1..67869cccb 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,12 +10,12 @@ - Fixed an buffer overflow in the checksum2 code if SHA1 is being used for the checksum2 algorithm. -- Fixed a string-comparison issue in the internal file-list code that affected - tr_TR.utf-8. - - Add a backtick to the list of characters that the filename quoting needs to escape using backslashes. +- Fixed a string-comparison issue in the internal file-list code that affected + tr_TR.utf-8. + - Make sure that a local transfer marks the sender side as trusted. - Change the argv handling to work with a newer popt library -- one that likes @@ -100,7 +100,7 @@ - The `--fuzzy` option was optimized a bit to try to cut down on the amount of computations when considering a big pool of files. The simple heuristic from - Kenneth Finnegan resuled in about a 2x speedup. + Kenneth Finnegan resulted in about a 2x speedup. - If rsync is forced to use protocol 29 or before (perhaps due to talking to an rsync before 3.0.0), the modify time of a file is limited to 4-bytes. Rsync diff --git a/rsync.1.md b/rsync.1.md index 16dbf20c2..894b36632 100644 --- a/rsync.1.md +++ b/rsync.1.md @@ -245,7 +245,7 @@ to be copied to different destination directories using more than one copy. While a copy of a case-ignoring filesystem to a case-ignoring filesystem can work out fairly well, if no `--delete-during` or `--delete-before` option is -active, rsync can potentially update an existing file on the receiveing side +active, rsync can potentially update an existing file on the receiving side without noticing that the upper-/lower-case of the filename should be changed to match the sender. From 05a683900f747cab2f66d94a1bba5c884eb49e8f Mon Sep 17 00:00:00 2001 From: zhangwenlong Date: Thu, 4 May 2023 23:41:52 +0800 Subject: [PATCH 014/101] update config.guess config.sub (#478) - curl -sL -o config.guess 'https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD' - curl -sL -o config.sub 'https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD' Signed-off-by: Wenlong Zhang --- config.guess | 1210 +++++++++++++++++++++++++++----------------------- config.sub | 676 ++++++++++++++++------------ 2 files changed, 1045 insertions(+), 841 deletions(-) mode change 100644 => 100755 config.guess mode change 100644 => 100755 config.sub diff --git a/config.guess b/config.guess old mode 100644 new mode 100755 index 92bfc33e2..69188da73 --- a/config.guess +++ b/config.guess @@ -1,12 +1,14 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2020 Free Software Foundation, Inc. +# Copyright 1992-2023 Free Software Foundation, Inc. -timestamp='2020-04-26' +# shellcheck disable=SC2006,SC2268 # see below for rationale + +timestamp='2023-01-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or +# the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but @@ -27,11 +29,19 @@ timestamp='2020-04-26' # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: -# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess +# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess # # Please send patches to . +# The "shellcheck disable" line above the timestamp inhibits complaints +# about features and limitations of the classic Bourne shell that were +# superseded or lifted in POSIX. However, this script identifies a wide +# variety of pre-POSIX systems that do not have POSIX shells at all, and +# even some reasonably current systems (Solaris 10 as case-in-point) still +# have a pre-POSIX /bin/sh. + + me=`echo "$0" | sed -e 's,.*/,,'` usage="\ @@ -50,7 +60,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2020 Free Software Foundation, Inc. +Copyright 1992-2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -84,6 +94,9 @@ if test $# != 0; then exit 1 fi +# Just in case it came from the environment. +GUESS= + # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a @@ -102,7 +115,7 @@ set_cc_for_build() { # prevent multiple calls if $tmp is already set test "$tmp" && return 0 : "${TMPDIR=/tmp}" - # shellcheck disable=SC2039 + # shellcheck disable=SC2039,SC3028 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || @@ -112,7 +125,7 @@ set_cc_for_build() { ,,) echo "int x;" > "$dummy.c" for driver in cc gcc c89 c99 ; do if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then - CC_FOR_BUILD="$driver" + CC_FOR_BUILD=$driver break fi done @@ -133,14 +146,12 @@ fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown -UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown -case "$UNAME_SYSTEM" in +case $UNAME_SYSTEM in Linux|GNU|GNU/*) - # If the system lacks a compiler, then just pick glibc. - # We could probably try harder. - LIBC=gnu + LIBC=unknown set_cc_for_build cat <<-EOF > "$dummy.c" @@ -149,24 +160,37 @@ Linux|GNU|GNU/*) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc - #else + #elif defined(__GLIBC__) LIBC=gnu + #else + #include + /* First heuristic to detect musl libc. */ + #ifdef __DEFINED_va_list + LIBC=musl + #endif #endif EOF - eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`" + cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + eval "$cc_set_libc" - # If ldd exists, use it to detect musl libc. - if command -v ldd >/dev/null && \ - ldd --version 2>&1 | grep -q ^musl - then - LIBC=musl + # Second heuristic to detect musl libc. + if [ "$LIBC" = unknown ] && + command -v ldd >/dev/null && + ldd --version 2>&1 | grep -q ^musl; then + LIBC=musl + fi + + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + if [ "$LIBC" = unknown ]; then + LIBC=gnu fi ;; esac # Note: order is significant - the case branches are not exclusive. -case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in +case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, @@ -178,12 +202,12 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". - sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ - "/sbin/$sysctl" 2>/dev/null || \ - "/usr/sbin/$sysctl" 2>/dev/null || \ + /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ + /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ echo unknown)` - case "$UNAME_MACHINE_ARCH" in + case $UNAME_MACHINE_ARCH in + aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; @@ -192,13 +216,13 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in earmv*) arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` - machine="${arch}${endian}"-unknown + machine=${arch}${endian}-unknown ;; - *) machine="$UNAME_MACHINE_ARCH"-unknown ;; + *) machine=$UNAME_MACHINE_ARCH-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. - case "$UNAME_MACHINE_ARCH" in + case $UNAME_MACHINE_ARCH in earm*) os=netbsdelf ;; @@ -219,7 +243,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in ;; esac # Determine ABI tags. - case "$UNAME_MACHINE_ARCH" in + case $UNAME_MACHINE_ARCH in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` @@ -230,7 +254,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. - case "$UNAME_VERSION" in + case $UNAME_VERSION in Debian*) release='-gnu' ;; @@ -241,51 +265,57 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "$machine-${os}${release}${abi-}" - exit ;; + GUESS=$machine-${os}${release}${abi-} + ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` - echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE + ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` - echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE + ;; + *:SecBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE + ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` - echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE + ;; *:MidnightBSD:*:*) - echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE + ;; *:ekkoBSD:*:*) - echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE + ;; *:SolidBSD:*:*) - echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE + ;; *:OS108:*:*) - echo "$UNAME_MACHINE"-unknown-os108_"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE + ;; macppc:MirBSD:*:*) - echo powerpc-unknown-mirbsd"$UNAME_RELEASE" - exit ;; + GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE + ;; *:MirBSD:*:*) - echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE + ;; *:Sortix:*:*) - echo "$UNAME_MACHINE"-unknown-sortix - exit ;; + GUESS=$UNAME_MACHINE-unknown-sortix + ;; *:Twizzler:*:*) - echo "$UNAME_MACHINE"-unknown-twizzler - exit ;; + GUESS=$UNAME_MACHINE-unknown-twizzler + ;; *:Redox:*:*) - echo "$UNAME_MACHINE"-unknown-redox - exit ;; + GUESS=$UNAME_MACHINE-unknown-redox + ;; mips:OSF1:*.*) - echo mips-dec-osf1 - exit ;; + GUESS=mips-dec-osf1 + ;; alpha:OSF1:*:*) + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + trap '' 0 case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` @@ -299,7 +329,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` - case "$ALPHA_CPU_TYPE" in + case $ALPHA_CPU_TYPE in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") @@ -336,117 +366,121 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`" - # Reset EXIT trap before exiting to avoid spurious non-zero exit code. - exitcode=$? - trap '' 0 - exit $exitcode ;; + OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + GUESS=$UNAME_MACHINE-dec-osf$OSF_REL + ;; Amiga*:UNIX_System_V:4.0:*) - echo m68k-unknown-sysv4 - exit ;; + GUESS=m68k-unknown-sysv4 + ;; *:[Aa]miga[Oo][Ss]:*:*) - echo "$UNAME_MACHINE"-unknown-amigaos - exit ;; + GUESS=$UNAME_MACHINE-unknown-amigaos + ;; *:[Mm]orph[Oo][Ss]:*:*) - echo "$UNAME_MACHINE"-unknown-morphos - exit ;; + GUESS=$UNAME_MACHINE-unknown-morphos + ;; *:OS/390:*:*) - echo i370-ibm-openedition - exit ;; + GUESS=i370-ibm-openedition + ;; *:z/VM:*:*) - echo s390-ibm-zvmoe - exit ;; + GUESS=s390-ibm-zvmoe + ;; *:OS400:*:*) - echo powerpc-ibm-os400 - exit ;; + GUESS=powerpc-ibm-os400 + ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - echo arm-acorn-riscix"$UNAME_RELEASE" - exit ;; + GUESS=arm-acorn-riscix$UNAME_RELEASE + ;; arm*:riscos:*:*|arm*:RISCOS:*:*) - echo arm-unknown-riscos - exit ;; + GUESS=arm-unknown-riscos + ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) - echo hppa1.1-hitachi-hiuxmpp - exit ;; + GUESS=hppa1.1-hitachi-hiuxmpp + ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. - if test "`(/bin/universe) 2>/dev/null`" = att ; then - echo pyramid-pyramid-sysv3 - else - echo pyramid-pyramid-bsd - fi - exit ;; + case `(/bin/universe) 2>/dev/null` in + att) GUESS=pyramid-pyramid-sysv3 ;; + *) GUESS=pyramid-pyramid-bsd ;; + esac + ;; NILE*:*:*:dcosx) - echo pyramid-pyramid-svr4 - exit ;; + GUESS=pyramid-pyramid-svr4 + ;; DRS?6000:unix:4.0:6*) - echo sparc-icl-nx6 - exit ;; + GUESS=sparc-icl-nx6 + ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in - sparc) echo sparc-icl-nx7; exit ;; - esac ;; + sparc) GUESS=sparc-icl-nx7 ;; + esac + ;; s390x:SunOS:*:*) - echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL + ;; sun4H:SunOS:5.*:*) - echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-hal-solaris2$SUN_REL + ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-sun-solaris2$SUN_REL + ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) - echo i386-pc-auroraux"$UNAME_RELEASE" - exit ;; + GUESS=i386-pc-auroraux$UNAME_RELEASE + ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. - if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi - echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=$SUN_ARCH-pc-solaris2$SUN_REL + ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. - echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-sun-solaris3$SUN_REL + ;; sun4*:SunOS:*:*) - case "`/usr/bin/arch -k`" in + case `/usr/bin/arch -k` in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. - echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`" - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` + GUESS=sparc-sun-sunos$SUN_REL + ;; sun3*:SunOS:*:*) - echo m68k-sun-sunos"$UNAME_RELEASE" - exit ;; + GUESS=m68k-sun-sunos$UNAME_RELEASE + ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 - case "`/bin/arch`" in + case `/bin/arch` in sun3) - echo m68k-sun-sunos"$UNAME_RELEASE" + GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun4) - echo sparc-sun-sunos"$UNAME_RELEASE" + GUESS=sparc-sun-sunos$UNAME_RELEASE ;; esac - exit ;; + ;; aushp:SunOS:*:*) - echo sparc-auspex-sunos"$UNAME_RELEASE" - exit ;; + GUESS=sparc-auspex-sunos$UNAME_RELEASE + ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor @@ -456,41 +490,41 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint"$UNAME_RELEASE" - exit ;; + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint"$UNAME_RELEASE" - exit ;; + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint"$UNAME_RELEASE" - exit ;; + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint"$UNAME_RELEASE" - exit ;; + GUESS=m68k-milan-mint$UNAME_RELEASE + ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint"$UNAME_RELEASE" - exit ;; + GUESS=m68k-hades-mint$UNAME_RELEASE + ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint"$UNAME_RELEASE" - exit ;; + GUESS=m68k-unknown-mint$UNAME_RELEASE + ;; m68k:machten:*:*) - echo m68k-apple-machten"$UNAME_RELEASE" - exit ;; + GUESS=m68k-apple-machten$UNAME_RELEASE + ;; powerpc:machten:*:*) - echo powerpc-apple-machten"$UNAME_RELEASE" - exit ;; + GUESS=powerpc-apple-machten$UNAME_RELEASE + ;; RISC*:Mach:*:*) - echo mips-dec-mach_bsd4.3 - exit ;; + GUESS=mips-dec-mach_bsd4.3 + ;; RISC*:ULTRIX:*:*) - echo mips-dec-ultrix"$UNAME_RELEASE" - exit ;; + GUESS=mips-dec-ultrix$UNAME_RELEASE + ;; VAX*:ULTRIX*:*:*) - echo vax-dec-ultrix"$UNAME_RELEASE" - exit ;; + GUESS=vax-dec-ultrix$UNAME_RELEASE + ;; 2020:CLIX:*:* | 2430:CLIX:*:*) - echo clipper-intergraph-clix"$UNAME_RELEASE" - exit ;; + GUESS=clipper-intergraph-clix$UNAME_RELEASE + ;; mips:*:*:UMIPS | mips:*:*:RISCos) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" @@ -518,75 +552,76 @@ EOF dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } - echo mips-mips-riscos"$UNAME_RELEASE" - exit ;; + GUESS=mips-mips-riscos$UNAME_RELEASE + ;; Motorola:PowerMAX_OS:*:*) - echo powerpc-motorola-powermax - exit ;; + GUESS=powerpc-motorola-powermax + ;; Motorola:*:4.3:PL8-*) - echo powerpc-harris-powermax - exit ;; + GUESS=powerpc-harris-powermax + ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) - echo powerpc-harris-powermax - exit ;; + GUESS=powerpc-harris-powermax + ;; Night_Hawk:Power_UNIX:*:*) - echo powerpc-harris-powerunix - exit ;; + GUESS=powerpc-harris-powerunix + ;; m88k:CX/UX:7*:*) - echo m88k-harris-cxux7 - exit ;; + GUESS=m88k-harris-cxux7 + ;; m88k:*:4*:R4*) - echo m88k-motorola-sysv4 - exit ;; + GUESS=m88k-motorola-sysv4 + ;; m88k:*:3*:R3*) - echo m88k-motorola-sysv3 - exit ;; + GUESS=m88k-motorola-sysv3 + ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` - if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ] + if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then - if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \ - [ "$TARGET_BINARY_INTERFACE"x = x ] + if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ + test "$TARGET_BINARY_INTERFACE"x = x then - echo m88k-dg-dgux"$UNAME_RELEASE" + GUESS=m88k-dg-dgux$UNAME_RELEASE else - echo m88k-dg-dguxbcs"$UNAME_RELEASE" + GUESS=m88k-dg-dguxbcs$UNAME_RELEASE fi else - echo i586-dg-dgux"$UNAME_RELEASE" + GUESS=i586-dg-dgux$UNAME_RELEASE fi - exit ;; + ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) - echo m88k-dolphin-sysv3 - exit ;; + GUESS=m88k-dolphin-sysv3 + ;; M88*:*:R3*:*) # Delta 88k system running SVR3 - echo m88k-motorola-sysv3 - exit ;; + GUESS=m88k-motorola-sysv3 + ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) - echo m88k-tektronix-sysv3 - exit ;; + GUESS=m88k-tektronix-sysv3 + ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) - echo m68k-tektronix-bsd - exit ;; + GUESS=m68k-tektronix-bsd + ;; *:IRIX*:*:*) - echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`" - exit ;; + IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` + GUESS=mips-sgi-irix$IRIX_REL + ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. - echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id - exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id + ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) - echo i386-ibm-aix - exit ;; + GUESS=i386-ibm-aix + ;; ia64:AIX:*:*) - if [ -x /usr/bin/oslevel ] ; then + if test -x /usr/bin/oslevel ; then IBM_REV=`/usr/bin/oslevel` else - IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" + IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi - echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" - exit ;; + GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV + ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then set_cc_for_build @@ -603,16 +638,16 @@ EOF EOF if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then - echo "$SYSTEM_NAME" + GUESS=$SYSTEM_NAME else - echo rs6000-ibm-aix3.2.5 + GUESS=rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then - echo rs6000-ibm-aix3.2.4 + GUESS=rs6000-ibm-aix3.2.4 else - echo rs6000-ibm-aix3.2 + GUESS=rs6000-ibm-aix3.2 fi - exit ;; + ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then @@ -620,56 +655,56 @@ EOF else IBM_ARCH=powerpc fi - if [ -x /usr/bin/lslpp ] ; then - IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + if test -x /usr/bin/lslpp ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else - IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" + IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi - echo "$IBM_ARCH"-ibm-aix"$IBM_REV" - exit ;; + GUESS=$IBM_ARCH-ibm-aix$IBM_REV + ;; *:AIX:*:*) - echo rs6000-ibm-aix - exit ;; + GUESS=rs6000-ibm-aix + ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) - echo romp-ibm-bsd4.4 - exit ;; + GUESS=romp-ibm-bsd4.4 + ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and - echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to - exit ;; # report: romp-ibm BSD 4.3 + GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to + ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) - echo rs6000-bull-bosx - exit ;; + GUESS=rs6000-bull-bosx + ;; DPX/2?00:B.O.S.:*:*) - echo m68k-bull-sysv3 - exit ;; + GUESS=m68k-bull-sysv3 + ;; 9000/[34]??:4.3bsd:1.*:*) - echo m68k-hp-bsd - exit ;; + GUESS=m68k-hp-bsd + ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) - echo m68k-hp-bsd4.4 - exit ;; + GUESS=m68k-hp-bsd4.4 + ;; 9000/[34678]??:HP-UX:*:*) - HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` - case "$UNAME_MACHINE" in + HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` + case $UNAME_MACHINE in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) - if [ -x /usr/bin/getconf ]; then + if test -x /usr/bin/getconf; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case "$sc_cpu_version" in + case $sc_cpu_version in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 - case "$sc_kernel_bits" in + case $sc_kernel_bits in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi - if [ "$HP_ARCH" = "" ]; then + if test "$HP_ARCH" = ""; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" @@ -708,7 +743,7 @@ EOF test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac - if [ "$HP_ARCH" = hppa2.0w ] + if test "$HP_ARCH" = hppa2.0w then set_cc_for_build @@ -729,12 +764,12 @@ EOF HP_ARCH=hppa64 fi fi - echo "$HP_ARCH"-hp-hpux"$HPUX_REV" - exit ;; + GUESS=$HP_ARCH-hp-hpux$HPUX_REV + ;; ia64:HP-UX:*:*) - HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` - echo ia64-hp-hpux"$HPUX_REV" - exit ;; + HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` + GUESS=ia64-hp-hpux$HPUX_REV + ;; 3050*:HI-UX:*:*) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" @@ -764,36 +799,36 @@ EOF EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } - echo unknown-hitachi-hiuxwe2 - exit ;; + GUESS=unknown-hitachi-hiuxwe2 + ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) - echo hppa1.1-hp-bsd - exit ;; + GUESS=hppa1.1-hp-bsd + ;; 9000/8??:4.3bsd:*:*) - echo hppa1.0-hp-bsd - exit ;; + GUESS=hppa1.0-hp-bsd + ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) - echo hppa1.0-hp-mpeix - exit ;; + GUESS=hppa1.0-hp-mpeix + ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) - echo hppa1.1-hp-osf - exit ;; + GUESS=hppa1.1-hp-osf + ;; hp8??:OSF1:*:*) - echo hppa1.0-hp-osf - exit ;; + GUESS=hppa1.0-hp-osf + ;; i*86:OSF1:*:*) - if [ -x /usr/sbin/sysversion ] ; then - echo "$UNAME_MACHINE"-unknown-osf1mk + if test -x /usr/sbin/sysversion ; then + GUESS=$UNAME_MACHINE-unknown-osf1mk else - echo "$UNAME_MACHINE"-unknown-osf1 + GUESS=$UNAME_MACHINE-unknown-osf1 fi - exit ;; + ;; parisc*:Lites*:*:*) - echo hppa1.1-hp-lites - exit ;; + GUESS=hppa1.1-hp-lites + ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) - echo c1-convex-bsd - exit ;; + GUESS=c1-convex-bsd + ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd @@ -801,17 +836,18 @@ EOF fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) - echo c34-convex-bsd - exit ;; + GUESS=c34-convex-bsd + ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) - echo c38-convex-bsd - exit ;; + GUESS=c38-convex-bsd + ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) - echo c4-convex-bsd - exit ;; + GUESS=c4-convex-bsd + ;; CRAY*Y-MP:*:*:*) - echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=ymp-cray-unicos$CRAY_REL + ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ @@ -819,112 +855,133 @@ EOF -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) - echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=t90-cray-unicos$CRAY_REL + ;; CRAY*T3E:*:*:*) - echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=alphaev5-cray-unicosmk$CRAY_REL + ;; CRAY*SV1:*:*:*) - echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=sv1-cray-unicos$CRAY_REL + ;; *:UNICOS/mp:*:*) - echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=craynv-cray-unicosmp$CRAY_REL + ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` - echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; + GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} + ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` - echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; + GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} + ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) - echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE + ;; sparc*:BSD/OS:*:*) - echo sparc-unknown-bsdi"$UNAME_RELEASE" - exit ;; + GUESS=sparc-unknown-bsdi$UNAME_RELEASE + ;; *:BSD/OS:*:*) - echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE + ;; arm:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` set_cc_for_build if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then - echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabi + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi else - echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabihf + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf fi - exit ;; + ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` - case "$UNAME_PROCESSOR" in + case $UNAME_PROCESSOR in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac - echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" - exit ;; + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL + ;; i*:CYGWIN*:*) - echo "$UNAME_MACHINE"-pc-cygwin - exit ;; + GUESS=$UNAME_MACHINE-pc-cygwin + ;; *:MINGW64*:*) - echo "$UNAME_MACHINE"-pc-mingw64 - exit ;; + GUESS=$UNAME_MACHINE-pc-mingw64 + ;; *:MINGW*:*) - echo "$UNAME_MACHINE"-pc-mingw32 - exit ;; + GUESS=$UNAME_MACHINE-pc-mingw32 + ;; *:MSYS*:*) - echo "$UNAME_MACHINE"-pc-msys - exit ;; + GUESS=$UNAME_MACHINE-pc-msys + ;; i*:PW*:*) - echo "$UNAME_MACHINE"-pc-pw32 - exit ;; + GUESS=$UNAME_MACHINE-pc-pw32 + ;; + *:SerenityOS:*:*) + GUESS=$UNAME_MACHINE-pc-serenity + ;; *:Interix*:*) - case "$UNAME_MACHINE" in + case $UNAME_MACHINE in x86) - echo i586-pc-interix"$UNAME_RELEASE" - exit ;; + GUESS=i586-pc-interix$UNAME_RELEASE + ;; authenticamd | genuineintel | EM64T) - echo x86_64-unknown-interix"$UNAME_RELEASE" - exit ;; + GUESS=x86_64-unknown-interix$UNAME_RELEASE + ;; IA64) - echo ia64-unknown-interix"$UNAME_RELEASE" - exit ;; + GUESS=ia64-unknown-interix$UNAME_RELEASE + ;; esac ;; i*:UWIN*:*) - echo "$UNAME_MACHINE"-pc-uwin - exit ;; + GUESS=$UNAME_MACHINE-pc-uwin + ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) - echo x86_64-pc-cygwin - exit ;; + GUESS=x86_64-pc-cygwin + ;; prep*:SunOS:5.*:*) - echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=powerpcle-unknown-solaris2$SUN_REL + ;; *:GNU:*:*) # the GNU system - echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`" - exit ;; + GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` + GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL + ;; *:GNU/*:*:*) # other systems with GNU libc and userland - echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC" - exit ;; + GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC + ;; + x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*) + GUESS="$UNAME_MACHINE-pc-managarm-mlibc" + ;; + *:[Mm]anagarm:*:*) + GUESS="$UNAME_MACHINE-unknown-managarm-mlibc" + ;; *:Minix:*:*) - echo "$UNAME_MACHINE"-unknown-minix - exit ;; + GUESS=$UNAME_MACHINE-unknown-minix + ;; aarch64:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; @@ -937,60 +994,63 @@ EOF esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - arc:Linux:*:* | arceb:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; arm*:Linux:*:*) set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi + GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi else - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf + GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf fi fi - exit ;; + ;; avr32*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; cris:Linux:*:*) - echo "$UNAME_MACHINE"-axis-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-axis-linux-$LIBC + ;; crisv32:Linux:*:*) - echo "$UNAME_MACHINE"-axis-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-axis-linux-$LIBC + ;; e2k:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; frv:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; hexagon:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; i*86:Linux:*:*) - echo "$UNAME_MACHINE"-pc-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-pc-linux-$LIBC + ;; ia64:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; k1om:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + loongarch32:Linux:*:* | loongarch64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; m32r*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; m68*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; mips:Linux:*:* | mips64:Linux:*:*) set_cc_for_build IS_GLIBC=0 @@ -1035,123 +1095,135 @@ EOF #endif #endif EOF - eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'`" + cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` + eval "$cc_set_vars" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; openrisc*:Linux:*:*) - echo or1k-unknown-linux-"$LIBC" - exit ;; + GUESS=or1k-unknown-linux-$LIBC + ;; or32:Linux:*:* | or1k*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; padre:Linux:*:*) - echo sparc-unknown-linux-"$LIBC" - exit ;; + GUESS=sparc-unknown-linux-$LIBC + ;; parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-"$LIBC" - exit ;; + GUESS=hppa64-unknown-linux-$LIBC + ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in - PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; - PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; - *) echo hppa-unknown-linux-"$LIBC" ;; + PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; + PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; + *) GUESS=hppa-unknown-linux-$LIBC ;; esac - exit ;; + ;; ppc64:Linux:*:*) - echo powerpc64-unknown-linux-"$LIBC" - exit ;; + GUESS=powerpc64-unknown-linux-$LIBC + ;; ppc:Linux:*:*) - echo powerpc-unknown-linux-"$LIBC" - exit ;; + GUESS=powerpc-unknown-linux-$LIBC + ;; ppc64le:Linux:*:*) - echo powerpc64le-unknown-linux-"$LIBC" - exit ;; + GUESS=powerpc64le-unknown-linux-$LIBC + ;; ppcle:Linux:*:*) - echo powerpcle-unknown-linux-"$LIBC" - exit ;; - riscv32:Linux:*:* | riscv64:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=powerpcle-unknown-linux-$LIBC + ;; + riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; s390:Linux:*:* | s390x:Linux:*:*) - echo "$UNAME_MACHINE"-ibm-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-ibm-linux-$LIBC + ;; sh64*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; sh*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; sparc:Linux:*:* | sparc64:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; tile*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; vax:Linux:*:*) - echo "$UNAME_MACHINE"-dec-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-dec-linux-$LIBC + ;; x86_64:Linux:*:*) set_cc_for_build + CPU=$UNAME_MACHINE LIBCABI=$LIBC - if [ "$CC_FOR_BUILD" != no_compiler_found ]; then - if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_X32 >/dev/null - then - LIBCABI="$LIBC"x32 - fi + if test "$CC_FOR_BUILD" != no_compiler_found; then + ABI=64 + sed 's/^ //' << EOF > "$dummy.c" + #ifdef __i386__ + ABI=x86 + #else + #ifdef __ILP32__ + ABI=x32 + #endif + #endif +EOF + cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` + eval "$cc_set_abi" + case $ABI in + x86) CPU=i686 ;; + x32) LIBCABI=${LIBC}x32 ;; + esac fi - echo "$UNAME_MACHINE"-pc-linux-"$LIBCABI" - exit ;; + GUESS=$CPU-pc-linux-$LIBCABI + ;; xtensa*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. - echo i386-sequent-sysv4 - exit ;; + GUESS=i386-sequent-sysv4 + ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. - echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION" - exit ;; + GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION + ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. - echo "$UNAME_MACHINE"-pc-os2-emx - exit ;; + GUESS=$UNAME_MACHINE-pc-os2-emx + ;; i*86:XTS-300:*:STOP) - echo "$UNAME_MACHINE"-unknown-stop - exit ;; + GUESS=$UNAME_MACHINE-unknown-stop + ;; i*86:atheos:*:*) - echo "$UNAME_MACHINE"-unknown-atheos - exit ;; + GUESS=$UNAME_MACHINE-unknown-atheos + ;; i*86:syllable:*:*) - echo "$UNAME_MACHINE"-pc-syllable - exit ;; + GUESS=$UNAME_MACHINE-pc-syllable + ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) - echo i386-unknown-lynxos"$UNAME_RELEASE" - exit ;; + GUESS=i386-unknown-lynxos$UNAME_RELEASE + ;; i*86:*DOS:*:*) - echo "$UNAME_MACHINE"-pc-msdosdjgpp - exit ;; + GUESS=$UNAME_MACHINE-pc-msdosdjgpp + ;; i*86:*:4.*:*) UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" + GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL else - echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL" + GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL fi - exit ;; + ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in @@ -1159,12 +1231,12 @@ EOF *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac - echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}" - exit ;; + GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 @@ -1174,11 +1246,11 @@ EOF && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 - echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL" + GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL else - echo "$UNAME_MACHINE"-pc-sysv32 + GUESS=$UNAME_MACHINE-pc-sysv32 fi - exit ;; + ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about @@ -1186,31 +1258,31 @@ EOF # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. - echo i586-pc-msdosdjgpp - exit ;; + GUESS=i586-pc-msdosdjgpp + ;; Intel:Mach:3*:*) - echo i386-pc-mach3 - exit ;; + GUESS=i386-pc-mach3 + ;; paragon:*:*:*) - echo i860-intel-osf1 - exit ;; + GUESS=i860-intel-osf1 + ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then - echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4 + GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. - echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4 + GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 fi - exit ;; + ;; mini*:CTIX:SYS*5:*) # "miniframe" - echo m68010-convergent-sysv - exit ;; + GUESS=m68010-convergent-sysv + ;; mc68k:UNIX:SYSTEM5:3.51m) - echo m68k-convergent-sysv - exit ;; + GUESS=m68k-convergent-sysv + ;; M680?0:D-NIX:5.3:*) - echo m68k-diab-dnix - exit ;; + GUESS=m68k-diab-dnix + ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) @@ -1235,113 +1307,119 @@ EOF /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) - echo m68k-unknown-lynxos"$UNAME_RELEASE" - exit ;; + GUESS=m68k-unknown-lynxos$UNAME_RELEASE + ;; mc68030:UNIX_System_V:4.*:*) - echo m68k-atari-sysv4 - exit ;; + GUESS=m68k-atari-sysv4 + ;; TSUNAMI:LynxOS:2.*:*) - echo sparc-unknown-lynxos"$UNAME_RELEASE" - exit ;; + GUESS=sparc-unknown-lynxos$UNAME_RELEASE + ;; rs6000:LynxOS:2.*:*) - echo rs6000-unknown-lynxos"$UNAME_RELEASE" - exit ;; + GUESS=rs6000-unknown-lynxos$UNAME_RELEASE + ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) - echo powerpc-unknown-lynxos"$UNAME_RELEASE" - exit ;; + GUESS=powerpc-unknown-lynxos$UNAME_RELEASE + ;; SM[BE]S:UNIX_SV:*:*) - echo mips-dde-sysv"$UNAME_RELEASE" - exit ;; + GUESS=mips-dde-sysv$UNAME_RELEASE + ;; RM*:ReliantUNIX-*:*:*) - echo mips-sni-sysv4 - exit ;; + GUESS=mips-sni-sysv4 + ;; RM*:SINIX-*:*:*) - echo mips-sni-sysv4 - exit ;; + GUESS=mips-sni-sysv4 + ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` - echo "$UNAME_MACHINE"-sni-sysv4 + GUESS=$UNAME_MACHINE-sni-sysv4 else - echo ns32k-sni-sysv + GUESS=ns32k-sni-sysv fi - exit ;; + ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says - echo i586-unisys-sysv4 - exit ;; + GUESS=i586-unisys-sysv4 + ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm - echo hppa1.1-stratus-sysv4 - exit ;; + GUESS=hppa1.1-stratus-sysv4 + ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. - echo i860-stratus-sysv4 - exit ;; + GUESS=i860-stratus-sysv4 + ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. - echo "$UNAME_MACHINE"-stratus-vos - exit ;; + GUESS=$UNAME_MACHINE-stratus-vos + ;; *:VOS:*:*) # From Paul.Green@stratus.com. - echo hppa1.1-stratus-vos - exit ;; + GUESS=hppa1.1-stratus-vos + ;; mc68*:A/UX:*:*) - echo m68k-apple-aux"$UNAME_RELEASE" - exit ;; + GUESS=m68k-apple-aux$UNAME_RELEASE + ;; news*:NEWS-OS:6*:*) - echo mips-sony-newsos6 - exit ;; + GUESS=mips-sony-newsos6 + ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) - if [ -d /usr/nec ]; then - echo mips-nec-sysv"$UNAME_RELEASE" + if test -d /usr/nec; then + GUESS=mips-nec-sysv$UNAME_RELEASE else - echo mips-unknown-sysv"$UNAME_RELEASE" + GUESS=mips-unknown-sysv$UNAME_RELEASE fi - exit ;; + ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. - echo powerpc-be-beos - exit ;; + GUESS=powerpc-be-beos + ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. - echo powerpc-apple-beos - exit ;; + GUESS=powerpc-apple-beos + ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. - echo i586-pc-beos - exit ;; + GUESS=i586-pc-beos + ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. - echo i586-pc-haiku - exit ;; - x86_64:Haiku:*:*) - echo x86_64-unknown-haiku - exit ;; + GUESS=i586-pc-haiku + ;; + ppc:Haiku:*:*) # Haiku running on Apple PowerPC + GUESS=powerpc-apple-haiku + ;; + *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) + GUESS=$UNAME_MACHINE-unknown-haiku + ;; SX-4:SUPER-UX:*:*) - echo sx4-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sx4-nec-superux$UNAME_RELEASE + ;; SX-5:SUPER-UX:*:*) - echo sx5-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sx5-nec-superux$UNAME_RELEASE + ;; SX-6:SUPER-UX:*:*) - echo sx6-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sx6-nec-superux$UNAME_RELEASE + ;; SX-7:SUPER-UX:*:*) - echo sx7-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sx7-nec-superux$UNAME_RELEASE + ;; SX-8:SUPER-UX:*:*) - echo sx8-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sx8-nec-superux$UNAME_RELEASE + ;; SX-8R:SUPER-UX:*:*) - echo sx8r-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sx8r-nec-superux$UNAME_RELEASE + ;; SX-ACE:SUPER-UX:*:*) - echo sxace-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sxace-nec-superux$UNAME_RELEASE + ;; Power*:Rhapsody:*:*) - echo powerpc-apple-rhapsody"$UNAME_RELEASE" - exit ;; + GUESS=powerpc-apple-rhapsody$UNAME_RELEASE + ;; *:Rhapsody:*:*) - echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE + ;; + arm64:Darwin:*:*) + GUESS=aarch64-apple-darwin$UNAME_RELEASE + ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in @@ -1356,7 +1434,7 @@ EOF else set_cc_for_build fi - if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null @@ -1377,109 +1455,119 @@ EOF # uname -m returns i386 or x86_64 UNAME_PROCESSOR=$UNAME_MACHINE fi - echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE + ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi - echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE + ;; *:QNX:*:4*) - echo i386-pc-qnx - exit ;; + GUESS=i386-pc-qnx + ;; NEO-*:NONSTOP_KERNEL:*:*) - echo neo-tandem-nsk"$UNAME_RELEASE" - exit ;; + GUESS=neo-tandem-nsk$UNAME_RELEASE + ;; NSE-*:NONSTOP_KERNEL:*:*) - echo nse-tandem-nsk"$UNAME_RELEASE" - exit ;; + GUESS=nse-tandem-nsk$UNAME_RELEASE + ;; NSR-*:NONSTOP_KERNEL:*:*) - echo nsr-tandem-nsk"$UNAME_RELEASE" - exit ;; + GUESS=nsr-tandem-nsk$UNAME_RELEASE + ;; NSV-*:NONSTOP_KERNEL:*:*) - echo nsv-tandem-nsk"$UNAME_RELEASE" - exit ;; + GUESS=nsv-tandem-nsk$UNAME_RELEASE + ;; NSX-*:NONSTOP_KERNEL:*:*) - echo nsx-tandem-nsk"$UNAME_RELEASE" - exit ;; + GUESS=nsx-tandem-nsk$UNAME_RELEASE + ;; *:NonStop-UX:*:*) - echo mips-compaq-nonstopux - exit ;; + GUESS=mips-compaq-nonstopux + ;; BS2000:POSIX*:*:*) - echo bs2000-siemens-sysv - exit ;; + GUESS=bs2000-siemens-sysv + ;; DS/*:UNIX_System_V:*:*) - echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE + ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. - # shellcheck disable=SC2154 - if test "$cputype" = 386; then + if test "${cputype-}" = 386; then UNAME_MACHINE=i386 - else - UNAME_MACHINE="$cputype" + elif test "x${cputype-}" != x; then + UNAME_MACHINE=$cputype fi - echo "$UNAME_MACHINE"-unknown-plan9 - exit ;; + GUESS=$UNAME_MACHINE-unknown-plan9 + ;; *:TOPS-10:*:*) - echo pdp10-unknown-tops10 - exit ;; + GUESS=pdp10-unknown-tops10 + ;; *:TENEX:*:*) - echo pdp10-unknown-tenex - exit ;; + GUESS=pdp10-unknown-tenex + ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) - echo pdp10-dec-tops20 - exit ;; + GUESS=pdp10-dec-tops20 + ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) - echo pdp10-xkl-tops20 - exit ;; + GUESS=pdp10-xkl-tops20 + ;; *:TOPS-20:*:*) - echo pdp10-unknown-tops20 - exit ;; + GUESS=pdp10-unknown-tops20 + ;; *:ITS:*:*) - echo pdp10-unknown-its - exit ;; + GUESS=pdp10-unknown-its + ;; SEI:*:*:SEIUX) - echo mips-sei-seiux"$UNAME_RELEASE" - exit ;; + GUESS=mips-sei-seiux$UNAME_RELEASE + ;; *:DragonFly:*:*) - echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" - exit ;; + DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL + ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` - case "$UNAME_MACHINE" in - A*) echo alpha-dec-vms ; exit ;; - I*) echo ia64-dec-vms ; exit ;; - V*) echo vax-dec-vms ; exit ;; + case $UNAME_MACHINE in + A*) GUESS=alpha-dec-vms ;; + I*) GUESS=ia64-dec-vms ;; + V*) GUESS=vax-dec-vms ;; esac ;; *:XENIX:*:SysV) - echo i386-pc-xenix - exit ;; + GUESS=i386-pc-xenix + ;; i*86:skyos:*:*) - echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`" - exit ;; + SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` + GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL + ;; i*86:rdos:*:*) - echo "$UNAME_MACHINE"-pc-rdos - exit ;; - i*86:AROS:*:*) - echo "$UNAME_MACHINE"-pc-aros - exit ;; + GUESS=$UNAME_MACHINE-pc-rdos + ;; + i*86:Fiwix:*:*) + GUESS=$UNAME_MACHINE-pc-fiwix + ;; + *:AROS:*:*) + GUESS=$UNAME_MACHINE-unknown-aros + ;; x86_64:VMkernel:*:*) - echo "$UNAME_MACHINE"-unknown-esx - exit ;; + GUESS=$UNAME_MACHINE-unknown-esx + ;; amd64:Isilon\ OneFS:*:*) - echo x86_64-unknown-onefs - exit ;; + GUESS=x86_64-unknown-onefs + ;; *:Unleashed:*:*) - echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE + ;; esac +# Do we have a guess based on uname results? +if test "x$GUESS" != x; then + echo "$GUESS" + exit +fi + # No uname command or uname output not recognized. set_cc_for_build cat > "$dummy.c" </dev/null && SYSTEM_NAME=`$dummy` && +$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. @@ -1619,7 +1707,7 @@ test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } echo "$0: unable to guess system type" >&2 -case "$UNAME_MACHINE:$UNAME_SYSTEM" in +case $UNAME_MACHINE:$UNAME_SYSTEM in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&2 <&2 - exit 1 + # No normalization, but not necessarily accepted, that comes below. ;; esac + else # Here we handle the default operating systems that come with various machines. @@ -1528,6 +1531,7 @@ else # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. +kernel= case $cpu-$vendor in score-*) os=elf @@ -1539,7 +1543,8 @@ case $cpu-$vendor in os=riscix1.2 ;; arm*-rebel) - os=linux + kernel=linux + os=gnu ;; arm*-semi) os=aout @@ -1705,84 +1710,193 @@ case $cpu-$vendor in os=none ;; esac + fi +# Now, validate our (potentially fixed-up) OS. +case $os in + # Sometimes we do "kernel-libc", so those need to count as OSes. + musl* | newlib* | relibc* | uclibc*) + ;; + # Likewise for "kernel-abi" + eabi* | gnueabi*) + ;; + # VxWorks passes extra cpu info in the 4th filed. + simlinux | simwindows | spe) + ;; + # Now accept the basic system types. + # The portable systems comes first. + # Each alternative MUST end in a * to match a version number. + gnu* | android* | bsd* | mach* | minix* | genix* | ultrix* | irix* \ + | *vms* | esix* | aix* | cnk* | sunos | sunos[34]* \ + | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ + | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \ + | hiux* | abug | nacl* | netware* | windows* \ + | os9* | macos* | osx* | ios* \ + | mpw* | magic* | mmixware* | mon960* | lnews* \ + | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ + | aos* | aros* | cloudabi* | sortix* | twizzler* \ + | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \ + | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \ + | mirbsd* | netbsd* | dicos* | openedition* | ose* \ + | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \ + | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \ + | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ + | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \ + | udi* | lites* | ieee* | go32* | aux* | hcos* \ + | chorusrdb* | cegcc* | glidix* | serenity* \ + | cygwin* | msys* | pe* | moss* | proelf* | rtems* \ + | midipix* | mingw32* | mingw64* | mint* \ + | uxpv* | beos* | mpeix* | udk* | moxiebox* \ + | interix* | uwin* | mks* | rhapsody* | darwin* \ + | openstep* | oskit* | conix* | pw32* | nonstopux* \ + | storm-chaos* | tops10* | tenex* | tops20* | its* \ + | os2* | vos* | palmos* | uclinux* | nucleus* | morphos* \ + | scout* | superux* | sysv* | rtmk* | tpf* | windiss* \ + | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \ + | skyos* | haiku* | rdos* | toppers* | drops* | es* \ + | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ + | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ + | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \ + | fiwix* | mlibc* ) + ;; + # This one is extra strict with allowed versions + sco3.2v2 | sco3.2v[4-9]* | sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + ;; + none) + ;; + kernel* ) + # Restricted further below + ;; + *) + echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2 + exit 1 + ;; +esac + +# As a final step for OS-related things, validate the OS-kernel combination +# (given a valid OS), if there is a kernel. +case $kernel-$os in + linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \ + | linux-musl* | linux-relibc* | linux-uclibc* | linux-mlibc* ) + ;; + uclinux-uclibc* ) + ;; + managarm-mlibc* | managarm-kernel* ) + ;; + -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* | -mlibc* ) + # These are just libc implementations, not actual OSes, and thus + # require a kernel. + echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 + exit 1 + ;; + -kernel* ) + echo "Invalid configuration \`$1': \`$os' needs explicit kernel." 1>&2 + exit 1 + ;; + *-kernel* ) + echo "Invalid configuration \`$1': \`$kernel' does not support \`$os'." 1>&2 + exit 1 + ;; + kfreebsd*-gnu* | kopensolaris*-gnu*) + ;; + vxworks-simlinux | vxworks-simwindows | vxworks-spe) + ;; + nto-qnx*) + ;; + os2-emx) + ;; + *-eabi* | *-gnueabi*) + ;; + -*) + # Blank kernel with real OS is always fine. + ;; + *-*) + echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 + exit 1 + ;; +esac + # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. case $vendor in unknown) - case $os in - riscix*) + case $cpu-$os in + *-riscix*) vendor=acorn ;; - sunos*) + *-sunos*) vendor=sun ;; - cnk*|-aix*) + *-cnk* | *-aix*) vendor=ibm ;; - beos*) + *-beos*) vendor=be ;; - hpux*) + *-hpux*) vendor=hp ;; - mpeix*) + *-mpeix*) vendor=hp ;; - hiux*) + *-hiux*) vendor=hitachi ;; - unos*) + *-unos*) vendor=crds ;; - dgux*) + *-dgux*) vendor=dg ;; - luna*) + *-luna*) vendor=omron ;; - genix*) + *-genix*) vendor=ns ;; - clix*) + *-clix*) vendor=intergraph ;; - mvs* | opened*) + *-mvs* | *-opened*) + vendor=ibm + ;; + *-os400*) vendor=ibm ;; - os400*) + s390-* | s390x-*) vendor=ibm ;; - ptx*) + *-ptx*) vendor=sequent ;; - tpf*) + *-tpf*) vendor=ibm ;; - vxsim* | vxworks* | windiss*) + *-vxsim* | *-vxworks* | *-windiss*) vendor=wrs ;; - aux*) + *-aux*) vendor=apple ;; - hms*) + *-hms*) vendor=hitachi ;; - mpw* | macos*) + *-mpw* | *-macos*) vendor=apple ;; - *mint | mint[0-9]* | *MiNT | MiNT[0-9]*) + *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) vendor=atari ;; - vos*) + *-vos*) vendor=stratus ;; esac ;; esac -echo "$cpu-$vendor-$os" +echo "$cpu-$vendor-${kernel:+$kernel-}$os" exit # Local variables: From cd76993461d929aa44fabde9f5eff0791358c996 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Thu, 4 May 2023 08:45:42 -0700 Subject: [PATCH 015/101] Mention updated config files. --- NEWS.md | 5 +++++ config.guess | 0 config.sub | 0 3 files changed, 5 insertions(+) mode change 100755 => 100644 config.guess mode change 100755 => 100644 config.sub diff --git a/NEWS.md b/NEWS.md index 67869cccb..2821a9904 100644 --- a/NEWS.md +++ b/NEWS.md @@ -46,6 +46,11 @@ - Changed the mapfrom & mapto perl scripts (in the support dir) into a single python script named idmap. Converted a couple more perl scripts into python. +### DEVELOPER RELATED: + + - Updated config.guess (timestamp 2023-01-01) and config.sub (timestamp + 2023-01-21). + ------------------------------------------------------------------------------ # NEWS for rsync 3.2.7 (20 Oct 2022) diff --git a/config.guess b/config.guess old mode 100755 new mode 100644 diff --git a/config.sub b/config.sub old mode 100755 new mode 100644 From 79fda353425daba6b23753c8b1b01dc35ecaac7d Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Thu, 4 May 2023 08:56:10 -0700 Subject: [PATCH 016/101] A couple more NEWS improvements. --- NEWS.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/NEWS.md b/NEWS.md index 2821a9904..562240091 100644 --- a/NEWS.md +++ b/NEWS.md @@ -13,8 +13,9 @@ - Add a backtick to the list of characters that the filename quoting needs to escape using backslashes. -- Fixed a string-comparison issue in the internal file-list code that affected - tr_TR.utf-8. +- Fixed a string-comparison issue in the internal handling of `--progress` (a + locale such as tr_TR.utf-8 needed the internal triggering of `--info` options + to use upper-case flag names to ensure that they match). - Make sure that a local transfer marks the sender side as trusted. @@ -25,7 +26,7 @@ openssl library. - Fixed a problem in the daemon auth for older protocols (29 and before) if the - openssl library is being used to compute md4 checksums. + openssl library is being used to compute MD4 checksums. - Fixed `rsync -VV` on Cygwin -- it needed a flush of stdout. From 6f3c5eccee6cf4dead68b9f3fda8fc2ff90dc311 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Tue, 16 May 2023 22:44:54 -0700 Subject: [PATCH 017/101] Fix old stats bug that counted devices as symlinks. --- NEWS.md | 2 ++ delete.c | 2 +- flist.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 562240091..ca60c32cb 100644 --- a/NEWS.md +++ b/NEWS.md @@ -30,6 +30,8 @@ - Fixed `rsync -VV` on Cygwin -- it needed a flush of stdout. +- Fixed an old stats bug that counted devices as symlinks. + ### ENHANCEMENTS: - Enhanced rrsync with the `-no-overwrite` option that allows you to ensure diff --git a/delete.c b/delete.c index 4a2948530..807661643 100644 --- a/delete.c +++ b/delete.c @@ -188,7 +188,7 @@ enum delret delete_item(char *fbuf, uint16 mode, uint16 flags) stats.deleted_symlinks++; #endif else if (IS_DEVICE(mode)) - stats.deleted_symlinks++; + stats.deleted_devices++; else stats.deleted_specials++; } diff --git a/flist.c b/flist.c index 311bbcf1e..464d556ec 100644 --- a/flist.c +++ b/flist.c @@ -2659,7 +2659,7 @@ struct file_list *recv_file_list(int f, int dir_ndx) } else if (S_ISLNK(file->mode)) stats.num_symlinks++; else if (IS_DEVICE(file->mode)) - stats.num_symlinks++; + stats.num_devices++; else stats.num_specials++; From 3476caea3e10ec06b839d0e95b09c145dd3cbfaf Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Mon, 22 May 2023 08:29:15 -0700 Subject: [PATCH 018/101] Convert mnt-excl into python. --- support/mnt-excl | 48 +++++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/support/mnt-excl b/support/mnt-excl index ed7b49ba5..bc8b5bcd8 100755 --- a/support/mnt-excl +++ b/support/mnt-excl @@ -1,4 +1,4 @@ -#!/usr/bin/env perl +#!/usr/bin/env python3 # This script takes a command-line arg of a source directory # that will be passed to rsync, and generates a set of excludes # that will exclude all mount points from the list. This is @@ -27,23 +27,33 @@ # awk '{print $2}' /proc/mounts | grep -v '^/$' | \ # rsync -avf 'merge,/- -' /dir host:/dest/ -use strict; -use warnings; -use Cwd 'abs_path'; +import os, argparse -my $file = '/proc/mounts'; -my $dir = shift || '/'; -my $trailing_slash = $dir =~ m{./$} ? '/' : ''; -$dir = abs_path($dir) . $trailing_slash; -$dir =~ s{([^/]*)$}{}; -my $trailing = $1; -$trailing = '' if $trailing eq '.' || !-d "$dir$trailing"; -$trailing .= '/' if $trailing ne ''; +MNT_FILE = '/proc/mounts'; -open(IN, $file) or die "Unable to open $file: $!\n"; -while () { - $_ = (split)[1]; - next unless s{^\Q$dir$trailing\E}{}o && $_ ne ''; - print "- /$trailing$_\n"; -} -close IN; +def main(): + trailing_slash = '/' if args.path.endswith(('/', '/.')) and args.path != '/' else '' + args.path = os.path.realpath(args.path) + trailing_slash + parent_dir = os.path.dirname(args.path) + trailing = os.path.basename(args.path) + if not os.path.isdir(args.path): + trailing = '' + elif trailing != '': + trailing += '/' + want_path = os.path.join(parent_dir, trailing) + wp_len = len(want_path) + + with open(MNT_FILE) as fh: + for line in fh: + mnt_path = line.split()[1] + if mnt_path.startswith(want_path) and mnt_path != want_path: + print(f"- /{trailing}{mnt_path[wp_len:]}") + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description="Output mount points as rsync excludes.", add_help=False) + parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.") + parser.add_argument('path', metavar='PATH', nargs='?', default='/', help="Limit output to those within the PATH hierarchy.") + args = parser.parse_args() + main() + +# vim: sw=4 et From 2f9b963abaa52e44891180fe6c0d1c2219f6686d Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Tue, 27 Jun 2023 09:01:15 -0700 Subject: [PATCH 019/101] Make `--max-alloc=0` safer. Always do size checking in my_alloc(), even for `--max-alloc=0`. --- options.c | 2 ++ rsync.1.md | 3 ++- util2.c | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/options.c b/options.c index 93bbe7b06..fd674754c 100644 --- a/options.c +++ b/options.c @@ -1946,6 +1946,8 @@ int parse_arguments(int *argc_p, const char ***argv_p) goto cleanup; max_alloc = size; } + if (!max_alloc) + max_alloc = SIZE_MAX; if (old_style_args < 0) { if (!am_server && protect_args <= 0 && (arg = getenv("RSYNC_OLD_ARGS")) != NULL && *arg) { diff --git a/rsync.1.md b/rsync.1.md index 894b36632..2ae6f4816 100644 --- a/rsync.1.md +++ b/rsync.1.md @@ -2106,7 +2106,8 @@ expand it. See the [`--max-size`](#opt) option for a description of how SIZE can be specified. The default suffix if none is given is bytes. - Beginning in 3.2.3, a value of 0 specifies no limit. + Beginning in 3.2.7, a value of 0 is an easy way to specify SIZE_MAX (the + largest limit possible). You can set a default value using the environment variable [`RSYNC_MAX_ALLOC`](#) using the same SIZE values as supported by this diff --git a/util2.c b/util2.c index a8609a5d5..3b5a8f414 100644 --- a/util2.c +++ b/util2.c @@ -72,7 +72,7 @@ int msleep(int t) void *my_alloc(void *ptr, size_t num, size_t size, const char *file, int line) { - if (max_alloc && num >= max_alloc/size) { + if (num >= max_alloc/size) { if (!file) return NULL; rprintf(FERROR, "[%s] exceeded --max-alloc=%s setting (file=%s, line=%d)\n", From a47ae6fad901d94c1853fa27b56bc458a48bbee2 Mon Sep 17 00:00:00 2001 From: Grant Gardner Date: Sun, 17 Mar 2024 14:00:16 +1100 Subject: [PATCH 020/101] typo in rsyncd.conf.5.md --- rsyncd.conf.5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rsyncd.conf.5.md b/rsyncd.conf.5.md index 3d91cd93d..cd10e659c 100644 --- a/rsyncd.conf.5.md +++ b/rsyncd.conf.5.md @@ -1023,7 +1023,7 @@ in the values of parameters. See that section for details. _not_ displayed if the script returns success. The other programs cannot send any text to the user. All output except for the `pre-xfer exec` stdout goes to the corresponding daemon's stdout/stderr, which is typically - discarded. See the `--no-detatch` option for a way to see the daemon's + discarded. See the `--no-detach` option for a way to see the daemon's output, which can assist with debugging. Note that the `early exec` command runs before any part of the transfer From 99ab59464bf44f18d668e373bc3d0f65190b87ac Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 18 Aug 2023 08:26:20 +0200 Subject: [PATCH 021/101] exclude: fix crashes with fortified strlcpy() Fortified (-D_FORTIFY_SOURCE=2 for gcc) builds make strlcpy() crash when its third parameter (size) is larger than the buffer: $ rsync -FFXHav '--filter=merge global-rsync-filter' Align-37-43/ xxx sending incremental file list *** buffer overflow detected ***: terminated It's in the exclude code in setup_merge_file(): strlcpy(y, save, MAXPATHLEN); Note the 'y' pointer was incremented, so it no longer points to memory with MAXPATHLEN "owned" bytes. Fix it by remembering the number of copied bytes into the 'save' buffer and use that instead of MAXPATHLEN which is clearly incorrect. Fixes #511. --- exclude.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/exclude.c b/exclude.c index ffe55b167..1a5de3b9e 100644 --- a/exclude.c +++ b/exclude.c @@ -720,7 +720,8 @@ static BOOL setup_merge_file(int mergelist_num, filter_rule *ex, parent_dirscan = True; while (*y) { char save[MAXPATHLEN]; - strlcpy(save, y, MAXPATHLEN); + /* copylen is strlen(y) which is < MAXPATHLEN. +1 for \0 */ + size_t copylen = strlcpy(save, y, MAXPATHLEN) + 1; *y = '\0'; dirbuf_len = y - dirbuf; strlcpy(x, ex->pattern, MAXPATHLEN - (x - buf)); @@ -734,7 +735,7 @@ static BOOL setup_merge_file(int mergelist_num, filter_rule *ex, lp->head = NULL; } lp->tail = NULL; - strlcpy(y, save, MAXPATHLEN); + strlcpy(y, save, copylen); while ((*x++ = *y++) != '/') {} } parent_dirscan = False; From abc3c746527bb030db37010e03ef574ddc47fe36 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sat, 6 Apr 2024 09:17:16 -0700 Subject: [PATCH 022/101] Mention latest changes in NEWS. --- NEWS.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/NEWS.md b/NEWS.md index ca60c32cb..da1e18528 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,6 +10,11 @@ - Fixed an buffer overflow in the checksum2 code if SHA1 is being used for the checksum2 algorithm. +- Fixed an issue when rsync is compiled using `_FORTIFY_SOURCE` so that the + extra tests don't complain about a strlcpy() limit value (which was too + large, even though it wasn't possible for the larger value to cause an + overflow). + - Add a backtick to the list of characters that the filename quoting needs to escape using backslashes. @@ -49,6 +54,8 @@ - Changed the mapfrom & mapto perl scripts (in the support dir) into a single python script named idmap. Converted a couple more perl scripts into python. +- Changed the mnt-excl perl script (in the support dir) into a python script. + ### DEVELOPER RELATED: - Updated config.guess (timestamp 2023-01-01) and config.sub (timestamp From 079e74a30f3615ccd70864621dab6d8df0ae0122 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sat, 6 Apr 2024 09:21:44 -0700 Subject: [PATCH 023/101] Some year updates. --- delete.c | 2 +- latest-year.h | 2 +- util2.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/delete.c b/delete.c index 807661643..dcb6a9afa 100644 --- a/delete.c +++ b/delete.c @@ -4,7 +4,7 @@ * Copyright (C) 1996-2000 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2002 Martin Pool - * Copyright (C) 2003-2020 Wayne Davison + * Copyright (C) 2003-2023 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/latest-year.h b/latest-year.h index 0dcf3464b..f978fb8b2 100644 --- a/latest-year.h +++ b/latest-year.h @@ -1 +1 @@ -#define LATEST_YEAR "2023" +#define LATEST_YEAR "2024" diff --git a/util2.c b/util2.c index 3b5a8f414..e398340e3 100644 --- a/util2.c +++ b/util2.c @@ -4,7 +4,7 @@ * Copyright (C) 1996-2000 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2001, 2002 Martin Pool - * Copyright (C) 2003-2020 Wayne Davison + * Copyright (C) 2003-2023 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From 6c8ca91c731b7bf2b081694bda85b7dadc2b7aff Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sat, 6 Apr 2024 09:30:21 -0700 Subject: [PATCH 024/101] Preparing for release of 3.3.0 [buildall] --- NEWS.md | 4 ++-- delete.c | 2 +- exclude.c | 2 +- packaging/lsb/rsync.spec | 10 +++++----- util2.c | 2 +- version.h | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/NEWS.md b/NEWS.md index da1e18528..846ed0ac5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -# NEWS for rsync 3.3.0 (UNRELEASED) +# NEWS for rsync 3.3.0 (6 Apr 2024) ## Changes in this version: @@ -4762,7 +4762,7 @@ | RELEASE DATE | VER. | DATE OF COMMIT\* | PROTOCOL | |--------------|--------|------------------|-------------| -| ?? May 2023 | 3.3.0 | | 31 | +| 06 Apr 2024 | 3.3.0 | | 31 | | 20 Oct 2022 | 3.2.7 | | 31 | | 09 Sep 2022 | 3.2.6 | | 31 | | 14 Aug 2022 | 3.2.5 | | 31 | diff --git a/delete.c b/delete.c index dcb6a9afa..89c1f8d67 100644 --- a/delete.c +++ b/delete.c @@ -4,7 +4,7 @@ * Copyright (C) 1996-2000 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2002 Martin Pool - * Copyright (C) 2003-2023 Wayne Davison + * Copyright (C) 2003-2024 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/exclude.c b/exclude.c index 1a5de3b9e..87edbcf71 100644 --- a/exclude.c +++ b/exclude.c @@ -4,7 +4,7 @@ * Copyright (C) 1996-2001 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2002 Martin Pool - * Copyright (C) 2003-2022 Wayne Davison + * Copyright (C) 2003-2024 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/packaging/lsb/rsync.spec b/packaging/lsb/rsync.spec index 5df58b966..10385a396 100644 --- a/packaging/lsb/rsync.spec +++ b/packaging/lsb/rsync.spec @@ -1,9 +1,9 @@ Summary: A fast, versatile, remote (and local) file-copying tool Name: rsync Version: 3.3.0 -%define fullversion %{version}pre1 -Release: 0.1.pre1 -%define srcdir src-previews +%define fullversion %{version} +Release: 1 +%define srcdir src Group: Applications/Internet License: GPL Source0: https://rsync.samba.org/ftp/rsync/%{srcdir}/rsync-%{fullversion}.tar.gz @@ -79,8 +79,8 @@ rm -rf $RPM_BUILD_ROOT %dir /etc/rsync-ssl/certs %changelog -* Sat Apr 29 2023 Wayne Davison -Released 3.3.0pre1. +* Sat Apr 06 2024 Wayne Davison +Released 3.3.0. * Fri Mar 21 2008 Wayne Davison Added installation of /etc/xinetd.d/rsync file and some commented-out diff --git a/util2.c b/util2.c index e398340e3..b59bff0a0 100644 --- a/util2.c +++ b/util2.c @@ -4,7 +4,7 @@ * Copyright (C) 1996-2000 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2001, 2002 Martin Pool - * Copyright (C) 2003-2023 Wayne Davison + * Copyright (C) 2003-2024 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/version.h b/version.h index da4bb3688..b162146ef 100644 --- a/version.h +++ b/version.h @@ -1,2 +1,2 @@ -#define RSYNC_VERSION "3.3.0pre1" +#define RSYNC_VERSION "3.3.0" #define MAINTAINER_TZ_OFFSET -7.0 From ae3e13ba99d0d6c1727ca7930b0eab5f60122ae0 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sat, 6 Apr 2024 10:33:42 -0700 Subject: [PATCH 025/101] Update github links. --- README.md | 6 +++--- configure.ac | 2 +- rsync.1.md | 2 +- rsyncd.conf.5.md | 2 +- support/rrsync.1.md | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index a86c77105..f9689972f 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ If you need to build rsync yourself, check out the [INSTALL][1] page for information on what libraries and packages you can use to get the maximum features in your build. -[1]: https://github.com/WayneD/rsync/blob/master/INSTALL.md +[1]: https://github.com/RsyncProject/rsync/blob/master/INSTALL.md SETUP ----- @@ -120,7 +120,7 @@ If you want to get the very latest version of rsync direct from the source code repository, then you will need to use git. The git repo is hosted [on GitHub][6] and [on Samba's site][7]. -[6]: https://github.com/WayneD/rsync +[6]: https://github.com/RsyncProject/rsync [7]: https://git.samba.org/?p=rsync.git;a=summary See [the download page][8] for full details on all the ways to grab the @@ -140,5 +140,5 @@ Rsync may be used, modified and redistributed only under the terms of the GNU General Public License, found in the file [COPYING][9] in this distribution, or at [the Free Software Foundation][10]. -[9]: https://github.com/WayneD/rsync/blob/master/COPYING +[9]: https://github.com/RsyncProject/rsync/blob/master/COPYING [10]: https://www.fsf.org/licenses/gpl.html diff --git a/configure.ac b/configure.ac index ccad7f132..0d8685715 100644 --- a/configure.ac +++ b/configure.ac @@ -573,7 +573,7 @@ if test x"$no_lib" != x; then echo "" echo "See the INSTALL file for hints on how to install the missing libraries and/or" echo "how to generate (or fetch) manpages:" - echo " https://github.com/WayneD/rsync/blob/master/INSTALL.md" + echo " https://github.com/RsyncProject/rsync/blob/master/INSTALL.md" echo "" echo "To disable one or more features, the relevant configure options are:" for lib in $no_lib; do diff --git a/rsync.1.md b/rsync.1.md index 2ae6f4816..afaf1de89 100644 --- a/rsync.1.md +++ b/rsync.1.md @@ -4818,7 +4818,7 @@ An rsync web site is available at . The site includes an FAQ-O-Matic which may cover questions unanswered by this manual page. -The rsync github project is . +The rsync github project is . We would be delighted to hear from you if you like this program. Please contact the mailing-list at . diff --git a/rsyncd.conf.5.md b/rsyncd.conf.5.md index cd10e659c..ec976bacc 100644 --- a/rsyncd.conf.5.md +++ b/rsyncd.conf.5.md @@ -1260,7 +1260,7 @@ Rsync is distributed under the GNU General Public License. See the file [COPYING](COPYING) for details. An rsync web site is available at and its github -project is . +project is . ## THANKS diff --git a/support/rrsync.1.md b/support/rrsync.1.md index 24892900d..5f33930e2 100644 --- a/support/rrsync.1.md +++ b/support/rrsync.1.md @@ -163,7 +163,7 @@ rsync is distributed under the GNU General Public License. See the file [COPYING](COPYING) for details. An rsync web site is available at and its github -project is . +project is . ## AUTHOR From 0dd25d4752520ed405315f1d2a8454fd507631bb Mon Sep 17 00:00:00 2001 From: Ivan Babrou Date: Mon, 1 Jan 2024 19:31:01 -0800 Subject: [PATCH 026/101] configure.ac: fix failing IPv6 check due to missing return type Fixing this warning escalated to an error, resuting in no IPv6 support: ``` configure.sh:7679: checking whether to enable ipv6 configure.sh:7718: clang -o conftest -g -O2 -DHAVE_CONFIG_H -Wall -W conftest.c >&5 conftest.c:73:1: error: type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int [-Wimplicit-int] main() ^ int 1 error generated. configure.sh:7718: $? = 1 configure.sh: program exited with status 1 ``` --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0d8685715..57ee32f34 100644 --- a/configure.ac +++ b/configure.ac @@ -392,7 +392,7 @@ AS_HELP_STRING([--disable-ipv6],[disable to omit ipv6 support]), #include #include #include -main() +int main() { if (socket(AF_INET6, SOCK_STREAM, 0) < 0) exit(1); From 9505ac59455278b54708b7c2790d93eb3d0b960b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 7 Apr 2024 07:11:47 +1000 Subject: [PATCH 027/101] removed old cirrus CI --- .cirrus.yml | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 .cirrus.yml diff --git a/.cirrus.yml b/.cirrus.yml deleted file mode 100644 index 33e2685eb..000000000 --- a/.cirrus.yml +++ /dev/null @@ -1,23 +0,0 @@ -freebsd_task: - name: FreeBSD - freebsd_instance: - image_family: freebsd-13-1 - env: - PATH: /usr/local/bin:$PATH - prep_script: - - dd if=/dev/zero of=/tmp/zpool bs=1M count=1024 - - zpool create -m `pwd`/testtmp zpool /tmp/zpool - - pkg install -y bash autotools m4 xxhash zstd liblz4 wget - - wget -O git-version.h https://gist.githubusercontent.com/WayneD/c11243fa374fc64d4e42f2855c8e3827/raw/rsync-git-version.h - configure_script: - - CPPFLAGS=-I/usr/local/include/ LDFLAGS=-L/usr/local/lib/ ./configure --disable-md2man - make_script: - - make - install_script: - - make install - info_script: - - rsync --version - test_script: - - RSYNC_EXPECT_SKIPPED=acls-default,acls,crtimes,protected-regular make check - ssl_file_list_script: - - rsync-ssl --no-motd download.samba.org::rsyncftp/ || true From 99673f937f36ab90a160a1b8c1e37645893d7b77 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 7 Apr 2024 07:11:31 +1000 Subject: [PATCH 028/101] CI: added FreeBSD build --- .github/workflows/freebsd-build.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/freebsd-build.yml diff --git a/.github/workflows/freebsd-build.yml b/.github/workflows/freebsd-build.yml new file mode 100644 index 000000000..8ec2e0f15 --- /dev/null +++ b/.github/workflows/freebsd-build.yml @@ -0,0 +1,23 @@ +name: Test rsync on FreeBSD + +on: [push] + +jobs: + test: + runs-on: ubuntu-latest + name: Test rsync on FreeBSD + steps: + - uses: actions/checkout@v4 + - name: Test in FreeBSD + id: test + uses: vmactions/freebsd-vm@v1 + with: + usesh: true + prepare: | + pkg install -y bash autotools m4 devel/xxhash zstd liblz4 wget python3 archivers/liblz4 + run: | + freebsd-version + ./configure --with-rrsync -disable-zstd --disable-md2man --disable-xxhash --disable-lz4 + make + ./rsync --version + ./rsync-ssl --no-motd download.samba.org::rsyncftp/ || true From 35f5a21a16ca2689710e0503464bb736d136edd6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 5 Apr 2023 13:08:02 +0200 Subject: [PATCH 029/101] hint that a proxy can handle plain and ssl stream at the same time --- rsyncd.conf.5.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rsyncd.conf.5.md b/rsyncd.conf.5.md index ec976bacc..2ba71111e 100644 --- a/rsyncd.conf.5.md +++ b/rsyncd.conf.5.md @@ -1188,6 +1188,9 @@ An example nginx proxy setup is as follows: > } > ``` +If rsyncd should be accessible encrypted and unencrypted at the same time make +the proxy listen on port 873 as well and let it handle both streams. + ## DAEMON CONFIG EXAMPLES A simple rsyncd.conf file that allow anonymous rsync to a ftp area at From 85c906f96425195f8ba8646fbb37142206399ba0 Mon Sep 17 00:00:00 2001 From: Rose <83477269+AtariDreams@users.noreply.github.com> Date: Wed, 3 May 2023 09:50:31 -0400 Subject: [PATCH 030/101] Silence unused var warning recv_ida_entries still needs to be called regardless, so we cannot take that out. Let's just quiet the compiler instead. --- acls.c | 1 + 1 file changed, 1 insertion(+) diff --git a/acls.c b/acls.c index 3cf12eeb0..a2b0ff3ec 100644 --- a/acls.c +++ b/acls.c @@ -765,6 +765,7 @@ static int recv_rsync_acl(int f, item_list *racl_list, SMB_ACL_TYPE_T type, mode /* If we received a superfluous mask, throw it away. */ duo_item->racl.mask_obj = NO_ENTRY; (void)mode; + (void)computed_mask_bits; #else if (duo_item->racl.names.count && duo_item->racl.mask_obj == NO_ENTRY) { /* Mask must be non-empty with lists. */ From 4c8683c8753f2493ef13c3425fb5847960a6e305 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 8 Apr 2024 12:45:59 +1000 Subject: [PATCH 031/101] update to popt 1.19 --- Makefile.in | 2 +- configure.ac | 2 + popt/lookup3.c | 959 ++++++++++++++++++++++++++++++ popt/popt.c | 1447 +++++++++++++++++++++++++++++---------------- popt/popt.h | 475 ++++++++------- popt/poptconfig.c | 526 ++++++++++++---- popt/popthelp.c | 786 ++++++++++++------------ popt/poptint.c | 194 ++++++ popt/poptint.h | 118 ++-- popt/poptparse.c | 100 ++-- popt/system.h | 148 ++--- 11 files changed, 3365 insertions(+), 1392 deletions(-) create mode 100644 popt/lookup3.c create mode 100644 popt/poptint.c diff --git a/Makefile.in b/Makefile.in index a1253e5d5..6bf304d1b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -50,7 +50,7 @@ OBJS2=options.o io.o compat.o hlink.o token.o uidlist.o socket.o hashtable.o \ OBJS3=progress.o pipe.o @MD5_ASM@ @ROLL_SIMD@ @ROLL_ASM@ DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \ - popt/popthelp.o popt/poptparse.o + popt/popthelp.o popt/poptparse.o popt/poptint.o OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) @BUILD_ZLIB@ @BUILD_POPT@ TLS_OBJ = tls.o syscall.o util2.o t_stub.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o @BUILD_POPT@ diff --git a/configure.ac b/configure.ac index 57ee32f34..a65cde147 100644 --- a/configure.ac +++ b/configure.ac @@ -1084,6 +1084,8 @@ if test x"$with_included_popt" = x"yes"; then AC_MSG_RESULT($srcdir/popt) BUILD_POPT='$(popt_OBJS)' CFLAGS="-I$srcdir/popt $CFLAGS" + AC_DEFINE(POPT_SYSCONFDIR, "/etc", [sysconfig dir for popt]) + AC_DEFINE(PACKAGE, "rsync", [package name for rsync]) if test x"$ALLOCA" != x then # this can be removed when/if we add an included alloca.c; diff --git a/popt/lookup3.c b/popt/lookup3.c new file mode 100644 index 000000000..e974cad87 --- /dev/null +++ b/popt/lookup3.c @@ -0,0 +1,959 @@ +/* -------------------------------------------------------------------- */ +/* + * lookup3.c, by Bob Jenkins, May 2006, Public Domain. + * + * These are functions for producing 32-bit hashes for hash table lookup. + * jlu32w(), jlu32l(), jlu32lpair(), jlu32b(), _JLU3_MIX(), and _JLU3_FINAL() + * are externally useful functions. Routines to test the hash are included + * if SELF_TEST is defined. You can use this free for any purpose. It's in + * the public domain. It has no warranty. + * + * You probably want to use jlu32l(). jlu32l() and jlu32b() + * hash byte arrays. jlu32l() is is faster than jlu32b() on + * little-endian machines. Intel and AMD are little-endian machines. + * On second thought, you probably want jlu32lpair(), which is identical to + * jlu32l() except it returns two 32-bit hashes for the price of one. + * You could implement jlu32bpair() if you wanted but I haven't bothered here. + * + * If you want to find a hash of, say, exactly 7 integers, do + * a = i1; b = i2; c = i3; + * _JLU3_MIX(a,b,c); + * a += i4; b += i5; c += i6; + * _JLU3_MIX(a,b,c); + * a += i7; + * _JLU3_FINAL(a,b,c); + * then use c as the hash value. If you have a variable size array of + * 4-byte integers to hash, use jlu32w(). If you have a byte array (like + * a character string), use jlu32l(). If you have several byte arrays, or + * a mix of things, see the comments above jlu32l(). + * + * Why is this so big? I read 12 bytes at a time into 3 4-byte integers, + * then mix those integers. This is fast (you can do a lot more thorough + * mixing with 12*3 instructions on 3 integers than you can with 3 instructions + * on 1 byte), but shoehorning those bytes into integers efficiently is messy. +*/ +/* -------------------------------------------------------------------- */ + +#include + +#if defined(_JLU3_SELFTEST) +# define _JLU3_jlu32w 1 +# define _JLU3_jlu32l 1 +# define _JLU3_jlu32lpair 1 +# define _JLU3_jlu32b 1 +#endif + +static const union _dbswap { + const uint32_t ui; + const unsigned char uc[4]; +} endian = { .ui = 0x11223344 }; +# define HASH_LITTLE_ENDIAN (endian.uc[0] == (unsigned char) 0x44) +# define HASH_BIG_ENDIAN (endian.uc[0] == (unsigned char) 0x11) + +#ifndef ROTL32 +# define ROTL32(x, s) (((x) << (s)) | ((x) >> (32 - (s)))) +#endif + +/* NOTE: The _size parameter should be in bytes. */ +#define _JLU3_INIT(_h, _size) (0xdeadbeef + ((uint32_t)(_size)) + (_h)) + +/* -------------------------------------------------------------------- */ +/* + * _JLU3_MIX -- mix 3 32-bit values reversibly. + * + * This is reversible, so any information in (a,b,c) before _JLU3_MIX() is + * still in (a,b,c) after _JLU3_MIX(). + * + * If four pairs of (a,b,c) inputs are run through _JLU3_MIX(), or through + * _JLU3_MIX() in reverse, there are at least 32 bits of the output that + * are sometimes the same for one pair and different for another pair. + * This was tested for: + * * pairs that differed by one bit, by two bits, in any combination + * of top bits of (a,b,c), or in any combination of bottom bits of + * (a,b,c). + * * "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + * the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + * is commonly produced by subtraction) look like a single 1-bit + * difference. + * * the base values were pseudorandom, all zero but one bit set, or + * all zero plus a counter that starts at zero. + * + * Some k values for my "a-=c; a^=ROTL32(c,k); c+=b;" arrangement that + * satisfy this are + * 4 6 8 16 19 4 + * 9 15 3 18 27 15 + * 14 9 3 7 17 3 + * Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing + * for "differ" defined as + with a one-bit base and a two-bit delta. I + * used http://burtleburtle.net/bob/hash/avalanche.html to choose + * the operations, constants, and arrangements of the variables. + * + * This does not achieve avalanche. There are input bits of (a,b,c) + * that fail to affect some output bits of (a,b,c), especially of a. The + * most thoroughly mixed value is c, but it doesn't really even achieve + * avalanche in c. + * + * This allows some parallelism. Read-after-writes are good at doubling + * the number of bits affected, so the goal of mixing pulls in the opposite + * direction as the goal of parallelism. I did what I could. Rotates + * seem to cost as much as shifts on every machine I could lay my hands + * on, and rotates are much kinder to the top and bottom bits, so I used + * rotates. + */ +/* -------------------------------------------------------------------- */ +#define _JLU3_MIX(a,b,c) \ +{ \ + a -= c; a ^= ROTL32(c, 4); c += b; \ + b -= a; b ^= ROTL32(a, 6); a += c; \ + c -= b; c ^= ROTL32(b, 8); b += a; \ + a -= c; a ^= ROTL32(c,16); c += b; \ + b -= a; b ^= ROTL32(a,19); a += c; \ + c -= b; c ^= ROTL32(b, 4); b += a; \ +} + +/* -------------------------------------------------------------------- */ +/** + * _JLU3_FINAL -- final mixing of 3 32-bit values (a,b,c) into c + * + * Pairs of (a,b,c) values differing in only a few bits will usually + * produce values of c that look totally different. This was tested for + * * pairs that differed by one bit, by two bits, in any combination + * of top bits of (a,b,c), or in any combination of bottom bits of + * (a,b,c). + * * "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + * the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + * is commonly produced by subtraction) look like a single 1-bit + * difference. + * * the base values were pseudorandom, all zero but one bit set, or + * all zero plus a counter that starts at zero. + * + * These constants passed: + * 14 11 25 16 4 14 24 + * 12 14 25 16 4 14 24 + * and these came close: + * 4 8 15 26 3 22 24 + * 10 8 15 26 3 22 24 + * 11 8 15 26 3 22 24 + */ +/* -------------------------------------------------------------------- */ +#define _JLU3_FINAL(a,b,c) \ +{ \ + c ^= b; c -= ROTL32(b,14); \ + a ^= c; a -= ROTL32(c,11); \ + b ^= a; b -= ROTL32(a,25); \ + c ^= b; c -= ROTL32(b,16); \ + a ^= c; a -= ROTL32(c,4); \ + b ^= a; b -= ROTL32(a,14); \ + c ^= b; c -= ROTL32(b,24); \ +} + +#if defined(_JLU3_jlu32w) +uint32_t jlu32w(uint32_t h, const uint32_t *k, size_t size); +/* -------------------------------------------------------------------- */ +/** + * This works on all machines. To be useful, it requires + * -- that the key be an array of uint32_t's, and + * -- that the size be the number of uint32_t's in the key + * + * The function jlu32w() is identical to jlu32l() on little-endian + * machines, and identical to jlu32b() on big-endian machines, + * except that the size has to be measured in uint32_ts rather than in + * bytes. jlu32l() is more complicated than jlu32w() only because + * jlu32l() has to dance around fitting the key bytes into registers. + * + * @param h the previous hash, or an arbitrary value + * @param *k the key, an array of uint32_t values + * @param size the size of the key, in uint32_ts + * @return the lookup3 hash + */ +/* -------------------------------------------------------------------- */ +uint32_t jlu32w(uint32_t h, const uint32_t *k, size_t size) +{ + uint32_t a = _JLU3_INIT(h, (size * sizeof(*k))); + uint32_t b = a; + uint32_t c = a; + + if (k == NULL) + goto exit; + + /*----------------------------------------------- handle most of the key */ + while (size > 3) { + a += k[0]; + b += k[1]; + c += k[2]; + _JLU3_MIX(a,b,c); + size -= 3; + k += 3; + } + + /*----------------------------------------- handle the last 3 uint32_t's */ + switch (size) { + case 3 : c+=k[2]; + case 2 : b+=k[1]; + case 1 : a+=k[0]; + _JLU3_FINAL(a,b,c); + /* fallthrough */ + case 0: + break; + } + /*---------------------------------------------------- report the result */ +exit: + return c; +} +#endif /* defined(_JLU3_jlu32w) */ + +#if defined(_JLU3_jlu32l) +uint32_t jlu32l(uint32_t h, const void *key, size_t size); +/* -------------------------------------------------------------------- */ +/* + * jlu32l() -- hash a variable-length key into a 32-bit value + * h : can be any 4-byte value + * k : the key (the unaligned variable-length array of bytes) + * size : the size of the key, counting by bytes + * Returns a 32-bit value. Every bit of the key affects every bit of + * the return value. Two keys differing by one or two bits will have + * totally different hash values. + * + * The best hash table sizes are powers of 2. There is no need to do + * mod a prime (mod is sooo slow!). If you need less than 32 bits, + * use a bitmask. For example, if you need only 10 bits, do + * h = (h & hashmask(10)); + * In which case, the hash table should have hashsize(10) elements. + * + * If you are hashing n strings (uint8_t **)k, do it like this: + * for (i=0, h=0; i 12) { + a += k[0]; + b += k[1]; + c += k[2]; + _JLU3_MIX(a,b,c); + size -= 12; + k += 3; + } + + /*------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticeably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch (size) { + case 12: c += k[2]; b+=k[1]; a+=k[0]; break; + case 11: c += k[2]&0xffffff; b+=k[1]; a+=k[0]; break; + case 10: c += k[2]&0xffff; b+=k[1]; a+=k[0]; break; + case 9: c += k[2]&0xff; b+=k[1]; a+=k[0]; break; + case 8: b += k[1]; a+=k[0]; break; + case 7: b += k[1]&0xffffff; a+=k[0]; break; + case 6: b += k[1]&0xffff; a+=k[0]; break; + case 5: b += k[1]&0xff; a+=k[0]; break; + case 4: a += k[0]; break; + case 3: a += k[0]&0xffffff; break; + case 2: a += k[0]&0xffff; break; + case 1: a += k[0]&0xff; break; + case 0: goto exit; + } + +#else /* make valgrind happy */ + + k8 = (const uint8_t *)k; + switch (size) { + case 12: c += k[2]; b+=k[1]; a+=k[0] break; + case 11: c += ((uint32_t)k8[10])<<16; /* fallthrough */ + case 10: c += ((uint32_t)k8[9])<<8; /* fallthrough */ + case 9: c += k8[8]; /* fallthrough */ + case 8: b += k[1]; a+=k[0]; break; + case 7: b += ((uint32_t)k8[6])<<16; /* fallthrough */ + case 6: b += ((uint32_t)k8[5])<<8; /* fallthrough */ + case 5: b += k8[4]; /* fallthrough */ + case 4: a += k[0]; break; + case 3: a += ((uint32_t)k8[2])<<16; /* fallthrough */ + case 2: a += ((uint32_t)k8[1])<<8; /* fallthrough */ + case 1: a += k8[0]; break; + case 0: goto exit; + } + +#endif /* !valgrind */ + + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*----------- all but last block: aligned reads and different mixing */ + while (size > 12) { + a += k[0] + (((uint32_t)k[1])<<16); + b += k[2] + (((uint32_t)k[3])<<16); + c += k[4] + (((uint32_t)k[5])<<16); + _JLU3_MIX(a,b,c); + size -= 12; + k += 6; + } + + /*------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch (size) { + case 12: + c += k[4]+(((uint32_t)k[5])<<16); + b += k[2]+(((uint32_t)k[3])<<16); + a += k[0]+(((uint32_t)k[1])<<16); + break; + case 11: + c += ((uint32_t)k8[10])<<16; + /* fallthrough */ + case 10: + c += (uint32_t)k[4]; + b += k[2]+(((uint32_t)k[3])<<16); + a += k[0]+(((uint32_t)k[1])<<16); + break; + case 9: + c += (uint32_t)k8[8]; + /* fallthrough */ + case 8: + b += k[2]+(((uint32_t)k[3])<<16); + a += k[0]+(((uint32_t)k[1])<<16); + break; + case 7: + b += ((uint32_t)k8[6])<<16; + /* fallthrough */ + case 6: + b += (uint32_t)k[2]; + a += k[0]+(((uint32_t)k[1])<<16); + break; + case 5: + b += (uint32_t)k8[4]; + /* fallthrough */ + case 4: + a += k[0]+(((uint32_t)k[1])<<16); + break; + case 3: + a += ((uint32_t)k8[2])<<16; + /* fallthrough */ + case 2: + a += (uint32_t)k[0]; + break; + case 1: + a += (uint32_t)k8[0]; + break; + case 0: + goto exit; + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*----------- all but the last block: affect some 32 bits of (a,b,c) */ + while (size > 12) { + a += (uint32_t)k[0]; + a += ((uint32_t)k[1])<<8; + a += ((uint32_t)k[2])<<16; + a += ((uint32_t)k[3])<<24; + b += (uint32_t)k[4]; + b += ((uint32_t)k[5])<<8; + b += ((uint32_t)k[6])<<16; + b += ((uint32_t)k[7])<<24; + c += (uint32_t)k[8]; + c += ((uint32_t)k[9])<<8; + c += ((uint32_t)k[10])<<16; + c += ((uint32_t)k[11])<<24; + _JLU3_MIX(a,b,c); + size -= 12; + k += 12; + } + + /*---------------------------- last block: affect all 32 bits of (c) */ + switch (size) { + case 12: c += ((uint32_t)k[11])<<24; /* fallthrough */ + case 11: c += ((uint32_t)k[10])<<16; /* fallthrough */ + case 10: c += ((uint32_t)k[9])<<8; /* fallthrough */ + case 9: c += (uint32_t)k[8]; /* fallthrough */ + case 8: b += ((uint32_t)k[7])<<24; /* fallthrough */ + case 7: b += ((uint32_t)k[6])<<16; /* fallthrough */ + case 6: b += ((uint32_t)k[5])<<8; /* fallthrough */ + case 5: b += (uint32_t)k[4]; /* fallthrough */ + case 4: a += ((uint32_t)k[3])<<24; /* fallthrough */ + case 3: a += ((uint32_t)k[2])<<16; /* fallthrough */ + case 2: a += ((uint32_t)k[1])<<8; /* fallthrough */ + case 1: a += (uint32_t)k[0]; + break; + case 0: + goto exit; + } + } + + _JLU3_FINAL(a,b,c); + +exit: + return c; +} +#endif /* defined(_JLU3_jlu32l) */ + +#if defined(_JLU3_jlu32lpair) +/** + * jlu32lpair: return 2 32-bit hash values. + * + * This is identical to jlu32l(), except it returns two 32-bit hash + * values instead of just one. This is good enough for hash table + * lookup with 2^^64 buckets, or if you want a second hash if you're not + * happy with the first, or if you want a probably-unique 64-bit ID for + * the key. *pc is better mixed than *pb, so use *pc first. If you want + * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)". + * + * @param h the previous hash, or an arbitrary value + * @param *key the key, an array of uint8_t values + * @param size the size of the key in bytes + * @retval *pc, IN: primary initval, OUT: primary hash + * *retval *pb IN: secondary initval, OUT: secondary hash + */ +void jlu32lpair(const void *key, size_t size, uint32_t *pc, uint32_t *pb) +{ + union { const void *ptr; size_t i; } u; + uint32_t a = _JLU3_INIT(*pc, size); + uint32_t b = a; + uint32_t c = a; + + if (key == NULL) + goto exit; + + c += *pb; /* Add the secondary hash. */ + + u.ptr = key; + if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) { + const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ +#ifdef VALGRIND + const uint8_t *k8; +#endif + + /*-- all but last block: aligned reads and affect 32 bits of (a,b,c) */ + while (size > (size_t)12) { + a += k[0]; + b += k[1]; + c += k[2]; + _JLU3_MIX(a,b,c); + size -= 12; + k += 3; + } + /*------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticeably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch (size) { + case 12: c += k[2]; b+=k[1]; a+=k[0]; break; + case 11: c += k[2]&0xffffff; b+=k[1]; a+=k[0]; break; + case 10: c += k[2]&0xffff; b+=k[1]; a+=k[0]; break; + case 9: c += k[2]&0xff; b+=k[1]; a+=k[0]; break; + case 8: b += k[1]; a+=k[0]; break; + case 7: b += k[1]&0xffffff; a+=k[0]; break; + case 6: b += k[1]&0xffff; a+=k[0]; break; + case 5: b += k[1]&0xff; a+=k[0]; break; + case 4: a += k[0]; break; + case 3: a += k[0]&0xffffff; break; + case 2: a += k[0]&0xffff; break; + case 1: a += k[0]&0xff; break; + case 0: goto exit; + } + +#else /* make valgrind happy */ + + k8 = (const uint8_t *)k; + switch (size) { + case 12: c += k[2]; b+=k[1]; a+=k[0]; break; + case 11: c += ((uint32_t)k8[10])<<16; /* fallthrough */ + case 10: c += ((uint32_t)k8[9])<<8; /* fallthrough */ + case 9: c += k8[8]; /* fallthrough */ + case 8: b += k[1]; a+=k[0]; break; + case 7: b += ((uint32_t)k8[6])<<16; /* fallthrough */ + case 6: b += ((uint32_t)k8[5])<<8; /* fallthrough */ + case 5: b += k8[4]; /* fallthrough */ + case 4: a += k[0]; break; + case 3: a += ((uint32_t)k8[2])<<16; /* fallthrough */ + case 2: a += ((uint32_t)k8[1])<<8; /* fallthrough */ + case 1: a += k8[0]; break; + case 0: goto exit; + } + +#endif /* !valgrind */ + + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*----------- all but last block: aligned reads and different mixing */ + while (size > (size_t)12) { + a += k[0] + (((uint32_t)k[1])<<16); + b += k[2] + (((uint32_t)k[3])<<16); + c += k[4] + (((uint32_t)k[5])<<16); + _JLU3_MIX(a,b,c); + size -= 12; + k += 6; + } + + /*------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch (size) { + case 12: + c += k[4]+(((uint32_t)k[5])<<16); + b += k[2]+(((uint32_t)k[3])<<16); + a += k[0]+(((uint32_t)k[1])<<16); + break; + case 11: + c += ((uint32_t)k8[10])<<16; + /* fallthrough */ + case 10: + c += k[4]; + b += k[2]+(((uint32_t)k[3])<<16); + a += k[0]+(((uint32_t)k[1])<<16); + break; + case 9: + c += k8[8]; + /* fallthrough */ + case 8: + b += k[2]+(((uint32_t)k[3])<<16); + a += k[0]+(((uint32_t)k[1])<<16); + break; + case 7: + b += ((uint32_t)k8[6])<<16; + /* fallthrough */ + case 6: + b += k[2]; + a += k[0]+(((uint32_t)k[1])<<16); + break; + case 5: + b += k8[4]; + /* fallthrough */ + case 4: + a += k[0]+(((uint32_t)k[1])<<16); + break; + case 3: + a += ((uint32_t)k8[2])<<16; + /* fallthrough */ + case 2: + a += k[0]; + break; + case 1: + a += k8[0]; + break; + case 0: + goto exit; + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*----------- all but the last block: affect some 32 bits of (a,b,c) */ + while (size > (size_t)12) { + a += k[0]; + a += ((uint32_t)k[1])<<8; + a += ((uint32_t)k[2])<<16; + a += ((uint32_t)k[3])<<24; + b += k[4]; + b += ((uint32_t)k[5])<<8; + b += ((uint32_t)k[6])<<16; + b += ((uint32_t)k[7])<<24; + c += k[8]; + c += ((uint32_t)k[9])<<8; + c += ((uint32_t)k[10])<<16; + c += ((uint32_t)k[11])<<24; + _JLU3_MIX(a,b,c); + size -= 12; + k += 12; + } + + /*---------------------------- last block: affect all 32 bits of (c) */ + switch (size) { + case 12: c += ((uint32_t)k[11])<<24; /* fallthrough */ + case 11: c += ((uint32_t)k[10])<<16; /* fallthrough */ + case 10: c += ((uint32_t)k[9])<<8; /* fallthrough */ + case 9: c += k[8]; /* fallthrough */ + case 8: b += ((uint32_t)k[7])<<24; /* fallthrough */ + case 7: b += ((uint32_t)k[6])<<16; /* fallthrough */ + case 6: b += ((uint32_t)k[5])<<8; /* fallthrough */ + case 5: b += k[4]; /* fallthrough */ + case 4: a += ((uint32_t)k[3])<<24; /* fallthrough */ + case 3: a += ((uint32_t)k[2])<<16; /* fallthrough */ + case 2: a += ((uint32_t)k[1])<<8; /* fallthrough */ + case 1: a += k[0]; + break; + case 0: + goto exit; + } + } + + _JLU3_FINAL(a,b,c); + +exit: + *pc = c; + *pb = b; + return; +} +#endif /* defined(_JLU3_jlu32lpair) */ + +#if defined(_JLU3_jlu32b) +uint32_t jlu32b(uint32_t h, const void *key, size_t size); +/* + * jlu32b(): + * This is the same as jlu32w() on big-endian machines. It is different + * from jlu32l() on all machines. jlu32b() takes advantage of + * big-endian byte ordering. + * + * @param h the previous hash, or an arbitrary value + * @param *k the key, an array of uint8_t values + * @param size the size of the key + * @return the lookup3 hash + */ +uint32_t jlu32b(uint32_t h, const void *key, size_t size) +{ + union { const void *ptr; size_t i; } u; + uint32_t a = _JLU3_INIT(h, size); + uint32_t b = a; + uint32_t c = a; + + if (key == NULL) + return h; + + u.ptr = key; + if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) { + const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ +#ifdef VALGRIND + const uint8_t *k8; +#endif + + /*-- all but last block: aligned reads and affect 32 bits of (a,b,c) */ + while (size > 12) { + a += k[0]; + b += k[1]; + c += k[2]; + _JLU3_MIX(a,b,c); + size -= 12; + k += 3; + } + + /*------------------------- handle the last (probably partial) block */ + /* + * "k[2]<<8" actually reads beyond the end of the string, but + * then shifts out the part it's not allowed to read. Because the + * string is aligned, the illegal read is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticeably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch (size) { + case 12: c += k[2]; b+=k[1]; a+=k[0]; break; + case 11: c += k[2]&0xffffff00; b+=k[1]; a+=k[0]; break; + case 10: c += k[2]&0xffff0000; b+=k[1]; a+=k[0]; break; + case 9: c += k[2]&0xff000000; b+=k[1]; a+=k[0]; break; + case 8: b += k[1]; a+=k[0]; break; + case 7: b += k[1]&0xffffff00; a+=k[0]; break; + case 6: b += k[1]&0xffff0000; a+=k[0]; break; + case 5: b += k[1]&0xff000000; a+=k[0]; break; + case 4: a += k[0]; break; + case 3: a += k[0]&0xffffff00; break; + case 2: a += k[0]&0xffff0000; break; + case 1: a += k[0]&0xff000000; break; + case 0: goto exit; + } + +#else /* make valgrind happy */ + + k8 = (const uint8_t *)k; + switch (size) { /* all the case statements fall through */ + case 12: c += k[2]; b+=k[1]; a+=k[0]; break; + case 11: c += ((uint32_t)k8[10])<<8; /* fallthrough */ + case 10: c += ((uint32_t)k8[9])<<16; /* fallthrough */ + case 9: c += ((uint32_t)k8[8])<<24; /* fallthrough */ + case 8: b += k[1]; a+=k[0]; break; + case 7: b += ((uint32_t)k8[6])<<8; /* fallthrough */ + case 6: b += ((uint32_t)k8[5])<<16; /* fallthrough */ + case 5: b += ((uint32_t)k8[4])<<24; /* fallthrough */ + case 4: a += k[0]; break; + case 3: a += ((uint32_t)k8[2])<<8; /* fallthrough */ + case 2: a += ((uint32_t)k8[1])<<16; /* fallthrough */ + case 1: a += ((uint32_t)k8[0])<<24; break; + case 0: goto exit; + } + +#endif /* !VALGRIND */ + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*----------- all but the last block: affect some 32 bits of (a,b,c) */ + while (size > 12) { + a += ((uint32_t)k[0])<<24; + a += ((uint32_t)k[1])<<16; + a += ((uint32_t)k[2])<<8; + a += ((uint32_t)k[3]); + b += ((uint32_t)k[4])<<24; + b += ((uint32_t)k[5])<<16; + b += ((uint32_t)k[6])<<8; + b += ((uint32_t)k[7]); + c += ((uint32_t)k[8])<<24; + c += ((uint32_t)k[9])<<16; + c += ((uint32_t)k[10])<<8; + c += ((uint32_t)k[11]); + _JLU3_MIX(a,b,c); + size -= 12; + k += 12; + } + + /*---------------------------- last block: affect all 32 bits of (c) */ + switch (size) { /* all the case statements fall through */ + case 12: c += k[11]; /* fallthrough */ + case 11: c += ((uint32_t)k[10])<<8; /* fallthrough */ + case 10: c += ((uint32_t)k[9])<<16; /* fallthrough */ + case 9: c += ((uint32_t)k[8])<<24; /* fallthrough */ + case 8: b += k[7]; /* fallthrough */ + case 7: b += ((uint32_t)k[6])<<8; /* fallthrough */ + case 6: b += ((uint32_t)k[5])<<16; /* fallthrough */ + case 5: b += ((uint32_t)k[4])<<24; /* fallthrough */ + case 4: a += k[3]; /* fallthrough */ + case 3: a += ((uint32_t)k[2])<<8; /* fallthrough */ + case 2: a += ((uint32_t)k[1])<<16; /* fallthrough */ + case 1: a += ((uint32_t)k[0])<<24; /* fallthrough */ + break; + case 0: + goto exit; + } + } + + _JLU3_FINAL(a,b,c); + +exit: + return c; +} +#endif /* defined(_JLU3_jlu32b) */ + +#if defined(_JLU3_SELFTEST) + +/* used for timings */ +static void driver1(void) +{ + uint8_t buf[256]; + uint32_t i; + uint32_t h=0; + time_t a,z; + + time(&a); + for (i=0; i<256; ++i) buf[i] = 'x'; + for (i=0; i<1; ++i) { + h = jlu32l(h, &buf[0], sizeof(buf[0])); + } + time(&z); + if (z-a > 0) printf("time %d %.8x\n", (int)(z-a), h); +} + +/* check that every input bit changes every output bit half the time */ +#define HASHSTATE 1 +#define HASHLEN 1 +#define MAXPAIR 60 +#define MAXLEN 70 +static void driver2(void) +{ + uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1]; + uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z; + uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE]; + uint32_t x[HASHSTATE],y[HASHSTATE]; + uint32_t hlen; + + printf("No more than %d trials should ever be needed \n",MAXPAIR/2); + for (hlen=0; hlen < MAXLEN; ++hlen) { + z=0; + for (i=0; i>(8-j)); + c[0] = jlu32l(m, a, hlen); + b[i] ^= ((k+1)<>(8-j)); + d[0] = jlu32l(m, b, hlen); + /* check every bit is 1, 0, set, and not set at least once */ + for (l=0; lz) z=k; + if (k == MAXPAIR) { + printf("Some bit didn't change: "); + printf("%.8x %.8x %.8x %.8x %.8x %.8x ", + e[0],f[0],g[0],h[0],x[0],y[0]); + printf("i %u j %u m %u len %u\n", i, j, m, hlen); + } + if (z == MAXPAIR) goto done; + } + } + } + done: + if (z < MAXPAIR) { + printf("Mix success %2u bytes %2u initvals ",i,m); + printf("required %u trials\n", z/2); + } + } + printf("\n"); +} + +/* Check for reading beyond the end of the buffer and alignment problems */ +static void driver3(void) +{ + uint8_t buf[MAXLEN+20], *b; + uint32_t len; + uint8_t q[] = "This is the time for all good men to come to the aid of their country..."; + uint32_t h; + uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country..."; + uint32_t i; + uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country..."; + uint32_t j; + uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country..."; + uint32_t ref,x,y; + uint8_t *p; + uint32_t m = 13; + + printf("Endianness. These lines should all be the same (for values filled in):\n"); + printf("%.8x %.8x %.8x\n", + jlu32w(m, (const uint32_t *)q, (sizeof(q)-1)/4), + jlu32w(m, (const uint32_t *)q, (sizeof(q)-5)/4), + jlu32w(m, (const uint32_t *)q, (sizeof(q)-9)/4)); + p = q; + printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", + jlu32l(m, p, sizeof(q)-1), jlu32l(m, p, sizeof(q)-2), + jlu32l(m, p, sizeof(q)-3), jlu32l(m, p, sizeof(q)-4), + jlu32l(m, p, sizeof(q)-5), jlu32l(m, p, sizeof(q)-6), + jlu32l(m, p, sizeof(q)-7), jlu32l(m, p, sizeof(q)-8), + jlu32l(m, p, sizeof(q)-9), jlu32l(m, p, sizeof(q)-10), + jlu32l(m, p, sizeof(q)-11), jlu32l(m, p, sizeof(q)-12)); + p = &qq[1]; + printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", + jlu32l(m, p, sizeof(q)-1), jlu32l(m, p, sizeof(q)-2), + jlu32l(m, p, sizeof(q)-3), jlu32l(m, p, sizeof(q)-4), + jlu32l(m, p, sizeof(q)-5), jlu32l(m, p, sizeof(q)-6), + jlu32l(m, p, sizeof(q)-7), jlu32l(m, p, sizeof(q)-8), + jlu32l(m, p, sizeof(q)-9), jlu32l(m, p, sizeof(q)-10), + jlu32l(m, p, sizeof(q)-11), jlu32l(m, p, sizeof(q)-12)); + p = &qqq[2]; + printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", + jlu32l(m, p, sizeof(q)-1), jlu32l(m, p, sizeof(q)-2), + jlu32l(m, p, sizeof(q)-3), jlu32l(m, p, sizeof(q)-4), + jlu32l(m, p, sizeof(q)-5), jlu32l(m, p, sizeof(q)-6), + jlu32l(m, p, sizeof(q)-7), jlu32l(m, p, sizeof(q)-8), + jlu32l(m, p, sizeof(q)-9), jlu32l(m, p, sizeof(q)-10), + jlu32l(m, p, sizeof(q)-11), jlu32l(m, p, sizeof(q)-12)); + p = &qqqq[3]; + printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", + jlu32l(m, p, sizeof(q)-1), jlu32l(m, p, sizeof(q)-2), + jlu32l(m, p, sizeof(q)-3), jlu32l(m, p, sizeof(q)-4), + jlu32l(m, p, sizeof(q)-5), jlu32l(m, p, sizeof(q)-6), + jlu32l(m, p, sizeof(q)-7), jlu32l(m, p, sizeof(q)-8), + jlu32l(m, p, sizeof(q)-9), jlu32l(m, p, sizeof(q)-10), + jlu32l(m, p, sizeof(q)-11), jlu32l(m, p, sizeof(q)-12)); + printf("\n"); + for (h=0, b=buf+1; h<8; ++h, ++b) { + for (i=0; i -#endif #include +#include +#include +#include -#include "findme.h" #include "poptint.h" -#ifndef DBL_EPSILON -#define DBL_EPSILON 2.2204460492503131e-16 +#ifdef HAVE_STDALIGN_H +#include +#define ALIGNOF(x) alignof(x) +#elif defined __GNUC__ +#define ALIGNOF(x) __alignof__(x) +#else +#define ALIGNOF(x) sizeof(x) #endif #ifdef MYDEBUG -/*@unchecked@*/ int _popt_debug = 0; #endif -#if !defined(HAVE_STRERROR) && !defined(__LCLINT__) +unsigned int _poptArgMask = POPT_ARG_MASK; +unsigned int _poptGroupMask = POPT_GROUP_MASK; + +#if !defined(HAVE_STRERROR) static char * strerror(int errno) { extern int sys_nerr; @@ -41,7 +48,6 @@ static char * strerror(int errno) #endif #ifdef MYDEBUG -/*@unused@*/ static void prtcon(const char *msg, poptContext con) { if (msg) fprintf(stderr, "%s", msg); @@ -60,119 +66,93 @@ void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) con->execPath = _free(con->execPath); con->execPath = xstrdup(path); con->execAbsolute = allowAbsolute; - /*@-nullstate@*/ /* LCL: con->execPath not NULL */ return; - /*@=nullstate@*/ } static void invokeCallbacksPRE(poptContext con, const struct poptOption * opt) - /*@globals internalState@*/ - /*@modifies internalState@*/ { if (opt != NULL) for (; opt->longName || opt->shortName || opt->arg; opt++) { - if (opt->arg == NULL) continue; /* XXX program error. */ - if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { - void * arg = opt->arg; -/*@-branchstate@*/ - /* XXX sick hack to preserve pretense of ABI. */ - if (arg == poptHelpOptions) arg = poptHelpOptionsI18N; -/*@=branchstate@*/ - /* Recurse on included sub-tables. */ - invokeCallbacksPRE(con, arg); - } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK && - (opt->argInfo & POPT_CBFLAG_PRE)) - { /*@-castfcnptr@*/ - poptCallbackType cb = (poptCallbackType)opt->arg; - /*@=castfcnptr@*/ - /* Perform callback. */ - /*@-noeffectuncon @*/ - cb(con, POPT_CALLBACK_REASON_PRE, NULL, NULL, opt->descrip); - /*@=noeffectuncon @*/ + poptArg arg = { .ptr = opt->arg }; + if (arg.ptr) + switch (poptArgType(opt)) { + case POPT_ARG_INCLUDE_TABLE: /* Recurse on included sub-tables. */ + poptSubstituteHelpI18N(arg.opt); /* XXX side effects */ + invokeCallbacksPRE(con, arg.opt); + break; + case POPT_ARG_CALLBACK: /* Perform callback. */ + if (!CBF_ISSET(opt, PRE)) + break; + arg.cb(con, POPT_CALLBACK_REASON_PRE, NULL, NULL, opt->descrip); + break; } } } static void invokeCallbacksPOST(poptContext con, const struct poptOption * opt) - /*@globals internalState@*/ - /*@modifies internalState@*/ { if (opt != NULL) for (; opt->longName || opt->shortName || opt->arg; opt++) { - if (opt->arg == NULL) continue; /* XXX program error. */ - if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { - void * arg = opt->arg; -/*@-branchstate@*/ - /* XXX sick hack to preserve pretense of ABI. */ - if (arg == poptHelpOptions) arg = poptHelpOptionsI18N; -/*@=branchstate@*/ - /* Recurse on included sub-tables. */ - invokeCallbacksPOST(con, arg); - } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK && - (opt->argInfo & POPT_CBFLAG_POST)) - { /*@-castfcnptr@*/ - poptCallbackType cb = (poptCallbackType)opt->arg; - /*@=castfcnptr@*/ - /* Perform callback. */ - /*@-noeffectuncon @*/ - cb(con, POPT_CALLBACK_REASON_POST, NULL, NULL, opt->descrip); - /*@=noeffectuncon @*/ + poptArg arg = { .ptr = opt->arg }; + if (arg.ptr) + switch (poptArgType(opt)) { + case POPT_ARG_INCLUDE_TABLE: /* Recurse on included sub-tables. */ + poptSubstituteHelpI18N(arg.opt); /* XXX side effects */ + invokeCallbacksPOST(con, arg.opt); + break; + case POPT_ARG_CALLBACK: /* Perform callback. */ + if (!CBF_ISSET(opt, POST)) + break; + arg.cb(con, POPT_CALLBACK_REASON_POST, NULL, NULL, opt->descrip); + break; } } } static void invokeCallbacksOPTION(poptContext con, - const struct poptOption * opt, - const struct poptOption * myOpt, - /*@null@*/ const void * myData, int shorty) - /*@globals internalState@*/ - /*@modifies internalState@*/ + const struct poptOption * opt, + const struct poptOption * myOpt, + const void * myData, int shorty) { const struct poptOption * cbopt = NULL; + poptArg cbarg = { .ptr = NULL }; if (opt != NULL) for (; opt->longName || opt->shortName || opt->arg; opt++) { - if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { - void * arg = opt->arg; -/*@-branchstate@*/ - /* XXX sick hack to preserve pretense of ABI. */ - if (arg == poptHelpOptions) arg = poptHelpOptionsI18N; -/*@=branchstate@*/ - /* Recurse on included sub-tables. */ - if (opt->arg != NULL) /* XXX program error */ + poptArg arg = { .ptr = opt->arg }; + switch (poptArgType(opt)) { + case POPT_ARG_INCLUDE_TABLE: /* Recurse on included sub-tables. */ + poptSubstituteHelpI18N(arg.opt); /* XXX side effects */ + if (opt->arg != NULL) invokeCallbacksOPTION(con, opt->arg, myOpt, myData, shorty); - } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK && - !(opt->argInfo & POPT_CBFLAG_SKIPOPTION)) { - /* Save callback info. */ + break; + case POPT_ARG_CALLBACK: /* Save callback info. */ + if (CBF_ISSET(opt, SKIPOPTION)) + break; cbopt = opt; - } else if (cbopt != NULL && - ((myOpt->shortName && opt->shortName && shorty && - myOpt->shortName == opt->shortName) || - (myOpt->longName && opt->longName && - /*@-nullpass@*/ /* LCL: opt->longName != NULL */ + cbarg.ptr = opt->arg; + break; + default: /* Perform callback on matching option. */ + if (cbopt == NULL || cbarg.cb == NULL) + break; + if ((myOpt->shortName && opt->shortName && shorty && + myOpt->shortName == opt->shortName) + || (myOpt->longName != NULL && opt->longName != NULL && !strcmp(myOpt->longName, opt->longName))) - /*@=nullpass@*/ - ) - { /*@-castfcnptr@*/ - poptCallbackType cb = (poptCallbackType)cbopt->arg; - /*@=castfcnptr@*/ - const void * cbData = (cbopt->descrip ? cbopt->descrip : myData); - /* Perform callback. */ - if (cb != NULL) { /* XXX program error */ - /*@-noeffectuncon @*/ - cb(con, POPT_CALLBACK_REASON_OPTION, myOpt, - con->os->nextArg, cbData); - /*@=noeffectuncon @*/ + { const void *cbData = (cbopt->descrip ? cbopt->descrip : myData); + cbarg.cb(con, POPT_CALLBACK_REASON_OPTION, + myOpt, con->os->nextArg, cbData); + /* Terminate (unless explcitly continuing). */ + if (!CBF_ISSET(cbopt, CONTINUE)) + return; } - /* Terminate (unless explcitly continuing). */ - if (!(cbopt->argInfo & POPT_CBFLAG_CONTINUE)) - return; + break; } } } poptContext poptGetContext(const char * name, int argc, const char ** argv, - const struct poptOption * options, int flags) + const struct poptOption * options, unsigned int flags) { poptContext con = malloc(sizeof(*con)); @@ -181,58 +161,44 @@ poptContext poptGetContext(const char * name, int argc, const char ** argv, con->os = con->optionStack; con->os->argc = argc; - /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */ con->os->argv = argv; - /*@=dependenttrans =assignexpose@*/ con->os->argb = NULL; if (!(flags & POPT_CONTEXT_KEEP_FIRST)) - con->os->next = 1; /* skip argv[0] */ + con->os->next = 1; /* skip argv[0] */ - con->leftovers = calloc( (argc + 1), sizeof(*con->leftovers) ); - /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */ + con->leftovers = calloc( (size_t)(argc + 1), sizeof(*con->leftovers) ); + con->allocLeftovers = argc + 1; con->options = options; - /*@=dependenttrans =assignexpose@*/ con->aliases = NULL; con->numAliases = 0; con->flags = flags; con->execs = NULL; con->numExecs = 0; + con->execFail = NULL; con->finalArgvAlloced = argc * 2; - con->finalArgv = calloc( con->finalArgvAlloced, sizeof(*con->finalArgv) ); + con->finalArgv = calloc( (size_t)con->finalArgvAlloced, sizeof(*con->finalArgv) ); con->execAbsolute = 1; con->arg_strip = NULL; if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER")) con->flags |= POPT_CONTEXT_POSIXMEHARDER; - if (name) { - size_t bufsize = strlen(name) + 1; - char * t = malloc(bufsize); - if (t) { - strlcpy(t, name, bufsize); - con->appName = t; - } - } + if (name) + con->appName = xstrdup(name); - /*@-internalglobs@*/ invokeCallbacksPRE(con, con->options); - /*@=internalglobs@*/ return con; } -static void cleanOSE(/*@special@*/ struct optionStackEntry *os) - /*@uses os @*/ - /*@releases os->nextArg, os->argv, os->argb @*/ - /*@modifies os @*/ +static void cleanOSE(struct optionStackEntry *os) { os->nextArg = _free(os->nextArg); os->argv = _free(os->argv); os->argb = PBM_FREE(os->argb); } -/*@-boundswrite@*/ void poptResetContext(poptContext con) { int i; @@ -244,36 +210,34 @@ void poptResetContext(poptContext con) con->os->argb = PBM_FREE(con->os->argb); con->os->currAlias = NULL; con->os->nextCharArg = NULL; - con->os->nextArg = NULL; - con->os->next = 1; /* skip argv[0] */ + con->os->nextArg = _free(con->os->nextArg); + if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) + con->os->next = 1; /* skip argv[0] */ + else + con->os->next = 0; + for (i = 0; i < con->numLeftovers; i++) { + con->leftovers[i] = _free(con->leftovers[i]); + } con->numLeftovers = 0; con->nextLeftover = 0; con->restLeftover = 0; con->doExec = NULL; + con->execFail = _free(con->execFail); if (con->finalArgv != NULL) for (i = 0; i < con->finalArgvCount; i++) { - /*@-unqualifiedtrans@*/ /* FIX: typedef double indirection. */ con->finalArgv[i] = _free(con->finalArgv[i]); - /*@=unqualifiedtrans@*/ } con->finalArgvCount = 0; con->arg_strip = PBM_FREE(con->arg_strip); - /*@-nullstate@*/ /* FIX: con->finalArgv != NULL */ return; - /*@=nullstate@*/ } -/*@=boundswrite@*/ /* Only one of longName, shortName should be set, not both. */ -/*@-boundswrite@*/ -static int handleExec(/*@special@*/ poptContext con, - /*@null@*/ const char * longName, char shortName) - /*@uses con->execs, con->numExecs, con->flags, con->doExec, - con->finalArgv, con->finalArgvAlloced, con->finalArgvCount @*/ - /*@modifies con @*/ +static int handleExec(poptContext con, + const char * longName, char shortName) { poptItem item; int i; @@ -311,40 +275,75 @@ static int handleExec(/*@special@*/ poptContext con, i = con->finalArgvCount++; if (con->finalArgv != NULL) /* XXX can't happen */ - { size_t bufsize = (longName ? strlen(longName) : 0) + 3; - char *s = malloc(bufsize); + { char *s = malloc((longName ? strlen(longName) : 0) + sizeof("--")); if (s != NULL) { /* XXX can't happen */ + con->finalArgv[i] = s; + *s++ = '-'; if (longName) - snprintf(s, bufsize, "--%s", longName); + s = stpcpy( stpcpy(s, "-"), longName); else - snprintf(s, bufsize, "-%c", shortName); - con->finalArgv[i] = s; + *s++ = shortName; + *s = '\0'; } else con->finalArgv[i] = NULL; } - /*@-nullstate@*/ /* FIX: con->finalArgv[] == NULL */ return 1; - /*@=nullstate@*/ } -/*@=boundswrite@*/ + +/** + * Compare long option for equality, adjusting for POPT_ARGFLAG_TOGGLE. + * @param opt option + * @param longName arg option + * @param longNameLen arg option length + * @return does long option match? + */ +static int +longOptionStrcmp(const struct poptOption * opt, + const char * longName, size_t longNameLen) +{ + const char * optLongName = opt->longName; + int rc; + + if (optLongName == NULL || longName == NULL) /* XXX can't heppen */ + return 0; + + if (F_ISSET(opt, TOGGLE)) { + if (optLongName[0] == 'n' && optLongName[1] == 'o') { + optLongName += sizeof("no") - 1; + if (optLongName[0] == '-') + optLongName++; + } + if (longName[0] == 'n' && longName[1] == 'o') { + longName += sizeof("no") - 1; + longNameLen -= sizeof("no") - 1; + if (longName[0] == '-') { + longName++; + longNameLen--; + } + } + } + rc = (int)(strlen(optLongName) == longNameLen); + if (rc) + rc = (int)(strncmp(optLongName, longName, longNameLen) == 0); + return rc; +} /* Only one of longName, shortName may be set at a time */ -static int handleAlias(/*@special@*/ poptContext con, - /*@null@*/ const char * longName, char shortName, - /*@exposed@*/ /*@null@*/ const char * nextCharArg) - /*@uses con->aliases, con->numAliases, con->optionStack, con->os, - con->os->currAlias, con->os->currAlias->option.longName @*/ - /*@modifies con @*/ +static int handleAlias(poptContext con, + const char * longName, size_t longNameLen, + char shortName, + const char * nextArg) { poptItem item = con->os->currAlias; int rc; int i; if (item) { - if (longName && (item->option.longName && - !strcmp(longName, item->option.longName))) + if (longName && item->option.longName != NULL + && longOptionStrcmp(&item->option, longName, longNameLen)) return 0; + else if (shortName && shortName == item->option.shortName) return 0; } @@ -354,10 +353,12 @@ static int handleAlias(/*@special@*/ poptContext con, for (i = con->numAliases - 1; i >= 0; i--) { item = con->aliases + i; - if (longName && !(item->option.longName && - !strcmp(longName, item->option.longName))) - continue; - else if (shortName != item->option.shortName) + if (longName) { + if (item->option.longName == NULL) + continue; + if (!longOptionStrcmp(&item->option, longName, longNameLen)) + continue; + } else if (shortName != item->option.shortName) continue; break; } @@ -366,10 +367,8 @@ static int handleAlias(/*@special@*/ poptContext con, if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH) return POPT_ERROR_OPTSTOODEEP; -/*@-boundsread@*/ - if (nextCharArg && *nextCharArg) - con->os->nextCharArg = nextCharArg; -/*@=boundsread@*/ + if (longName == NULL && nextArg != NULL && *nextArg != '\0') + con->os->nextCharArg = nextArg; con->os++; con->os->next = 0; @@ -377,21 +376,82 @@ static int handleAlias(/*@special@*/ poptContext con, con->os->nextArg = NULL; con->os->nextCharArg = NULL; con->os->currAlias = con->aliases + i; - rc = poptDupArgv(con->os->currAlias->argc, con->os->currAlias->argv, - &con->os->argc, &con->os->argv); + { const char ** av; + int ac = con->os->currAlias->argc; + /* Append --foo=bar arg to alias argv array (if present). */ + if (longName && nextArg != NULL && *nextArg != '\0') { + av = malloc((ac + 1 + 1) * sizeof(*av)); + if (av != NULL) { /* XXX won't happen. */ + for (i = 0; i < ac; i++) { + av[i] = con->os->currAlias->argv[i]; + } + av[ac++] = nextArg; + av[ac] = NULL; + } else /* XXX revert to old popt behavior if malloc fails. */ + av = con->os->currAlias->argv; + } else + av = con->os->currAlias->argv; + rc = poptDupArgv(ac, av, &con->os->argc, &con->os->argv); + if (av != NULL && av != con->os->currAlias->argv) + free(av); + } con->os->argb = NULL; return (rc ? rc : 1); } -/*@-bounds -boundswrite @*/ +/** + * Return absolute path to executable by searching PATH. + * @param argv0 name of executable + * @return (malloc'd) absolute path to executable (or NULL) + */ +static +const char * findProgramPath(const char * argv0) +{ + char *path = NULL, *s = NULL, *se; + char *t = NULL; + + if (argv0 == NULL) return NULL; /* XXX can't happen */ + + /* If there is a / in argv[0], it has to be an absolute path. */ + /* XXX Hmmm, why not if (argv0[0] == '/') ... instead? */ + if (strchr(argv0, '/')) + return xstrdup(argv0); + + if ((path = getenv("PATH")) == NULL || (path = xstrdup(path)) == NULL) + return NULL; + + /* The return buffer in t is big enough for any path. */ + if ((t = malloc(strlen(path) + strlen(argv0) + sizeof("/"))) != NULL) + for (s = path; s && *s; s = se) { + + /* Snip PATH element into [s,se). */ + if ((se = strchr(s, ':'))) + *se++ = '\0'; + + /* Append argv0 to PATH element. */ + (void) stpcpy(stpcpy(stpcpy(t, s), "/"), argv0); + + /* If file is executable, bingo! */ + if (!access(t, X_OK)) + break; + } + + /* If no executable was found in PATH, return NULL. */ + if (!(s && *s) && t != NULL) + t = _free(t); + path = _free(path); + + return t; +} + static int execCommand(poptContext con) - /*@globals internalState @*/ - /*@modifies internalState @*/ { poptItem item = con->doExec; - const char ** argv; + poptArgv argv = NULL; int argc = 0; + int rc; + int ec = POPT_ERROR_ERRNO; if (item == NULL) /*XXX can't happen*/ return POPT_ERROR_NOARG; @@ -405,13 +465,17 @@ static int execCommand(poptContext con) if (argv == NULL) return POPT_ERROR_MALLOC; if (!strchr(item->argv[0], '/') && con->execPath != NULL) { - size_t bufsize = strlen(con->execPath) + strlen(item->argv[0]) + sizeof "/"; - char *s = alloca(bufsize); - snprintf(s, bufsize, "%s/%s", con->execPath, item->argv[0]); + char *s = malloc(strlen(con->execPath) + strlen(item->argv[0]) + sizeof("/")); + if (s) + (void)stpcpy(stpcpy(stpcpy(s, con->execPath), "/"), item->argv[0]); + argv[argc] = s; } else argv[argc] = findProgramPath(item->argv[0]); - if (argv[argc++] == NULL) return POPT_ERROR_NOARG; + if (argv[argc++] == NULL) { + ec = POPT_ERROR_NOARG; + goto exit; + } if (item->argc > 1) { memcpy(argv + argc, item->argv + 1, sizeof(*argv) * (item->argc - 1)); @@ -431,12 +495,11 @@ static int execCommand(poptContext con) argv[argc] = NULL; - { -#ifdef __hpux - int rc = setresgid(getgid(), getgid(),-1); - if (rc) return POPT_ERROR_ERRNO; +#if defined(hpux) || defined(__hpux) + rc = setresgid(getgid(), getgid(),-1); + if (rc) goto exit; rc = setresuid(getuid(), getuid(),-1); - if (rc) return POPT_ERROR_ERRNO; + if (rc) goto exit; #else /* * XXX " ... on BSD systems setuid() should be preferred over setreuid()" @@ -444,27 +507,27 @@ static int execCommand(poptContext con) * XXX from Norbert Warmuth */ #if defined(HAVE_SETUID) - int rc = setgid(getgid()); - if (rc) return POPT_ERROR_ERRNO; + rc = setgid(getgid()); + if (rc) goto exit; rc = setuid(getuid()); - if (rc) return POPT_ERROR_ERRNO; + if (rc) goto exit; #elif defined (HAVE_SETREUID) - int rc = setregid(getgid(), getgid()); - if (rc) return POPT_ERROR_ERRNO; + rc = setregid(getgid(), getgid()); + if (rc) goto exit; rc = setreuid(getuid(), getuid()); - if (rc) return POPT_ERROR_ERRNO; + if (rc) goto exit; #else - ; /* Can't drop privileges */ + /* refuse to exec if we cannot drop suid/sgid privileges */ + if (getuid() != geteuid() || getgid() != getegid()) { + errno = ENOTSUP; + goto exit; + } #endif #endif - } - - if (argv[0] == NULL) - return POPT_ERROR_NOARG; #ifdef MYDEBUG if (_popt_debug) - { const char ** avp; + { poptArgv avp; fprintf(stderr, "==> execvp(%s) argv[%d]:", argv[0], argc); for (avp = argv; *avp; avp++) fprintf(stderr, " '%s'", *avp); @@ -472,56 +535,65 @@ if (_popt_debug) } #endif - execvp(argv[0], (char *const *)argv); + rc = execvp(argv[0], (char *const *)argv); - return POPT_ERROR_ERRNO; + /* only reached on execvp() failure */ + con->execFail = xstrdup(argv[0]); + +exit: + if (argv) { + if (argv[0]) + free((void *)argv[0]); + free(argv); + } + return ec; } -/*@=bounds =boundswrite @*/ -/*@-boundswrite@*/ -/*@observer@*/ /*@null@*/ static const struct poptOption * -findOption(const struct poptOption * opt, /*@null@*/ const char * longName, +static const struct poptOption * +findOption(const struct poptOption * opt, + const char * longName, size_t longNameLen, char shortName, - /*@null@*/ /*@out@*/ poptCallbackType * callback, - /*@null@*/ /*@out@*/ const void ** callbackData, - int singleDash) - /*@modifies *callback, *callbackData */ + poptCallbackType * callback, + const void ** callbackData, + unsigned int argInfo) { const struct poptOption * cb = NULL; + poptArg cbarg = { .ptr = NULL }; /* This happens when a single - is given */ - if (singleDash && !shortName && (longName && *longName == '\0')) + if (LF_ISSET(ONEDASH) && !shortName && (longName && *longName == '\0')) shortName = '-'; for (; opt->longName || opt->shortName || opt->arg; opt++) { + poptArg arg = { .ptr = opt->arg }; - if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { - const struct poptOption * opt2; - void * arg = opt->arg; - -/*@-branchstate@*/ - /* XXX sick hack to preserve pretense of ABI. */ - if (arg == poptHelpOptions) arg = poptHelpOptionsI18N; -/*@=branchstate@*/ - /* Recurse on included sub-tables. */ - if (arg == NULL) continue; /* XXX program error */ - opt2 = findOption(arg, longName, shortName, callback, - callbackData, singleDash); + switch (poptArgType(opt)) { + case POPT_ARG_INCLUDE_TABLE: /* Recurse on included sub-tables. */ + { const struct poptOption * opt2; + + poptSubstituteHelpI18N(arg.opt); /* XXX side effects */ + if (arg.ptr == NULL) continue; /* XXX program error */ + opt2 = findOption(arg.opt, longName, longNameLen, shortName, callback, + callbackData, argInfo); if (opt2 == NULL) continue; /* Sub-table data will be inheirited if no data yet. */ - if (!(callback && *callback)) return opt2; - if (!(callbackData && *callbackData == NULL)) return opt2; - /*@-observertrans -dependenttrans @*/ - *callbackData = opt->descrip; - /*@=observertrans =dependenttrans @*/ + if (callback && *callback + && callbackData && *callbackData == NULL) + *callbackData = opt->descrip; return opt2; - } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) { + } break; + case POPT_ARG_CALLBACK: cb = opt; - } else if (longName && opt->longName && - (!singleDash || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) && - /*@-nullpass@*/ /* LCL: opt->longName != NULL */ - !strcmp(longName, opt->longName)) - /*@=nullpass@*/ + cbarg.ptr = opt->arg; + continue; + break; + default: + break; + } + + if (longName != NULL && opt->longName != NULL && + (!LF_ISSET(ONEDASH) || F_ISSET(opt, ONEDASH)) && + longOptionStrcmp(opt, longName, longNameLen)) { break; } else if (shortName && shortName == opt->shortName) { @@ -529,34 +601,19 @@ findOption(const struct poptOption * opt, /*@null@*/ const char * longName, } } - if (!opt->longName && !opt->shortName) + if (opt->longName == NULL && !opt->shortName) return NULL; - /*@-modobserver -mods @*/ - if (callback) *callback = NULL; - if (callbackData) *callbackData = NULL; - if (cb) { - if (callback) - /*@-castfcnptr@*/ - *callback = (poptCallbackType)cb->arg; - /*@=castfcnptr@*/ - if (!(cb->argInfo & POPT_CBFLAG_INC_DATA)) { - if (callbackData) - /*@-observertrans@*/ /* FIX: typedef double indirection. */ - *callbackData = cb->descrip; - /*@=observertrans@*/ - } - } - /*@=modobserver =mods @*/ + + if (callback) + *callback = (cb ? cbarg.cb : NULL); + if (callbackData) + *callbackData = (cb && !CBF_ISSET(cb, INC_DATA) ? cb->descrip : NULL); return opt; } -/*@=boundswrite@*/ -static const char * findNextArg(/*@special@*/ poptContext con, +static const char * findNextArg(poptContext con, unsigned argx, int delete_arg) - /*@uses con->optionStack, con->os, - con->os->next, con->os->argb, con->os->argc, con->os->argv @*/ - /*@modifies con @*/ { struct optionStackEntry * os = con->os; const char * arg; @@ -568,151 +625,586 @@ static const char * findNextArg(/*@special@*/ poptContext con, if (os->next == os->argc && os == con->optionStack) break; if (os->argv != NULL) for (i = os->next; i < os->argc; i++) { - /*@-sizeoftype@*/ if (os->argb && PBM_ISSET(i, os->argb)) - /*@innercontinue@*/ continue; + continue; if (*os->argv[i] == '-') - /*@innercontinue@*/ continue; + continue; if (--argx > 0) - /*@innercontinue@*/ continue; + continue; arg = os->argv[i]; if (delete_arg) { if (os->argb == NULL) os->argb = PBM_ALLOC(os->argc); if (os->argb != NULL) /* XXX can't happen */ - PBM_SET(i, os->argb); + PBM_SET(i, os->argb); } - /*@innerbreak@*/ break; - /*@=sizeoftype@*/ + break; } if (os > con->optionStack) os--; } while (arg == NULL); return arg; } -/*@-boundswrite@*/ -static /*@only@*/ /*@null@*/ const char * -expandNextArg(/*@special@*/ poptContext con, const char * s) - /*@uses con->optionStack, con->os, - con->os->next, con->os->argb, con->os->argc, con->os->argv @*/ - /*@modifies con @*/ +static const char * +expandNextArg(poptContext con, const char * s) { const char * a = NULL; - size_t alen, pos; - char *t, *te; + char *t, *t_tmp, *te; size_t tn = strlen(s) + 1; char c; - te = t = malloc(tn);; + te = t = malloc(tn); if (t == NULL) return NULL; /* XXX can't happen */ + *t = '\0'; while ((c = *s++) != '\0') { switch (c) { #if 0 /* XXX can't do this */ case '\\': /* escape */ c = *s++; - /*@switchbreak@*/ break; + break; #endif case '!': if (!(s[0] == '#' && s[1] == ':' && s[2] == '+')) - /*@switchbreak@*/ break; + break; /* XXX Make sure that findNextArg deletes only next arg. */ if (a == NULL) { - if ((a = findNextArg(con, 1, 1)) == NULL) - /*@switchbreak@*/ break; + if ((a = findNextArg(con, 1U, 1)) == NULL) + break; + } + s += sizeof("#:+") - 1; + + tn += strlen(a); + { size_t pos = (size_t) (te - t); + if ((t_tmp = realloc(t, tn)) == NULL) { /* XXX can't happen */ + free(t); + return NULL; + } + t = t_tmp; + te = stpcpy(t + pos, a); } - s += 3; - - alen = strlen(a); - tn += alen; - pos = te - t; - t = realloc(t, tn); - te = t + pos; - memcpy(te, a, alen+1); te += alen; continue; - /*@notreached@*/ /*@switchbreak@*/ break; + break; default: - /*@switchbreak@*/ break; + break; } *te++ = c; } - *te = '\0'; - t = realloc(t, strlen(t) + 1); /* XXX memory leak, hard to plug */ + *te++ = '\0'; + /* If the new string is longer than needed, shorten. */ + if ((t + tn) > te) { + if ((te = realloc(t, (size_t)(te - t))) == NULL) + free(t); + t = te; + } return t; } -/*@=boundswrite@*/ -static void poptStripArg(/*@special@*/ poptContext con, int which) - /*@uses con->arg_strip, con->optionStack @*/ - /*@defines con->arg_strip @*/ - /*@modifies con @*/ +static void poptStripArg(poptContext con, int which) { - /*@-sizeoftype@*/ if (con->arg_strip == NULL) con->arg_strip = PBM_ALLOC(con->optionStack[0].argc); if (con->arg_strip != NULL) /* XXX can't happen */ PBM_SET(which, con->arg_strip); - /*@=sizeoftype@*/ - /*@-compdef@*/ /* LCL: con->arg_strip udefined? */ return; - /*@=compdef@*/ } -int poptSaveLong(long * arg, int argInfo, long aLong) +unsigned int _poptBitsN = _POPT_BITS_N; +unsigned int _poptBitsM = _POPT_BITS_M; +unsigned int _poptBitsK = _POPT_BITS_K; + +static int _poptBitsNew(poptBits *bitsp) +{ + if (bitsp == NULL) + return POPT_ERROR_NULLARG; + + /* XXX handle negated initialization. */ + if (*bitsp == NULL) { + if (_poptBitsN == 0) { + _poptBitsN = _POPT_BITS_N; + _poptBitsM = _POPT_BITS_M; + } + if (_poptBitsM == 0U) _poptBitsM = (3 * _poptBitsN) / 2; + if (_poptBitsK == 0U || _poptBitsK > 32U) _poptBitsK = _POPT_BITS_K; + *bitsp = PBM_ALLOC(_poptBitsM-1); + } + return 0; +} + +int poptBitsAdd(poptBits bits, const char * s) +{ + size_t ns = (s ? strlen(s) : 0); + uint32_t h0 = 0; + uint32_t h1 = 0; + + if (bits == NULL || ns == 0) + return POPT_ERROR_NULLARG; + + poptJlu32lpair(s, ns, &h0, &h1); + + for (ns = 0; ns < (size_t)_poptBitsK; ns++) { + uint32_t h = h0 + ns * h1; + uint32_t ix = (h % _poptBitsM); + PBM_SET(ix, bits); + } + return 0; +} + +int poptBitsChk(poptBits bits, const char * s) +{ + size_t ns = (s ? strlen(s) : 0); + uint32_t h0 = 0; + uint32_t h1 = 0; + int rc = 1; + + if (bits == NULL || ns == 0) + return POPT_ERROR_NULLARG; + + poptJlu32lpair(s, ns, &h0, &h1); + + for (ns = 0; ns < (size_t)_poptBitsK; ns++) { + uint32_t h = h0 + ns * h1; + uint32_t ix = (h % _poptBitsM); + if (PBM_ISSET(ix, bits)) + continue; + rc = 0; + break; + } + return rc; +} + +int poptBitsClr(poptBits bits) +{ + static size_t nbw = (__PBM_NBITS/8); + size_t nw = (__PBM_IX(_poptBitsM-1) + 1); + + if (bits == NULL) + return POPT_ERROR_NULLARG; + memset(bits, 0, nw * nbw); + return 0; +} + +int poptBitsDel(poptBits bits, const char * s) +{ + size_t ns = (s ? strlen(s) : 0); + uint32_t h0 = 0; + uint32_t h1 = 0; + + if (bits == NULL || ns == 0) + return POPT_ERROR_NULLARG; + + poptJlu32lpair(s, ns, &h0, &h1); + + for (ns = 0; ns < (size_t)_poptBitsK; ns++) { + uint32_t h = h0 + ns * h1; + uint32_t ix = (h % _poptBitsM); + PBM_CLR(ix, bits); + } + return 0; +} + +int poptBitsIntersect(poptBits *ap, const poptBits b) +{ + __pbm_bits *abits; + __pbm_bits *bbits; + __pbm_bits rc = 0; + size_t nw = (__PBM_IX(_poptBitsM-1) + 1); + size_t i; + + if (ap == NULL || b == NULL || _poptBitsNew(ap)) + return POPT_ERROR_NULLARG; + abits = __PBM_BITS(*ap); + bbits = __PBM_BITS(b); + + for (i = 0; i < nw; i++) { + abits[i] &= bbits[i]; + rc |= abits[i]; + } + return (rc ? 1 : 0); +} + +int poptBitsUnion(poptBits *ap, const poptBits b) +{ + __pbm_bits *abits; + __pbm_bits *bbits; + __pbm_bits rc = 0; + size_t nw = (__PBM_IX(_poptBitsM-1) + 1); + size_t i; + + if (ap == NULL || b == NULL || _poptBitsNew(ap)) + return POPT_ERROR_NULLARG; + abits = __PBM_BITS(*ap); + bbits = __PBM_BITS(b); + + for (i = 0; i < nw; i++) { + abits[i] |= bbits[i]; + rc |= abits[i]; + } + return (rc ? 1 : 0); +} + +int poptBitsArgs(poptContext con, poptBits *ap) +{ + const char ** av; + int rc = 0; + + if (con == NULL || ap == NULL || _poptBitsNew(ap) || + con->leftovers == NULL || con->numLeftovers == con->nextLeftover) + return POPT_ERROR_NULLARG; + + /* some apps like [like RPM ;-) ] need this NULL terminated */ + con->leftovers[con->numLeftovers] = NULL; + + for (av = con->leftovers + con->nextLeftover; *av != NULL; av++) { + if ((rc = poptBitsAdd(*ap, *av)) != 0) + break; + } + return rc; +} + +int poptSaveBits(poptBits * bitsp, + UNUSED(unsigned int argInfo), const char * s) +{ + char *tbuf = NULL; + char *t, *te; + int rc = 0; + + if (bitsp == NULL || s == NULL || *s == '\0' || _poptBitsNew(bitsp)) + return POPT_ERROR_NULLARG; + + /* Parse comma separated attributes. */ + te = tbuf = xstrdup(s); + while ((t = te) != NULL && *t) { + while (*te != '\0' && *te != ',') + te++; + if (*te != '\0') + *te++ = '\0'; + /* XXX Ignore empty strings. */ + if (*t == '\0') + continue; + /* XXX Permit negated attributes. caveat emptor: false negatives. */ + if (*t == '!') { + t++; + if ((rc = poptBitsChk(*bitsp, t)) > 0) + rc = poptBitsDel(*bitsp, t); + } else + rc = poptBitsAdd(*bitsp, t); + if (rc) + break; + } + tbuf = _free(tbuf); + return rc; +} + +int poptSaveString(const char *** argvp, + UNUSED(unsigned int argInfo), const char * val) +{ + int argc = 0; + + if (argvp == NULL || val == NULL) + return POPT_ERROR_NULLARG; + + /* XXX likely needs an upper bound on argc. */ + if (*argvp != NULL) + while ((*argvp)[argc] != NULL) + argc++; + + if ((*argvp = xrealloc(*argvp, (argc + 1 + 1) * sizeof(**argvp))) != NULL) { + (*argvp)[argc++] = xstrdup(val); + (*argvp)[argc ] = NULL; + } + return 0; +} + +static long long poptRandomValue(long long limit) +{ +#if defined(HAVE_SRANDOM) + static int seed = 1; + + if (seed) { + srandom((unsigned)getpid()); + srandom((unsigned)random()); + seed = 0; + } + + return random() % limit + 1; +#else + /* XXX avoid adding POPT_ERROR_UNIMPLEMENTED to minimize i18n churn. */ + return POPT_ERROR_BADOPERATION; +#endif +} + +int poptSaveLongLong(long long * arg, unsigned int argInfo, long long aLongLong) { /* XXX Check alignment, may fail on funky platforms. */ - if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1))) + if (arg == NULL || (((unsigned long)arg) & (ALIGNOF(*arg)-1))) return POPT_ERROR_NULLARG; - if (argInfo & POPT_ARGFLAG_NOT) - aLong = ~aLong; - switch (argInfo & POPT_ARGFLAG_LOGICALOPS) { + if (aLongLong != 0 && LF_ISSET(RANDOM)) { + aLongLong = poptRandomValue(aLongLong); + if (aLongLong < 0) + return aLongLong; + } + if (LF_ISSET(NOT)) + aLongLong = ~aLongLong; + switch (LF_ISSET(LOGICALOPS)) { case 0: - *arg = aLong; + *arg = aLongLong; break; case POPT_ARGFLAG_OR: - *arg |= aLong; + *(unsigned long long *)arg |= (unsigned long long)aLongLong; break; case POPT_ARGFLAG_AND: - *arg &= aLong; + *(unsigned long long *)arg &= (unsigned long long)aLongLong; break; case POPT_ARGFLAG_XOR: - *arg ^= aLong; + *(unsigned long long *)arg ^= (unsigned long long)aLongLong; break; default: return POPT_ERROR_BADOPERATION; - /*@notreached@*/ break; + break; } return 0; } -int poptSaveInt(/*@null@*/ int * arg, int argInfo, long aLong) +int poptSaveLong(long * arg, unsigned int argInfo, long aLong) { /* XXX Check alignment, may fail on funky platforms. */ - if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1))) + if (arg == NULL || (((unsigned long)arg) & (ALIGNOF(*arg)-1))) return POPT_ERROR_NULLARG; - if (argInfo & POPT_ARGFLAG_NOT) + if (aLong != 0 && LF_ISSET(RANDOM)) { + aLong = (long)poptRandomValue(aLong); + if (aLong < 0) + return aLong; + } + if (LF_ISSET(NOT)) aLong = ~aLong; - switch (argInfo & POPT_ARGFLAG_LOGICALOPS) { - case 0: - *arg = aLong; + switch (LF_ISSET(LOGICALOPS)) { + case 0: *arg = aLong; break; + case POPT_ARGFLAG_OR: *(unsigned long *)arg |= (unsigned long)aLong; break; + case POPT_ARGFLAG_AND: *(unsigned long *)arg &= (unsigned long)aLong; break; + case POPT_ARGFLAG_XOR: *(unsigned long *)arg ^= (unsigned long)aLong; break; + default: + return POPT_ERROR_BADOPERATION; break; - case POPT_ARGFLAG_OR: - *arg |= aLong; + } + return 0; +} + +int poptSaveInt(int * arg, unsigned int argInfo, long aLong) +{ + /* XXX Check alignment, may fail on funky platforms. */ + if (arg == NULL || (((unsigned long)arg) & (ALIGNOF(*arg)-1))) + return POPT_ERROR_NULLARG; + + if (aLong != 0 && LF_ISSET(RANDOM)) { + aLong = (int)poptRandomValue(aLong); + if (aLong < 0) + return aLong; + } + if (LF_ISSET(NOT)) + aLong = ~aLong; + switch (LF_ISSET(LOGICALOPS)) { + case 0: *arg = (int) aLong; break; + case POPT_ARGFLAG_OR: *(unsigned int *)arg |= (unsigned int) aLong; break; + case POPT_ARGFLAG_AND: *(unsigned int *)arg &= (unsigned int) aLong; break; + case POPT_ARGFLAG_XOR: *(unsigned int *)arg ^= (unsigned int) aLong; break; + default: + return POPT_ERROR_BADOPERATION; break; - case POPT_ARGFLAG_AND: - *arg &= aLong; + } + return 0; +} + +int poptSaveShort(short * arg, unsigned int argInfo, long aLong) +{ + /* XXX Check alignment, may fail on funky platforms. */ + if (arg == NULL || (((unsigned long)arg) & (ALIGNOF(*arg)-1))) + return POPT_ERROR_NULLARG; + + if (aLong != 0 && LF_ISSET(RANDOM)) { + aLong = (short)poptRandomValue(aLong); + if (aLong < 0) + return aLong; + } + if (LF_ISSET(NOT)) + aLong = ~aLong; + switch (LF_ISSET(LOGICALOPS)) { + case 0: *arg = (short) aLong; break; - case POPT_ARGFLAG_XOR: - *arg ^= aLong; + case POPT_ARGFLAG_OR: *(unsigned short *)arg |= (unsigned short) aLong; + break; + case POPT_ARGFLAG_AND: *(unsigned short *)arg &= (unsigned short) aLong; + break; + case POPT_ARGFLAG_XOR: *(unsigned short *)arg ^= (unsigned short) aLong; + break; + default: return POPT_ERROR_BADOPERATION; break; - default: - return POPT_ERROR_BADOPERATION; - /*@notreached@*/ break; } return 0; } -/*@-boundswrite@*/ +/** + * Return argInfo field, handling POPT_ARGFLAG_TOGGLE overrides. + * @param con context + * @param opt option + * @return argInfo + */ +static unsigned int poptArgInfo(poptContext con, const struct poptOption * opt) +{ + unsigned int argInfo = opt->argInfo; + + if (con->os->argv != NULL && con->os->next > 0 && opt->longName != NULL) + if (LF_ISSET(TOGGLE)) { + const char * longName = con->os->argv[con->os->next-1]; + while (*longName == '-') longName++; + /* XXX almost good enough but consider --[no]nofoo corner cases. */ + if (longName[0] != opt->longName[0] || longName[1] != opt->longName[1]) + { + if (!LF_ISSET(XOR)) { /* XXX dont toggle with XOR */ + /* Toggle POPT_BIT_SET <=> POPT_BIT_CLR. */ + if (LF_ISSET(LOGICALOPS)) + argInfo ^= (POPT_ARGFLAG_OR|POPT_ARGFLAG_AND); + argInfo ^= POPT_ARGFLAG_NOT; + } + } + } + return argInfo; +} + +/** + * Parse an integer expression. + * @retval *llp integer expression value + * @param argInfo integer expression type + * @param val integer expression string + * @return 0 on success, otherwise POPT_* error. + */ +static int poptParseInteger(long long * llp, + UNUSED(unsigned int argInfo), + const char * val) +{ + if (val) { + char *end = NULL; + *llp = strtoll(val, &end, 0); + + /* XXX parse scaling suffixes here. */ + + if (!(end && *end == '\0')) + return POPT_ERROR_BADNUMBER; + } else + *llp = 0; + return 0; +} + +/** + * Save the option argument through the (*opt->arg) pointer. + * @param con context + * @param opt option + * @return 0 on success, otherwise POPT_* error. + */ +static int poptSaveArg(poptContext con, const struct poptOption * opt) +{ + poptArg arg = { .ptr = opt->arg }; + int rc = 0; /* assume success */ + + switch (poptArgType(opt)) { + case POPT_ARG_BITSET: + /* XXX memory leak, application is responsible for free. */ + rc = poptSaveBits(arg.ptr, opt->argInfo, con->os->nextArg); + break; + case POPT_ARG_ARGV: + /* XXX memory leak, application is responsible for free. */ + rc = poptSaveString(arg.ptr, opt->argInfo, con->os->nextArg); + break; + case POPT_ARG_STRING: + /* XXX memory leak, application is responsible for free. */ + arg.argv[0] = (con->os->nextArg) ? xstrdup(con->os->nextArg) : NULL; + break; + + case POPT_ARG_INT: + case POPT_ARG_SHORT: + case POPT_ARG_LONG: + case POPT_ARG_LONGLONG: + { unsigned int argInfo = poptArgInfo(con, opt); + long long aNUM = 0; + + if ((rc = poptParseInteger(&aNUM, argInfo, con->os->nextArg)) != 0) + break; + + switch (poptArgType(opt)) { + case POPT_ARG_LONGLONG: +/* XXX let's not demand C99 compiler flags for quite yet. */ +#if !defined(LLONG_MAX) +# define LLONG_MAX 9223372036854775807LL +# define LLONG_MIN (-LLONG_MAX - 1LL) +#endif + rc = !(aNUM == LLONG_MIN || aNUM == LLONG_MAX) + ? poptSaveLongLong(arg.longlongp, argInfo, aNUM) + : POPT_ERROR_OVERFLOW; + break; + case POPT_ARG_LONG: + rc = !(aNUM < (long long)LONG_MIN || aNUM > (long long)LONG_MAX) + ? poptSaveLong(arg.longp, argInfo, (long)aNUM) + : POPT_ERROR_OVERFLOW; + break; + case POPT_ARG_INT: + rc = !(aNUM < (long long)INT_MIN || aNUM > (long long)INT_MAX) + ? poptSaveInt(arg.intp, argInfo, (long)aNUM) + : POPT_ERROR_OVERFLOW; + break; + case POPT_ARG_SHORT: + rc = !(aNUM < (long long)SHRT_MIN || aNUM > (long long)SHRT_MAX) + ? poptSaveShort(arg.shortp, argInfo, (long)aNUM) + : POPT_ERROR_OVERFLOW; + break; + } + } break; + + case POPT_ARG_FLOAT: + case POPT_ARG_DOUBLE: + { char *end = NULL; + double aDouble = 0.0; + + if (con->os->nextArg) { + int saveerrno = errno; + errno = 0; + aDouble = strtod(con->os->nextArg, &end); + if (errno == ERANGE) { + rc = POPT_ERROR_OVERFLOW; + break; + } + errno = saveerrno; + if (*end != '\0') { + rc = POPT_ERROR_BADNUMBER; + break; + } + } + + switch (poptArgType(opt)) { + case POPT_ARG_DOUBLE: + arg.doublep[0] = aDouble; + break; + case POPT_ARG_FLOAT: +#define POPT_ABS(a) ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a)) + if ((FLT_MIN - POPT_ABS(aDouble)) > DBL_EPSILON + || (POPT_ABS(aDouble) - FLT_MAX) > DBL_EPSILON) + rc = POPT_ERROR_OVERFLOW; + else + arg.floatp[0] = (float) aDouble; + break; + } + } break; + case POPT_ARG_MAINCALL: + con->maincall = opt->arg; + break; + default: + fprintf(stdout, POPT_("option type (%u) not implemented in popt\n"), + poptArgType(opt)); + exit(EXIT_FAILURE); + break; + } + return rc; +} + /* returns 'val' element, -1 on last item, POPT_ERROR_* on error */ int poptGetNextOpt(poptContext con) { @@ -734,24 +1226,27 @@ int poptGetNextOpt(poptContext con) cleanOSE(con->os--); } if (!con->os->nextCharArg && con->os->next == con->os->argc) { - /*@-internalglobs@*/ invokeCallbacksPOST(con, con->options); - /*@=internalglobs@*/ + + if (con->maincall) { + (void) (*con->maincall) (con->finalArgvCount, con->finalArgv); + return -1; + } + if (con->doExec) return execCommand(con); return -1; } /* Process next long option */ if (!con->os->nextCharArg) { - char * localOptString, * optString; + const char * optString; + size_t optStringLen; int thisopt; - /*@-sizeoftype@*/ if (con->os->argb && PBM_ISSET(con->os->next, con->os->argb)) { con->os->next++; continue; } - /*@=sizeoftype@*/ thisopt = con->os->next; if (con->os->argv != NULL) /* XXX can't happen */ origOptString = con->os->argv[con->os->next++]; @@ -759,25 +1254,35 @@ int poptGetNextOpt(poptContext con) if (origOptString == NULL) /* XXX can't happen */ return POPT_ERROR_BADOPT; - if (con->restLeftover || *origOptString != '-') { + if (con->restLeftover || *origOptString != '-' || + (*origOptString == '-' && origOptString[1] == '\0')) + { if (con->flags & POPT_CONTEXT_POSIXMEHARDER) con->restLeftover = 1; if (con->flags & POPT_CONTEXT_ARG_OPTS) { con->os->nextArg = xstrdup(origOptString); return 0; } - if (con->leftovers != NULL) /* XXX can't happen */ - con->leftovers[con->numLeftovers++] = origOptString; + if (con->leftovers != NULL) { /* XXX can't happen */ + /* One might think we can never overflow the leftovers + array. Actually, that's true, as long as you don't + use poptStuffArgs()... */ + if ((con->numLeftovers + 1) >= (con->allocLeftovers)) { + con->allocLeftovers += 10; + con->leftovers = + realloc(con->leftovers, + sizeof(*con->leftovers) * con->allocLeftovers); + } + con->leftovers[con->numLeftovers++] + = xstrdup(origOptString); /* so a free of a stuffed + argv doesn't give us a + dangling pointer */ + } continue; } /* Make a copy we can hack at */ - { size_t bufsize = strlen(origOptString) + 1; - localOptString = optString = alloca(bufsize); - if (optString == NULL) /* XXX can't happen */ - return POPT_ERROR_BADOPT; - strlcpy(optString, origOptString, bufsize); - } + optString = origOptString; if (optString[0] == '\0') return POPT_ERROR_BADOPT; @@ -786,46 +1291,42 @@ int poptGetNextOpt(poptContext con) con->restLeftover = 1; continue; } else { - char *oe; - int singleDash; + const char *oe; + unsigned int argInfo = 0; optString++; if (*optString == '-') - singleDash = 0, optString++; + optString++; else - singleDash = 1; + argInfo |= POPT_ARGFLAG_ONEDASH; + + /* Check for "--long=arg" option. */ + for (oe = optString; *oe && *oe != '='; oe++) + {}; + optStringLen = (size_t)(oe - optString); + if (*oe == '=') + longArg = oe + 1; /* XXX aliases with arg substitution need "--alias=arg" */ - if (handleAlias(con, optString, '\0', NULL)) + if (handleAlias(con, optString, optStringLen, '\0', longArg)) { + longArg = NULL; continue; + } if (handleExec(con, optString, '\0')) continue; - /* Check for "--long=arg" option. */ - for (oe = optString; *oe && *oe != '='; oe++) - {}; - if (*oe == '=') { - *oe++ = '\0'; - /* XXX longArg is mapped back to persistent storage. */ - longArg = origOptString + (oe - localOptString); - } else - oe = NULL; - - opt = findOption(con->options, optString, '\0', &cb, &cbData, - singleDash); - if (!opt && !singleDash) + opt = findOption(con->options, optString, optStringLen, '\0', &cb, &cbData, + argInfo); + if (!opt && !LF_ISSET(ONEDASH)) return POPT_ERROR_BADOPT; - if (!opt && oe) - oe[-1] = '='; /* restore overwritten '=' */ } if (!opt) { con->os->nextCharArg = origOptString + 1; longArg = NULL; } else { - if (con->os == con->optionStack && - opt->argInfo & POPT_ARGFLAG_STRIP) + if (con->os == con->optionStack && F_ISSET(opt, STRIP)) { canstrip = 1; poptStripArg(con, thisopt); @@ -835,66 +1336,63 @@ int poptGetNextOpt(poptContext con) } /* Process next short option */ - /*@-branchstate@*/ /* FIX: W2DO? */ if (con->os->nextCharArg) { - origOptString = con->os->nextCharArg; + const char * nextCharArg = con->os->nextCharArg; con->os->nextCharArg = NULL; - if (handleAlias(con, NULL, *origOptString, origOptString + 1)) + if (handleAlias(con, NULL, 0, *nextCharArg, nextCharArg + 1)) continue; - if (handleExec(con, NULL, *origOptString)) { + if (handleExec(con, NULL, *nextCharArg)) { /* Restore rest of short options for further processing */ - origOptString++; - if (*origOptString != '\0') - con->os->nextCharArg = origOptString; + nextCharArg++; + if (*nextCharArg != '\0') + con->os->nextCharArg = nextCharArg; continue; } - opt = findOption(con->options, NULL, *origOptString, &cb, + opt = findOption(con->options, NULL, 0, *nextCharArg, &cb, &cbData, 0); if (!opt) return POPT_ERROR_BADOPT; shorty = 1; - origOptString++; - if (*origOptString != '\0') - con->os->nextCharArg = origOptString; + nextCharArg++; + if (*nextCharArg != '\0') + con->os->nextCharArg = nextCharArg; } - /*@=branchstate@*/ if (opt == NULL) return POPT_ERROR_BADOPT; /* XXX can't happen */ - if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE - || (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) { + if (poptArgType(opt) == POPT_ARG_NONE || poptArgType(opt) == POPT_ARG_VAL) { if (longArg || (con->os->nextCharArg && con->os->nextCharArg[0] == '=')) return POPT_ERROR_UNWANTEDARG; if (opt->arg) { - long val = (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL ? opt->val : 1; - if (poptSaveInt((int *)opt->arg, opt->argInfo, val)) + long val = poptArgType(opt) == POPT_ARG_VAL ? opt->val : 1; + unsigned int argInfo = poptArgInfo(con, opt); + if (poptSaveInt((int *)opt->arg, argInfo, val)) return POPT_ERROR_BADOPERATION; } } else { + int rc; + con->os->nextArg = _free(con->os->nextArg); - /*@-usedef@*/ /* FIX: W2DO? */ if (longArg) { - /*@=usedef@*/ longArg = expandNextArg(con, longArg); - con->os->nextArg = longArg; + con->os->nextArg = (char *) longArg; } else if (con->os->nextCharArg) { - longArg = expandNextArg(con, con->os->nextCharArg + (con->os->nextCharArg[0] == '=')); - con->os->nextArg = longArg; + longArg = expandNextArg(con, con->os->nextCharArg + (int)(*con->os->nextCharArg == '=')); + con->os->nextArg = (char *) longArg; con->os->nextCharArg = NULL; } else { while (con->os->next == con->os->argc && - con->os > con->optionStack) { + con->os > con->optionStack) + { cleanOSE(con->os--); } if (con->os->next == con->os->argc) { - if (!(opt->argInfo & POPT_ARGFLAG_OPTIONAL)) - /*@-compdef@*/ /* FIX: con->os->argv not defined */ + if (!F_ISSET(opt, OPTIONAL)) return POPT_ERROR_NOARG; - /*@=compdef@*/ con->os->nextArg = NULL; } else { @@ -902,98 +1400,35 @@ int poptGetNextOpt(poptContext con) * Make sure this isn't part of a short arg or the * result of an alias expansion. */ - if (con->os == con->optionStack && - (opt->argInfo & POPT_ARGFLAG_STRIP) && - canstrip) { + if (con->os == con->optionStack + && F_ISSET(opt, STRIP) && canstrip) + { poptStripArg(con, con->os->next); } if (con->os->argv != NULL) { /* XXX can't happen */ - /* XXX watchout: subtle side-effects live here. */ - longArg = con->os->argv[con->os->next++]; - longArg = expandNextArg(con, longArg); - con->os->nextArg = longArg; + if (F_ISSET(opt, OPTIONAL) && + con->os->argv[con->os->next][0] == '-') { + con->os->nextArg = NULL; + } else { + /* XXX watchout: subtle side-effects live here. */ + longArg = con->os->argv[con->os->next++]; + longArg = expandNextArg(con, longArg); + con->os->nextArg = (char *) longArg; + } } } } longArg = NULL; - if (opt->arg) { - switch (opt->argInfo & POPT_ARG_MASK) { - case POPT_ARG_STRING: - /* XXX memory leak, hard to plug */ - *((const char **) opt->arg) = (con->os->nextArg) - ? xstrdup(con->os->nextArg) : NULL; - /*@switchbreak@*/ break; - - case POPT_ARG_INT: - case POPT_ARG_LONG: - { long aLong = 0; - char *end; - - if (con->os->nextArg) { - aLong = strtol(con->os->nextArg, &end, 0); - if (!(end && *end == '\0')) - return POPT_ERROR_BADNUMBER; - } - - if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_LONG) { - if (aLong == LONG_MIN || aLong == LONG_MAX) - return POPT_ERROR_OVERFLOW; - if (poptSaveLong((long *)opt->arg, opt->argInfo, aLong)) - return POPT_ERROR_BADOPERATION; - } else { - if (aLong > INT_MAX || aLong < INT_MIN) - return POPT_ERROR_OVERFLOW; - if (poptSaveInt((int *)opt->arg, opt->argInfo, aLong)) - return POPT_ERROR_BADOPERATION; - } - } /*@switchbreak@*/ break; - - case POPT_ARG_FLOAT: - case POPT_ARG_DOUBLE: - { double aDouble = 0.0; - char *end; - - if (con->os->nextArg) { - /*@-mods@*/ - int saveerrno = errno; - errno = 0; - aDouble = strtod(con->os->nextArg, &end); - if (errno == ERANGE) - return POPT_ERROR_OVERFLOW; - errno = saveerrno; - /*@=mods@*/ - if (*end != '\0') - return POPT_ERROR_BADNUMBER; - } - - if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_DOUBLE) { - *((double *) opt->arg) = aDouble; - } else { -#define MY_ABS(a) ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a)) - if ((MY_ABS(aDouble) - FLT_MAX) > DBL_EPSILON) - return POPT_ERROR_OVERFLOW; - if ((FLT_MIN - MY_ABS(aDouble)) > DBL_EPSILON) - return POPT_ERROR_OVERFLOW; - *((float *) opt->arg) = aDouble; - } - } /*@switchbreak@*/ break; - default: - fprintf(stdout, - POPT_("option type (%d) not implemented in popt\n"), - (opt->argInfo & POPT_ARG_MASK)); - exit(EXIT_FAILURE); - /*@notreached@*/ /*@switchbreak@*/ break; - } - } + /* Save the option argument through a (*opt->arg) pointer. */ + if (opt->arg != NULL && (rc = poptSaveArg(con, opt)) != 0) + return rc; } - if (cb) { - /*@-internalglobs@*/ + if (cb) invokeCallbacksOPTION(con, con->options, opt, cbData, shorty); - /*@=internalglobs@*/ - } else if (opt->val && ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL)) + else if (opt->val && (poptArgType(opt) != POPT_ARG_VAL)) done = 1; if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) { @@ -1003,46 +1438,43 @@ int poptGetNextOpt(poptContext con) } if (con->finalArgv != NULL) - { ssize_t bufsize = (opt->longName ? strlen(opt->longName) : 0) + 3; - char *s = malloc(bufsize); + { char *s = malloc((opt->longName ? strlen(opt->longName) : 0) + sizeof("--")); if (s != NULL) { /* XXX can't happen */ - if (opt->longName) - snprintf(s, bufsize, "%s%s", - ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"), - opt->longName); - else - snprintf(s, bufsize, "-%c", opt->shortName); con->finalArgv[con->finalArgvCount++] = s; + *s++ = '-'; + if (opt->longName) { + if (!F_ISSET(opt, ONEDASH)) + *s++ = '-'; + s = stpcpy(s, opt->longName); + } else { + *s++ = opt->shortName; + *s = '\0'; + } } else con->finalArgv[con->finalArgvCount++] = NULL; } - if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) - /*@-ifempty@*/ ; /*@=ifempty@*/ - else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) - /*@-ifempty@*/ ; /*@=ifempty@*/ - else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) { - if (con->finalArgv != NULL && con->os->nextArg) + if (opt->arg && poptArgType(opt) == POPT_ARG_NONE) + ; + else if (poptArgType(opt) == POPT_ARG_VAL) + ; + else if (poptArgType(opt) != POPT_ARG_NONE) { + if (con->finalArgv != NULL && con->os->nextArg != NULL) con->finalArgv[con->finalArgvCount++] = - /*@-nullpass@*/ /* LCL: con->os->nextArg != NULL */ xstrdup(con->os->nextArg); - /*@=nullpass@*/ } } return (opt ? opt->val : -1); /* XXX can't happen */ } -/*@=boundswrite@*/ -const char * poptGetOptArg(poptContext con) +char * poptGetOptArg(poptContext con) { - const char * ret = NULL; - /*@-branchstate@*/ + char * ret = NULL; if (con) { ret = con->os->nextArg; con->os->nextArg = NULL; } - /*@=branchstate@*/ return ret; } @@ -1062,7 +1494,6 @@ const char * poptPeekArg(poptContext con) return ret; } -/*@-boundswrite@*/ const char ** poptGetArgs(poptContext con) { if (con == NULL || @@ -1072,46 +1503,44 @@ const char ** poptGetArgs(poptContext con) /* some apps like [like RPM ;-) ] need this NULL terminated */ con->leftovers[con->numLeftovers] = NULL; - /*@-nullret -nullstate @*/ /* FIX: typedef double indirection. */ return (con->leftovers + con->nextLeftover); - /*@=nullret =nullstate @*/ } -/*@=boundswrite@*/ + +static +poptItem poptFreeItems(poptItem items, int nitems) +{ + if (items != NULL) { + poptItem item = items; + while (--nitems >= 0) { + item->option.longName = _free(item->option.longName); + item->option.descrip = _free(item->option.descrip); + item->option.argDescrip = _free(item->option.argDescrip); + item->argv = _free(item->argv); + item++; + } + _free(items); + } + return NULL; +} poptContext poptFreeContext(poptContext con) { - poptItem item; int i; if (con == NULL) return con; poptResetContext(con); - con->os->argb = _free(con->os->argb); - if (con->aliases != NULL) - for (i = 0; i < con->numAliases; i++) { - item = con->aliases + i; - /*@-modobserver -observertrans -dependenttrans@*/ - item->option.longName = _free(item->option.longName); - item->option.descrip = _free(item->option.descrip); - item->option.argDescrip = _free(item->option.argDescrip); - /*@=modobserver =observertrans =dependenttrans@*/ - item->argv = _free(item->argv); - } - con->aliases = _free(con->aliases); + con->aliases = poptFreeItems(con->aliases, con->numAliases); + con->numAliases = 0; - if (con->execs != NULL) - for (i = 0; i < con->numExecs; i++) { - item = con->execs + i; - /*@-modobserver -observertrans -dependenttrans@*/ - item->option.longName = _free(item->option.longName); - item->option.descrip = _free(item->option.descrip); - item->option.argDescrip = _free(item->option.argDescrip); - /*@=modobserver =observertrans =dependenttrans@*/ - item->argv = _free(item->argv); - } - con->execs = _free(con->execs); + con->execs = poptFreeItems(con->execs, con->numExecs); + con->numExecs = 0; + for (i = 0; i < con->numLeftovers; i++) { + con->leftovers[i] = _free(con->leftovers[i]); + } con->leftovers = _free(con->leftovers); + con->finalArgv = _free(con->finalArgv); con->appName = _free(con->appName); con->otherHelp = _free(con->otherHelp); @@ -1123,9 +1552,10 @@ poptContext poptFreeContext(poptContext con) } int poptAddAlias(poptContext con, struct poptAlias alias, - /*@unused@*/ UNUSED(int flags)) + UNUSED(int flags)) { - poptItem item = (poptItem) alloca(sizeof(*item)); + struct poptItem_s item_buf; + poptItem item = &item_buf; memset(item, 0, sizeof(*item)); item->option.longName = alias.longName; item->option.shortName = alias.shortName; @@ -1139,11 +1569,9 @@ int poptAddAlias(poptContext con, struct poptAlias alias, return poptAddItem(con, item, 0); } -/*@-boundswrite@*/ -/*@-mustmod@*/ /* LCL: con not modified? */ int poptAddItem(poptContext con, poptItem newItem, int flags) { - poptItem * items, item; + poptItem * items, item_tmp, item; int * nitems; switch (flags) { @@ -1157,12 +1585,13 @@ int poptAddItem(poptContext con, poptItem newItem, int flags) break; default: return 1; - /*@notreached@*/ break; + break; } - *items = realloc((*items), ((*nitems) + 1) * sizeof(**items)); - if ((*items) == NULL) + item_tmp = realloc((*items), ((*nitems) + 1) * sizeof(**items)); + if (item_tmp == NULL) return 1; + *items = item_tmp; item = (*items) + (*nitems); @@ -1183,19 +1612,23 @@ int poptAddItem(poptContext con, poptItem newItem, int flags) return 0; } -/*@=mustmod@*/ -/*@=boundswrite@*/ -const char * poptBadOption(poptContext con, int flags) +const char * poptBadOption(poptContext con, unsigned int flags) { struct optionStackEntry * os = NULL; + const char *badOpt = NULL; + + if (con != NULL) { + /* Stupid hack to return something semi-meaningful from exec failure */ + if (con->execFail) { + badOpt = con->execFail; + } else { + os = (flags & POPT_BADOPTION_NOALIAS) ? con->optionStack : con->os; + badOpt = os->argv[os->next - 1]; + } + } - if (con != NULL) - os = (flags & POPT_BADOPTION_NOALIAS) ? con->optionStack : con->os; - - /*@-nullderef@*/ /* LCL: os->argv != NULL */ - return (os && os->argv ? os->argv[os->next - 1] : NULL); - /*@=nullderef@*/ + return badOpt; } const char * poptStrerror(const int error) @@ -1221,6 +1654,8 @@ const char * poptStrerror(const int error) return POPT_("number too large or too small"); case POPT_ERROR_MALLOC: return POPT_("memory allocation failed"); + case POPT_ERROR_BADCONFIG: + return POPT_("config file failed sanity test"); case POPT_ERROR_ERRNO: return strerror(errno); default: @@ -1256,14 +1691,12 @@ const char * poptGetInvocationName(poptContext con) return (con->os->argv ? con->os->argv[0] : ""); } -/*@-boundswrite@*/ int poptStrippedArgv(poptContext con, int argc, char ** argv) { int numargs = argc; int j = 1; int i; - /*@-sizeoftype@*/ if (con->arg_strip) for (i = 1; i < argc; i++) { if (PBM_ISSET(i, con->arg_strip)) @@ -1276,8 +1709,6 @@ int poptStrippedArgv(poptContext con, int argc, char ** argv) argv[j] = (j < numargs) ? argv[i] : NULL; j++; } - /*@=sizeoftype@*/ return numargs; } -/*@=boundswrite@*/ diff --git a/popt/popt.h b/popt/popt.h index 8d85f7312..bd1606110 100644 --- a/popt/popt.h +++ b/popt/popt.h @@ -1,5 +1,4 @@ -/** \file popt/popt.h - * \ingroup popt +/** @file */ /* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING @@ -13,45 +12,49 @@ #define POPT_OPTION_DEPTH 10 -/** \ingroup popt +/** * \name Arg type identifiers */ -/*@{*/ -#define POPT_ARG_NONE 0 /*!< no arg */ -#define POPT_ARG_STRING 1 /*!< arg will be saved as string */ -#define POPT_ARG_INT 2 /*!< arg will be converted to int */ -#define POPT_ARG_LONG 3 /*!< arg will be converted to long */ -#define POPT_ARG_INCLUDE_TABLE 4 /*!< arg points to table */ -#define POPT_ARG_CALLBACK 5 /*!< table-wide callback... must be +#define POPT_ARG_NONE 0U /*!< no arg */ +#define POPT_ARG_STRING 1U /*!< arg will be saved as string */ +#define POPT_ARG_INT 2U /*!< arg ==> int */ +#define POPT_ARG_LONG 3U /*!< arg ==> long */ +#define POPT_ARG_INCLUDE_TABLE 4U /*!< arg points to table */ +#define POPT_ARG_CALLBACK 5U /*!< table-wide callback... must be set first in table; arg points to callback, descrip points to callback data to pass */ -#define POPT_ARG_INTL_DOMAIN 6 /*!< set the translation domain +#define POPT_ARG_INTL_DOMAIN 6U /*!< set the translation domain for this table and any included tables; arg points to the domain string */ -#define POPT_ARG_VAL 7 /*!< arg should take value val */ -#define POPT_ARG_FLOAT 8 /*!< arg will be converted to float */ -#define POPT_ARG_DOUBLE 9 /*!< arg will be converted to double */ +#define POPT_ARG_VAL 7U /*!< arg should take value val */ +#define POPT_ARG_FLOAT 8U /*!< arg ==> float */ +#define POPT_ARG_DOUBLE 9U /*!< arg ==> double */ +#define POPT_ARG_LONGLONG 10U /*!< arg ==> long long */ + +#define POPT_ARG_MAINCALL (16U+11U) /*!< EXPERIMENTAL: return (*arg) (argc, argv) */ +#define POPT_ARG_ARGV 12U /*!< dupe'd arg appended to realloc'd argv array. */ +#define POPT_ARG_SHORT 13U /*!< arg ==> short */ +#define POPT_ARG_BITSET (16U+14U) /*!< arg ==> bit set */ -#define POPT_ARG_MASK 0x0000FFFF -/*@}*/ +#define POPT_ARG_MASK 0x000000FFU +#define POPT_GROUP_MASK 0x0000FF00U -/** \ingroup popt +/** * \name Arg modifiers */ -/*@{*/ -#define POPT_ARGFLAG_ONEDASH 0x80000000 /*!< allow -longoption */ -#define POPT_ARGFLAG_DOC_HIDDEN 0x40000000 /*!< don't show in help/usage */ -#define POPT_ARGFLAG_STRIP 0x20000000 /*!< strip this arg from argv(only applies to long args) */ -#define POPT_ARGFLAG_OPTIONAL 0x10000000 /*!< arg may be missing */ - -#define POPT_ARGFLAG_OR 0x08000000 /*!< arg will be or'ed */ -#define POPT_ARGFLAG_NOR 0x09000000 /*!< arg will be nor'ed */ -#define POPT_ARGFLAG_AND 0x04000000 /*!< arg will be and'ed */ -#define POPT_ARGFLAG_NAND 0x05000000 /*!< arg will be nand'ed */ -#define POPT_ARGFLAG_XOR 0x02000000 /*!< arg will be xor'ed */ -#define POPT_ARGFLAG_NOT 0x01000000 /*!< arg will be negated */ +#define POPT_ARGFLAG_ONEDASH 0x80000000U /*!< allow -longoption */ +#define POPT_ARGFLAG_DOC_HIDDEN 0x40000000U /*!< don't show in help/usage */ +#define POPT_ARGFLAG_STRIP 0x20000000U /*!< strip this arg from argv(only applies to long args) */ +#define POPT_ARGFLAG_OPTIONAL 0x10000000U /*!< arg may be missing */ + +#define POPT_ARGFLAG_OR 0x08000000U /*!< arg will be or'ed */ +#define POPT_ARGFLAG_NOR 0x09000000U /*!< arg will be nor'ed */ +#define POPT_ARGFLAG_AND 0x04000000U /*!< arg will be and'ed */ +#define POPT_ARGFLAG_NAND 0x05000000U /*!< arg will be nand'ed */ +#define POPT_ARGFLAG_XOR 0x02000000U /*!< arg will be xor'ed */ +#define POPT_ARGFLAG_NOT 0x01000000U /*!< arg will be negated */ #define POPT_ARGFLAG_LOGICALOPS \ (POPT_ARGFLAG_OR|POPT_ARGFLAG_AND|POPT_ARGFLAG_XOR) @@ -60,158 +63,126 @@ #define POPT_BIT_CLR (POPT_ARG_VAL|POPT_ARGFLAG_NAND) /*!< clear arg bit(s) */ -#define POPT_ARGFLAG_SHOW_DEFAULT 0x00800000 /*!< show default value in --help */ - -/*@}*/ +#define POPT_ARGFLAG_SHOW_DEFAULT 0x00800000U /*!< show default value in --help */ +#define POPT_ARGFLAG_RANDOM 0x00400000U /*!< random value in [1,arg] */ +#define POPT_ARGFLAG_TOGGLE 0x00200000U /*!< permit --[no]opt prefix toggle */ -/** \ingroup popt +/** * \name Callback modifiers */ -/*@{*/ -#define POPT_CBFLAG_PRE 0x80000000 /*!< call the callback before parse */ -#define POPT_CBFLAG_POST 0x40000000 /*!< call the callback after parse */ -#define POPT_CBFLAG_INC_DATA 0x20000000 /*!< use data from the include line, +#define POPT_CBFLAG_PRE 0x80000000U /*!< call the callback before parse */ +#define POPT_CBFLAG_POST 0x40000000U /*!< call the callback after parse */ +#define POPT_CBFLAG_INC_DATA 0x20000000U /*!< use data from the include line, not the subtable */ -#define POPT_CBFLAG_SKIPOPTION 0x10000000 /*!< don't callback with option */ -#define POPT_CBFLAG_CONTINUE 0x08000000 /*!< continue callbacks with option */ -/*@}*/ +#define POPT_CBFLAG_SKIPOPTION 0x10000000U /*!< don't callback with option */ +#define POPT_CBFLAG_CONTINUE 0x08000000U /*!< continue callbacks with option */ -/** \ingroup popt +/** * \name Error return values */ -/*@{*/ #define POPT_ERROR_NOARG -10 /*!< missing argument */ #define POPT_ERROR_BADOPT -11 /*!< unknown option */ #define POPT_ERROR_UNWANTEDARG -12 /*!< option does not take an argument */ #define POPT_ERROR_OPTSTOODEEP -13 /*!< aliases nested too deeply */ -#define POPT_ERROR_BADQUOTE -15 /*!< error in paramter quoting */ +#define POPT_ERROR_BADQUOTE -15 /*!< error in parameter quoting */ #define POPT_ERROR_ERRNO -16 /*!< errno set, use strerror(errno) */ #define POPT_ERROR_BADNUMBER -17 /*!< invalid numeric value */ #define POPT_ERROR_OVERFLOW -18 /*!< number too large or too small */ #define POPT_ERROR_BADOPERATION -19 /*!< mutually exclusive logical operations requested */ #define POPT_ERROR_NULLARG -20 /*!< opt->arg should not be NULL */ #define POPT_ERROR_MALLOC -21 /*!< memory allocation failed */ -/*@}*/ +#define POPT_ERROR_BADCONFIG -22 /*!< config file failed sanity test */ -/** \ingroup popt +/** * \name poptBadOption() flags */ -/*@{*/ -#define POPT_BADOPTION_NOALIAS (1 << 0) /*!< don't go into an alias */ -/*@}*/ +#define POPT_BADOPTION_NOALIAS (1U << 0) /*!< don't go into an alias */ -/** \ingroup popt +/** * \name poptGetContext() flags */ -/*@{*/ -#define POPT_CONTEXT_NO_EXEC (1 << 0) /*!< ignore exec expansions */ -#define POPT_CONTEXT_KEEP_FIRST (1 << 1) /*!< pay attention to argv[0] */ -#define POPT_CONTEXT_POSIXMEHARDER (1 << 2) /*!< options can't follow args */ -#define POPT_CONTEXT_ARG_OPTS (1 << 4) /*!< return args as options with value 0 */ -/*@}*/ +#define POPT_CONTEXT_NO_EXEC (1U << 0) /*!< ignore exec expansions */ +#define POPT_CONTEXT_KEEP_FIRST (1U << 1) /*!< pay attention to argv[0] */ +#define POPT_CONTEXT_POSIXMEHARDER (1U << 2) /*!< options can't follow args */ +#define POPT_CONTEXT_ARG_OPTS (1U << 4) /*!< return args as options with value 0 */ -/** \ingroup popt +/** */ struct poptOption { -/*@observer@*/ /*@null@*/ const char * longName; /*!< may be NULL */ - char shortName; /*!< may be NUL */ - int argInfo; -/*@shared@*/ /*@null@*/ + char shortName; /*!< may be '\0' */ + unsigned int argInfo; /*!< type of argument expected after the option */ void * arg; /*!< depends on argInfo */ - int val; /*!< 0 means don't return, just update flag */ -/*@observer@*/ /*@null@*/ + int val; /*!< 0 means don't return, just update arg */ const char * descrip; /*!< description for autohelp -- may be NULL */ -/*@observer@*/ /*@null@*/ - const char * argDescrip; /*!< argument description for autohelp */ + const char * argDescrip; /*!< argument description for autohelp -- may be NULL */ }; -/** \ingroup popt +/** * A popt alias argument for poptAddAlias(). */ struct poptAlias { -/*@owned@*/ /*@null@*/ const char * longName; /*!< may be NULL */ char shortName; /*!< may be NUL */ int argc; -/*@owned@*/ const char ** argv; /*!< must be free()able */ }; -/** \ingroup popt +/** * A popt alias or exec argument for poptAddItem(). */ -/*@-exporttype@*/ typedef struct poptItem_s { struct poptOption option; /*!< alias/exec name(s) and description. */ int argc; /*!< (alias) no. of args. */ -/*@owned@*/ const char ** argv; /*!< (alias) args, must be free()able. */ } * poptItem; -/*@=exporttype@*/ -/** \ingroup popt +/** * \name Auto-generated help/usage */ -/*@{*/ /** * Empty table marker to enable displaying popt alias/exec options. */ -/*@-exportvar@*/ -/*@unchecked@*/ /*@observer@*/ extern struct poptOption poptAliasOptions[]; -/*@=exportvar@*/ #define POPT_AUTOALIAS { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptAliasOptions, \ 0, "Options implemented via popt alias/exec:", NULL }, /** * Auto help table options. */ -/*@-exportvar@*/ -/*@unchecked@*/ /*@observer@*/ extern struct poptOption poptHelpOptions[]; -/*@=exportvar@*/ -/*@-exportvar@*/ -/*@unchecked@*/ /*@observer@*/ extern struct poptOption * poptHelpOptionsI18N; -/*@=exportvar@*/ #define POPT_AUTOHELP { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptHelpOptions, \ 0, "Help options:", NULL }, -#define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL } -/*@}*/ +#define POPT_TABLEEND { NULL, '\0', 0, NULL, 0, NULL, NULL } -/** \ingroup popt +/** */ -/*@-exporttype@*/ -typedef /*@abstract@*/ struct poptContext_s * poptContext; -/*@=exporttype@*/ +typedef struct poptContext_s * poptContext; -/** \ingroup popt +/** */ #ifndef __cplusplus -/*@-exporttype -typeuse@*/ typedef struct poptOption * poptOption; -/*@=exporttype =typeuse@*/ #endif -/*@-exportconst@*/ +/** + */ enum poptCallbackReason { POPT_CALLBACK_REASON_PRE = 0, POPT_CALLBACK_REASON_POST = 1, POPT_CALLBACK_REASON_OPTION = 2 }; -/*@=exportconst@*/ #ifdef __cplusplus extern "C" { #endif -/*@-type@*/ -/** \ingroup popt +/** * Table callback prototype. * @param con context * @param reason reason for callback @@ -221,13 +192,18 @@ extern "C" { */ typedef void (*poptCallbackType) (poptContext con, enum poptCallbackReason reason, - /*@null@*/ const struct poptOption * opt, - /*@null@*/ const char * arg, - /*@null@*/ const void * data) - /*@globals internalState @*/ - /*@modifies internalState @*/; + const struct poptOption * opt, + const char * arg, + const void * data); -/** \ingroup popt +/** + * Destroy context. + * @param con context + * @return NULL always + */ +poptContext poptFreeContext( poptContext con); + +/** * Initialize popt context. * @param name context name (usually argv[0] program name) * @param argc no. of arguments @@ -236,97 +212,90 @@ typedef void (*poptCallbackType) (poptContext con, * @param flags or'd POPT_CONTEXT_* bits * @return initialized popt context */ -/*@only@*/ /*@null@*/ poptContext poptGetContext( - /*@dependent@*/ /*@keep@*/ const char * name, - int argc, /*@dependent@*/ /*@keep@*/ const char ** argv, - /*@dependent@*/ /*@keep@*/ const struct poptOption * options, - int flags) - /*@*/; + const char * name, + int argc, const char ** argv, + const struct poptOption * options, + unsigned int flags); -/** \ingroup popt +/** + * Destroy context (alternative implementation). + * @param con context + * @return NULL always + */ +poptContext poptFini( poptContext con); + +/** + * Initialize popt context (alternative implementation). + * This routine does poptGetContext() and then poptReadConfigFiles(). + * @param argc no. of arguments + * @param argv argument array + * @param options address of popt option table + * @param configPaths colon separated file path(s) to read. + * @return initialized popt context (NULL on error). + */ +poptContext poptInit(int argc, const char ** argv, + const struct poptOption * options, + const char * configPaths); + +/** * Reinitialize popt context. * @param con context */ -/*@unused@*/ -void poptResetContext(/*@null@*/poptContext con) - /*@modifies con @*/; +void poptResetContext(poptContext con); -/** \ingroup popt +/** * Return value of next option found. * @param con context * @return next option val, -1 on last item, POPT_ERROR_* on error */ -int poptGetNextOpt(/*@null@*/poptContext con) - /*@globals fileSystem, internalState @*/ - /*@modifies con, fileSystem, internalState @*/; +int poptGetNextOpt(poptContext con); -/** \ingroup popt +/** * Return next option argument (if any). * @param con context * @return option argument, NULL if no argument is available */ -/*@observer@*/ /*@null@*/ /*@unused@*/ -const char * poptGetOptArg(/*@null@*/poptContext con) - /*@modifies con @*/; +char * poptGetOptArg(poptContext con); -/** \ingroup popt +/** * Return next argument. * @param con context * @return next argument, NULL if no argument is available */ -/*@observer@*/ /*@null@*/ /*@unused@*/ -const char * poptGetArg(/*@null@*/poptContext con) - /*@modifies con @*/; +const char * poptGetArg(poptContext con); -/** \ingroup popt +/** * Peek at current argument. * @param con context * @return current argument, NULL if no argument is available */ -/*@observer@*/ /*@null@*/ /*@unused@*/ -const char * poptPeekArg(/*@null@*/poptContext con) - /*@*/; +const char * poptPeekArg(poptContext con); -/** \ingroup popt +/** * Return remaining arguments. * @param con context * @return argument array, NULL terminated */ -/*@observer@*/ /*@null@*/ -const char ** poptGetArgs(/*@null@*/poptContext con) - /*@modifies con @*/; +const char ** poptGetArgs(poptContext con); -/** \ingroup popt +/** * Return the option which caused the most recent error. * @param con context * @param flags * @return offending option */ -/*@observer@*/ -const char * poptBadOption(/*@null@*/poptContext con, int flags) - /*@*/; - -/** \ingroup popt - * Destroy context. - * @param con context - * @return NULL always - */ -/*@null@*/ -poptContext poptFreeContext( /*@only@*/ /*@null@*/ poptContext con) - /*@modifies con @*/; +const char * poptBadOption(poptContext con, unsigned int flags); -/** \ingroup popt +/** * Add arguments to context. * @param con context * @param argv argument array, NULL terminated * @return 0 on success, POPT_ERROR_OPTSTOODEEP on failure */ -/*@unused@*/ -int poptStuffArgs(poptContext con, /*@keep@*/ const char ** argv) - /*@modifies con @*/; +int poptStuffArgs(poptContext con, const char ** argv); -/** \ingroup popt +/** * Add alias to context. * @todo Pass alias by reference, not value. * @deprecated Use poptAddItem instead. @@ -335,44 +304,64 @@ int poptStuffArgs(poptContext con, /*@keep@*/ const char ** argv) * @param flags (unused) * @return 0 on success */ -/*@unused@*/ -int poptAddAlias(poptContext con, struct poptAlias alias, int flags) - /*@modifies con @*/; +int poptAddAlias(poptContext con, struct poptAlias alias, int flags); -/** \ingroup popt +/** * Add alias/exec item to context. * @param con context * @param newItem alias/exec item to add * @param flags 0 for alias, 1 for exec * @return 0 on success */ -int poptAddItem(poptContext con, poptItem newItem, int flags) - /*@modifies con @*/; +int poptAddItem(poptContext con, poptItem newItem, int flags); -/** \ingroup popt +/** + * Test path/file for config file sanity (regular file, permissions etc) + * @param fn file name + * @return 1 on OK, 0 on NOTOK. + */ +int poptSaneFile(const char * fn); + +/** + * Read a file into a buffer. + * @param fn file name + * @retval *bp buffer (malloc'd) (or NULL) + * @retval *nbp no. of bytes in buffer (including final NUL) (or NULL) + * @param flags 1 to trim escaped newlines + * return 0 on success + */ +int poptReadFile(const char * fn, char ** bp, + size_t * nbp, int flags); +#define POPT_READFILE_TRIMNEWLINES 1 + +/** * Read configuration file. * @param con context * @param fn file name to read * @return 0 on success, POPT_ERROR_ERRNO on failure */ -int poptReadConfigFile(poptContext con, const char * fn) - /*@globals errno, fileSystem, internalState @*/ - /*@modifies con->execs, con->numExecs, - errno, fileSystem, internalState @*/; +int poptReadConfigFile(poptContext con, const char * fn); -/** \ingroup popt +/** + * Read configuration file(s). + * Colon separated files to read, looping over poptReadConfigFile(). + * Note that an '@' character preceding a path in the list will + * also perform additional sanity checks on the file before reading. + * @param con context + * @param paths colon separated file name(s) to read + * @return 0 on success, POPT_ERROR_BADCONFIG on failure + */ +int poptReadConfigFiles(poptContext con, const char * paths); + +/** * Read default configuration from /etc/popt and $HOME/.popt. * @param con context * @param useEnv (unused) * @return 0 on success, POPT_ERROR_ERRNO on failure */ -/*@unused@*/ -int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv) - /*@globals fileSystem, internalState @*/ - /*@modifies con->execs, con->numExecs, - fileSystem, internalState @*/; +int poptReadDefaultConfig(poptContext con, int useEnv); -/** \ingroup popt +/** * Duplicate an argument array. * @note: The argument array is malloc'd as a single area, so only argv must * be free'd. @@ -383,12 +372,11 @@ int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv) * @retval argvPtr address of returned argument array * @return 0 on success, POPT_ERROR_NOARG on failure */ -int poptDupArgv(int argc, /*@null@*/ const char **argv, - /*@null@*/ /*@out@*/ int * argcPtr, - /*@null@*/ /*@out@*/ const char *** argvPtr) - /*@modifies *argcPtr, *argvPtr @*/; +int poptDupArgv(int argc, const char **argv, + int * argcPtr, + const char *** argvPtr); -/** \ingroup popt +/** * Parse a string into an argument array. * The parse allows ', ", and \ quoting, but ' is treated the same as " and * both may include \ quotes. @@ -400,10 +388,9 @@ int poptDupArgv(int argc, /*@null@*/ const char **argv, * @retval argvPtr address of returned argument array */ int poptParseArgvString(const char * s, - /*@out@*/ int * argcPtr, /*@out@*/ const char *** argvPtr) - /*@modifies *argcPtr, *argvPtr @*/; + int * argcPtr, const char *** argvPtr); -/** \ingroup popt +/** * Parses an input configuration file and returns an string that is a * command line. For use with popt. You must free the return value when done. * @@ -418,8 +405,8 @@ bla=bla this_is = fdsafdas bad_line= - reall bad line - reall bad line = again + really bad line + really bad line = again 5555= 55555 test = with lots of spaces \endverbatim @@ -449,83 +436,82 @@ this_is = fdsafdas * @return 0 on success * @see poptParseArgvString */ -/*@-fcnuse@*/ -int poptConfigFileToString(FILE *fp, /*@out@*/ char ** argstrp, int flags) - /*@globals fileSystem @*/ - /*@modifies *fp, *argstrp, fileSystem @*/; -/*@=fcnuse@*/ +int poptConfigFileToString(FILE *fp, char ** argstrp, int flags); -/** \ingroup popt +/** * Return formatted error string for popt failure. * @param error popt error * @return error string */ -/*@observer@*/ -const char * poptStrerror(const int error) - /*@*/; +const char * poptStrerror(const int error); -/** \ingroup popt +/** * Limit search for executables. * @param con context * @param path single path to search for executables * @param allowAbsolute absolute paths only? */ -/*@unused@*/ -void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) - /*@modifies con @*/; +void poptSetExecPath(poptContext con, const char * path, int allowAbsolute); -/** \ingroup popt +/** * Print detailed description of options. * @param con context - * @param fp ouput file handle + * @param fp output file handle * @param flags (unused) */ -void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags) - /*@globals fileSystem @*/ - /*@modifies *fp, fileSystem @*/; +void poptPrintHelp(poptContext con, FILE * fp, int flags); -/** \ingroup popt +/** * Print terse description of options. * @param con context - * @param fp ouput file handle + * @param fp output file handle * @param flags (unused) */ -void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags) - /*@globals fileSystem @*/ - /*@modifies *fp, fileSystem @*/; +void poptPrintUsage(poptContext con, FILE * fp, int flags); -/** \ingroup popt +/** * Provide text to replace default "[OPTION...]" in help/usage output. * @param con context * @param text replacement text */ -/*@-fcnuse@*/ -void poptSetOtherOptionHelp(poptContext con, const char * text) - /*@modifies con @*/; -/*@=fcnuse@*/ +void poptSetOtherOptionHelp(poptContext con, const char * text); -/** \ingroup popt +/** * Return argv[0] from context. * @param con context * @return argv[0] */ -/*@-fcnuse@*/ -/*@observer@*/ -const char * poptGetInvocationName(poptContext con) - /*@*/; -/*@=fcnuse@*/ +const char * poptGetInvocationName(poptContext con); -/** \ingroup popt +/** * Shuffle argv pointers to remove stripped args, returns new argc. * @param con context * @param argc no. of args * @param argv arg vector * @return new argc */ -/*@-fcnuse@*/ -int poptStrippedArgv(poptContext con, int argc, char ** argv) - /*@modifies *argv @*/; -/*@=fcnuse@*/ +int poptStrippedArgv(poptContext con, int argc, char ** argv); + +/** + * Add a string to an argv array. + * @retval *argvp argv array + * @param argInfo (unused) + * @param val string arg to add (using strdup) + * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION + */ +int poptSaveString(const char *** argvp, unsigned int argInfo, + const char * val); + +/** + * Save a long long, performing logical operation with value. + * @warning Alignment check may be too strict on certain platorms. + * @param arg integer pointer, aligned on int boundary. + * @param argInfo logical operation (see POPT_ARGFLAG_*) + * @param aLongLong value to use + * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION + */ +int poptSaveLongLong(long long * arg, unsigned int argInfo, + long long aLongLong); /** * Save a long, performing logical operation with value. @@ -535,12 +521,17 @@ int poptStrippedArgv(poptContext con, int argc, char ** argv) * @param aLong value to use * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION */ -/*@-incondefs@*/ -/*@unused@*/ -int poptSaveLong(/*@null@*/ long * arg, int argInfo, long aLong) - /*@modifies *arg @*/ - /*@requires maxSet(arg) >= 0 /\ maxRead(arg) == 0 @*/; -/*@=incondefs@*/ +int poptSaveLong(long * arg, unsigned int argInfo, long aLong); + +/** + * Save a short integer, performing logical operation with value. + * @warning Alignment check may be too strict on certain platorms. + * @param arg short pointer, aligned on short boundary. + * @param argInfo logical operation (see POPT_ARGFLAG_*) + * @param aLong value to use + * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION + */ +int poptSaveShort(short * arg, unsigned int argInfo, long aLong); /** * Save an integer, performing logical operation with value. @@ -550,14 +541,40 @@ int poptSaveLong(/*@null@*/ long * arg, int argInfo, long aLong) * @param aLong value to use * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION */ -/*@-incondefs@*/ -/*@unused@*/ -int poptSaveInt(/*@null@*/ int * arg, int argInfo, long aLong) - /*@modifies *arg @*/ - /*@requires maxSet(arg) >= 0 /\ maxRead(arg) == 0 @*/; -/*@=incondefs@*/ +int poptSaveInt(int * arg, unsigned int argInfo, long aLong); + +/* The bit set typedef. */ +typedef struct poptBits_s { + unsigned int bits[1]; +} * poptBits; + +#define _POPT_BITS_N 1024U /*!< estimated population */ +#define _POPT_BITS_M ((3U * _POPT_BITS_N) / 2U) +#define _POPT_BITS_K 16U /*!< no. of linear hash combinations */ + +extern unsigned int _poptBitsN; +extern unsigned int _poptBitsM; +extern unsigned int _poptBitsK; + +int poptBitsAdd(poptBits bits, const char * s); +int poptBitsChk(poptBits bits, const char * s); +int poptBitsClr(poptBits bits); +int poptBitsDel(poptBits bits, const char * s); +int poptBitsIntersect(poptBits * ap, const poptBits b); +int poptBitsUnion(poptBits * ap, const poptBits b); +int poptBitsArgs(poptContext con, poptBits * ap); + +/** + * Save a string into a bit set (experimental). + * @retval *bits bit set (lazily malloc'd if NULL) + * @param argInfo logical operation (see POPT_ARGFLAG_*) + * @param s string to add to bit set + * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION + */ +int poptSaveBits(poptBits * bitsp, unsigned int argInfo, + const char * s); + -/*@=type@*/ #ifdef __cplusplus } #endif diff --git a/popt/poptconfig.c b/popt/poptconfig.c index 9733d1529..bf201e26f 100644 --- a/popt/poptconfig.c +++ b/popt/poptconfig.c @@ -1,5 +1,5 @@ /** \ingroup popt - * \file popt/poptconfig.c + * @file */ /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING @@ -8,54 +8,300 @@ #include "system.h" #include "poptint.h" -/*@access poptContext @*/ +#include +#include +#include +#include -/*@-compmempass@*/ /* FIX: item->option.longName kept, not dependent. */ -static void configLine(poptContext con, char * line) - /*@modifies con @*/ +#if defined(HAVE_FNMATCH_H) +#include + +#endif + +#if defined(HAVE_GLOB_H) +#include + +#if !defined(HAVE_GLOB_PATTERN_P) +/* Return nonzero if PATTERN contains any metacharacters. + Metacharacters can be quoted with backslashes if QUOTE is nonzero. */ +static int +glob_pattern_p (const char * pattern, int quote) +{ + const char * p; + int open = 0; + + for (p = pattern; *p != '\0'; ++p) + switch (*p) { + case '?': + case '*': + return 1; + break; + case '\\': + if (quote && p[1] != '\0') + ++p; + break; + case '[': + open = 1; + break; + case ']': + if (open) + return 1; + break; + } + return 0; +} +#endif /* !defined(__GLIBC__) */ + +static int poptGlobFlags = 0; + +static int poptGlob_error(UNUSED(const char * epath), + UNUSED(int eerrno)) +{ + return 1; +} +#endif /* HAVE_GLOB_H */ + +/** + * Return path(s) from a glob pattern. + * @param con context + * @param pattern glob pattern + * @retval *acp no. of paths + * @retval *avp array of paths + * @return 0 on success + */ +static int poptGlob(UNUSED(poptContext con), const char * pattern, + int * acp, const char *** avp) +{ + const char * pat = pattern; + int rc = 0; /* assume success */ + +#if defined(HAVE_GLOB_H) + if (glob_pattern_p(pat, 0)) { + glob_t _g, *pglob = &_g; + + if (!(rc = glob(pat, poptGlobFlags, poptGlob_error, pglob))) { + if (acp) { + *acp = (int) pglob->gl_pathc; + pglob->gl_pathc = 0; + } + if (avp) { + *avp = (const char **) pglob->gl_pathv; + pglob->gl_pathv = NULL; + } + globfree(pglob); + } else if (rc == GLOB_NOMATCH) { + *avp = NULL; + *acp = 0; + rc = 0; + } else + rc = POPT_ERROR_ERRNO; + } else +#endif /* HAVE_GLOB_H */ + { + if (acp) + *acp = 1; + if (avp && (*avp = calloc((size_t)(1 + 1), sizeof (**avp))) != NULL) + (*avp)[0] = xstrdup(pat); + } + + return rc; +} + + +int poptSaneFile(const char * fn) +{ + struct stat sb; + + if (fn == NULL || strstr(fn, ".rpmnew") || strstr(fn, ".rpmsave")) + return 0; + if (stat(fn, &sb) == -1) + return 0; + if (!S_ISREG(sb.st_mode)) + return 0; + if (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) + return 0; + return 1; +} + +int poptReadFile(const char * fn, char ** bp, size_t * nbp, int flags) +{ + int fdno; + char * b = NULL; + off_t nb = 0; + char * s, * t, * se; + int rc = POPT_ERROR_ERRNO; /* assume failure */ + + fdno = open(fn, O_RDONLY); + if (fdno < 0) + goto exit; + + if ((nb = lseek(fdno, 0, SEEK_END)) == (off_t)-1 + || (uintmax_t)nb >= SIZE_MAX + || lseek(fdno, 0, SEEK_SET) == (off_t)-1 + || (b = calloc(sizeof(*b), (size_t)nb + 1)) == NULL + || read(fdno, (char *)b, (size_t)nb) != (ssize_t)nb) + { + int oerrno = errno; + (void) close(fdno); + if (nb != (off_t)-1 && (uintmax_t)nb >= SIZE_MAX) + errno = -EOVERFLOW; + else + errno = oerrno; + goto exit; + } + if (close(fdno) == -1) + goto exit; + if (b == NULL) { + rc = POPT_ERROR_MALLOC; + goto exit; + } + rc = 0; + + /* Trim out escaped newlines. */ + if (flags & POPT_READFILE_TRIMNEWLINES) + { + for (t = b, s = b, se = b + nb; *s && s < se; s++) { + switch (*s) { + case '\\': + if (s[1] == '\n') { + s++; + continue; + } + /* fallthrough */ + default: + *t++ = *s; + break; + } + } + *t++ = '\0'; + nb = (off_t)(t - b); + } + +exit: + if (rc != 0) { + if (b) + free(b); + b = NULL; + nb = 0; + } + if (bp) + *bp = b; + else if (b) + free(b); + if (nbp) + *nbp = (size_t)nb; + return rc; +} + +/** + * Check for application match. + * @param con context + * @param s config application name + * return 0 if config application matches + */ +static int configAppMatch(poptContext con, const char * s) { - size_t nameLength; + int rc = 1; + + if (con->appName == NULL) /* XXX can't happen. */ + return rc; + +#if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H) + if (glob_pattern_p(s, 1)) { + static int flags = FNM_PATHNAME | FNM_PERIOD; +#ifdef FNM_EXTMATCH + flags |= FNM_EXTMATCH; +#endif + rc = fnmatch(s, con->appName, flags); + } else +#endif + rc = strcmp(s, con->appName); + return rc; +} + +static int poptConfigLine(poptContext con, char * line) +{ + char *b = NULL; + size_t nb = 0; + char * se = line; + const char * appName; const char * entryType; const char * opt; - poptItem item = (poptItem) alloca(sizeof(*item)); + struct poptItem_s item_buf; + poptItem item = &item_buf; int i, j; + int rc = POPT_ERROR_BADCONFIG; if (con->appName == NULL) - return; - nameLength = strlen(con->appName); + goto exit; -/*@-boundswrite@*/ memset(item, 0, sizeof(*item)); - if (strncmp(line, con->appName, nameLength)) return; + appName = se; + while (*se != '\0' && !_isspaceptr(se)) se++; + if (*se == '\0') + goto exit; + else + *se++ = '\0'; - line += nameLength; - if (*line == '\0' || !isSpace(line)) return; + if (configAppMatch(con, appName)) goto exit; - while (*line != '\0' && isSpace(line)) line++; - entryType = line; - while (*line == '\0' || !isSpace(line)) line++; - *line++ = '\0'; + while (*se != '\0' && _isspaceptr(se)) se++; + entryType = se; + while (*se != '\0' && !_isspaceptr(se)) se++; + if (*se != '\0') *se++ = '\0'; - while (*line != '\0' && isSpace(line)) line++; - if (*line == '\0') return; - opt = line; - while (*line == '\0' || !isSpace(line)) line++; - *line++ = '\0'; + while (*se != '\0' && _isspaceptr(se)) se++; + if (*se == '\0') goto exit; + opt = se; + while (*se != '\0' && !_isspaceptr(se)) se++; + if (opt[0] == '-' && *se == '\0') goto exit; + if (*se != '\0') *se++ = '\0'; - while (*line != '\0' && isSpace(line)) line++; - if (*line == '\0') return; + while (*se != '\0' && _isspaceptr(se)) se++; + if (opt[0] == '-' && *se == '\0') goto exit; - /*@-temptrans@*/ /* FIX: line alias is saved */ if (opt[0] == '-' && opt[1] == '-') item->option.longName = opt + 2; else if (opt[0] == '-' && opt[2] == '\0') item->option.shortName = opt[1]; - /*@=temptrans@*/ + else { + const char * fn = opt; + + /* XXX handle globs and directories in fn? */ + if ((rc = poptReadFile(fn, &b, &nb, POPT_READFILE_TRIMNEWLINES)) != 0) + goto exit; + if (b == NULL || nb == 0) + goto exit; + + /* Append remaining text to the interpolated file option text. */ + if (*se != '\0') { + size_t nse = strlen(se) + 1; + if ((b = realloc(b, (nb + nse))) == NULL) /* XXX can't happen */ + goto exit; + (void) stpcpy( stpcpy(&b[nb-1], " "), se); + nb += nse; + } + se = b; + + /* Use the basename of the path as the long option name. */ + { const char * longName = strrchr(fn, '/'); + if (longName != NULL) + longName++; + else + longName = fn; + if (longName == NULL) /* XXX can't happen. */ + goto exit; + /* Single character basenames are treated as short options. */ + if (longName[1] != '\0') + item->option.longName = longName; + else + item->option.shortName = longName[0]; + } + } - if (poptParseArgvString(line, &item->argc, &item->argv)) return; + if (poptParseArgvString(se, &item->argc, &item->argv)) goto exit; - /*@-modobserver@*/ item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN; for (i = 0, j = 0; i < item->argc; i++, j++) { const char * f; @@ -81,103 +327,183 @@ static void configLine(poptContext con, char * line) item->argv[j] = NULL; item->argc = j; } - /*@=modobserver@*/ -/*@=boundswrite@*/ - /*@-nullstate@*/ /* FIX: item->argv[] may be NULL */ if (!strcmp(entryType, "alias")) - (void) poptAddItem(con, item, 0); + rc = poptAddItem(con, item, 0); else if (!strcmp(entryType, "exec")) - (void) poptAddItem(con, item, 1); - /*@=nullstate@*/ + rc = poptAddItem(con, item, 1); +exit: + rc = 0; /* XXX for now, always return success */ + if (b) + free(b); + return rc; } -/*@=compmempass@*/ int poptReadConfigFile(poptContext con, const char * fn) { - const char * file, * chptr, * end; - char * buf; -/*@dependent@*/ char * dst; - int fd, rc; - off_t fileLength; - - fd = open(fn, O_RDONLY); - if (fd < 0) - return (errno == ENOENT ? 0 : POPT_ERROR_ERRNO); - - fileLength = lseek(fd, 0, SEEK_END); - if (fileLength == -1 || lseek(fd, 0, 0) == -1) { - rc = errno; - (void) close(fd); - errno = rc; - return POPT_ERROR_ERRNO; - } + char * b = NULL, *be; + size_t nb = 0; + const char *se; + char *t = NULL, *te; + int rc; - file = alloca(fileLength + 1); - if (read(fd, (char *)file, fileLength) != fileLength) { - rc = errno; - (void) close(fd); - errno = rc; - return POPT_ERROR_ERRNO; + if ((rc = poptReadFile(fn, &b, &nb, POPT_READFILE_TRIMNEWLINES)) != 0) + return (errno == ENOENT ? 0 : rc); + if (b == NULL || nb == 0) { + rc = POPT_ERROR_BADCONFIG; + goto exit; } - if (close(fd) == -1) - return POPT_ERROR_ERRNO; -/*@-boundswrite@*/ - dst = buf = alloca(fileLength + 1); + if ((t = malloc(nb + 1)) == NULL) + goto exit; + te = t; - chptr = file; - end = (file + fileLength); - /*@-infloops@*/ /* LCL: can't detect chptr++ */ - while (chptr < end) { - switch (*chptr) { + be = (b + nb); + for (se = b; se < be; se++) { + switch (*se) { case '\n': - *dst = '\0'; - dst = buf; - while (*dst && isSpace(dst)) dst++; - if (*dst && *dst != '#') - configLine(con, dst); - chptr++; - /*@switchbreak@*/ break; + *te = '\0'; + te = t; + while (*te && _isspaceptr(te)) te++; + if (*te && *te != '#') + if ((rc = poptConfigLine(con, te)) != 0) + goto exit; + break; case '\\': - *dst++ = *chptr++; - if (chptr < end) { - if (*chptr == '\n') - dst--, chptr++; - /* \ at the end of a line does not insert a \n */ - else - *dst++ = *chptr++; + *te = *se++; + /* \ at the end of a line does not insert a \n */ + if (se < be && *se != '\n') { + te++; + *te++ = *se; } - /*@switchbreak@*/ break; + break; default: - *dst++ = *chptr++; - /*@switchbreak@*/ break; + *te++ = *se; + break; } } - /*@=infloops@*/ -/*@=boundswrite@*/ + rc = 0; - return 0; +exit: + free(t); + if (b) + free(b); + return rc; } -int poptReadDefaultConfig(poptContext con, /*@unused@*/ UNUSED(int useEnv)) +int poptReadConfigFiles(poptContext con, const char * paths) { - char * fn, * home; - int rc; + char * buf = (paths ? xstrdup(paths) : NULL); + const char * p; + char * pe; + int rc = 0; /* assume success */ + + for (p = buf; p != NULL && *p != '\0'; p = pe) { + const char ** av = NULL; + int ac = 0; + int i; + int xx; + + /* locate start of next path element */ + pe = strchr(p, ':'); + if (pe != NULL && *pe == ':') + *pe++ = '\0'; + else + pe = (char *) (p + strlen(p)); + + xx = poptGlob(con, p, &ac, &av); + + /* work-off each resulting file from the path element */ + for (i = 0; i < ac; i++) { + const char * fn = av[i]; + if (!poptSaneFile(fn)) + continue; + xx = poptReadConfigFile(con, fn); + if (xx && rc == 0) + rc = xx; + free((void *)av[i]); + av[i] = NULL; + } + free(av); + av = NULL; + } - if (con->appName == NULL) return 0; + if (buf) + free(buf); - rc = poptReadConfigFile(con, "/etc/popt"); - if (rc) return rc; + return rc; +} + +int poptReadDefaultConfig(poptContext con, UNUSED(int useEnv)) +{ + char * home; + struct stat sb; + int rc = 0; /* assume success */ + + if (con->appName == NULL) goto exit; + + rc = poptReadConfigFile(con, POPT_SYSCONFDIR "/popt"); + if (rc) goto exit; + +#if defined(HAVE_GLOB_H) + if (!stat(POPT_SYSCONFDIR "/popt.d", &sb) && S_ISDIR(sb.st_mode)) { + const char ** av = NULL; + int ac = 0; + int i; + + if ((rc = poptGlob(con, POPT_SYSCONFDIR "/popt.d/*", &ac, &av)) == 0) { + for (i = 0; rc == 0 && i < ac; i++) { + const char * fn = av[i]; + if (!poptSaneFile(fn)) + continue; + rc = poptReadConfigFile(con, fn); + free((void *)av[i]); + av[i] = NULL; + } + free(av); + av = NULL; + } + } + if (rc) goto exit; +#endif if ((home = getenv("HOME"))) { - size_t bufsize = strlen(home) + 20; - fn = alloca(bufsize); - if (fn == NULL) return 0; - snprintf(fn, bufsize, "%s/.popt", home); - rc = poptReadConfigFile(con, fn); - if (rc) return rc; + char * fn = malloc(strlen(home) + 20); + if (fn != NULL) { + (void) stpcpy(stpcpy(fn, home), "/.popt"); + rc = poptReadConfigFile(con, fn); + free(fn); + } else + rc = POPT_ERROR_ERRNO; + if (rc) goto exit; } - return 0; +exit: + return rc; +} + +poptContext +poptFini(poptContext con) +{ + return poptFreeContext(con); +} + +poptContext +poptInit(int argc, const char ** argv, + const struct poptOption * options, const char * configPaths) +{ + poptContext con = NULL; + const char * argv0; + + if (argv == NULL || argv[0] == NULL || options == NULL) + return con; + + if ((argv0 = strrchr(argv[0], '/')) != NULL) argv0++; + else argv0 = argv[0]; + + con = poptGetContext(argv0, argc, (const char **)argv, options, 0); + if (con != NULL&& poptReadConfigFiles(con, configPaths)) + con = poptFini(con); + + return con; } diff --git a/popt/popthelp.c b/popt/popthelp.c index 6a009766d..6738f6add 100644 --- a/popt/popthelp.c +++ b/popt/popthelp.c @@ -1,7 +1,7 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /** \ingroup popt - * \file popt/popthelp.c + * @file */ /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING @@ -10,14 +10,16 @@ #include "system.h" -/*#define POPT_WCHAR_HACK*/ -#ifdef POPT_WCHAR_HACK +#define POPT_USE_TIOCGWINSZ +#ifdef POPT_USE_TIOCGWINSZ +#include +#endif + +#ifdef HAVE_MBSRTOWCS #include /* for mbsrtowcs */ -/*@access mbstate_t @*/ #endif #include "poptint.h" -/*@access poptContext@*/ /** * Display arguments. @@ -27,29 +29,29 @@ * @param arg (unused) * @param data (unused) */ +NORETURN static void displayArgs(poptContext con, - /*@unused@*/ UNUSED(enum poptCallbackReason foo), + UNUSED(enum poptCallbackReason foo), struct poptOption * key, - /*@unused@*/ UNUSED(const char * arg), /*@unused@*/ UNUSED(void * data)) - /*@globals fileSystem@*/ - /*@modifies fileSystem@*/ + UNUSED(const char * arg), + UNUSED(void * data)) { if (key->shortName == '?') poptPrintHelp(con, stdout, 0); else poptPrintUsage(con, stdout, 0); + + poptFreeContext(con); exit(0); } #ifdef NOTYET -/*@unchecked@*/ static int show_option_defaults = 0; #endif /** * Empty table marker to enable displaying popt alias/exec options. */ -/*@observer@*/ /*@unchecked@*/ struct poptOption poptAliasOptions[] = { POPT_TABLEEND }; @@ -57,45 +59,88 @@ struct poptOption poptAliasOptions[] = { /** * Auto help table options. */ -/*@-castfcnptr@*/ -/*@observer@*/ /*@unchecked@*/ struct poptOption poptHelpOptions[] = { - { NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL }, - { "help", '?', 0, NULL, '?', N_("Show this help message"), NULL }, - { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL }, + { NULL, '\0', POPT_ARG_CALLBACK, (void *)displayArgs, 0, NULL, NULL }, + { "help", '?', 0, NULL, (int)'?', N_("Show this help message"), NULL }, + { "usage", '\0', 0, NULL, (int)'u', N_("Display brief usage message"), NULL }, POPT_TABLEEND } ; -/*@observer@*/ /*@unchecked@*/ static struct poptOption poptHelpOptions2[] = { -/*@-readonlytrans@*/ - { NULL, '\0', POPT_ARG_INTL_DOMAIN, PACKAGE, 0, NULL, NULL}, -/*@=readonlytrans@*/ - { NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL }, - { "help", '?', 0, NULL, '?', N_("Show this help message"), NULL }, - { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL }, + { NULL, '\0', POPT_ARG_INTL_DOMAIN, (void *)PACKAGE, 0, NULL, NULL}, + { NULL, '\0', POPT_ARG_CALLBACK, (void *)displayArgs, 0, NULL, NULL }, + { "help", '?', 0, NULL, (int)'?', N_("Show this help message"), NULL }, + { "usage", '\0', 0, NULL, (int)'u', N_("Display brief usage message"), NULL }, #ifdef NOTYET { "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0, N_("Display option defaults in message"), NULL }, #endif + { NULL, '\0', 0, NULL, 0, N_("Terminate options"), NULL }, POPT_TABLEEND } ; -/*@observer@*/ /*@unchecked@*/ struct poptOption * poptHelpOptionsI18N = poptHelpOptions2; -/*@=castfcnptr@*/ + +#define _POPTHELP_MAXLINE ((size_t)79) + +typedef struct columns_s { + size_t cur; + size_t max; +} * columns_t; + +/** + * Return no. of columns in output window. + * @param fp FILE + * @return no. of columns + */ +static size_t maxColumnWidth(FILE *fp) +{ + size_t maxcols = _POPTHELP_MAXLINE; +#if defined(TIOCGWINSZ) + struct winsize ws; + int fdno = fileno(fp ? fp : stdout); + + memset(&ws, 0, sizeof(ws)); + if (fdno >= 0 && !ioctl(fdno, (unsigned long)TIOCGWINSZ, &ws)) { + size_t ws_col = (size_t)ws.ws_col; + if (ws_col > maxcols && ws_col < (size_t)256) + maxcols = ws_col - 1; + } +#endif + return maxcols; +} /** - * @param table option(s) + * Determine number of display characters in a string. + * @param s string + * @return no. of display characters. */ -/*@observer@*/ /*@null@*/ static const char * -getTableTranslationDomain(/*@null@*/ const struct poptOption *table) - /*@*/ +static inline size_t stringDisplayWidth(const char *s) { - const struct poptOption *opt; + size_t n = strlen(s); +#ifdef HAVE_MBSRTOWCS + mbstate_t t; - if (table != NULL) - for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) { + memset ((void *)&t, 0, sizeof (t)); /* In initial state. */ + /* Determine number of display characters. */ + n = mbsrtowcs (NULL, &s, n, &t); +#else + n = 0; + for (; *s; s = POPT_next_char(s)) + n++; +#endif + + return n; +} + +/** + * @param opt option(s) + */ +static const char * +getTableTranslationDomain(const struct poptOption *opt) +{ + if (opt != NULL) + for (; opt->longName || opt->shortName || opt->arg; opt++) { if (opt->argInfo == POPT_ARG_INTL_DOMAIN) return opt->arg; } @@ -106,32 +151,46 @@ getTableTranslationDomain(/*@null@*/ const struct poptOption *table) * @param opt option(s) * @param translation_domain translation domain */ -/*@observer@*/ /*@null@*/ static const char * +static const char * getArgDescrip(const struct poptOption * opt, - /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */ - /*@null@*/ UNUSED(const char * translation_domain)) - /*@=paramuse@*/ - /*@*/ + /* FIX: i18n macros disabled with lclint */ + const char * translation_domain) { - if (!(opt->argInfo & POPT_ARG_MASK)) return NULL; - - if (opt == (poptHelpOptions + 1) || opt == (poptHelpOptions + 2)) - if (opt->argDescrip) return POPT_(opt->argDescrip); - - if (opt->argDescrip) return D_(translation_domain, opt->argDescrip); + if (!poptArgType(opt)) return NULL; + + if (poptArgType(opt) == POPT_ARG_MAINCALL) + return opt->argDescrip; + if (poptArgType(opt) == POPT_ARG_ARGV) + return opt->argDescrip; + + if (opt->argDescrip) { + /* Some strings need popt library, not application, i18n domain. */ + if (opt == (poptHelpOptions + 1) + || opt == (poptHelpOptions + 2) + || !strcmp(opt->argDescrip, N_("Help options:")) + || !strcmp(opt->argDescrip, N_("Options implemented via popt alias/exec:"))) + return POPT_(opt->argDescrip); + + /* Use the application i18n domain. */ + return D_(translation_domain, opt->argDescrip); + } - switch (opt->argInfo & POPT_ARG_MASK) { - /*case POPT_ARG_NONE: return POPT_("NONE");*/ /* impossible */ + switch (poptArgType(opt)) { + case POPT_ARG_NONE: return POPT_("NONE"); #ifdef DYING case POPT_ARG_VAL: return POPT_("VAL"); #else case POPT_ARG_VAL: return NULL; #endif case POPT_ARG_INT: return POPT_("INT"); + case POPT_ARG_SHORT: return POPT_("SHORT"); case POPT_ARG_LONG: return POPT_("LONG"); + case POPT_ARG_LONGLONG: return POPT_("LONGLONG"); case POPT_ARG_STRING: return POPT_("STRING"); case POPT_ARG_FLOAT: return POPT_("FLOAT"); case POPT_ARG_DOUBLE: return POPT_("DOUBLE"); + case POPT_ARG_MAINCALL: return NULL; + case POPT_ARG_ARGV: return NULL; default: return POPT_("ARG"); } } @@ -143,59 +202,62 @@ getArgDescrip(const struct poptOption * opt, * @param translation_domain translation domain * @return */ -static /*@only@*/ /*@null@*/ char * +static char * singleOptionDefaultValue(size_t lineLength, const struct poptOption * opt, - /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */ - /*@null@*/ UNUSED(const char * translation_domain)) - /*@=paramuse@*/ - /*@*/ + /* FIX: i18n macros disabled with lclint */ + const char * translation_domain) { const char * defstr = D_(translation_domain, "default"); - size_t limit, bufsize = 4*lineLength + 1; - char * le = malloc(bufsize); + char * le = malloc(4*lineLength + 1); char * l = le; if (le == NULL) return NULL; /* XXX can't happen */ -/*@-boundswrite@*/ + *le = '\0'; *le++ = '('; - le += strlcpy(le, defstr, bufsize - 3); + le = stpcpy(le, defstr); *le++ = ':'; *le++ = ' '; - limit = bufsize - (le - l) - 1; /* -1 for closing paren */ - if (opt->arg) /* XXX programmer error */ - switch (opt->argInfo & POPT_ARG_MASK) { + if (opt->arg) { /* XXX programmer error */ + poptArg arg = { .ptr = opt->arg }; + switch (poptArgType(opt)) { case POPT_ARG_VAL: case POPT_ARG_INT: - { long aLong = *((int *)opt->arg); - le += snprintf(le, limit, "%ld", aLong); - } break; + le += sprintf(le, "%d", arg.intp[0]); + break; + case POPT_ARG_SHORT: + le += sprintf(le, "%hd", arg.shortp[0]); + break; case POPT_ARG_LONG: - { long aLong = *((long *)opt->arg); - le += snprintf(le, limit, "%ld", aLong); - } break; + le += sprintf(le, "%ld", arg.longp[0]); + break; + case POPT_ARG_LONGLONG: + le += sprintf(le, "%lld", arg.longlongp[0]); + break; case POPT_ARG_FLOAT: - { double aDouble = *((float *)opt->arg); - le += snprintf(le, limit, "%g", aDouble); + { double aDouble = (double) arg.floatp[0]; + le += sprintf(le, "%g", aDouble); } break; case POPT_ARG_DOUBLE: - { double aDouble = *((double *)opt->arg); - le += snprintf(le, limit, "%g", aDouble); - } break; + le += sprintf(le, "%g", arg.doublep[0]); + break; + case POPT_ARG_MAINCALL: + le += sprintf(le, "%p", opt->arg); + break; + case POPT_ARG_ARGV: + le += sprintf(le, "%p", opt->arg); + break; case POPT_ARG_STRING: - { const char * s = *(const char **)opt->arg; - if (s == NULL) { - le += strlcpy(le, "null", limit); - } else { - size_t len; - limit -= 2; /* make room for quotes */ + { const char * s = arg.argv[0]; + if (s == NULL) + le = stpcpy(le, "null"); + else { + size_t limit = 4*lineLength - (le - l) - sizeof("\"\")"); + size_t slen; *le++ = '"'; - len = strlcpy(le, s, limit); - if (len >= limit) { - le += limit - 3 - 1; - *le++ = '.'; *le++ = '.'; *le++ = '.'; - } else - le += len; + strncpy(le, s, limit); le[limit] = '\0'; le += (slen = strlen(le)); + if (slen == limit && s[limit]) + le[-1] = le[-2] = le[-3] = '.'; *le++ = '"'; } } break; @@ -203,11 +265,11 @@ singleOptionDefaultValue(size_t lineLength, default: l = _free(l); return NULL; - /*@notreached@*/ break; + break; } + } *le++ = ')'; *le = '\0'; -/*@=boundswrite@*/ return l; } @@ -215,80 +277,101 @@ singleOptionDefaultValue(size_t lineLength, /** * Display help text for an option. * @param fp output file handle - * @param maxLeftCol largest argument display width + * @param columns output display width control * @param opt option(s) * @param translation_domain translation domain */ -static void singleOptionHelp(FILE * fp, size_t maxLeftCol, +static void singleOptionHelp(FILE * fp, columns_t columns, const struct poptOption * opt, - /*@null@*/ UNUSED(const char * translation_domain)) - /*@globals fileSystem @*/ - /*@modifies *fp, fileSystem @*/ + const char * translation_domain) { + size_t maxLeftCol = columns->cur; size_t indentLength = maxLeftCol + 5; - size_t lineLength = 79 - indentLength; + size_t lineLength = columns->max - indentLength; const char * help = D_(translation_domain, opt->descrip); const char * argDescrip = getArgDescrip(opt, translation_domain); + /* Display shortName iff printable non-space. */ + int prtshort = (int)(isprint((int)opt->shortName) && opt->shortName != ' '); size_t helpLength; char * defs = NULL; char * left; - size_t lelen, limit; size_t nb = maxLeftCol + 1; int displaypad = 0; /* Make sure there's more than enough room in target buffer. */ if (opt->longName) nb += strlen(opt->longName); + if (F_ISSET(opt, TOGGLE)) nb += sizeof("[no]") - 1; if (argDescrip) nb += strlen(argDescrip); -/*@-boundswrite@*/ left = malloc(nb); if (left == NULL) return; /* XXX can't happen */ left[0] = '\0'; left[maxLeftCol] = '\0'; - if (opt->longName && opt->shortName) - snprintf(left, nb, "-%c, %s%s", opt->shortName, - ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"), - opt->longName); - else if (opt->shortName != '\0') - snprintf(left, nb, "-%c", opt->shortName); - else if (opt->longName) - snprintf(left, nb, "%s%s", - ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"), - opt->longName); - if (!*left) goto out; +#define prtlong (opt->longName != NULL) /* XXX splint needs a clue */ + if (!(prtshort || prtlong)) + goto out; + if (prtshort && prtlong) { + const char *dash = F_ISSET(opt, ONEDASH) ? "-" : "--"; + left[0] = '-'; + left[1] = opt->shortName; + (void) stpcpy(stpcpy(stpcpy(left+2, ", "), dash), opt->longName); + } else if (prtshort) { + left[0] = '-'; + left[1] = opt->shortName; + left[2] = '\0'; + } else if (prtlong) { + /* XXX --long always padded for alignment with/without "-X, ". */ + const char *dash = poptArgType(opt) == POPT_ARG_MAINCALL ? "" + : (F_ISSET(opt, ONEDASH) ? "-" : "--"); + const char *longName = opt->longName; + const char *toggle; + if (F_ISSET(opt, TOGGLE)) { + toggle = "[no]"; + if (longName[0] == 'n' && longName[1] == 'o') { + longName += sizeof("no") - 1; + if (longName[0] == '-') + longName++; + } + } else + toggle = ""; + (void) stpcpy(stpcpy(stpcpy(stpcpy(left, " "), dash), toggle), longName); + } +#undef prtlong if (argDescrip) { char * le = left + strlen(left); - if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) + if (F_ISSET(opt, OPTIONAL)) *le++ = '['; /* Choose type of output */ - /*@-branchstate@*/ - if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) { + if (F_ISSET(opt, SHOW_DEFAULT)) { defs = singleOptionDefaultValue(lineLength, opt, translation_domain); if (defs) { - size_t bufsize = (help ? strlen(help) : 0) + sizeof " " + strlen(defs); - char * t = malloc(bufsize); + char * t = malloc((help ? strlen(help) : 0) + + strlen(defs) + sizeof(" ")); if (t) { - snprintf(t, bufsize, "%s %s", help ? help : "", defs); + char * te = t; + if (help) + te = stpcpy(te, help); + *te++ = ' '; + strcpy(te, defs); defs = _free(defs); + defs = t; } - defs = t; } } - /*@=branchstate@*/ if (opt->argDescrip == NULL) { - switch (opt->argInfo & POPT_ARG_MASK) { + switch (poptArgType(opt)) { case POPT_ARG_NONE: break; case POPT_ARG_VAL: #ifdef NOTNOW /* XXX pug ugly nerdy output */ { long aLong = opt->val; - int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS); - int negate = (opt->argInfo & POPT_ARGFLAG_NOT); + int ops = F_ISSET(opt, LOGICALOPS); + int negate = F_ISSET(opt, NOT); /* Don't bother displaying typical values */ if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L)) @@ -297,111 +380,102 @@ static void singleOptionHelp(FILE * fp, size_t maxLeftCol, switch (ops) { case POPT_ARGFLAG_OR: *le++ = '|'; - /*@innerbreak@*/ break; + break; case POPT_ARGFLAG_AND: *le++ = '&'; - /*@innerbreak@*/ break; + break; case POPT_ARGFLAG_XOR: *le++ = '^'; - /*@innerbreak@*/ break; + break; default: - /*@innerbreak@*/ break; + break; } *le++ = (opt->longName != NULL ? '=' : ' '); if (negate) *le++ = '~'; - /*@-formatconst@*/ - limit = nb - (le - left); - lelen = snprintf(le, limit, (ops ? "0x%lx" : "%ld"), aLong); - le += lelen >= limit ? limit - 1 : lelen; - /*@=formatconst@*/ + le += sprintf(le, (ops ? "0x%lx" : "%ld"), aLong); *le++ = ']'; } #endif break; case POPT_ARG_INT: + case POPT_ARG_SHORT: case POPT_ARG_LONG: + case POPT_ARG_LONGLONG: case POPT_ARG_FLOAT: case POPT_ARG_DOUBLE: case POPT_ARG_STRING: *le++ = (opt->longName != NULL ? '=' : ' '); - limit = nb - (le - left); - lelen = strlcpy(le, argDescrip, limit); - le += lelen >= limit ? limit - 1 : lelen; + le = stpcpy(le, argDescrip); break; default: break; } } else { + char *leo; - *le++ = '='; - limit = nb - (le - left); - lelen = strlcpy(le, argDescrip, limit); - if (lelen >= limit) - lelen = limit - 1; - le += lelen; - -#ifdef POPT_WCHAR_HACK - { const char * scopy = argDescrip; - mbstate_t t; - size_t n; - - memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */ - /* Determine number of characters. */ - n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t); + /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */ + if (!strchr(" =(", argDescrip[0])) + *le++ = ((poptArgType(opt) == POPT_ARG_MAINCALL) ? ' ' : + (poptArgType(opt) == POPT_ARG_ARGV) ? ' ' : + opt->longName == NULL ? ' ' : '='); + le = stpcpy(leo = le, argDescrip); - displaypad = (int) (lelen-n); - } -#endif + /* Adjust for (possible) wide characters. */ + displaypad = (int)((le - leo) - stringDisplayWidth(argDescrip)); } - if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) + if (F_ISSET(opt, OPTIONAL)) *le++ = ']'; *le = '\0'; } -/*@=boundswrite@*/ if (help) - fprintf(fp," %-*s ", (int)maxLeftCol+displaypad, left); + POPT_fprintf(fp," %-*s ", (int)(maxLeftCol+displaypad), left); else { - fprintf(fp," %s\n", left); + POPT_fprintf(fp," %s\n", left); goto out; } left = _free(left); -/*@-branchstate@*/ - if (defs) { + if (defs) help = defs; - defs = NULL; - } -/*@=branchstate@*/ helpLength = strlen(help); -/*@-boundsread@*/ while (helpLength > lineLength) { const char * ch; char format[16]; ch = help + lineLength - 1; - while (ch > help && !isSpace(ch)) ch--; + while (ch > help && !_isspaceptr(ch)) + ch = POPT_prev_char(ch); if (ch == help) break; /* give up */ - while (ch > (help + 1) && isSpace(ch)) ch--; - ch++; + while (ch > (help + 1) && _isspaceptr(ch)) + ch = POPT_prev_char (ch); + ch = POPT_next_char(ch); + + /* + * XXX strdup is necessary to add NUL terminator so that an unknown + * no. of (possible) multi-byte characters can be displayed. + */ + { char * fmthelp = xstrdup(help); + if (fmthelp) { + fmthelp[ch - help] = '\0'; + sprintf(format, "%%s\n%%%ds", (int) indentLength); + POPT_fprintf(fp, format, fmthelp, " "); + free(fmthelp); + } + } - snprintf(format, sizeof format, "%%.%ds\n%%%ds", (int) (ch - help), (int) indentLength); - /*@-formatconst@*/ - fprintf(fp, format, help, " "); - /*@=formatconst@*/ help = ch; - while (isSpace(help) && *help) help++; + while (_isspaceptr(help) && *help) + help = POPT_next_char(help); helpLength = strlen(help); } -/*@=boundsread@*/ if (helpLength) fprintf(fp, "%s\n", help); + help = NULL; out: - /*@-dependenttrans@*/ defs = _free(defs); - /*@=dependenttrans@*/ left = _free(left); } @@ -412,54 +486,45 @@ static void singleOptionHelp(FILE * fp, size_t maxLeftCol, * @return display width */ static size_t maxArgWidth(const struct poptOption * opt, - /*@null@*/ UNUSED(const char * translation_domain)) - /*@*/ + const char * translation_domain) { size_t max = 0; size_t len = 0; - const char * s; + const char * argDescrip; if (opt != NULL) while (opt->longName || opt->shortName || opt->arg) { - if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { - if (opt->arg) /* XXX program error */ - len = maxArgWidth(opt->arg, translation_domain); + if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) { + void * arg = opt->arg; + /* XXX sick hack to preserve pretense of ABI. */ + if (arg == poptHelpOptions) + arg = poptHelpOptionsI18N; + if (arg) /* XXX program error */ + len = maxArgWidth(arg, translation_domain); if (len > max) max = len; - } else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { + } else if (!F_ISSET(opt, DOC_HIDDEN)) { len = sizeof(" ")-1; - if (opt->shortName != '\0') len += sizeof("-X")-1; - if (opt->shortName != '\0' && opt->longName) len += sizeof(", ")-1; + /* XXX --long always padded for alignment with/without "-X, ". */ + len += sizeof("-X, ")-1; if (opt->longName) { - len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH) - ? sizeof("-")-1 : sizeof("--")-1); + len += (F_ISSET(opt, ONEDASH) ? sizeof("-") : sizeof("--")) - 1; len += strlen(opt->longName); } - s = getArgDescrip(opt, translation_domain); - -#ifdef POPT_WCHAR_HACK - /* XXX Calculate no. of display characters. */ - if (s) { - const char * scopy = s; - mbstate_t t; - size_t n; - -/*@-boundswrite@*/ - memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */ -/*@=boundswrite@*/ - /* Determine number of characters. */ - n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t); - len += sizeof("=")-1 + n; + argDescrip = getArgDescrip(opt, translation_domain); + + if (argDescrip) { + + /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */ + if (!strchr(" =(", argDescrip[0])) len += sizeof("=")-1; + + /* Adjust for (possible) wide characters. */ + len += stringDisplayWidth(argDescrip); } -#else - if (s) - len += sizeof("=")-1 + strlen(s); -#endif - if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1; + if (F_ISSET(opt, OPTIONAL)) len += sizeof("[]")-1; if (len > max) max = len; } - opt++; } @@ -471,14 +536,13 @@ static size_t maxArgWidth(const struct poptOption * opt, * @param fp output file handle * @param items alias/exec array * @param nitems no. of alias/exec entries - * @param left largest argument display width + * @param columns output display width control * @param translation_domain translation domain */ static void itemHelp(FILE * fp, - /*@null@*/ poptItem items, int nitems, size_t left, - /*@null@*/ UNUSED(const char * translation_domain)) - /*@globals fileSystem @*/ - /*@modifies *fp, fileSystem @*/ + poptItem items, int nitems, + columns_t columns, + const char * translation_domain) { poptItem item; int i; @@ -487,9 +551,8 @@ static void itemHelp(FILE * fp, for (i = 0, item = items; i < nitems; i++, item++) { const struct poptOption * opt; opt = &item->option; - if ((opt->longName || opt->shortName) && - !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) - singleOptionHelp(fp, left, opt, translation_domain); + if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) + singleOptionHelp(fp, columns, opt, translation_domain); } } @@ -498,43 +561,48 @@ static void itemHelp(FILE * fp, * @param con context * @param fp output file handle * @param table option(s) - * @param left largest argument display width + * @param columns output display width control * @param translation_domain translation domain */ static void singleTableHelp(poptContext con, FILE * fp, - /*@null@*/ const struct poptOption * table, size_t left, - /*@null@*/ UNUSED(const char * translation_domain)) - /*@globals fileSystem @*/ - /*@modifies *fp, fileSystem @*/ + const struct poptOption * table, + columns_t columns, + const char * translation_domain) { const struct poptOption * opt; const char *sub_transdom; if (table == poptAliasOptions) { - itemHelp(fp, con->aliases, con->numAliases, left, NULL); - itemHelp(fp, con->execs, con->numExecs, left, NULL); + itemHelp(fp, con->aliases, con->numAliases, columns, NULL); + itemHelp(fp, con->execs, con->numExecs, columns, NULL); return; } if (table != NULL) - for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) { - if ((opt->longName || opt->shortName) && - !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) - singleOptionHelp(fp, left, opt, translation_domain); + for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) { + if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) + singleOptionHelp(fp, columns, opt, translation_domain); } if (table != NULL) - for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) { - if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_INCLUDE_TABLE) + for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) { + void * arg = opt->arg; + if (poptArgType(opt) != POPT_ARG_INCLUDE_TABLE) continue; - sub_transdom = getTableTranslationDomain(opt->arg); + /* XXX sick hack to preserve pretense of ABI. */ + if (arg == poptHelpOptions) + arg = poptHelpOptionsI18N; + sub_transdom = getTableTranslationDomain(arg); if (sub_transdom == NULL) sub_transdom = translation_domain; + /* If no popt aliases/execs, skip poptAliasOption processing. */ + if (arg == poptAliasOptions && !(con->numAliases || con->numExecs)) + continue; if (opt->descrip) - fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip)); + POPT_fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip)); - singleTableHelp(con, fp, opt->arg, left, sub_transdom); + singleTableHelp(con, fp, arg, columns, sub_transdom); } } @@ -542,22 +610,18 @@ static void singleTableHelp(poptContext con, FILE * fp, * @param con context * @param fp output file handle */ -static int showHelpIntro(poptContext con, FILE * fp) - /*@globals fileSystem @*/ - /*@modifies *fp, fileSystem @*/ +static size_t showHelpIntro(poptContext con, FILE * fp) { - int len = 6; - const char * fn; + const char *usage_str = POPT_("Usage:"); + size_t len = strlen(usage_str); + POPT_fprintf(fp, "%s", usage_str); - fprintf(fp, POPT_("Usage:")); if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) { -/*@-boundsread@*/ - /*@-nullderef -type@*/ /* LCL: wazzup? */ - fn = con->optionStack->argv[0]; - /*@=nullderef =type@*/ -/*@=boundsread@*/ + struct optionStackEntry * os = con->optionStack; + const char * fn = (os->argv ? os->argv[0] : NULL); if (fn == NULL) return len; if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1; + /* XXX POPT_fprintf not needed for argv[0] display. */ fprintf(fp, " %s", fn); len += strlen(fn) + 1; } @@ -565,126 +629,114 @@ static int showHelpIntro(poptContext con, FILE * fp) return len; } -void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags)) +void poptPrintHelp(poptContext con, FILE * fp, UNUSED(int flags)) { - size_t leftColWidth; + columns_t columns = calloc((size_t)1, sizeof(*columns)); (void) showHelpIntro(con, fp); if (con->otherHelp) - fprintf(fp, " %s\n", con->otherHelp); + POPT_fprintf(fp, " %s\n", con->otherHelp); else - fprintf(fp, " %s\n", POPT_("[OPTION...]")); + POPT_fprintf(fp, " %s\n", POPT_("[OPTION...]")); - leftColWidth = maxArgWidth(con->options, NULL); - singleTableHelp(con, fp, con->options, leftColWidth, NULL); + if (columns) { + columns->cur = maxArgWidth(con->options, NULL); + columns->max = maxColumnWidth(fp); + singleTableHelp(con, fp, con->options, columns, NULL); + free(columns); + } } /** * Display usage text for an option. * @param fp output file handle - * @param cursor current display position + * @param columns output display width control * @param opt option(s) * @param translation_domain translation domain */ -static size_t singleOptionUsage(FILE * fp, size_t cursor, +static size_t singleOptionUsage(FILE * fp, columns_t columns, const struct poptOption * opt, - /*@null@*/ const char *translation_domain) - /*@globals fileSystem @*/ - /*@modifies *fp, fileSystem @*/ + const char *translation_domain) { - size_t len = 4; - char shortStr[2] = { '\0', '\0' }; - const char * item = shortStr; + size_t len = sizeof(" []")-1; const char * argDescrip = getArgDescrip(opt, translation_domain); - - if (opt->shortName != '\0' && opt->longName != NULL) { - len += 2; - if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++; + /* Display shortName iff printable non-space. */ + int prtshort = (int)(isprint((int)opt->shortName) && opt->shortName != ' '); + +#define prtlong (opt->longName != NULL) /* XXX splint needs a clue */ + if (!(prtshort || prtlong)) + return columns->cur; + + len = sizeof(" []")-1; + if (prtshort) + len += sizeof("-c")-1; + if (prtlong) { + if (prtshort) len += sizeof("|")-1; + len += (F_ISSET(opt, ONEDASH) ? sizeof("-") : sizeof("--")) - 1; len += strlen(opt->longName); - } else if (opt->shortName != '\0') { - len++; - shortStr[0] = opt->shortName; - shortStr[1] = '\0'; - } else if (opt->longName) { - len += strlen(opt->longName); - if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++; - item = opt->longName; } - if (len == 4) return cursor; - -#ifdef POPT_WCHAR_HACK - /* XXX Calculate no. of display characters. */ if (argDescrip) { - const char * scopy = argDescrip; - mbstate_t t; - size_t n; - -/*@-boundswrite@*/ - memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */ -/*@=boundswrite@*/ - /* Determine number of characters. */ - n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t); - len += sizeof("=")-1 + n; + + /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */ + if (!strchr(" =(", argDescrip[0])) len += sizeof("=")-1; + + /* Adjust for (possible) wide characters. */ + len += stringDisplayWidth(argDescrip); } -#else - if (argDescrip) - len += sizeof("=")-1 + strlen(argDescrip); -#endif - if ((cursor + len) > 79) { + if ((columns->cur + len) > columns->max) { fprintf(fp, "\n "); - cursor = 7; + columns->cur = (size_t)7; } - if (opt->longName && opt->shortName) { - fprintf(fp, " [-%c|-%s%s%s%s]", - opt->shortName, ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "" : "-"), - opt->longName, - (argDescrip ? " " : ""), - (argDescrip ? argDescrip : "")); - } else { - fprintf(fp, " [-%s%s%s%s]", - ((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"), - item, - (argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""), - (argDescrip ? argDescrip : "")); + fprintf(fp, " ["); + if (prtshort) + fprintf(fp, "-%c", opt->shortName); + if (prtlong) + fprintf(fp, "%s%s%s", + (prtshort ? "|" : ""), + (F_ISSET(opt, ONEDASH) ? "-" : "--"), + opt->longName); +#undef prtlong + + if (argDescrip) { + /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */ + if (!strchr(" =(", argDescrip[0])) fputc(opt->longName == NULL ? ' ' : '=', fp); + fprintf(fp, "%s", argDescrip); } + fprintf(fp, "]"); - return cursor + len + 1; + return columns->cur + len + 1; } /** * Display popt alias and exec usage. * @param fp output file handle - * @param cursor current display position + * @param columns output display width control * @param item alias/exec array * @param nitems no. of ara/exec entries * @param translation_domain translation domain */ -static size_t itemUsage(FILE * fp, size_t cursor, - /*@null@*/ poptItem item, int nitems, - /*@null@*/ UNUSED(const char * translation_domain)) - /*@globals fileSystem @*/ - /*@modifies *fp, fileSystem @*/ +static size_t itemUsage(FILE * fp, columns_t columns, + poptItem item, int nitems, + const char * translation_domain) { int i; - /*@-branchstate@*/ /* FIX: W2DO? */ if (item != NULL) for (i = 0; i < nitems; i++, item++) { const struct poptOption * opt; opt = &item->option; - if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) { + if (poptArgType(opt) == POPT_ARG_INTL_DOMAIN) { translation_domain = (const char *)opt->arg; - } else if ((opt->longName || opt->shortName) && - !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { - cursor = singleOptionUsage(fp, cursor, opt, translation_domain); + } else + if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) { + columns->cur = singleOptionUsage(fp, columns, opt, translation_domain); } } - /*@=branchstate@*/ - return cursor; + return columns->cur; } /** @@ -700,53 +752,51 @@ typedef struct poptDone_s { * Display usage text for a table of options. * @param con context * @param fp output file handle - * @param cursor current display position + * @param columns output display width control * @param opt option(s) * @param translation_domain translation domain * @param done tables already processed * @return */ -static size_t singleTableUsage(poptContext con, FILE * fp, size_t cursor, - /*@null@*/ const struct poptOption * opt, - /*@null@*/ UNUSED(const char * translation_domain), - /*@null@*/ poptDone done) - /*@globals fileSystem @*/ - /*@modifies *fp, done, fileSystem @*/ +static size_t singleTableUsage(poptContext con, FILE * fp, columns_t columns, + const struct poptOption * opt, + const char * translation_domain, + poptDone done) { - /*@-branchstate@*/ /* FIX: W2DO? */ if (opt != NULL) for (; (opt->longName || opt->shortName || opt->arg) ; opt++) { - if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) { + if (poptArgType(opt) == POPT_ARG_INTL_DOMAIN) { translation_domain = (const char *)opt->arg; - } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { + } else + if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) { + void * arg = opt->arg; + /* XXX sick hack to preserve pretense of ABI. */ + if (arg == poptHelpOptions) + arg = poptHelpOptionsI18N; if (done) { int i = 0; + if (done->opts != NULL) for (i = 0; i < done->nopts; i++) { -/*@-boundsread@*/ const void * that = done->opts[i]; -/*@=boundsread@*/ - if (that == NULL || that != opt->arg) - /*@innercontinue@*/ continue; - /*@innerbreak@*/ break; + if (that == NULL || that != arg) + continue; + break; } /* Skip if this table has already been processed. */ - if (opt->arg == NULL || i < done->nopts) + if (arg == NULL || i < done->nopts) continue; -/*@-boundswrite@*/ - if (done->nopts < done->maxopts) - done->opts[done->nopts++] = (const void *) opt->arg; -/*@=boundswrite@*/ + if (done->opts != NULL && done->nopts < done->maxopts) + done->opts[done->nopts++] = (const void *) arg; } - cursor = singleTableUsage(con, fp, cursor, opt->arg, + columns->cur = singleTableUsage(con, fp, columns, opt->arg, translation_domain, done); - } else if ((opt->longName || opt->shortName) && - !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { - cursor = singleOptionUsage(fp, cursor, opt, translation_domain); + } else + if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) { + columns->cur = singleOptionUsage(fp, columns, opt, translation_domain); } } - /*@=branchstate@*/ - return cursor; + return columns->cur; } /** @@ -757,66 +807,78 @@ static size_t singleTableUsage(poptContext con, FILE * fp, size_t cursor, * @retval str concatenation of short options * @return length of display string */ -static int showShortOptions(const struct poptOption * opt, FILE * fp, - /*@null@*/ char * str) - /*@globals fileSystem @*/ - /*@modifies *str, *fp, fileSystem @*/ - /*@requires maxRead(str) >= 0 @*/ +static size_t showShortOptions(const struct poptOption * opt, FILE * fp, + char * str) { - /* bufsize larger then the ascii set, lazy alloca on top level call. */ - char * s = (str != NULL ? str : memset(alloca(300), 0, 300)); - int len = 0; + /* bufsize larger then the ascii set, lazy allocation on top level call. */ + size_t nb = (size_t)300; + char * s = (str != NULL ? str : calloc((size_t)1, nb)); + size_t len = (size_t)0; if (s == NULL) return 0; -/*@-boundswrite@*/ if (opt != NULL) for (; (opt->longName || opt->shortName || opt->arg); opt++) { - if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK)) - s[strlen(s)] = opt->shortName; - else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) - if (opt->arg) /* XXX program error */ - len = showShortOptions(opt->arg, fp, s); + if (!F_ISSET(opt, DOC_HIDDEN) && opt->shortName && !poptArgType(opt)) + { + /* Display shortName iff unique printable non-space. */ + if (!strchr(s, opt->shortName) && isprint((int)opt->shortName) + && opt->shortName != ' ') + s[strlen(s)] = opt->shortName; + } else if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) { + void * arg = opt->arg; + /* XXX sick hack to preserve pretense of ABI. */ + if (arg == poptHelpOptions) + arg = poptHelpOptionsI18N; + if (arg) /* XXX program error */ + len = showShortOptions(arg, fp, s); + } } -/*@=boundswrite@*/ /* On return to top level, print the short options, return print length. */ - if (s == str && *s != '\0') { + if (s != str && *s != '\0') { fprintf(fp, " [-%s]", s); len = strlen(s) + sizeof(" [-]")-1; } + if (s != str) + free(s); return len; } -void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags)) +void poptPrintUsage(poptContext con, FILE * fp, UNUSED(int flags)) { - poptDone done = memset(alloca(sizeof(*done)), 0, sizeof(*done)); - size_t cursor; + columns_t columns = calloc((size_t)1, sizeof(*columns)); + struct poptDone_s done_buf; + poptDone done = &done_buf; + memset(done, 0, sizeof(*done)); done->nopts = 0; done->maxopts = 64; - cursor = done->maxopts * sizeof(*done->opts); -/*@-boundswrite@*/ - done->opts = memset(alloca(cursor), 0, cursor); - /*@-keeptrans@*/ - done->opts[done->nopts++] = (const void *) con->options; - /*@=keeptrans@*/ -/*@=boundswrite@*/ - - cursor = showHelpIntro(con, fp); - cursor += showShortOptions(con->options, fp, NULL); - cursor = singleTableUsage(con, fp, cursor, con->options, NULL, done); - cursor = itemUsage(fp, cursor, con->aliases, con->numAliases, NULL); - cursor = itemUsage(fp, cursor, con->execs, con->numExecs, NULL); + if (columns) { + columns->cur = done->maxopts * sizeof(*done->opts); + columns->max = maxColumnWidth(fp); + done->opts = calloc((size_t)1, columns->cur); + if (done->opts != NULL) + done->opts[done->nopts++] = (const void *) con->options; + + columns->cur = showHelpIntro(con, fp); + columns->cur += showShortOptions(con->options, fp, NULL); + columns->cur = singleTableUsage(con, fp, columns, con->options, NULL, done); + columns->cur = itemUsage(fp, columns, con->aliases, con->numAliases, NULL); + columns->cur = itemUsage(fp, columns, con->execs, con->numExecs, NULL); if (con->otherHelp) { - cursor += strlen(con->otherHelp) + 1; - if (cursor > 79) fprintf(fp, "\n "); + columns->cur += strlen(con->otherHelp) + 1; + if (columns->cur > columns->max) fprintf(fp, "\n "); fprintf(fp, " %s", con->otherHelp); } fprintf(fp, "\n"); + if (done->opts != NULL) + free(done->opts); + free(columns); + } } void poptSetOtherOptionHelp(poptContext con, const char * text) diff --git a/popt/poptint.c b/popt/poptint.c new file mode 100644 index 000000000..b8dc90f42 --- /dev/null +++ b/popt/poptint.c @@ -0,0 +1,194 @@ +#include "system.h" +#include +#include +#ifdef HAVE_LANGINFO_H +#include +#endif +#include "poptint.h" + +/* Any pair of 32 bit hashes can be used. lookup3.c generates pairs, will do. */ +#define _JLU3_jlu32lpair 1 +#define jlu32lpair poptJlu32lpair +#include "lookup3.c" + +const char * +POPT_prev_char (const char *str) +{ + const char *p = str; + + while (1) { + p--; + if (((unsigned)*p & 0xc0) != (unsigned)0x80) + return p; + } +} + +const char * +POPT_next_char (const char *str) +{ + const char *p = str; + + while (*p != '\0') { + p++; + if (((unsigned)*p & 0xc0) != (unsigned)0x80) + break; + } + return p; +} + +#if !defined(POPT_fprintf) /* XXX lose all the goop ... */ + +#if defined(ENABLE_NLS) && defined(HAVE_LIBINTL_H) && defined(HAVE_DCGETTEXT) +/* + * Rebind a "UTF-8" codeset for popt's internal use. + */ +char * +POPT_dgettext(const char * dom, const char * str) +{ + char * codeset = NULL; + char * retval = NULL; + + if (!dom) + dom = textdomain(NULL); + codeset = bind_textdomain_codeset(dom, NULL); + bind_textdomain_codeset(dom, "UTF-8"); + retval = dgettext(dom, str); + bind_textdomain_codeset(dom, codeset); + + return retval; +} +#endif + +#ifdef HAVE_ICONV +/** + * Return malloc'd string converted from UTF-8 to current locale. + * @param istr input string (UTF-8 encoding assumed) + * @return localized string + */ +static char * +strdup_locale_from_utf8 (char * istr) +{ + char * codeset = NULL; + char * ostr = NULL; + iconv_t cd; + + if (istr == NULL) + return NULL; + +#ifdef HAVE_LANGINFO_H + codeset = nl_langinfo ((nl_item)CODESET); +#endif + + if (codeset != NULL && strcmp(codeset, "UTF-8") != 0 + && (cd = iconv_open(codeset, "UTF-8")) != (iconv_t)-1) + { + char * shift_pin = NULL; + size_t db = strlen(istr); + char * dstr = malloc((db + 1) * sizeof(*dstr)); + char * dstr_tmp; + char * pin = istr; + char * pout = dstr; + size_t ib = db; + size_t ob = db; + size_t err; + + if (dstr == NULL) { + (void) iconv_close(cd); + return NULL; + } + err = iconv(cd, NULL, NULL, NULL, NULL); + while (1) { + *pout = '\0'; + err = iconv(cd, &pin, &ib, &pout, &ob); + if (err != (size_t)-1) { + if (shift_pin == NULL) { + shift_pin = pin; + pin = NULL; + ib = 0; + continue; + } + } else + switch (errno) { + case E2BIG: + { size_t used = (size_t)(pout - dstr); + db *= 2; + dstr_tmp = realloc(dstr, (db + 1) * sizeof(*dstr)); + if (dstr_tmp == NULL) { + free(dstr); + (void) iconv_close(cd); + return NULL; + } + dstr = dstr_tmp; + pout = dstr + used; + ob = db - used; + continue; + } break; + case EINVAL: + case EILSEQ: + default: + break; + } + break; + } + (void) iconv_close(cd); + *pout = '\0'; + ostr = xstrdup(dstr); + free(dstr); + } else + ostr = xstrdup(istr); + + return ostr; +} +#endif + +int +POPT_fprintf (FILE * stream, const char * format, ...) +{ + char * b = NULL, * ob = NULL; + int rc; + va_list ap; + +#if defined(HAVE_VASPRINTF) + va_start(ap, format); + if ((rc = vasprintf(&b, format, ap)) < 0) + b = NULL; + va_end(ap); +#else + size_t nb = (size_t)1; + + /* HACK: add +1 to the realloc no. of bytes "just in case". */ + /* XXX Likely unneeded, the issues wrto vsnprintf(3) return b0rkage have + * to do with whether the final '\0' is counted (or not). The code + * below already adds +1 for the (possibly already counted) trailing NUL. + */ + while ((b = realloc(b, nb+1)) != NULL) { + va_start(ap, format); + rc = vsnprintf(b, nb, format, ap); + va_end(ap); + if (rc > -1) { /* glibc 2.1 */ + if ((size_t)rc < nb) + break; + nb = (size_t)(rc + 1); /* precise buffer length known */ + } else /* glibc 2.0 */ + nb += (nb < (size_t)100 ? (size_t)100 : nb); + ob = b; + } +#endif + + rc = 0; + if (b != NULL) { +#ifdef HAVE_ICONV + ob = strdup_locale_from_utf8(b); + if (ob != NULL) { + rc = fprintf(stream, "%s", ob); + free(ob); + } else +#endif + rc = fprintf(stream, "%s", b); + free (b); + } + + return rc; +} + +#endif /* !defined(POPT_fprintf) */ diff --git a/popt/poptint.h b/popt/poptint.h index bec7c9769..001c5c35d 100644 --- a/popt/poptint.h +++ b/popt/poptint.h @@ -1,5 +1,5 @@ /** \ingroup popt - * \file popt/poptint.h + * @file */ /* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING @@ -9,108 +9,145 @@ #ifndef H_POPTINT #define H_POPTINT +#include + /** * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL. * @param p memory to free * @retval NULL always */ -/*@unused@*/ static inline /*@null@*/ void * -_free(/*@only@*/ /*@null@*/ const void * p) - /*@modifies p @*/ +static inline void * +_free(const void * p) { if (p != NULL) free((void *)p); return NULL; } -static inline int -isSpace(const char *ptr) -{ - return isspace(*(unsigned char *)ptr); -} - /* Bit mask macros. */ -/*@-exporttype -redef @*/ typedef unsigned int __pbm_bits; -/*@=exporttype =redef @*/ #define __PBM_NBITS (8 * sizeof (__pbm_bits)) #define __PBM_IX(d) ((d) / __PBM_NBITS) #define __PBM_MASK(d) ((__pbm_bits) 1 << (((unsigned)(d)) % __PBM_NBITS)) -/*@-exporttype -redef @*/ typedef struct { __pbm_bits bits[1]; } pbm_set; -/*@=exporttype =redef @*/ #define __PBM_BITS(set) ((set)->bits) -#define PBM_ALLOC(d) calloc(__PBM_IX (d) + 1, sizeof(__pbm_bits)) +#define PBM_ALLOC(d) calloc(__PBM_IX (d) + 1, sizeof(pbm_set)) #define PBM_FREE(s) _free(s); #define PBM_SET(d, s) (__PBM_BITS (s)[__PBM_IX (d)] |= __PBM_MASK (d)) #define PBM_CLR(d, s) (__PBM_BITS (s)[__PBM_IX (d)] &= ~__PBM_MASK (d)) #define PBM_ISSET(d, s) ((__PBM_BITS (s)[__PBM_IX (d)] & __PBM_MASK (d)) != 0) +extern void poptJlu32lpair(const void *key, size_t size, + uint32_t *pc, uint32_t *pb); + +/** \ingroup popt + * Typedef's for string and array of strings. + */ +typedef const char * poptString; +typedef poptString * poptArgv; + +/** \ingroup popt + * A union to simplify opt->arg access without casting. + */ +typedef union poptArg_u { + void * ptr; + int * intp; + short * shortp; + long * longp; + long long * longlongp; + float * floatp; + double * doublep; + const char ** argv; + poptCallbackType cb; + poptOption opt; +} poptArg; + +extern unsigned int _poptArgMask; +extern unsigned int _poptGroupMask; + +#define poptArgType(_opt) ((_opt)->argInfo & _poptArgMask) +#define poptGroup(_opt) ((_opt)->argInfo & _poptGroupMask) + +#define F_ISSET(_opt, _FLAG) ((_opt)->argInfo & POPT_ARGFLAG_##_FLAG) +#define LF_ISSET(_FLAG) (argInfo & POPT_ARGFLAG_##_FLAG) +#define CBF_ISSET(_opt, _FLAG) ((_opt)->argInfo & POPT_CBFLAG_##_FLAG) + +/* XXX sick hack to preserve pretense of a popt-1.x ABI. */ +#define poptSubstituteHelpI18N(opt) \ + { if ((opt) == poptHelpOptions) (opt) = poptHelpOptionsI18N; } + struct optionStackEntry { int argc; -/*@only@*/ /*@null@*/ - const char ** argv; -/*@only@*/ /*@null@*/ + poptArgv argv; pbm_set * argb; int next; -/*@only@*/ /*@null@*/ - const char * nextArg; -/*@observer@*/ /*@null@*/ + char * nextArg; const char * nextCharArg; -/*@dependent@*/ /*@null@*/ poptItem currAlias; int stuffed; }; struct poptContext_s { struct optionStackEntry optionStack[POPT_OPTION_DEPTH]; -/*@dependent@*/ struct optionStackEntry * os; -/*@owned@*/ /*@null@*/ - const char ** leftovers; + poptArgv leftovers; int numLeftovers; + int allocLeftovers; int nextLeftover; -/*@keep@*/ const struct poptOption * options; int restLeftover; -/*@only@*/ /*@null@*/ const char * appName; -/*@only@*/ /*@null@*/ poptItem aliases; int numAliases; - int flags; -/*@owned@*/ /*@null@*/ + unsigned int flags; poptItem execs; int numExecs; -/*@only@*/ /*@null@*/ - const char ** finalArgv; + char * execFail; + poptArgv finalArgv; int finalArgvCount; int finalArgvAlloced; -/*@dependent@*/ /*@null@*/ + int (*maincall) (int argc, const char **argv); poptItem doExec; -/*@only@*/ const char * execPath; int execAbsolute; -/*@only@*/ /*@relnull@*/ const char * otherHelp; -/*@null@*/ pbm_set * arg_strip; }; -#ifdef HAVE_LIBINTL_H +#if defined(POPT_fprintf) +#define POPT_dgettext dgettext +#else +#ifdef HAVE_ICONV +#include +#endif + +#if defined(HAVE_DCGETTEXT) +char *POPT_dgettext(const char * dom, const char * str); +#endif + +FORMAT(printf, 2, 3) +int POPT_fprintf (FILE* stream, const char *format, ...); +#endif /* !defined(POPT_fprintf) */ + +const char *POPT_prev_char (const char *str); +const char *POPT_next_char (const char *str); + +#endif + +#if defined(ENABLE_NLS) && defined(HAVE_LIBINTL_H) #include #endif -#if defined(HAVE_GETTEXT) && !defined(__LCLINT__) +#if defined(ENABLE_NLS) && defined(HAVE_GETTEXT) #define _(foo) gettext(foo) #else #define _(foo) foo #endif -#if defined(HAVE_DCGETTEXT) && !defined(__LCLINT__) -#define D_(dom, str) dgettext(dom, str) +#if defined(ENABLE_NLS) && defined(HAVE_LIBINTL_H) && defined(HAVE_DCGETTEXT) +#define D_(dom, str) POPT_dgettext(dom, str) #define POPT_(foo) D_("popt", foo) #else #define D_(dom, str) str @@ -119,4 +156,3 @@ struct poptContext_s { #define N_(foo) foo -#endif diff --git a/popt/poptparse.c b/popt/poptparse.c index e003a04a9..5afc6c551 100644 --- a/popt/poptparse.c +++ b/popt/poptparse.c @@ -1,5 +1,5 @@ /** \ingroup popt - * \file popt/poptparse.c + * @file */ /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING @@ -8,11 +8,8 @@ #include "system.h" -#include "poptint.h" - #define POPT_ARGV_ARRAY_GROW_DELTA 5 -/*@-boundswrite@*/ int poptDupArgv(int argc, const char **argv, int * argcPtr, const char *** argvPtr) { @@ -34,13 +31,13 @@ int poptDupArgv(int argc, const char **argv, return POPT_ERROR_MALLOC; argv2 = (void *) dst; dst += (argc + 1) * sizeof(*argv); + *dst = '\0'; - /*@-branchstate@*/ for (i = 0; i < argc; i++) { argv2[i] = dst; - dst += strlcpy(dst, argv[i], nb) + 1; + dst = stpcpy(dst, argv[i]); + dst++; /* trailing NUL */ } - /*@=branchstate@*/ argv2[argc] = NULL; if (argvPtr) { @@ -53,21 +50,25 @@ int poptDupArgv(int argc, const char **argv, *argcPtr = argc; return 0; } -/*@=boundswrite@*/ -/*@-bounds@*/ int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr) { const char * src; char quote = '\0'; int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA; const char ** argv = malloc(sizeof(*argv) * argvAlloced); + const char ** argv_tmp; int argc = 0; - int buflen = strlen(s) + 1; - char * buf = memset(alloca(buflen), 0, buflen); + size_t buflen = strlen(s) + 1; + char * buf, * bufOrig = NULL; int rc = POPT_ERROR_MALLOC; if (argv == NULL) return rc; + buf = bufOrig = calloc((size_t)1, buflen); + if (buf == NULL) { + free(argv); + return rc; + } argv[argc] = buf; for (src = s; *src != '\0'; src++) { @@ -83,13 +84,14 @@ int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr) if (*src != quote) *buf++ = '\\'; } *buf++ = *src; - } else if (isSpace(src)) { + } else if (_isspaceptr(src)) { if (*argv[argc] != '\0') { buf++, argc++; if (argc == argvAlloced) { argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA; - argv = realloc(argv, sizeof(*argv) * argvAlloced); - if (argv == NULL) goto exit; + argv_tmp = realloc(argv, sizeof(*argv) * argvAlloced); + if (argv_tmp == NULL) goto exit; + argv = argv_tmp; } argv[argc] = buf; } @@ -97,17 +99,17 @@ int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr) case '"': case '\'': quote = *src; - /*@switchbreak@*/ break; + break; case '\\': src++; if (!*src) { rc = POPT_ERROR_BADQUOTE; goto exit; } - /*@fallthrough@*/ + /* fallthrough */ default: *buf++ = *src; - /*@switchbreak@*/ break; + break; } } @@ -118,29 +120,30 @@ int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr) rc = poptDupArgv(argc, argv, argcPtr, argvPtr); exit: + if (bufOrig) free(bufOrig); if (argv) free(argv); return rc; } -/*@=bounds@*/ /* still in the dev stage. - * return values, perhaps 1== file erro + * return values, perhaps 1== file error * 2== line to long * 3== umm.... more? */ -int poptConfigFileToString(FILE *fp, char ** argstrp, /*@unused@*/ UNUSED(int flags)) +int poptConfigFileToString(FILE *fp, char ** argstrp, + UNUSED(int flags)) { char line[999]; char * argstr; + char * argstr_tmp; char * p; char * q; char * x; - int t; - int argvlen = 0; + size_t t; + size_t argvlen = 0; size_t maxlinelen = sizeof(line); size_t linelen; - int maxargvlen = 480; - int linenum = 0; + size_t maxargvlen = (size_t)480; *argstrp = NULL; @@ -155,11 +158,10 @@ int poptConfigFileToString(FILE *fp, char ** argstrp, /*@unused@*/ UNUSED(int fl if (argstr == NULL) return POPT_ERROR_MALLOC; while (fgets(line, (int)maxlinelen, fp) != NULL) { - linenum++; p = line; /* loop until first non-space char or EOL */ - while( *p != '\0' && isSpace(p) ) + while( *p != '\0' && _isspaceptr(p) ) p++; linelen = strlen(p); @@ -173,25 +175,29 @@ int poptConfigFileToString(FILE *fp, char ** argstrp, /*@unused@*/ UNUSED(int fl q = p; - while (*q != '\0' && (!isSpace(q)) && *q != '=') + while (*q != '\0' && (!_isspaceptr(q)) && *q != '=') q++; - if (isSpace(q)) { + if (_isspaceptr(q)) { /* a space after the name, find next non space */ *q++='\0'; - while( *q != '\0' && isSpace(q) ) q++; + while( *q != '\0' && _isspaceptr(q) ) q++; } if (*q == '\0') { /* single command line option (ie, no name=val, just name) */ q[-1] = '\0'; /* kill off newline from fgets() call */ - argvlen += (t = q - p) + (sizeof(" --")-1); + argvlen += (t = (size_t)(q - p)) + (sizeof(" --")-1); if (argvlen >= maxargvlen) { maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2; - argstr = realloc(argstr, maxargvlen); - if (argstr == NULL) return POPT_ERROR_MALLOC; + argstr_tmp = realloc(argstr, maxargvlen); + if (argstr_tmp == NULL) { + free(argstr); + return POPT_ERROR_MALLOC; + } + argstr = argstr_tmp; } - strlcat(argstr, " --", maxargvlen); - strlcat(argstr, p, maxargvlen); + strcat(argstr, " --"); + strcat(argstr, p); continue; } if (*q != '=') @@ -201,29 +207,33 @@ int poptConfigFileToString(FILE *fp, char ** argstrp, /*@unused@*/ UNUSED(int fl *q++ = '\0'; /* find next non-space letter of value */ - while (*q != '\0' && isSpace(q)) + while (*q != '\0' && _isspaceptr(q)) q++; if (*q == '\0') continue; /* XXX silently ignore missing value */ /* now, loop and strip all ending whitespace */ x = p + linelen; - while (isSpace(--x)) - *x = 0; /* null out last char if space (including fgets() NL) */ + while (_isspaceptr(--x)) + *x = '\0'; /* null out last char if space (including fgets() NL) */ /* rest of line accept */ - t = x - p; + t = (size_t)(x - p); argvlen += t + (sizeof("' --='")-1); if (argvlen >= maxargvlen) { maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2; - argstr = realloc(argstr, maxargvlen); - if (argstr == NULL) return POPT_ERROR_MALLOC; + argstr_tmp = realloc(argstr, maxargvlen); + if (argstr_tmp == NULL) { + free(argstr); + return POPT_ERROR_MALLOC; + } + argstr = argstr_tmp; } - strlcat(argstr, " --", maxargvlen); - strlcat(argstr, p, maxargvlen); - strlcat(argstr, "=\"", maxargvlen); - strlcat(argstr, q, maxargvlen); - strlcat(argstr, "\"", maxargvlen); + strcat(argstr, " --"); + strcat(argstr, p); + strcat(argstr, "=\""); + strcat(argstr, q); + strcat(argstr, "\""); } *argstrp = argstr; diff --git a/popt/system.h b/popt/system.h index 25c22daee..f731d206d 100644 --- a/popt/system.h +++ b/popt/system.h @@ -1,134 +1,70 @@ +/** + * @file + */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif -#if defined (__GLIBC__) && defined(__LCLINT__) -/*@-declundef@*/ -/*@unchecked@*/ -extern __const __int32_t *__ctype_tolower; -/*@unchecked@*/ -extern __const __int32_t *__ctype_toupper; -/*@=declundef@*/ -#endif - -#ifdef __TANDEM -# include -#endif - #include -#include -#include -#include +/* XXX isspace(3) has i18n encoding signedness issues on Solaris. */ +#define _isspaceptr(_chp) isspace((int)(*(unsigned const char *)(_chp))) -#if HAVE_MCHECK_H +#ifdef HAVE_MCHECK_H #include #endif -#include -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif -#ifdef HAVE_STRING_H -# if !defined STDC_HEADERS && defined HAVE_MEMORY_H -# include -# endif -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif +#include +#include +#include -#ifndef __GNUC__ -#define __attribute__(x) -#endif +void * xmalloc (size_t size); -#ifdef __NeXT -/* access macros are not declared in non posix mode in unistd.h - - don't try to use posix on NeXTstep 3.3 ! */ -#include -#endif +void * xcalloc (size_t nmemb, size_t size); -#if defined(__LCLINT__) -/*@-declundef -incondefs @*/ /* LCL: missing annotation */ -/*@only@*/ /*@out@*/ -void * alloca (size_t __size) - /*@ensures MaxSet(result) == (__size - 1) @*/ - /*@*/; -/*@=declundef =incondefs @*/ -#endif +void * xrealloc (void * ptr, size_t size); -/* AIX requires this to be the first thing in the file. */ -#ifndef __GNUC__ -# if HAVE_ALLOCA_H -# include -# else -# ifdef _AIX -#pragma alloca -# else -# ifdef HAVE_ALLOCA -# ifndef alloca /* predefined by HP cc +Olibcalls */ -char *alloca(size_t size); -# endif -# else -# ifdef alloca -# undef alloca -# endif -# define alloca(sz) malloc(sz) /* Kludge this for now */ -# endif -# endif -# endif -#elif !defined(alloca) -#define alloca __builtin_alloca -#endif +char * xstrdup (const char *str); -#ifndef HAVE_STRLCPY -size_t strlcpy(char *d, const char *s, size_t bufsize); -#endif +#if !defined(HAVE_STPCPY) +/* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */ +static inline char * stpcpy (char *dest, const char * src) { + register char *d = dest; + register const char *s = src; -#ifndef HAVE_STRLCAT -size_t strlcat(char *d, const char *s, size_t bufsize); + do + *d++ = *s; + while (*s++ != '\0'); + return d - 1; +} #endif -#if HAVE_MCHECK_H && defined(__GNUC__) -static inline char * -xstrdup(const char *s) -{ - size_t memsize = strlen(s) + 1; - char *ptr = malloc(memsize); - if (!ptr) { - fprintf(stderr, "virtual memory exhausted.\n"); - exit(EXIT_FAILURE); - } - strlcpy(ptr, s, memsize); - return ptr; -} +/* Memory allocation via macro defs to get meaningful locations from mtrace() */ +#if defined(HAVE_MCHECK_H) && defined(__GNUC__) +#define vmefail() (fprintf(stderr, "virtual memory exhausted.\n"), exit(EXIT_FAILURE), NULL) +#define xmalloc(_size) (malloc(_size) ? : vmefail()) +#define xcalloc(_nmemb, _size) (calloc((_nmemb), (_size)) ? : vmefail()) +#define xrealloc(_ptr, _size) (realloc((_ptr), (_size)) ? : vmefail()) +#define xstrdup(_str) (strcpy((malloc(strlen(_str)+1) ? : vmefail()), (_str))) #else +#define xmalloc(_size) malloc(_size) +#define xcalloc(_nmemb, _size) calloc((_nmemb), (_size)) +#define xrealloc(_ptr, _size) realloc((_ptr), (_size)) #define xstrdup(_str) strdup(_str) -#endif /* HAVE_MCHECK_H && defined(__GNUC__) */ +#endif /* defined(HAVE_MCHECK_H) && defined(__GNUC__) */ -#if HAVE___SECURE_GETENV && !defined(__LCLINT__) +#if defined(HAVE_SECURE_GETENV) +#define getenv(_s) secure_getenv(_s) +#elif defined(HAVE___SECURE_GETENV) #define getenv(_s) __secure_getenv(_s) #endif -#if !defined HAVE_SNPRINTF || !defined HAVE_C99_VSNPRINTF -#define snprintf rsync_snprintf -int snprintf(char *str,size_t count,const char *fmt,...); +#if !defined(__GNUC__) && !defined(__attribute__) +#define __attribute__(x) #endif - #define UNUSED(x) x __attribute__((__unused__)) - -#define PACKAGE "rsync" +#define FORMAT(a, b, c) __attribute__((__format__ (a, b, c))) +#define NORETURN __attribute__((__noreturn__)) #include "popt.h" From 231b239f304fb2daa1240eec567880d225b7f730 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 8 Apr 2024 13:40:58 +1000 Subject: [PATCH 032/101] check for stpcpy needed for popt on macos --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index a65cde147..390c5961c 100644 --- a/configure.ac +++ b/configure.ac @@ -870,7 +870,7 @@ AC_CHECK_FUNCS(waitpid wait4 getcwd chown chmod lchmod mknod mkfifo \ fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \ chflags getattrlist mktime innetgr linkat \ memmove lchown vsnprintf snprintf vasprintf asprintf setsid strpbrk \ - strlcat strlcpy strtol mallinfo mallinfo2 getgroups setgroups geteuid getegid \ + strlcat strlcpy stpcpy strtol mallinfo mallinfo2 getgroups setgroups geteuid getegid \ setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \ seteuid strerror putenv iconv_open locale_charset nl_langinfo getxattr \ extattr_get_link sigaction sigprocmask setattrlist getgrouplist \ From 411c4789dfb2561d3400a5f8282f5f1bab76eeae Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 8 Apr 2024 10:16:31 +1000 Subject: [PATCH 033/101] support: added install_deps_ubuntu.sh convenient way to bootstrap quickly --- INSTALL.md | 2 ++ support/install_deps_ubuntu.sh | 11 +++++++++++ 2 files changed, 13 insertions(+) create mode 100755 support/install_deps_ubuntu.sh diff --git a/INSTALL.md b/INSTALL.md index 1605ab435..8ef574a54 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -104,6 +104,8 @@ like. > sudo apt install -y liblz4-dev > sudo apt install -y libssl-dev +Or run support/install_deps_ubuntu.sh + - For CentOS (use EPEL for python3-pip): > sudo yum -y install epel-release diff --git a/support/install_deps_ubuntu.sh b/support/install_deps_ubuntu.sh new file mode 100755 index 000000000..ac49055bb --- /dev/null +++ b/support/install_deps_ubuntu.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# install script for build dependencies for ubuntu/debian systems + +sudo apt install -y gcc g++ gawk autoconf automake python3-cmarkgfm +sudo apt install -y acl libacl1-dev +sudo apt install -y attr libattr1-dev +sudo apt install -y libxxhash-dev +sudo apt install -y libzstd-dev +sudo apt install -y liblz4-dev +sudo apt install -y libssl-dev From 7bc3be2b9e32cf95ce9d67c6227a8e5367d0b8ad Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 8 Apr 2024 15:35:42 +1000 Subject: [PATCH 034/101] CI: fixed rules for when to trigger --- .github/workflows/build.yml | 2 -- .github/workflows/freebsd-build.yml | 6 +++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3439e181e..9273e11a9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,10 +3,8 @@ name: build on: push: branches: [ master ] - paths-ignore: [ .cirrus.yml ] pull_request: branches: [ master ] - paths-ignore: [ .cirrus.yml ] schedule: - cron: '42 8 * * *' diff --git a/.github/workflows/freebsd-build.yml b/.github/workflows/freebsd-build.yml index 8ec2e0f15..747bc35b2 100644 --- a/.github/workflows/freebsd-build.yml +++ b/.github/workflows/freebsd-build.yml @@ -1,6 +1,10 @@ name: Test rsync on FreeBSD -on: [push] +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] jobs: test: From 56a039b04a186678e8e150a95529f23d93e2ca56 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Mon, 8 Apr 2024 13:14:59 -0700 Subject: [PATCH 035/101] Changes for 3.3.1dev. --- NEWS.md | 15 +++++++++++++++ version.h | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 846ed0ac5..1a88a70d9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,17 @@ +# NEWS for rsync 3.3.1 (UNRELEASED) + +## Changes in this version: + +### BUG FIXES: + +- Fixed the included popt to avoid a memory error on modern gcc versions. + +### INTERNAL: + + - Updated included popt to version 1.19. + +------------------------------------------------------------------------------ + # NEWS for rsync 3.3.0 (6 Apr 2024) ## Changes in this version: @@ -4762,6 +4776,7 @@ | RELEASE DATE | VER. | DATE OF COMMIT\* | PROTOCOL | |--------------|--------|------------------|-------------| +| ?? Apr 2024 | 3.3.1 | | 31 | | 06 Apr 2024 | 3.3.0 | | 31 | | 20 Oct 2022 | 3.2.7 | | 31 | | 09 Sep 2022 | 3.2.6 | | 31 | diff --git a/version.h b/version.h index b162146ef..47d5dbe19 100644 --- a/version.h +++ b/version.h @@ -1,2 +1,2 @@ -#define RSYNC_VERSION "3.3.0" +#define RSYNC_VERSION "3.3.1pre" #define MAINTAINER_TZ_OFFSET -7.0 From 5510255f120ba13a1874086a1ef7ea8a7bf66570 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Mon, 8 Apr 2024 13:16:12 -0700 Subject: [PATCH 036/101] Tweak maintainer messaging. --- README.md | 8 +++++--- rsync.1.md | 3 +-- rsyncd.conf.5.md | 3 +-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index f9689972f..6bedf2e13 100644 --- a/README.md +++ b/README.md @@ -132,9 +132,11 @@ source. COPYRIGHT --------- -Rsync was originally written by Andrew Tridgell and is currently -maintained by Wayne Davison. It has been improved by many developers -from around the world. +Rsync was originally written by Andrew Tridgell and has been improved by many +developers from around the world. + +Rsync was originally written by Andrew Tridgell and Paul Mackerras. Many +people from around the world have helped to maintain and improve it. Rsync may be used, modified and redistributed only under the terms of the GNU General Public License, found in the file [COPYING][9] in this diff --git a/rsync.1.md b/rsync.1.md index afaf1de89..4407a013f 100644 --- a/rsync.1.md +++ b/rsync.1.md @@ -4838,8 +4838,7 @@ David Bell. I've probably missed some people, my apologies if I have. ## AUTHOR Rsync was originally written by Andrew Tridgell and Paul Mackerras. Many -people have later contributed to it. It is currently maintained by Wayne -Davison. +people from around the world have helped to maintain and improve it. Mailing lists for support and development are available at . diff --git a/rsyncd.conf.5.md b/rsyncd.conf.5.md index 2ba71111e..2f257659d 100644 --- a/rsyncd.conf.5.md +++ b/rsyncd.conf.5.md @@ -1273,8 +1273,7 @@ Thanks to Karsten Thygesen for his many suggestions and documentation! ## AUTHOR Rsync was originally written by Andrew Tridgell and Paul Mackerras. Many -people have later contributed to it. It is currently maintained by Wayne -Davison. +people from around the world have helped to maintain and improve it. Mailing lists for support and development are available at . From 3f2a38b01184cae9a931280b534acf5a3dae2e94 Mon Sep 17 00:00:00 2001 From: Charalampos Mitrodimas Date: Mon, 8 Apr 2024 11:40:02 +0300 Subject: [PATCH 037/101] CI: added Solaris build Signed-off-by: Charalampos Mitrodimas --- .github/workflows/solaris-build.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/solaris-build.yml diff --git a/.github/workflows/solaris-build.yml b/.github/workflows/solaris-build.yml new file mode 100644 index 000000000..4ef3b2cf6 --- /dev/null +++ b/.github/workflows/solaris-build.yml @@ -0,0 +1,27 @@ +name: Test rsync on Solaris + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + solaris-test: + runs-on: ubuntu-latest + name: Test rsync on Solaris + steps: + - uses: actions/checkout@v4 + - name: Test in Solaris + id: test + uses: vmactions/solaris-vm@v1 + with: + usesh: true + prepare: | + pkg install bash automake gnu-m4 wget pkg://solaris/runtime/python-35 autoconf gcc + run: | + uname -a + ./configure --with-rrsync -disable-zstd --disable-md2man --disable-xxhash --disable-lz4 + make + ./rsync --version + ./rsync-ssl --no-motd download.samba.org::rsyncftp/ || true From 50bdf9685dc823ef9930c6ca862ac1588f815970 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Wed, 10 Apr 2024 11:51:59 -0700 Subject: [PATCH 038/101] Remove duplicate paragraph. --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 6bedf2e13..82db21575 100644 --- a/README.md +++ b/README.md @@ -132,9 +132,6 @@ source. COPYRIGHT --------- -Rsync was originally written by Andrew Tridgell and has been improved by many -developers from around the world. - Rsync was originally written by Andrew Tridgell and Paul Mackerras. Many people from around the world have helped to maintain and improve it. From 0b1b2a3ff4b01b7ad6be5defe49172f04a0f7082 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Wed, 10 Apr 2024 11:53:07 -0700 Subject: [PATCH 039/101] Get the "dev" suffix right. --- version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.h b/version.h index 47d5dbe19..c6515f689 100644 --- a/version.h +++ b/version.h @@ -1,2 +1,2 @@ -#define RSYNC_VERSION "3.3.1pre" +#define RSYNC_VERSION "3.3.1dev" #define MAINTAINER_TZ_OFFSET -7.0 From 804411b7fd006d6a399a2b917b508259a752cfed Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Wed, 10 Apr 2024 12:15:49 -0700 Subject: [PATCH 040/101] Get rid of gensend target & cached git version. - Change the developer flow to not require updating the git-version repo that the builds used to download a git-version.h file. The Actions now do a full repo fetch so that the .h file can be generated via the git history. - Get rid of the gensend Makefile target that was used for the above. - Get rid of the pre-push git hook file that called "Make gensend". - Change the FreeBSD build to save an artifact with its built binaries. [buildall] --- .github/workflows/build.yml | 16 ++++++++-------- .github/workflows/freebsd-build.yml | 13 +++++++++++-- .github/workflows/solaris-build.yml | 3 ++- Makefile.in | 8 -------- packaging/auto-Makefile | 2 +- packaging/pkglib.py | 11 ----------- packaging/pre-push | 16 ---------------- packaging/release-rsync | 2 -- 8 files changed, 22 insertions(+), 49 deletions(-) delete mode 100755 packaging/pre-push diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9273e11a9..09a8ce247 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,11 +13,11 @@ jobs: ubuntu-build: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + fetch-depth: 0 - name: prep run: | - sudo apt-get install acl libacl1-dev attr libattr1-dev liblz4-dev libzstd-dev libxxhash-dev python3-cmarkgfm openssl wget - wget -O git-version.h https://gist.githubusercontent.com/WayneD/c11243fa374fc64d4e42f2855c8e3827/raw/rsync-git-version.h + sudo apt-get install acl libacl1-dev attr libattr1-dev liblz4-dev libzstd-dev libxxhash-dev python3-cmarkgfm openssl echo "/usr/local/bin" >>$GITHUB_PATH - name: configure run: ./configure --with-rrsync @@ -51,12 +51,12 @@ jobs: macos-build: runs-on: macos-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + fetch-depth: 0 - name: prep run: | - brew install automake openssl xxhash zstd lz4 wget + brew install automake openssl xxhash zstd lz4 sudo pip3 install commonmark - wget -O git-version.h https://gist.githubusercontent.com/WayneD/c11243fa374fc64d4e42f2855c8e3827/raw/rsync-git-version.h echo "/usr/local/bin" >>$GITHUB_PATH - name: configure run: CPPFLAGS=-I/usr/local/opt/openssl/include/ LDFLAGS=-L/usr/local/opt/openssl/lib/ ./configure --with-rrsync @@ -87,13 +87,13 @@ jobs: runs-on: windows-2022 if: (github.event_name == 'schedule' || contains(github.event.head_commit.message, '[buildall]')) steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + fetch-depth: 0 - name: cygwin run: choco install -y --no-progress cygwin cyg-get - name: prep run: | cyg-get make autoconf automake gcc-core attr libattr-devel python39 python39-pip libzstd-devel liblz4-devel libssl-devel libxxhash0 libxxhash-devel - curl.exe -o git-version.h https://gist.githubusercontent.com/WayneD/c11243fa374fc64d4e42f2855c8e3827/raw/rsync-git-version.h echo "C:/tools/cygwin/bin" >>$Env:GITHUB_PATH - name: commonmark run: bash -c 'python3 -mpip install --user commonmark' diff --git a/.github/workflows/freebsd-build.yml b/.github/workflows/freebsd-build.yml index 747bc35b2..0fb5adb09 100644 --- a/.github/workflows/freebsd-build.yml +++ b/.github/workflows/freebsd-build.yml @@ -12,16 +12,25 @@ jobs: name: Test rsync on FreeBSD steps: - uses: actions/checkout@v4 + fetch-depth: 0 - name: Test in FreeBSD id: test uses: vmactions/freebsd-vm@v1 with: usesh: true prepare: | - pkg install -y bash autotools m4 devel/xxhash zstd liblz4 wget python3 archivers/liblz4 + pkg install -y bash autotools m4 devel/xxhash zstd liblz4 python3 archivers/liblz4 run: | freebsd-version - ./configure --with-rrsync -disable-zstd --disable-md2man --disable-xxhash --disable-lz4 + ./configure --with-rrsync --disable-md2man make ./rsync --version ./rsync-ssl --no-motd download.samba.org::rsyncftp/ || true + - name: save artifact + uses: actions/upload-artifact@v3 + with: + name: freebsd-bin + path: | + rsync + rsync-ssl + rrsync diff --git a/.github/workflows/solaris-build.yml b/.github/workflows/solaris-build.yml index 4ef3b2cf6..feb4ad0b2 100644 --- a/.github/workflows/solaris-build.yml +++ b/.github/workflows/solaris-build.yml @@ -12,13 +12,14 @@ jobs: name: Test rsync on Solaris steps: - uses: actions/checkout@v4 + fetch-depth: 0 - name: Test in Solaris id: test uses: vmactions/solaris-vm@v1 with: usesh: true prepare: | - pkg install bash automake gnu-m4 wget pkg://solaris/runtime/python-35 autoconf gcc + pkg install bash automake gnu-m4 pkg://solaris/runtime/python-35 autoconf gcc run: | uname -a ./configure --with-rrsync -disable-zstd --disable-md2man --disable-xxhash --disable-lz4 diff --git a/Makefile.in b/Makefile.in index 6bf304d1b..d5fefe045 100644 --- a/Makefile.in +++ b/Makefile.in @@ -184,14 +184,6 @@ conf: configure.sh config.h.in .PHONY: gen gen: conf proto.h man git-version.h -.PHONY: gensend -gensend: gen - if ! diff git-version.h $(srcdir)/gists/rsync-git-version.h >/dev/null; then \ - ./rsync -ai git-version.h $(srcdir)/gists/rsync-git-version.h && \ - (cd $(srcdir)/gists && git commit --allow-empty-message -m '' rsync-git-version.h && git push) ; \ - fi - rsync -aic $(GENFILES) git-version.h $${SAMBA_HOST-samba.org}:/home/ftp/pub/rsync/generated-files/ || true - aclocal.m4: $(srcdir)/m4/*.m4 aclocal -I $(srcdir)/m4 diff --git a/packaging/auto-Makefile b/packaging/auto-Makefile index 7f2e2585c..032913d57 100644 --- a/packaging/auto-Makefile +++ b/packaging/auto-Makefile @@ -1,4 +1,4 @@ -TARGETS := all install install-ssl-daemon install-all install-strip conf gen gensend reconfigure restatus \ +TARGETS := all install install-ssl-daemon install-all install-strip conf gen reconfigure restatus \ proto man clean cleantests distclean test check check29 check30 installcheck splint \ doxygen doxygen-upload finddead rrsync diff --git a/packaging/pkglib.py b/packaging/pkglib.py index c4c5741df..c2b293074 100644 --- a/packaging/pkglib.py +++ b/packaging/pkglib.py @@ -170,17 +170,6 @@ def get_patch_branches(base_branch): return branches -def mandate_gensend_hook(): - hook = '.git/hooks/pre-push' - if not os.path.exists(hook): - print('Creating hook file:', hook) - cmd_chk(['./rsync', '-a', 'packaging/pre-push', hook]) - else: - ct = cmd_txt(['grep', 'make gensend', hook], discard='output') - if ct.rc: - die('Please add a "make gensend" into your', hook, 'script.') - - # Snag the GENFILES values out of the Makefile file and return them as a list. def get_gen_files(want_dir_plus_list=False): cont_re = re.compile(r'\\\n') diff --git a/packaging/pre-push b/packaging/pre-push deleted file mode 100755 index 8a713695e..000000000 --- a/packaging/pre-push +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -e - -cat >/dev/null # Just discard stdin data - -if [[ -f /proc/$PPID/cmdline ]]; then - while read -d $'\0' arg ; do - if [[ "$arg" == '--tags' ]] ; then - exit 0 - fi - done Date: Wed, 10 Apr 2024 12:30:05 -0700 Subject: [PATCH 041/101] Get fetch-depth:0 right. --- .github/workflows/build.yml | 9 ++++++--- .github/workflows/freebsd-build.yml | 3 ++- .github/workflows/solaris-build.yml | 3 ++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 09a8ce247..f407dab7b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,8 @@ jobs: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v4 - fetch-depth: 0 + with: + fetch-depth: 0 - name: prep run: | sudo apt-get install acl libacl1-dev attr libattr1-dev liblz4-dev libzstd-dev libxxhash-dev python3-cmarkgfm openssl @@ -52,7 +53,8 @@ jobs: runs-on: macos-latest steps: - uses: actions/checkout@v4 - fetch-depth: 0 + with: + fetch-depth: 0 - name: prep run: | brew install automake openssl xxhash zstd lz4 @@ -88,7 +90,8 @@ jobs: if: (github.event_name == 'schedule' || contains(github.event.head_commit.message, '[buildall]')) steps: - uses: actions/checkout@v4 - fetch-depth: 0 + with: + fetch-depth: 0 - name: cygwin run: choco install -y --no-progress cygwin cyg-get - name: prep diff --git a/.github/workflows/freebsd-build.yml b/.github/workflows/freebsd-build.yml index 0fb5adb09..2c0061ee0 100644 --- a/.github/workflows/freebsd-build.yml +++ b/.github/workflows/freebsd-build.yml @@ -12,7 +12,8 @@ jobs: name: Test rsync on FreeBSD steps: - uses: actions/checkout@v4 - fetch-depth: 0 + with: + fetch-depth: 0 - name: Test in FreeBSD id: test uses: vmactions/freebsd-vm@v1 diff --git a/.github/workflows/solaris-build.yml b/.github/workflows/solaris-build.yml index feb4ad0b2..7de3d35ef 100644 --- a/.github/workflows/solaris-build.yml +++ b/.github/workflows/solaris-build.yml @@ -12,7 +12,8 @@ jobs: name: Test rsync on Solaris steps: - uses: actions/checkout@v4 - fetch-depth: 0 + with: + fetch-depth: 0 - name: Test in Solaris id: test uses: vmactions/solaris-vm@v1 From a9a315575631015dbee5eb74a986bf0c784830b4 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Wed, 10 Apr 2024 12:39:53 -0700 Subject: [PATCH 042/101] Work around pkg install issue. The xxhash, lz4, and zstd libraries aren't getting installed on FreeBSD. [buildall] --- .github/workflows/freebsd-build.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/freebsd-build.yml b/.github/workflows/freebsd-build.yml index 2c0061ee0..2081f6229 100644 --- a/.github/workflows/freebsd-build.yml +++ b/.github/workflows/freebsd-build.yml @@ -23,7 +23,7 @@ jobs: pkg install -y bash autotools m4 devel/xxhash zstd liblz4 python3 archivers/liblz4 run: | freebsd-version - ./configure --with-rrsync --disable-md2man + ./configure --with-rrsync -disable-zstd --disable-md2man --disable-xxhash --disable-lz4 make ./rsync --version ./rsync-ssl --no-motd download.samba.org::rsyncftp/ || true @@ -34,4 +34,8 @@ jobs: path: | rsync rsync-ssl + rsync.1 + rsync-ssl.1 + rsyncd.conf.5 + rrsync.1 rrsync From 8bc363cc9fcc57a352135e244497469ce9b2c4f8 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Wed, 10 Apr 2024 13:02:34 -0700 Subject: [PATCH 043/101] Separate the builds and make Cygwin always run. --- .github/workflows/build.yml | 126 ---------------------------- .github/workflows/cygwin-build.yml | 50 +++++++++++ .github/workflows/freebsd-build.yml | 4 +- .github/workflows/macos-build.yml | 47 +++++++++++ .github/workflows/solaris-build.yml | 18 +++- .github/workflows/ubuntu-build.yml | 50 +++++++++++ 6 files changed, 166 insertions(+), 129 deletions(-) delete mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/cygwin-build.yml create mode 100644 .github/workflows/macos-build.yml create mode 100644 .github/workflows/ubuntu-build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index f407dab7b..000000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,126 +0,0 @@ -name: build - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - schedule: - - cron: '42 8 * * *' - -jobs: - - ubuntu-build: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: prep - run: | - sudo apt-get install acl libacl1-dev attr libattr1-dev liblz4-dev libzstd-dev libxxhash-dev python3-cmarkgfm openssl - echo "/usr/local/bin" >>$GITHUB_PATH - - name: configure - run: ./configure --with-rrsync - - name: make - run: make - - name: install - run: sudo make install - - name: info - run: rsync --version - - name: check - run: sudo RSYNC_EXPECT_SKIPPED=crtimes make check - - name: check30 - run: sudo RSYNC_EXPECT_SKIPPED=crtimes make check30 - - name: check29 - run: sudo RSYNC_EXPECT_SKIPPED=crtimes make check29 - - name: ssl file list - run: rsync-ssl --no-motd download.samba.org::rsyncftp/ || true - - name: save artifact - uses: actions/upload-artifact@v3 - with: - name: ubuntu-bin - path: | - rsync - rsync-ssl - rsync.1 - rsync-ssl.1 - rsyncd.conf.5 - rrsync.1 - rrsync - - macos-build: - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: prep - run: | - brew install automake openssl xxhash zstd lz4 - sudo pip3 install commonmark - echo "/usr/local/bin" >>$GITHUB_PATH - - name: configure - run: CPPFLAGS=-I/usr/local/opt/openssl/include/ LDFLAGS=-L/usr/local/opt/openssl/lib/ ./configure --with-rrsync - - name: make - run: make - - name: install - run: sudo make install - - name: info - run: rsync --version - - name: check - run: sudo RSYNC_EXPECT_SKIPPED=acls-default,chmod-temp-dir,chown-fake,devices-fake,dir-sgid,protected-regular,xattrs-hlink,xattrs make check - - name: ssl file list - run: rsync-ssl --no-motd download.samba.org::rsyncftp/ || true - - name: save artifact - uses: actions/upload-artifact@v3 - with: - name: macos-bin - path: | - rsync - rsync-ssl - rsync.1 - rsync-ssl.1 - rsyncd.conf.5 - rrsync.1 - rrsync - - cygwin-build: - runs-on: windows-2022 - if: (github.event_name == 'schedule' || contains(github.event.head_commit.message, '[buildall]')) - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: cygwin - run: choco install -y --no-progress cygwin cyg-get - - name: prep - run: | - cyg-get make autoconf automake gcc-core attr libattr-devel python39 python39-pip libzstd-devel liblz4-devel libssl-devel libxxhash0 libxxhash-devel - echo "C:/tools/cygwin/bin" >>$Env:GITHUB_PATH - - name: commonmark - run: bash -c 'python3 -mpip install --user commonmark' - - name: configure - run: bash -c './configure --with-rrsync' - - name: make - run: bash -c 'make' - - name: install - run: bash -c 'make install' - - name: info - run: bash -c '/usr/local/bin/rsync --version' - - name: check - run: bash -c 'RSYNC_EXPECT_SKIPPED=acls-default,acls,chown,devices,dir-sgid,protected-regular make check' - - name: ssl file list - run: bash -c 'PATH="/usr/local/bin:$PATH" rsync-ssl --no-motd download.samba.org::rsyncftp/ || true' - - name: save artifact - uses: actions/upload-artifact@v3 - with: - name: cygwin-bin - path: | - rsync.exe - rsync-ssl - rsync.1 - rsync-ssl.1 - rsyncd.conf.5 - rrsync.1 - rrsync diff --git a/.github/workflows/cygwin-build.yml b/.github/workflows/cygwin-build.yml new file mode 100644 index 000000000..a9635f2ed --- /dev/null +++ b/.github/workflows/cygwin-build.yml @@ -0,0 +1,50 @@ +name: Test rsync on Cygwin + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + schedule: + - cron: '42 8 * * *' + +jobs: + test: + runs-on: windows-2022 + name: Test rsync on Cygwin + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: cygwin + run: choco install -y --no-progress cygwin cyg-get + - name: prep + run: | + cyg-get make autoconf automake gcc-core attr libattr-devel python39 python39-pip libzstd-devel liblz4-devel libssl-devel libxxhash0 libxxhash-devel + echo "C:/tools/cygwin/bin" >>$Env:GITHUB_PATH + - name: commonmark + run: bash -c 'python3 -mpip install --user commonmark' + - name: configure + run: bash -c './configure --with-rrsync' + - name: make + run: bash -c 'make' + - name: install + run: bash -c 'make install' + - name: info + run: bash -c '/usr/local/bin/rsync --version' + - name: check + run: bash -c 'RSYNC_EXPECT_SKIPPED=acls-default,acls,chown,devices,dir-sgid,protected-regular make check' + - name: ssl file list + run: bash -c 'PATH="/usr/local/bin:$PATH" rsync-ssl --no-motd download.samba.org::rsyncftp/ || true' + - name: save artifact + uses: actions/upload-artifact@v3 + with: + name: cygwin-bin + path: | + rsync.exe + rsync-ssl + rsync.1 + rsync-ssl.1 + rsyncd.conf.5 + rrsync.1 + rrsync diff --git a/.github/workflows/freebsd-build.yml b/.github/workflows/freebsd-build.yml index 2081f6229..d82b160b6 100644 --- a/.github/workflows/freebsd-build.yml +++ b/.github/workflows/freebsd-build.yml @@ -5,6 +5,8 @@ on: branches: [ master ] pull_request: branches: [ master ] + schedule: + - cron: '42 8 * * *' jobs: test: @@ -14,7 +16,7 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Test in FreeBSD + - name: Test in FreeBSD VM id: test uses: vmactions/freebsd-vm@v1 with: diff --git a/.github/workflows/macos-build.yml b/.github/workflows/macos-build.yml new file mode 100644 index 000000000..bb85bb004 --- /dev/null +++ b/.github/workflows/macos-build.yml @@ -0,0 +1,47 @@ +name: Test rsync on macOS + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + schedule: + - cron: '42 8 * * *' + +jobs: + test: + runs-on: macos-latest + name: Test rsync on macOS + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: prep + run: | + brew install automake openssl xxhash zstd lz4 + sudo pip3 install commonmark + echo "/usr/local/bin" >>$GITHUB_PATH + - name: configure + run: CPPFLAGS=-I/usr/local/opt/openssl/include/ LDFLAGS=-L/usr/local/opt/openssl/lib/ ./configure --with-rrsync + - name: make + run: make + - name: install + run: sudo make install + - name: info + run: rsync --version + - name: check + run: sudo RSYNC_EXPECT_SKIPPED=acls-default,chmod-temp-dir,chown-fake,devices-fake,dir-sgid,protected-regular,xattrs-hlink,xattrs make check + - name: ssl file list + run: rsync-ssl --no-motd download.samba.org::rsyncftp/ || true + - name: save artifact + uses: actions/upload-artifact@v3 + with: + name: macos-bin + path: | + rsync + rsync-ssl + rsync.1 + rsync-ssl.1 + rsyncd.conf.5 + rrsync.1 + rrsync diff --git a/.github/workflows/solaris-build.yml b/.github/workflows/solaris-build.yml index 7de3d35ef..557a5781e 100644 --- a/.github/workflows/solaris-build.yml +++ b/.github/workflows/solaris-build.yml @@ -5,16 +5,18 @@ on: branches: [ master ] pull_request: branches: [ master ] + schedule: + - cron: '42 8 * * *' jobs: - solaris-test: + test: runs-on: ubuntu-latest name: Test rsync on Solaris steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Test in Solaris + - name: Test in Solaris VM id: test uses: vmactions/solaris-vm@v1 with: @@ -27,3 +29,15 @@ jobs: make ./rsync --version ./rsync-ssl --no-motd download.samba.org::rsyncftp/ || true + - name: save artifact + uses: actions/upload-artifact@v3 + with: + name: solaris-bin + path: | + rsync + rsync-ssl + rsync.1 + rsync-ssl.1 + rsyncd.conf.5 + rrsync.1 + rrsync diff --git a/.github/workflows/ubuntu-build.yml b/.github/workflows/ubuntu-build.yml new file mode 100644 index 000000000..60dc8d5f2 --- /dev/null +++ b/.github/workflows/ubuntu-build.yml @@ -0,0 +1,50 @@ +name: Test rsync on Ubuntu + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + schedule: + - cron: '42 8 * * *' + +jobs: + test: + runs-on: ubuntu-20.04 + name: Test rsync on Ubuntu + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: prep + run: | + sudo apt-get install acl libacl1-dev attr libattr1-dev liblz4-dev libzstd-dev libxxhash-dev python3-cmarkgfm openssl + echo "/usr/local/bin" >>$GITHUB_PATH + - name: configure + run: ./configure --with-rrsync + - name: make + run: make + - name: install + run: sudo make install + - name: info + run: rsync --version + - name: check + run: sudo RSYNC_EXPECT_SKIPPED=crtimes make check + - name: check30 + run: sudo RSYNC_EXPECT_SKIPPED=crtimes make check30 + - name: check29 + run: sudo RSYNC_EXPECT_SKIPPED=crtimes make check29 + - name: ssl file list + run: rsync-ssl --no-motd download.samba.org::rsyncftp/ || true + - name: save artifact + uses: actions/upload-artifact@v3 + with: + name: ubuntu-bin + path: | + rsync + rsync-ssl + rsync.1 + rsync-ssl.1 + rsyncd.conf.5 + rrsync.1 + rrsync From 4592aa770d51d5e83845b032feea1de441f03ee7 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Wed, 10 Apr 2024 13:12:52 -0700 Subject: [PATCH 044/101] More tweaks for Actions. - When a .github/workflows/*.yml file changes, skip running unaffected builds. - We need git to be installed for git-version.h generation. --- .github/workflows/cygwin-build.yml | 6 ++++++ .github/workflows/freebsd-build.yml | 8 +++++++- .github/workflows/macos-build.yml | 6 ++++++ .github/workflows/solaris-build.yml | 8 +++++++- .github/workflows/ubuntu-build.yml | 6 ++++++ 5 files changed, 32 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cygwin-build.yml b/.github/workflows/cygwin-build.yml index a9635f2ed..c6afb118b 100644 --- a/.github/workflows/cygwin-build.yml +++ b/.github/workflows/cygwin-build.yml @@ -3,8 +3,14 @@ name: Test rsync on Cygwin on: push: branches: [ master ] + paths-ignore: + - '.github/workflows/*.yml' + - '!.github/workflows/cygwin-build.yml' pull_request: branches: [ master ] + paths-ignore: + - '.github/workflows/*.yml' + - '!.github/workflows/cygwin-build.yml' schedule: - cron: '42 8 * * *' diff --git a/.github/workflows/freebsd-build.yml b/.github/workflows/freebsd-build.yml index d82b160b6..1ac22388a 100644 --- a/.github/workflows/freebsd-build.yml +++ b/.github/workflows/freebsd-build.yml @@ -3,8 +3,14 @@ name: Test rsync on FreeBSD on: push: branches: [ master ] + paths-ignore: + - '.github/workflows/*.yml' + - '!.github/workflows/freebsd-build.yml' pull_request: branches: [ master ] + paths-ignore: + - '.github/workflows/*.yml' + - '!.github/workflows/freebsd-build.yml' schedule: - cron: '42 8 * * *' @@ -22,7 +28,7 @@ jobs: with: usesh: true prepare: | - pkg install -y bash autotools m4 devel/xxhash zstd liblz4 python3 archivers/liblz4 + pkg install -y bash autotools m4 devel/xxhash zstd liblz4 python3 archivers/liblz4 git run: | freebsd-version ./configure --with-rrsync -disable-zstd --disable-md2man --disable-xxhash --disable-lz4 diff --git a/.github/workflows/macos-build.yml b/.github/workflows/macos-build.yml index bb85bb004..5471bf534 100644 --- a/.github/workflows/macos-build.yml +++ b/.github/workflows/macos-build.yml @@ -3,8 +3,14 @@ name: Test rsync on macOS on: push: branches: [ master ] + paths-ignore: + - '.github/workflows/*.yml' + - '!.github/workflows/macos-build.yml' pull_request: branches: [ master ] + paths-ignore: + - '.github/workflows/*.yml' + - '!.github/workflows/macos-build.yml' schedule: - cron: '42 8 * * *' diff --git a/.github/workflows/solaris-build.yml b/.github/workflows/solaris-build.yml index 557a5781e..231fbd4a7 100644 --- a/.github/workflows/solaris-build.yml +++ b/.github/workflows/solaris-build.yml @@ -3,8 +3,14 @@ name: Test rsync on Solaris on: push: branches: [ master ] + paths-ignore: + - '.github/workflows/*.yml' + - '!.github/workflows/solaris-build.yml' pull_request: branches: [ master ] + paths-ignore: + - '.github/workflows/*.yml' + - '!.github/workflows/solaris-build.yml' schedule: - cron: '42 8 * * *' @@ -22,7 +28,7 @@ jobs: with: usesh: true prepare: | - pkg install bash automake gnu-m4 pkg://solaris/runtime/python-35 autoconf gcc + pkg install bash automake gnu-m4 pkg://solaris/runtime/python-35 autoconf gcc git run: | uname -a ./configure --with-rrsync -disable-zstd --disable-md2man --disable-xxhash --disable-lz4 diff --git a/.github/workflows/ubuntu-build.yml b/.github/workflows/ubuntu-build.yml index 60dc8d5f2..1db9a4829 100644 --- a/.github/workflows/ubuntu-build.yml +++ b/.github/workflows/ubuntu-build.yml @@ -3,8 +3,14 @@ name: Test rsync on Ubuntu on: push: branches: [ master ] + paths-ignore: + - '.github/workflows/*.yml' + - '!.github/workflows/ubuntu-build.yml' pull_request: branches: [ master ] + paths-ignore: + - '.github/workflows/*.yml' + - '!.github/workflows/ubuntu-build.yml' schedule: - cron: '42 8 * * *' From 9615a2492bbf96bc145e738ebff55bbb91e0bbee Mon Sep 17 00:00:00 2001 From: vincent sgherzi Date: Fri, 19 Apr 2024 00:54:13 -0700 Subject: [PATCH 045/101] added apple silicon path details --- INSTALL.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/INSTALL.md b/INSTALL.md index 8ef574a54..19d390545 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -232,6 +232,9 @@ not completely implement the "New Sockets" API. [This site][5] says that Apple started to support IPv6 in 10.2 (Jaguar). If your build fails, try again after running configure with `--disable-ipv6`. +Apple Silicon macs may install packages in a slightly different location and require flags. +CFLAGS="-I /opt/homebrew/include" LDFLAGS="-L /opt/homebrew/lib" + [5]: http://www.ipv6.org/impl/mac.html ## IBM AIX notes From 0902b52f6687b1f7952422080d50b93108742e53 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Tue, 29 Oct 2024 22:55:29 -0700 Subject: [PATCH 046/101] Some checksum buffer fixes. - Put sum2_array into sum_struct to hold an array of sum2 checksums that are each xfer_sum_len bytes. - Remove sum2 buf from sum_buf. - Add macro sum2_at() to access each sum2 array element. - Throw an error if a sums header has an s2length larger than xfer_sum_len. --- io.c | 3 ++- match.c | 8 ++++---- rsync.c | 5 ++++- rsync.h | 4 +++- sender.c | 4 +++- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/io.c b/io.c index a99ac0ec5..bb60eecab 100644 --- a/io.c +++ b/io.c @@ -55,6 +55,7 @@ extern int read_batch; extern int compat_flags; extern int protect_args; extern int checksum_seed; +extern int xfer_sum_len; extern int daemon_connection; extern int protocol_version; extern int remove_source_files; @@ -1977,7 +1978,7 @@ void read_sum_head(int f, struct sum_struct *sum) exit_cleanup(RERR_PROTOCOL); } sum->s2length = protocol_version < 27 ? csum_length : (int)read_int(f); - if (sum->s2length < 0 || sum->s2length > MAX_DIGEST_LEN) { + if (sum->s2length < 0 || sum->s2length > xfer_sum_len) { rprintf(FERROR, "Invalid checksum length %d [%s]\n", sum->s2length, who_am_i()); exit_cleanup(RERR_PROTOCOL); diff --git a/match.c b/match.c index cdb30a15e..36e78ed2b 100644 --- a/match.c +++ b/match.c @@ -232,7 +232,7 @@ static void hash_search(int f,struct sum_struct *s, done_csum2 = 1; } - if (memcmp(sum2,s->sums[i].sum2,s->s2length) != 0) { + if (memcmp(sum2, sum2_at(s, i), s->s2length) != 0) { false_alarms++; continue; } @@ -252,7 +252,7 @@ static void hash_search(int f,struct sum_struct *s, if (i != aligned_i) { if (sum != s->sums[aligned_i].sum1 || l != s->sums[aligned_i].len - || memcmp(sum2, s->sums[aligned_i].sum2, s->s2length) != 0) + || memcmp(sum2, sum2_at(s, aligned_i), s->s2length) != 0) goto check_want_i; i = aligned_i; } @@ -271,7 +271,7 @@ static void hash_search(int f,struct sum_struct *s, if (sum != s->sums[i].sum1) goto check_want_i; get_checksum2((char *)map, l, sum2); - if (memcmp(sum2, s->sums[i].sum2, s->s2length) != 0) + if (memcmp(sum2, sum2_at(s, i), s->s2length) != 0) goto check_want_i; /* OK, we have a re-alignment match. Bump the offset * forward to the new match point. */ @@ -290,7 +290,7 @@ static void hash_search(int f,struct sum_struct *s, && (!updating_basis_file || s->sums[want_i].offset >= offset || s->sums[want_i].flags & SUMFLG_SAME_OFFSET) && sum == s->sums[want_i].sum1 - && memcmp(sum2, s->sums[want_i].sum2, s->s2length) == 0) { + && memcmp(sum2, sum2_at(s, want_i), s->s2length) == 0) { /* we've found an adjacent match - the RLL coder * will be happy */ i = want_i; diff --git a/rsync.c b/rsync.c index cd288f57d..b130aba56 100644 --- a/rsync.c +++ b/rsync.c @@ -437,7 +437,10 @@ int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr, cha */ void free_sums(struct sum_struct *s) { - if (s->sums) free(s->sums); + if (s->sums) { + free(s->sums); + free(s->sum2_array); + } free(s); } diff --git a/rsync.h b/rsync.h index d3709fe0f..8ddbe702e 100644 --- a/rsync.h +++ b/rsync.h @@ -958,12 +958,12 @@ struct sum_buf { uint32 sum1; /**< simple checksum */ int32 chain; /**< next hash-table collision */ short flags; /**< flag bits */ - char sum2[SUM_LENGTH]; /**< checksum */ }; struct sum_struct { OFF_T flength; /**< total file length */ struct sum_buf *sums; /**< points to info for each chunk */ + char *sum2_array; /**< checksums of length xfer_sum_len */ int32 count; /**< how many chunks */ int32 blength; /**< block_length */ int32 remainder; /**< flength % block_length */ @@ -982,6 +982,8 @@ struct map_struct { int status; /* first errno from read errors */ }; +#define sum2_at(s, i) ((s)->sum2_array + ((OFF_T)(i) * xfer_sum_len)) + #define NAME_IS_FILE (0) /* filter name as a file */ #define NAME_IS_DIR (1<<0) /* filter name as a dir */ #define NAME_IS_XATTR (1<<2) /* filter name as an xattr */ diff --git a/sender.c b/sender.c index 3d4f052e9..ab2053416 100644 --- a/sender.c +++ b/sender.c @@ -31,6 +31,7 @@ extern int log_before_transfer; extern int stdout_format_has_i; extern int logfile_format_has_i; extern int want_xattr_optim; +extern int xfer_sum_len; extern int csum_length; extern int append_mode; extern int copy_links; @@ -94,10 +95,11 @@ static struct sum_struct *receive_sums(int f) return(s); s->sums = new_array(struct sum_buf, s->count); + s->sum2_array = new_array(char, s->count * xfer_sum_len); for (i = 0; i < s->count; i++) { s->sums[i].sum1 = read_int(f); - read_buf(f, s->sums[i].sum2, s->s2length); + read_buf(f, sum2_at(s, i), s->s2length); s->sums[i].offset = offset; s->sums[i].flags = 0; From 42e2b56c4ede3ab164f9a5c6dae02aa84606a6c1 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Tue, 5 Nov 2024 11:01:03 -0800 Subject: [PATCH 047/101] Another cast when multiplying integers. --- rsync.h | 2 +- sender.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rsync.h b/rsync.h index 8ddbe702e..0f9e277f4 100644 --- a/rsync.h +++ b/rsync.h @@ -982,7 +982,7 @@ struct map_struct { int status; /* first errno from read errors */ }; -#define sum2_at(s, i) ((s)->sum2_array + ((OFF_T)(i) * xfer_sum_len)) +#define sum2_at(s, i) ((s)->sum2_array + ((size_t)(i) * xfer_sum_len)) #define NAME_IS_FILE (0) /* filter name as a file */ #define NAME_IS_DIR (1<<0) /* filter name as a dir */ diff --git a/sender.c b/sender.c index ab2053416..2bbff2faa 100644 --- a/sender.c +++ b/sender.c @@ -95,7 +95,7 @@ static struct sum_struct *receive_sums(int f) return(s); s->sums = new_array(struct sum_buf, s->count); - s->sum2_array = new_array(char, s->count * xfer_sum_len); + s->sum2_array = new_array(char, (size_t)s->count * xfer_sum_len); for (i = 0; i < s->count; i++) { s->sums[i].sum1 = read_int(f); From 8749ec64365dd724b7cb19d892794bdb62fd02c2 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Tue, 5 Nov 2024 11:14:46 -0800 Subject: [PATCH 048/101] Update to newer artifact version. --- .github/workflows/cygwin-build.yml | 2 +- .github/workflows/freebsd-build.yml | 2 +- .github/workflows/solaris-build.yml | 2 +- .github/workflows/ubuntu-build.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cygwin-build.yml b/.github/workflows/cygwin-build.yml index c6afb118b..dc14cb9f5 100644 --- a/.github/workflows/cygwin-build.yml +++ b/.github/workflows/cygwin-build.yml @@ -43,7 +43,7 @@ jobs: - name: ssl file list run: bash -c 'PATH="/usr/local/bin:$PATH" rsync-ssl --no-motd download.samba.org::rsyncftp/ || true' - name: save artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: cygwin-bin path: | diff --git a/.github/workflows/freebsd-build.yml b/.github/workflows/freebsd-build.yml index 1ac22388a..749a6d76f 100644 --- a/.github/workflows/freebsd-build.yml +++ b/.github/workflows/freebsd-build.yml @@ -36,7 +36,7 @@ jobs: ./rsync --version ./rsync-ssl --no-motd download.samba.org::rsyncftp/ || true - name: save artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: freebsd-bin path: | diff --git a/.github/workflows/solaris-build.yml b/.github/workflows/solaris-build.yml index 231fbd4a7..50ba7501d 100644 --- a/.github/workflows/solaris-build.yml +++ b/.github/workflows/solaris-build.yml @@ -36,7 +36,7 @@ jobs: ./rsync --version ./rsync-ssl --no-motd download.samba.org::rsyncftp/ || true - name: save artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: solaris-bin path: | diff --git a/.github/workflows/ubuntu-build.yml b/.github/workflows/ubuntu-build.yml index 1db9a4829..9deb935af 100644 --- a/.github/workflows/ubuntu-build.yml +++ b/.github/workflows/ubuntu-build.yml @@ -43,7 +43,7 @@ jobs: - name: ssl file list run: rsync-ssl --no-motd download.samba.org::rsyncftp/ || true - name: save artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ubuntu-bin path: | From bcf0738f9827d1bd9d49b84192f402928706c518 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Tue, 5 Nov 2024 11:20:17 -0800 Subject: [PATCH 049/101] Indentation tweak. --- options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options.c b/options.c index fd674754c..578507c6e 100644 --- a/options.c +++ b/options.c @@ -2563,7 +2563,7 @@ char *safe_arg(const char *opt, const char *arg) if (escape_leading_tilde) *t++ = '\\'; while (*f) { - if (*f == '\\') { + if (*f == '\\') { if (!is_filename_arg || !strchr(WILD_CHARS, f[1])) *t++ = '\\'; } else if (strchr(escapes, *f)) From 7c3c54b13216ba2beeffc2b95ad3c476574c1f14 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Tue, 5 Nov 2024 11:20:28 -0800 Subject: [PATCH 050/101] Don't force zsh use. --- packaging/branch-from-patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/branch-from-patch b/packaging/branch-from-patch index 440b5835a..40e5653c4 100755 --- a/packaging/branch-from-patch +++ b/packaging/branch-from-patch @@ -154,7 +154,7 @@ def create_branch(patch): s = cmd_run(['git', 'commit', '-a', '-m', f"Creating branch from {patch.name}.diff."]) if not s.returncode: break - s = cmd_run(['/bin/zsh']) + s = cmd_run([os.environ.get('SHELL', '/bin/sh')]) if s.returncode: die('Aborting due to shell error code') From 475ca7d43c659d8c68ef09959fb00dfac7cd3e32 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Tue, 5 Nov 2024 12:42:42 -0800 Subject: [PATCH 051/101] Add helper script for updating samba files. --- Makefile.in | 2 +- packaging/samba-rsync | 85 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) create mode 100755 packaging/samba-rsync diff --git a/Makefile.in b/Makefile.in index d5fefe045..7c75c2617 100644 --- a/Makefile.in +++ b/Makefile.in @@ -358,4 +358,4 @@ doxygen: .PHONY: doxygen-upload doxygen-upload: rsync -avzv $(srcdir)/dox/html/ --delete \ - $${SAMBA_HOST-samba.org}:/home/httpd/html/rsync/doxygen/head/ + $${RSYNC_SAMBA_HOST-samba.org}:/home/httpd/html/rsync/doxygen/head/ diff --git a/packaging/samba-rsync b/packaging/samba-rsync new file mode 100755 index 000000000..c36bf419e --- /dev/null +++ b/packaging/samba-rsync @@ -0,0 +1,85 @@ +#!/bin/sh +# This script makes it easy to update the ftp & html directories on the samba.org server. +# It expects the 2 *_DEST directories to contain updated files that need to be sent to +# the remote server. If these directories don't exist yet, they will be copied from the +# remote server (while also making the html dir a git checkout). + +FTP_SRC="$HOME/samba-rsync-ftp" +HTML_SRC="$HOME/samba-rsync-html" + +FTP_DEST="/home/ftp/pub/rsync" +HTML_DEST="/home/httpd/html/rsync" + +HTML_GIT='git.samba.org:/data/git/rsync-web.git' + +export RSYNC_PARTIAL_DIR='' + +case "$RSYNC_SAMBA_HOST" in + *.samba.org) ;; + *) + echo "You must set RSYNC_SAMBA_HOST in your environment to the samba hostname to use." >&2 + exit 1 + ;; +esac + +case "$1" in + f|-f|ftp|--ftp) MODE=ftp ;; + h|-h|html|--html) MODE=html ;; + '') + echo -n "Update ftp or html? " + read ans + case "$ans" in + f*) MODE=ftp ;; + h*) MODE=html ;; + *) + echo "Invalid answer." >&2 + exit 1 + ;; + esac + ;; + *) + echo "Invalid option: $1" >&2 + exit 1 + ;; +esac + +if [ "$MODE" = ftp ]; then + SRC_DIR="$FTP_SRC" + DEST_DIR="$FTP_DEST" + FILT=".filt" +else + SRC_DIR="$HTML_SRC" + DEST_DIR="$HTML_DEST" + FILT="filt" +fi + +if [ ! -d "$SRC_DIR" ]; then + echo "The directory $SRC_DIR does not exist yet." + echo -n "Do you want to create it? [n] " + read ans + case "$ans" in + y*) ;; + *) exit 1 ;; + esac + OPTS='-aiv' + TMP_FILT="$SRC_DIR/tmp-filt" + if [ "$MODE" = html ]; then + git clone "$HTML_GIT" "$SRC_DIR" + sed -n -e 's/[-P]/H/p' "$SRC_DIR/$FILT" >"$TMP_FILT" + OPTS="${OPTS}f._$TMP_FILT" + fi + rsync "$OPTS" "$RSYNC_SAMBA_HOST:$DEST_DIR/" "$SRC_DIR/" + rm -f "$TMP_FILT" + exit +fi + +cd "$SRC_DIR" || exit 1 +set -- -aivOHP --del -f._$FILT . "$RSYNC_SAMBA_HOST:$DEST_DIR/" + +rsync --dry-run "${@}" | grep -v 'is uptodate$' +echo '' +echo -n "Run without --dry-run? [n] " +read ans +case "$ans" in + y*) rsync "${@}" | grep -v 'is uptodate$' ;; +esac From 4490fb86605aebbd91cd849089362f7173286b51 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Tue, 5 Nov 2024 13:03:04 -0800 Subject: [PATCH 052/101] Add some info for making a release. --- packaging/release-rsync | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/packaging/release-rsync b/packaging/release-rsync index 03d9f6a3e..a00bedbca 100755 --- a/packaging/release-rsync +++ b/packaging/release-rsync @@ -3,7 +3,24 @@ # This script expects the directory ~/samba-rsync-ftp to exist and to be a # copy of the /home/ftp/pub/rsync dir on samba.org. When the script is done, # the git repository in the current directory will be updated, and the local -# ~/samba-rsync-ftp dir will be ready to be rsynced to samba.org. +# ~/samba-rsync-ftp dir will be ready to be rsynced to samba.org. See the +# script samba-rsync for an easy way to initialize the local ftp copy and to +# thereafter update the remote files from your local copy. + +# This script also expects to be able to gpg sign the resulting tar files +# using your default gpg key. Make sure that the html download.html file +# has a link to the relevant keys that are authorized to sign the tar files +# and also make sure that the following commands work as expected: +# +# touch TeMp +# gpg --sign TeMp +# gpg --verify TeMp.gpg +# gpg --sign TeMp +# rm TeMp* +# +# The second time you sign the file it should NOT prompt you for your password +# (unless the timeout period has passed). It will prompt about overriding the +# existing TeMp.gpg file, though. import os, sys, re, argparse, glob, shutil, signal from datetime import datetime From 4320c25fcc9a782f466be9c862cdadde60ffc73f Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Tue, 5 Nov 2024 13:25:34 -0800 Subject: [PATCH 053/101] More helper script improvements. --- packaging/samba-rsync | 99 ++++++++++++++++++++++++++++--------------- packaging/send-news | 33 +++++++++++++++ 2 files changed, 98 insertions(+), 34 deletions(-) create mode 100755 packaging/send-news diff --git a/packaging/samba-rsync b/packaging/samba-rsync index c36bf419e..c1661f46a 100755 --- a/packaging/samba-rsync +++ b/packaging/samba-rsync @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # This script makes it easy to update the ftp & html directories on the samba.org server. # It expects the 2 *_DEST directories to contain updated files that need to be sent to # the remote server. If these directories don't exist yet, they will be copied from the @@ -22,26 +22,39 @@ case "$RSYNC_SAMBA_HOST" in ;; esac -case "$1" in - f|-f|ftp|--ftp) MODE=ftp ;; - h|-h|html|--html) MODE=html ;; - '') - echo -n "Update ftp or html? " - read ans - case "$ans" in - f*) MODE=ftp ;; - h*) MODE=html ;; - *) - echo "Invalid answer." >&2 - exit 1 - ;; - esac - ;; - *) - echo "Invalid option: $1" >&2 - exit 1 - ;; -esac +MODE='' +REVERSE='' +while (( $# )); do + case "$1" in + -R|--reverse) REVERSE=yes ;; + f|ftp) MODE=ftp ;; + h|html) MODE=html ;; + *) + echo "Invalid option: $1" >&2 + exit 1 + ;; + -h|--help) + echo "Usage: [-R] [f|ftp|h|html]" + echo "-R --reverse Copy the files from the server to the local host." + echo "-h --help Output this help message." + exit + ;; + esac + shift +done + +if [ ! "$MODE" ]; then + echo -n "Update ftp or html? " + read ans + case "$ans" in + f*) MODE=ftp ;; + h*) MODE=html ;; + *) + echo "Invalid answer." >&2 + exit 1 + ;; + esac +fi if [ "$MODE" = ftp ]; then SRC_DIR="$FTP_SRC" @@ -53,7 +66,19 @@ else FILT="filt" fi -if [ ! -d "$SRC_DIR" ]; then +function do_rsync { + rsync --dry-run "${@}" | grep -v 'is uptodate$' + echo '' + echo -n "Run without --dry-run? [n] " + read ans + case "$ans" in + y*) rsync "${@}" | grep -v 'is uptodate$' ;; + esac +} + +if [ -d "$SRC_DIR" ]; then + REVERSE_RSYNC=do_rsync +else echo "The directory $SRC_DIR does not exist yet." echo -n "Do you want to create it? [n] " read ans @@ -61,25 +86,31 @@ if [ ! -d "$SRC_DIR" ]; then y*) ;; *) exit 1 ;; esac - OPTS='-aiv' + REVERSE=yes + REVERSE_RSYNC=rsync +fi + +if [ "$REVERSE" = yes ]; then + OPTS='-aivOHP' TMP_FILT="$SRC_DIR/tmp-filt" + echo "Copying files from $RSYNC_SAMBA_HOST to $SRC_DIR ..." if [ "$MODE" = html ]; then - git clone "$HTML_GIT" "$SRC_DIR" + if [ $REVERSE_RSYNC = rsync ]; then + git clone "$HTML_GIT" "$SRC_DIR" + else + cd "$SRC_DIR" || exit 1 + git pull + fi sed -n -e 's/[-P]/H/p' "$SRC_DIR/$FILT" >"$TMP_FILT" OPTS="${OPTS}f._$TMP_FILT" + else + OPTS="${OPTS}f:_$FILT" fi - rsync "$OPTS" "$RSYNC_SAMBA_HOST:$DEST_DIR/" "$SRC_DIR/" + $REVERSE_RSYNC "$OPTS" "$RSYNC_SAMBA_HOST:$DEST_DIR/" "$SRC_DIR/" rm -f "$TMP_FILT" exit fi cd "$SRC_DIR" || exit 1 -set -- -aivOHP --del -f._$FILT . "$RSYNC_SAMBA_HOST:$DEST_DIR/" - -rsync --dry-run "${@}" | grep -v 'is uptodate$' -echo '' -echo -n "Run without --dry-run? [n] " -read ans -case "$ans" in - y*) rsync "${@}" | grep -v 'is uptodate$' ;; -esac +echo "Copying files from $SRC_DIR to $RSYNC_SAMBA_HOST ..." +do_rsync -aivOHP --del -f._$FILT . "$RSYNC_SAMBA_HOST:$DEST_DIR/" diff --git a/packaging/send-news b/packaging/send-news new file mode 100755 index 000000000..c83a74c03 --- /dev/null +++ b/packaging/send-news @@ -0,0 +1,33 @@ +#!/bin/bash -e + +# This script expects the ~/src/rsync directory to contain the rsync +# source that has been updated. It also expects the auto-build-save +# directory to have been created prior to the running of configure so +# that each branch has its own build directory underneath. This supports +# the maintainer workflow for the rsync-patches files maintenace. + +FTP_SRC="$HOME/samba-rsync-ftp" +FTP_DEST="/home/ftp/pub/rsync" +MD_FILES="README.md INSTALL.md NEWS.md" + +case "$RSYNC_SAMBA_HOST" in + *.samba.org) ;; + *) + echo "You must set RSYNC_SAMBA_HOST in your environment to the samba hostname to use." >&2 + exit 1 + ;; +esac + +if [ ! -d "$FTP_SRC" ]; then + packaging/samba-rsync ftp # Ask to initialize the local ftp dir +fi + +cd ~/src/rsync + +make man +./md-convert --dest="$FTP_SRC" $MD_FILES +rsync -aiic $MD_FILES auto-build-save/master/*.?.html "$FTP_SRC" + +cd "$FTP_SRC" + +rsync -aiic README.* INSTALL.* NEWS.* *.?.html "$RSYNC_SAMBA_HOST:$FTP_DEST/" From f7ac7ffd165e20d7d18f3d131cd31226563a5c20 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Tue, 5 Nov 2024 17:34:09 -0800 Subject: [PATCH 054/101] Some minor option/prompt tweaks. --- packaging/samba-rsync | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/packaging/samba-rsync b/packaging/samba-rsync index c1661f46a..8691846a0 100755 --- a/packaging/samba-rsync +++ b/packaging/samba-rsync @@ -29,32 +29,40 @@ while (( $# )); do -R|--reverse) REVERSE=yes ;; f|ftp) MODE=ftp ;; h|html) MODE=html ;; - *) - echo "Invalid option: $1" >&2 - exit 1 - ;; -h|--help) echo "Usage: [-R] [f|ftp|h|html]" echo "-R --reverse Copy the files from the server to the local host." + echo " The default is to update the remote files." echo "-h --help Output this help message." + echo " " + echo "The script will prompt if ftp or html is not specified on the command line." + echo "Only one category can be copied at a time. When pulling html files, a git" + echo "checkout will be either created or updated prior to the rsync copy." exit ;; + *) + echo "Invalid option: $1" >&2 + exit 1 + ;; esac shift done -if [ ! "$MODE" ]; then - echo -n "Update ftp or html? " +while [ ! "$MODE" ]; do + if [ "$REVERSE" = yes ]; then + DIRECTION=FROM + else + DIRECTION=TO + fi + echo -n "Copy which files $DIRECTION the server? ftp or html? " read ans case "$ans" in f*) MODE=ftp ;; h*) MODE=html ;; - *) - echo "Invalid answer." >&2 - exit 1 - ;; + '') exit 1 ;; + *) echo "You must answer f or h to copy the ftp or html data." ;; esac -fi +done if [ "$MODE" = ftp ]; then SRC_DIR="$FTP_SRC" @@ -96,10 +104,10 @@ if [ "$REVERSE" = yes ]; then echo "Copying files from $RSYNC_SAMBA_HOST to $SRC_DIR ..." if [ "$MODE" = html ]; then if [ $REVERSE_RSYNC = rsync ]; then - git clone "$HTML_GIT" "$SRC_DIR" + git clone "$HTML_GIT" "$SRC_DIR" || exit 1 else cd "$SRC_DIR" || exit 1 - git pull + git pull || exit 1 fi sed -n -e 's/[-P]/H/p' "$SRC_DIR/$FILT" >"$TMP_FILT" OPTS="${OPTS}f._$TMP_FILT" From 66015104257ab2b9b28b21411abf0b25a979a954 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sat, 9 Nov 2024 11:05:16 -0800 Subject: [PATCH 055/101] Mention more NEWS. --- NEWS.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 1a88a70d9..a47fdbfcd 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,13 +2,21 @@ ## Changes in this version: +### SECURITY FIXES: + +- Fixed a buffer overflow when the sum2 digest algorithm is SHA1. + ### BUG FIXES: - Fixed the included popt to avoid a memory error on modern gcc versions. ### INTERNAL: - - Updated included popt to version 1.19. +- Updated included popt to version 1.19. + +### DEVELOPER RELATED: + +- Various improvements to the release scripts and git setup. ------------------------------------------------------------------------------ @@ -4776,7 +4784,7 @@ | RELEASE DATE | VER. | DATE OF COMMIT\* | PROTOCOL | |--------------|--------|------------------|-------------| -| ?? Apr 2024 | 3.3.1 | | 31 | +| ?? Nov 2024 | 3.3.1 | | 31 | | 06 Apr 2024 | 3.3.0 | | 31 | | 20 Oct 2022 | 3.2.7 | | 31 | | 09 Sep 2022 | 3.2.6 | | 31 | From 62bb9bba022ce6a29f8c92307d5569c338b2f711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlo=20Marcelo=20Arenas=20Bel=C3=B3n?= Date: Sat, 18 May 2024 17:44:22 -0700 Subject: [PATCH 056/101] acls: correct type/size for orig_umask Since 05278935 (- Call mkdir_defmode() instead of do_mkdir(). - Define orig_umask in this file, not options.c. - Made orig_umask a mode_t, not an int., 2006-02-24), the type for the global was changed, and therefore on systems where sizeof(mode_t) != sizeof(int), writes or reads to them will overflow to adjacent bytes. Change the type to the one used everywhere else and avoid this problem. While at it, silence again a warning that is being triggered by Apple's clang 15. --- acls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acls.c b/acls.c index a2b0ff3ec..bd119e8ee 100644 --- a/acls.c +++ b/acls.c @@ -28,7 +28,7 @@ extern int dry_run; extern int am_root; extern int read_only; extern int list_only; -extern int orig_umask; +extern mode_t orig_umask; extern int numeric_ids; extern int inc_recurse; extern int preserve_devices; @@ -982,7 +982,7 @@ static int set_rsync_acl(const char *fname, acl_duo *duo_item, && !pack_smb_acl(&duo_item->sacl, &duo_item->racl)) return -1; #ifdef HAVE_OSX_ACLS - mode = 0; /* eliminate compiler warning */ + (void)mode; /* eliminate compiler warning */ #else if (type == SMB_ACL_TYPE_ACCESS) { cur_mode = change_sacl_perms(duo_item->sacl, &duo_item->racl, cur_mode, mode); From fa28c5d693da4dcd10ce860558170a885c21dc78 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Thu, 14 Nov 2024 11:39:21 -0800 Subject: [PATCH 057/101] Improve packaging/var-checker. Make var-checker compare the variable type of the extern vars to ensure that they are all consistent. Fix the remaining issues. --- main.c | 2 +- packaging/var-checker | 46 ++++++++++++++++++++++++++++++++++--------- t_stub.c | 2 +- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/main.c b/main.c index 0c60b86d1..4f070accc 100644 --- a/main.c +++ b/main.c @@ -66,7 +66,7 @@ extern int protect_args; extern int relative_paths; extern int sanitize_paths; extern int curr_dir_depth; -extern int curr_dir_len; +extern unsigned int curr_dir_len; extern int module_id; extern int rsync_port; extern int whole_file; diff --git a/packaging/var-checker b/packaging/var-checker index f17c69a29..2b9cc8e50 100755 --- a/packaging/var-checker +++ b/packaging/var-checker @@ -6,9 +6,10 @@ import os, sys, re, argparse, glob -VARS_RE = re.compile(r'^(?!(?:extern|enum)\s)([a-zA-Z]\S*\s+.*);', re.M) +VARS_RE = re.compile(r'^(?!(?:extern|enum)\s)([a-zA-Z][^ \n\t:]*\s+.*);', re.M) EXTERNS_RE = re.compile(r'^extern\s+(.*);', re.M) +types = { } sizes = { } def main(): @@ -68,19 +69,46 @@ def parse_vars(fn, lines): for line in lines: line = re.sub(r'\s*\{.*\}', '', line) line = re.sub(r'\s*\(.*\)', '', line) - for item in re.split(r'\s*,\s*', line): - item = re.sub(r'\s*=.*', '', item) - m = re.search(r'(?P\w+)(?P\[.*?\])?$', item) + line = re.sub(r'\s*=\s*[^,]*', '', line) + m = re.search(r'^(?:(?:static|extern)\s+)?(?P[^\[,]+?)(?P\w+([\[,].+)?)$', line) + if not m: + print(f"Bogus match? ({line})") + continue + items = m['vars'] + main_type = m['type'].strip() + mt_len = len(main_type) + main_type = main_type.rstrip('*') + first_stars = '*' * (mt_len - len(main_type)) + if first_stars: + main_type = main_type.rstrip() + items = first_stars + items + for item in re.split(r'\s*,\s*', items): + m = re.search(r'(?P\*+\s*)?(?P\w+)(?P\[.*?\])?$', item) if not m: print(f"Bogus match? ({item})") continue - if m['sz']: - if m['var'] in sizes: - if sizes[m['var']] != m['sz']: + typ = main_type + if m['stars']: + typ = typ + m['stars'].strip() + chk = [ + 'type', typ, types, + 'size', m['sz'], sizes, + ] + while chk: + label = chk.pop(0) + new = chk.pop(0) + lst = chk.pop(0) + if not new: + continue + if label == 'type': + new = ' '.join(new.split()).replace(' *', '*') + if m['var'] in lst: + old = lst[m['var']] + if new != old: var = m['var'] - print(fn, f'has inconsistent size for "{var}":', m['sz'], 'vs', sizes[var]) + print(fn, f'has inconsistent {label} for "{var}":', new, 'vs', old) else: - sizes[m['var']] = m['sz'] + lst[m['var']] = new ret.append(m['var']) return ret diff --git a/t_stub.c b/t_stub.c index 085378a82..eee927299 100644 --- a/t_stub.c +++ b/t_stub.c @@ -28,7 +28,7 @@ int preallocate_files = 0; int protect_args = 0; int module_id = -1; int relative_paths = 0; -int module_dirlen = 0; +unsigned int module_dirlen = 0; int preserve_xattrs = 0; int preserve_perms = 0; int preserve_executability = 0; From 83ad3533d487aeaf80051c74a0e52239bf85d273 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Thu, 14 Nov 2024 11:53:40 -0800 Subject: [PATCH 058/101] Always check old==new, even for missing array size. --- packaging/var-checker | 2 -- 1 file changed, 2 deletions(-) diff --git a/packaging/var-checker b/packaging/var-checker index 2b9cc8e50..1573895c0 100755 --- a/packaging/var-checker +++ b/packaging/var-checker @@ -98,8 +98,6 @@ def parse_vars(fn, lines): label = chk.pop(0) new = chk.pop(0) lst = chk.pop(0) - if not new: - continue if label == 'type': new = ' '.join(new.split()).replace(' *', '*') if m['var'] in lst: From f654e47691629c7516095518dec4234a689a8351 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Thu, 14 Nov 2024 11:59:12 -0800 Subject: [PATCH 059/101] Mention latest NEWS. --- NEWS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS.md b/NEWS.md index a47fdbfcd..8864d6d74 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,6 +10,8 @@ - Fixed the included popt to avoid a memory error on modern gcc versions. +- Fixed an incorrect extern variable's type that caused an ACL issue on macOS. + ### INTERNAL: - Updated included popt to version 1.19. @@ -18,6 +20,8 @@ - Various improvements to the release scripts and git setup. +- Improved packaging/var-checker to identify variable type issues. + ------------------------------------------------------------------------------ # NEWS for rsync 3.3.0 (6 Apr 2024) From 48d51a1370f0facb54fa80864077fd7d769cb03d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Holger=20Hoffst=C3=A4tte?= Date: Mon, 4 Sep 2023 14:00:20 +0200 Subject: [PATCH 060/101] Fix __m128i_u / __m256i_u alignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building with clang-16 complains with: ./simd-checksum-x86_64.cpp:204:25: warning: passing 1-byte aligned argument to 16-byte aligned parameter 1 of '_mm_store_si128' may result in an unaligned pointer access [-Walign-mismatch] Signed-off-by: Holger Hoffstätte --- simd-checksum-x86_64.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/simd-checksum-x86_64.cpp b/simd-checksum-x86_64.cpp index 33f26e920..d649091ea 100644 --- a/simd-checksum-x86_64.cpp +++ b/simd-checksum-x86_64.cpp @@ -68,8 +68,8 @@ #endif // Missing from the headers on gcc 6 and older, clang 8 and older -typedef long long __m128i_u __attribute__((__vector_size__(16), __may_alias__, __aligned__(1))); -typedef long long __m256i_u __attribute__((__vector_size__(32), __may_alias__, __aligned__(1))); +typedef long long __m128i_u __attribute__((__vector_size__(16), __may_alias__, __aligned__(16))); +typedef long long __m256i_u __attribute__((__vector_size__(32), __may_alias__, __aligned__(16))); /* Compatibility macros to let our SSSE3 algorithm run with only SSE2. These used to be neat individual functions with target attributes switching between SSE2 and SSSE3 implementations From e55b190f4a7c0f9d942bc50be00ab176e3c4dc90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Holger=20Hoffst=C3=A4tte?= Date: Mon, 4 Sep 2023 14:05:21 +0200 Subject: [PATCH 061/101] Fix warning about missing bomb(..) prototype MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clang rightfully complains about invoking bomb(..) without a proper prototype: lib/pool_alloc.c:171:16: warning: passing arguments to a function without a prototype is deprecated in all versions of C and is not supported in C2x [-Wdeprecated-non-prototype] (*pool->bomb)(bomb_msg, __FILE__, __LINE__); ^ 1 warning generated. Signed-off-by: Holger Hoffstätte --- lib/pool_alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pool_alloc.c b/lib/pool_alloc.c index a1a7245f6..bc1cc1a6b 100644 --- a/lib/pool_alloc.c +++ b/lib/pool_alloc.c @@ -9,7 +9,7 @@ struct alloc_pool size_t size; /* extent size */ size_t quantum; /* allocation quantum */ struct pool_extent *extents; /* top extent is "live" */ - void (*bomb)(); /* called if malloc fails */ + void (*bomb)(const char*, const char*, int); /* called if malloc fails */ int flags; /* statistical data */ From 07069880a21bd43dbc3b240e87ba6699c8725baa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Holger=20Hoffst=C3=A4tte?= Date: Mon, 4 Sep 2023 14:07:14 +0200 Subject: [PATCH 062/101] Fix warning about conflicting lseek/lseek64 prototypes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clang rightfully complains about conflicting prototypes, as both lseek() variants are redefined: syscall.c:394:10: warning: a function declaration without a prototype is deprecated in all versions of C and is treated as a zero-parameter prototype in C2x, conflicting with a previous declaration [-Wdeprecated-non-prototype] off64_t lseek64(); ^ /usr/include/unistd.h:350:18: note: conflicting prototype is here extern __off64_t lseek64 (int __fd, __off64_t __offset, int __whence) ^ 1 warning generated. The point of the #ifdef is to build for the configured OFF_T; there is no reason to redefine lseek/lseek64, which should have been found via configure. Signed-off-by: Holger Hoffstätte --- syscall.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/syscall.c b/syscall.c index d92074aaa..b4b0f1f16 100644 --- a/syscall.c +++ b/syscall.c @@ -388,11 +388,6 @@ int do_fstat(int fd, STRUCT_STAT *st) OFF_T do_lseek(int fd, OFF_T offset, int whence) { #ifdef HAVE_LSEEK64 -#if !SIZEOF_OFF64_T - OFF_T lseek64(); -#else - off64_t lseek64(); -#endif return lseek64(fd, offset, whence); #else return lseek(fd, offset, whence); From 990fa5c1e1abe3ef09a32115c4817f9a5fa3a797 Mon Sep 17 00:00:00 2001 From: Samuel Henrique Date: Fri, 29 Dec 2023 15:23:27 +0000 Subject: [PATCH 063/101] rrsync: fix wrong parameter name in manpage SYNOPSIS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace ¨rw¨ with ¨ro¨. Reported on Debian by Adriano Rafael Gomes --- support/rrsync.1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/support/rrsync.1.md b/support/rrsync.1.md index 5f33930e2..09b2f2822 100644 --- a/support/rrsync.1.md +++ b/support/rrsync.1.md @@ -5,7 +5,7 @@ rrsync - a script to setup restricted rsync users via ssh logins ## SYNOPSIS ``` -rrsync [-ro|-rw] [-munge] [-no-del] [-no-lock] [-no-overwrite] DIR +rrsync [-ro|-wo] [-munge] [-no-del] [-no-lock] [-no-overwrite] DIR ``` The single non-option argument specifies the restricted _DIR_ to use. It can be From c9fe6ca30472b3ca22adb5550f6751334934e12f Mon Sep 17 00:00:00 2001 From: Rose <83477269+AtariDreams@users.noreply.github.com> Date: Wed, 3 May 2023 09:52:18 -0400 Subject: [PATCH 064/101] Introduce PTR_SUB This is more intuitive than adding a negative number. --- lib/pool_alloc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/pool_alloc.c b/lib/pool_alloc.c index bc1cc1a6b..b49e3a7bd 100644 --- a/lib/pool_alloc.c +++ b/lib/pool_alloc.c @@ -42,6 +42,7 @@ struct align_test { /* Temporarily cast a void* var into a char* var when adding an offset (to * keep some compilers from complaining about the pointer arithmetic). */ #define PTR_ADD(b,o) ( (void*) ((char*)(b) + (o)) ) +#define PTR_SUB(b,o) ( (void*) ((char*)(b) - (o)) ) alloc_pool_t pool_create(size_t size, size_t quantum, void (*bomb)(const char*, const char*, int), int flags) @@ -100,7 +101,7 @@ pool_destroy(alloc_pool_t p) for (cur = pool->extents; cur; cur = next) { next = cur->next; if (pool->flags & POOL_PREPEND) - free(PTR_ADD(cur->start, -sizeof (struct pool_extent))); + free(PTR_SUB(cur->start, sizeof (struct pool_extent))); else { free(cur->start); free(cur); @@ -235,7 +236,7 @@ pool_free(alloc_pool_t p, size_t len, void *addr) if (cur->free + cur->bound >= pool->size) { prev->next = cur->next; if (pool->flags & POOL_PREPEND) - free(PTR_ADD(cur->start, -sizeof (struct pool_extent))); + free(PTR_SUB(cur->start, sizeof (struct pool_extent))); else { free(cur->start); free(cur); @@ -292,7 +293,7 @@ pool_free_old(alloc_pool_t p, void *addr) while ((cur = next) != NULL) { next = cur->next; if (pool->flags & POOL_PREPEND) - free(PTR_ADD(cur->start, -sizeof (struct pool_extent))); + free(PTR_SUB(cur->start, sizeof (struct pool_extent))); else { free(cur->start); free(cur); From 1a95869dfcd966f3efef0aec07d1c787633ea638 Mon Sep 17 00:00:00 2001 From: Colin Watson Date: Fri, 29 Mar 2024 01:24:32 +0000 Subject: [PATCH 065/101] Allow basic connectivity check via rrsync rsbackup (https://github.com/ewxrjk/rsbackup) uses "ssh true" to check that the host in question is reachable. I like to configure my backed-up hosts to force the backup system to go via `rrsync`, but I always have to add a local tweak to allow `SSH_ORIGINAL_COMMAND=true` to work. I think this would be safe enough to include in rrsync. --- support/rrsync | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/support/rrsync b/support/rrsync index 4b4b87c55..e8b0cc0d2 100755 --- a/support/rrsync +++ b/support/rrsync @@ -156,6 +156,10 @@ def main(): command = os.environ.get('SSH_ORIGINAL_COMMAND', None) if not command: die("Not invoked via sshd") + if command == 'true': + # Allow checking connectivity with "ssh true". (For example, + # rsbackup uses this.) + sys.exit(0) command = command.split(' ', 2) if command[0:1] != ['rsync']: die("SSH_ORIGINAL_COMMAND does not run rsync") From 6f10f125778c87a494509f5612fc43869791d469 Mon Sep 17 00:00:00 2001 From: Romain Geissler Date: Sun, 10 Mar 2024 22:41:43 +0000 Subject: [PATCH 066/101] When not using the builtin zlib, link it before linking libcrypto, as libcrypto depends on zlib. This prevents "undefined symbol" errors which might arise from libcrypto.a if linking openssl statically. --- configure.ac | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/configure.ac b/configure.ac index 390c5961c..d2bcb471e 100644 --- a/configure.ac +++ b/configure.ac @@ -424,6 +424,26 @@ case $host_os in * ) AC_MSG_RESULT(no);; esac +# We default to using our zlib unless --with-included-zlib=no is given. +if test x"$with_included_zlib" != x"no"; then + with_included_zlib=yes +elif test x"$ac_cv_header_zlib_h" != x"yes"; then + with_included_zlib=yes +fi +if test x"$with_included_zlib" != x"yes"; then + AC_CHECK_LIB(z, deflateParams, , [with_included_zlib=yes]) +fi + +AC_MSG_CHECKING([whether to use included zlib]) +if test x"$with_included_zlib" = x"yes"; then + AC_MSG_RESULT($srcdir/zlib) + BUILD_ZLIB='$(zlib_OBJS)' + CFLAGS="-I$srcdir/zlib $CFLAGS" +else + AC_DEFINE(EXTERNAL_ZLIB, 1, [Define to 1 if using external zlib]) + AC_MSG_RESULT(no) +fi + AC_MSG_CHECKING([whether to enable use of openssl crypto library]) AC_ARG_ENABLE([openssl], AS_HELP_STRING([--disable-openssl],[disable to omit openssl crypto library])) @@ -1096,26 +1116,6 @@ else AC_MSG_RESULT(no) fi -# We default to using our zlib unless --with-included-zlib=no is given. -if test x"$with_included_zlib" != x"no"; then - with_included_zlib=yes -elif test x"$ac_cv_header_zlib_h" != x"yes"; then - with_included_zlib=yes -fi -if test x"$with_included_zlib" != x"yes"; then - AC_CHECK_LIB(z, deflateParams, , [with_included_zlib=yes]) -fi - -AC_MSG_CHECKING([whether to use included zlib]) -if test x"$with_included_zlib" = x"yes"; then - AC_MSG_RESULT($srcdir/zlib) - BUILD_ZLIB='$(zlib_OBJS)' - CFLAGS="-I$srcdir/zlib $CFLAGS" -else - AC_DEFINE(EXTERNAL_ZLIB, 1, [Define to 1 if using external zlib]) - AC_MSG_RESULT(no) -fi - AC_CACHE_CHECK([for unsigned char],rsync_cv_SIGNED_CHAR_OK,[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[signed char *s = (signed char *)""]])],[rsync_cv_SIGNED_CHAR_OK=yes],[rsync_cv_SIGNED_CHAR_OK=no])]) if test x"$rsync_cv_SIGNED_CHAR_OK" = x"yes"; then From 321dd78f8cbdb5d01fa8628eb872e967f19e0883 Mon Sep 17 00:00:00 2001 From: Frederic Grabowski Date: Fri, 10 May 2024 10:49:56 +0200 Subject: [PATCH 067/101] fix typo in manual page --- rsync.1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rsync.1.md b/rsync.1.md index 4407a013f..7e40e3617 100644 --- a/rsync.1.md +++ b/rsync.1.md @@ -3995,7 +3995,7 @@ option (though the 2 commands behave differently if deletions are enabled): > rsync -aiR x/y/file.txt host:/tmp/ The following command does not need an include of the "x" directory because it -is not a part of the transfer (note the traililng slash). Running this command +is not a part of the transfer (note the trailing slash). Running this command would copy just "`/tmp/x/file.txt`" because the "y" and "z" dirs get excluded: > rsync -ai -f'+ file.txt' -f'- *' x/ host:/tmp/x/ From 2b38542e0d3fda8081e06368196248b3b0070819 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 14 Dec 2024 14:23:30 +1100 Subject: [PATCH 068/101] added security email address to README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 82db21575..eb400592a 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,7 @@ page of the web site. Alternately, email your bug report to . +For security issues please email details of the issue to . GIT REPOSITORY -------------- From 36212021f0b8f64d28a5713f6b485f97857187f1 Mon Sep 17 00:00:00 2001 From: Charalampos Mitrodimas Date: Wed, 20 Nov 2024 14:55:50 +0200 Subject: [PATCH 069/101] hlink: Fix function pointer cast in qsort() Replace unsafe generic function pointer cast with proper type cast for qsort() comparison function. This fixes a potential type mismatch warning without changing the behavior. Signed-off-by: Charalampos Mitrodimas --- hlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hlink.c b/hlink.c index 20291f267..2c14407ad 100644 --- a/hlink.c +++ b/hlink.c @@ -117,7 +117,7 @@ static void match_gnums(int32 *ndx_list, int ndx_count) struct ht_int32_node *node = NULL; int32 gnum, gnum_next; - qsort(ndx_list, ndx_count, sizeof ndx_list[0], (int (*)()) hlink_compare_gnum); + qsort(ndx_list, ndx_count, sizeof ndx_list[0], (int (*)(const void*, const void*))hlink_compare_gnum); for (from = 0; from < ndx_count; from++) { file = hlink_flist->sorted[ndx_list[from]]; From 589b0691e59f761ccb05ddb8e1124991440db2c7 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 14 Nov 2024 09:57:08 +1100 Subject: [PATCH 070/101] prevent information leak off the stack prevent leak of uninitialised stack data in hash_search --- match.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/match.c b/match.c index 36e78ed2b..dfd6af2c9 100644 --- a/match.c +++ b/match.c @@ -147,6 +147,9 @@ static void hash_search(int f,struct sum_struct *s, int more; schar *map; + // prevent possible memory leaks + memset(sum2, 0, sizeof sum2); + /* want_i is used to encourage adjacent matches, allowing the RLL * coding of the output to work more efficiently. */ want_i = 0; From 8ad4b5d912fad1df29717dddaa775724da77d299 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 23 Nov 2024 11:08:03 +1100 Subject: [PATCH 071/101] refuse fuzzy options when fuzzy not selected this prevents a malicious server providing a file to compare to when the user has not given the fuzzy option --- receiver.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/receiver.c b/receiver.c index 6b4b369ee..2d7f60330 100644 --- a/receiver.c +++ b/receiver.c @@ -66,6 +66,7 @@ extern char sender_file_sum[MAX_DIGEST_LEN]; extern struct file_list *cur_flist, *first_flist, *dir_flist; extern filter_rule_list daemon_filter_list; extern OFF_T preallocated_len; +extern int fuzzy_basis; extern struct name_num_item *xfer_sum_nni; extern int xfer_sum_len; @@ -716,6 +717,10 @@ int recv_files(int f_in, int f_out, char *local_name) fnamecmp = get_backup_name(fname); break; case FNAMECMP_FUZZY: + if (fuzzy_basis == 0) { + rprintf(FERROR_XFER, "rsync: refusing malicious fuzzy operation for %s\n", xname); + exit_cleanup(RERR_PROTOCOL); + } if (file->dirname) { pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, file->dirname, xname); fnamecmp = fnamecmpbuf; From b4a27ca25d0abb6fcf14f41b7e11f3a6e1d8a4ff Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 23 Nov 2024 12:26:10 +1100 Subject: [PATCH 072/101] added secure_relative_open() this is an open that enforces no symlink following for all path components in a relative path --- syscall.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/syscall.c b/syscall.c index b4b0f1f16..cffc814b7 100644 --- a/syscall.c +++ b/syscall.c @@ -33,6 +33,8 @@ #include #endif +#include "ifuncs.h" + extern int dry_run; extern int am_root; extern int am_sender; @@ -707,3 +709,75 @@ int do_open_nofollow(const char *pathname, int flags) return fd; } + +/* + open a file relative to a base directory. The basedir can be NULL, + in which case the current working directory is used. The relpath + must be a relative path, and the relpath must not contain any + elements in the path which follow symlinks (ie. like O_NOFOLLOW, but + applies to all path components, not just the last component) +*/ +int secure_relative_open(const char *basedir, const char *relpath, int flags, mode_t mode) +{ + if (!relpath || relpath[0] == '/') { + // must be a relative path + errno = EINVAL; + return -1; + } + +#if !defined(O_NOFOLLOW) || !defined(O_DIRECTORY) + // really old system, all we can do is live with the risks + if (!basedir) { + return open(relpath, flags, mode); + } + char fullpath[MAXPATHLEN]; + pathjoin(fullpath, sizeof fullpath, basedir, relpath); + return open(fullpath, flags, mode); +#else + int dirfd = AT_FDCWD; + if (basedir != NULL) { + dirfd = openat(AT_FDCWD, basedir, O_RDONLY | O_DIRECTORY); + if (dirfd == -1) { + return -1; + } + } + int retfd = -1; + + char *path_copy = my_strdup(relpath, __FILE__, __LINE__); + if (!path_copy) { + return -1; + } + + for (const char *part = strtok(path_copy, "/"); + part != NULL; + part = strtok(NULL, "/")) + { + int next_fd = openat(dirfd, part, O_RDONLY | O_DIRECTORY | O_NOFOLLOW); + if (next_fd == -1 && errno == ENOTDIR) { + if (strtok(NULL, "/") != NULL) { + // this is not the last component of the path + errno = ELOOP; + goto cleanup; + } + // this could be the last component of the path, try as a file + retfd = openat(dirfd, part, flags | O_NOFOLLOW, mode); + goto cleanup; + } + if (next_fd == -1) { + goto cleanup; + } + if (dirfd != AT_FDCWD) close(dirfd); + dirfd = next_fd; + } + + // the path must be a directory + errno = EINVAL; + +cleanup: + free(path_copy); + if (dirfd != AT_FDCWD) { + close(dirfd); + } + return retfd; +#endif // O_NOFOLLOW, O_DIRECTORY +} From c35e28331f10ba6eba370611abd78bde32d54da7 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 23 Nov 2024 12:28:13 +1100 Subject: [PATCH 073/101] receiver: use secure_relative_open() for basis file this prevents attacks where the basis file is manipulated by a malicious sender to gain information about files outside the destination tree --- receiver.c | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/receiver.c b/receiver.c index 2d7f60330..8031b8f4b 100644 --- a/receiver.c +++ b/receiver.c @@ -552,6 +552,8 @@ int recv_files(int f_in, int f_out, char *local_name) progress_init(); while (1) { + const char *basedir = NULL; + cleanup_disable(); /* This call also sets cur_flist. */ @@ -722,27 +724,29 @@ int recv_files(int f_in, int f_out, char *local_name) exit_cleanup(RERR_PROTOCOL); } if (file->dirname) { - pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, file->dirname, xname); - fnamecmp = fnamecmpbuf; - } else - fnamecmp = xname; + basedir = file->dirname; + } + fnamecmp = xname; break; default: if (fnamecmp_type > FNAMECMP_FUZZY && fnamecmp_type-FNAMECMP_FUZZY <= basis_dir_cnt) { fnamecmp_type -= FNAMECMP_FUZZY + 1; if (file->dirname) { - stringjoin(fnamecmpbuf, sizeof fnamecmpbuf, - basis_dir[fnamecmp_type], "/", file->dirname, "/", xname, NULL); - } else - pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basis_dir[fnamecmp_type], xname); + pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basis_dir[fnamecmp_type], file->dirname); + basedir = fnamecmpbuf; + } else { + basedir = basis_dir[fnamecmp_type]; + } + fnamecmp = xname; } else if (fnamecmp_type >= basis_dir_cnt) { rprintf(FERROR, "invalid basis_dir index: %d.\n", fnamecmp_type); exit_cleanup(RERR_PROTOCOL); - } else - pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basis_dir[fnamecmp_type], fname); - fnamecmp = fnamecmpbuf; + } else { + basedir = basis_dir[fnamecmp_type]; + fnamecmp = fname; + } break; } if (!fnamecmp || (daemon_filter_list.head @@ -765,7 +769,7 @@ int recv_files(int f_in, int f_out, char *local_name) } /* open the file */ - fd1 = do_open(fnamecmp, O_RDONLY, 0); + fd1 = secure_relative_open(basedir, fnamecmp, O_RDONLY, 0); if (fd1 == -1 && protocol_version < 29) { if (fnamecmp != fname) { @@ -776,14 +780,20 @@ int recv_files(int f_in, int f_out, char *local_name) if (fd1 == -1 && basis_dir[0]) { /* pre-29 allowed only one alternate basis */ - pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, - basis_dir[0], fname); - fnamecmp = fnamecmpbuf; + basedir = basis_dir[0]; + fnamecmp = fname; fnamecmp_type = FNAMECMP_BASIS_DIR_LOW; - fd1 = do_open(fnamecmp, O_RDONLY, 0); + fd1 = secure_relative_open(basedir, fnamecmp, O_RDONLY, 0); } } + if (basedir) { + // for the following code we need the full + // path name as a single string + pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basedir, fnamecmp); + fnamecmp = fnamecmpbuf; + } + one_inplace = inplace_partial && fnamecmp_type == FNAMECMP_PARTIAL_DIR; updating_basis_or_equiv = one_inplace || (inplace && (fnamecmp == fname || fnamecmp_type == FNAMECMP_BACKUP)); From 9f86ddc9652247233f32b241a79d5aa4fb9d4afa Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 26 Nov 2024 09:16:31 +1100 Subject: [PATCH 074/101] disallow ../ elements in relpath for secure_relative_open --- syscall.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/syscall.c b/syscall.c index cffc814b7..081357bb9 100644 --- a/syscall.c +++ b/syscall.c @@ -716,6 +716,8 @@ int do_open_nofollow(const char *pathname, int flags) must be a relative path, and the relpath must not contain any elements in the path which follow symlinks (ie. like O_NOFOLLOW, but applies to all path components, not just the last component) + + The relpath must also not contain any ../ elements in the path */ int secure_relative_open(const char *basedir, const char *relpath, int flags, mode_t mode) { @@ -724,6 +726,11 @@ int secure_relative_open(const char *basedir, const char *relpath, int flags, mo errno = EINVAL; return -1; } + if (strncmp(relpath, "../", 3) == 0 || strstr(relpath, "/../")) { + // no ../ elements allowed in the relpath + errno = EINVAL; + return -1; + } #if !defined(O_NOFOLLOW) || !defined(O_DIRECTORY) // really old system, all we can do is live with the risks From 688f5c379a433038bde36897a156d589be373a98 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Thu, 14 Nov 2024 15:46:50 -0800 Subject: [PATCH 075/101] Refuse a duplicate dirlist. --- flist.c | 9 +++++++++ rsync.h | 1 + 2 files changed, 10 insertions(+) diff --git a/flist.c b/flist.c index 464d556ec..847b10548 100644 --- a/flist.c +++ b/flist.c @@ -2584,6 +2584,15 @@ struct file_list *recv_file_list(int f, int dir_ndx) init_hard_links(); #endif + if (inc_recurse && dir_ndx >= 0) { + struct file_struct *file = dir_flist->files[dir_ndx]; + if (file->flags & FLAG_GOT_DIR_FLIST) { + rprintf(FERROR_XFER, "rsync: refusing malicious duplicate flist for dir %d\n", dir_ndx); + exit_cleanup(RERR_PROTOCOL); + } + file->flags |= FLAG_GOT_DIR_FLIST; + } + flist = flist_new(0, "recv_file_list"); flist_expand(flist, FLIST_START_LARGE); diff --git a/rsync.h b/rsync.h index 0f9e277f4..b9a7101a7 100644 --- a/rsync.h +++ b/rsync.h @@ -84,6 +84,7 @@ #define FLAG_DUPLICATE (1<<4) /* sender */ #define FLAG_MISSING_DIR (1<<4) /* generator */ #define FLAG_HLINKED (1<<5) /* receiver/generator (checked on all types) */ +#define FLAG_GOT_DIR_FLIST (1<<5)/* sender/receiver/generator - dir_flist only */ #define FLAG_HLINK_FIRST (1<<6) /* receiver/generator (w/FLAG_HLINKED) */ #define FLAG_IMPLIED_DIR (1<<6) /* sender/receiver/generator (dirs only) */ #define FLAG_HLINK_LAST (1<<7) /* receiver/generator */ From 344327385fa47fa5bb67a32c237735e6240cfb93 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 26 Nov 2024 16:12:45 +1100 Subject: [PATCH 076/101] range check dir_ndx before use --- flist.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/flist.c b/flist.c index 847b10548..087f9da6c 100644 --- a/flist.c +++ b/flist.c @@ -2585,6 +2585,10 @@ struct file_list *recv_file_list(int f, int dir_ndx) #endif if (inc_recurse && dir_ndx >= 0) { + if (dir_ndx >= dir_flist->used) { + rprintf(FERROR_XFER, "rsync: refusing invalid dir_ndx %u >= %u\n", dir_ndx, dir_flist->used); + exit_cleanup(RERR_PROTOCOL); + } struct file_struct *file = dir_flist->files[dir_ndx]; if (file->flags & FLAG_GOT_DIR_FLIST) { rprintf(FERROR_XFER, "rsync: refusing malicious duplicate flist for dir %d\n", dir_ndx); From 407c71c7ce562137230e8ba19149c81ccc47c387 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 23 Nov 2024 15:15:53 +1100 Subject: [PATCH 077/101] make --safe-links stricter when --safe-links is used also reject links where a '../' component is included in the destination as other than the leading part of the filename --- testsuite/safe-links.test | 55 ++++++++++++++++++++++++++++++++++++ testsuite/unsafe-byname.test | 2 +- util1.c | 26 ++++++++++++++++- 3 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 testsuite/safe-links.test diff --git a/testsuite/safe-links.test b/testsuite/safe-links.test new file mode 100644 index 000000000..6e95a4b93 --- /dev/null +++ b/testsuite/safe-links.test @@ -0,0 +1,55 @@ +#!/bin/sh + +. "$suitedir/rsync.fns" + +test_symlink() { + is_a_link "$1" || test_fail "File $1 is not a symlink" +} + +test_regular() { + if [ ! -f "$1" ]; then + test_fail "File $1 is not regular file or not exists" + fi +} + +test_notexist() { + if [ -e "$1" ]; then + test_fail "File $1 exists" + fi + if [ -h "$1" ]; then + test_fail "File $1 exists as a symlink" + fi +} + +cd "$tmpdir" + +mkdir from + +mkdir "from/safe" +mkdir "from/unsafe" + +mkdir "from/safe/files" +mkdir "from/safe/links" + +touch "from/safe/files/file1" +touch "from/safe/files/file2" +touch "from/unsafe/unsafefile" + +ln -s ../files/file1 "from/safe/links/" +ln -s ../files/file2 "from/safe/links/" +ln -s ../../unsafe/unsafefile "from/safe/links/" +ln -s a/a/a/../../../unsafe2 "from/safe/links/" + +#echo "LISTING FROM" +#ls -lR from + +echo "rsync with relative path and just -a" +$RSYNC -avv --safe-links from/safe/ to + +#echo "LISTING TO" +#ls -lR to + +test_symlink to/links/file1 +test_symlink to/links/file2 +test_notexist to/links/unsafefile +test_notexist to/links/unsafe2 diff --git a/testsuite/unsafe-byname.test b/testsuite/unsafe-byname.test index 75e720145..d2e318ef4 100644 --- a/testsuite/unsafe-byname.test +++ b/testsuite/unsafe-byname.test @@ -40,7 +40,7 @@ test_unsafe ..//../dest from/dir unsafe test_unsafe .. from/file safe test_unsafe ../.. from/file unsafe test_unsafe ..//.. from//file unsafe -test_unsafe dir/.. from safe +test_unsafe dir/.. from unsafe test_unsafe dir/../.. from unsafe test_unsafe dir/..//.. from unsafe diff --git a/util1.c b/util1.c index da50ff1e8..f260d3980 100644 --- a/util1.c +++ b/util1.c @@ -1318,7 +1318,14 @@ int handle_partial_dir(const char *fname, int create) * * "src" is the top source directory currently applicable at the level * of the referenced symlink. This is usually the symlink's full path - * (including its name), as referenced from the root of the transfer. */ + * (including its name), as referenced from the root of the transfer. + * + * NOTE: this also rejects dest names with a .. component in other + * than the first component of the name ie. it rejects names such as + * a/b/../x/y. This needs to be done as the leading subpaths 'a' or + * 'b' could later be replaced with symlinks such as a link to '.' + * resulting in the link being transferred now becoming unsafe + */ int unsafe_symlink(const char *dest, const char *src) { const char *name, *slash; @@ -1328,6 +1335,23 @@ int unsafe_symlink(const char *dest, const char *src) if (!dest || !*dest || *dest == '/') return 1; + // reject destinations with /../ in the name other than at the start of the name + const char *dest2 = dest; + while (strncmp(dest2, "../", 3) == 0) { + dest2 += 3; + while (*dest2 == '/') { + // allow for ..//..///../foo + dest2++; + } + } + if (strstr(dest2, "/../")) + return 1; + + // reject if the destination ends in /.. + const size_t dlen = strlen(dest); + if (dlen > 3 && strcmp(&dest[dlen-3], "/..") == 0) + return 1; + /* find out what our safety margin is */ for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) { /* ".." segment starts the count over. "." segment is ignored. */ From 0590b09d9a34ae72741b91ec0708a820650198b0 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 18 Dec 2024 08:59:42 +1100 Subject: [PATCH 078/101] fixed symlink race condition in sender when we open a file that we don't expect to be a symlink use O_NOFOLLOW to prevent a race condition where an attacker could change a file between being a normal file and a symlink --- checksum.c | 2 +- flist.c | 2 +- generator.c | 4 ++-- receiver.c | 2 +- sender.c | 2 +- syscall.c | 20 ++++++++++++++++++++ t_unsafe.c | 3 +++ tls.c | 3 +++ trimslash.c | 2 ++ util1.c | 2 +- 10 files changed, 35 insertions(+), 7 deletions(-) diff --git a/checksum.c b/checksum.c index cb21882c5..66e808967 100644 --- a/checksum.c +++ b/checksum.c @@ -406,7 +406,7 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum) int32 remainder; int fd; - fd = do_open(fname, O_RDONLY, 0); + fd = do_open_checklinks(fname); if (fd == -1) { memset(sum, 0, file_sum_len); return; diff --git a/flist.c b/flist.c index 087f9da6c..17832533e 100644 --- a/flist.c +++ b/flist.c @@ -1390,7 +1390,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, if (copy_devices && am_sender && IS_DEVICE(st.st_mode)) { if (st.st_size == 0) { - int fd = do_open(fname, O_RDONLY, 0); + int fd = do_open_checklinks(fname); if (fd >= 0) { st.st_size = get_device_size(fd, fname); close(fd); diff --git a/generator.c b/generator.c index 110db28fc..3f13bb959 100644 --- a/generator.c +++ b/generator.c @@ -1798,7 +1798,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, if (write_devices && IS_DEVICE(sx.st.st_mode) && sx.st.st_size == 0) { /* This early open into fd skips the regular open below. */ - if ((fd = do_open(fnamecmp, O_RDONLY, 0)) >= 0) + if ((fd = do_open_nofollow(fnamecmp, O_RDONLY)) >= 0) real_sx.st.st_size = sx.st.st_size = get_device_size(fd, fnamecmp); } @@ -1867,7 +1867,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, } /* open the file */ - if (fd < 0 && (fd = do_open(fnamecmp, O_RDONLY, 0)) < 0) { + if (fd < 0 && (fd = do_open_checklinks(fnamecmp)) < 0) { rsyserr(FERROR, errno, "failed to open %s, continuing", full_fname(fnamecmp)); pretend_missing: diff --git a/receiver.c b/receiver.c index 8031b8f4b..edfbb2106 100644 --- a/receiver.c +++ b/receiver.c @@ -775,7 +775,7 @@ int recv_files(int f_in, int f_out, char *local_name) if (fnamecmp != fname) { fnamecmp = fname; fnamecmp_type = FNAMECMP_FNAME; - fd1 = do_open(fnamecmp, O_RDONLY, 0); + fd1 = do_open_nofollow(fnamecmp, O_RDONLY); } if (fd1 == -1 && basis_dir[0]) { diff --git a/sender.c b/sender.c index 2bbff2faa..a4d46c39e 100644 --- a/sender.c +++ b/sender.c @@ -350,7 +350,7 @@ void send_files(int f_in, int f_out) exit_cleanup(RERR_PROTOCOL); } - fd = do_open(fname, O_RDONLY, 0); + fd = do_open_checklinks(fname); if (fd == -1) { if (errno == ENOENT) { enum logcode c = am_daemon && protocol_version < 28 ? FERROR : FWARNING; diff --git a/syscall.c b/syscall.c index 081357bb9..8cea2900d 100644 --- a/syscall.c +++ b/syscall.c @@ -45,6 +45,8 @@ extern int preallocate_files; extern int preserve_perms; extern int preserve_executability; extern int open_noatime; +extern int copy_links; +extern int copy_unsafe_links; #ifndef S_BLKSIZE # if defined hpux || defined __hpux__ || defined __hpux @@ -788,3 +790,21 @@ int secure_relative_open(const char *basedir, const char *relpath, int flags, mo return retfd; #endif // O_NOFOLLOW, O_DIRECTORY } + +/* + varient of do_open/do_open_nofollow which does do_open() if the + copy_links or copy_unsafe_links options are set and does + do_open_nofollow() otherwise + + This is used to prevent a race condition where an attacker could be + switching a file between being a symlink and being a normal file + + The open is always done with O_RDONLY flags + */ +int do_open_checklinks(const char *pathname) +{ + if (copy_links || copy_unsafe_links) { + return do_open(pathname, O_RDONLY, 0); + } + return do_open_nofollow(pathname, O_RDONLY); +} diff --git a/t_unsafe.c b/t_unsafe.c index 010cac50d..e10619a2a 100644 --- a/t_unsafe.c +++ b/t_unsafe.c @@ -28,6 +28,9 @@ int am_root = 0; int am_sender = 1; int read_only = 0; int list_only = 0; +int copy_links = 0; +int copy_unsafe_links = 0; + short info_levels[COUNT_INFO], debug_levels[COUNT_DEBUG]; int diff --git a/tls.c b/tls.c index e6b0708ad..858f8f10c 100644 --- a/tls.c +++ b/tls.c @@ -49,6 +49,9 @@ int list_only = 0; int link_times = 0; int link_owner = 0; int nsec_times = 0; +int safe_symlinks = 0; +int copy_links = 0; +int copy_unsafe_links = 0; #ifdef SUPPORT_XATTRS diff --git a/trimslash.c b/trimslash.c index 1ec928cac..f2774cd73 100644 --- a/trimslash.c +++ b/trimslash.c @@ -26,6 +26,8 @@ int am_root = 0; int am_sender = 1; int read_only = 1; int list_only = 0; +int copy_links = 0; +int copy_unsafe_links = 0; int main(int argc, char **argv) diff --git a/util1.c b/util1.c index f260d3980..d84bc4140 100644 --- a/util1.c +++ b/util1.c @@ -365,7 +365,7 @@ int copy_file(const char *source, const char *dest, int tmpfilefd, mode_t mode) int len; /* Number of bytes read into `buf'. */ OFF_T prealloc_len = 0, offset = 0; - if ((ifd = do_open(source, O_RDONLY, 0)) < 0) { + if ((ifd = do_open_nofollow(source, O_RDONLY)) < 0) { int save_errno = errno; rsyserr(FERROR_XFER, errno, "open %s", full_fname(source)); errno = save_errno; From 536ae3f4efbcd95bee1f9794bbeceb50ba5f0dba Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 10 Dec 2024 13:34:01 +1100 Subject: [PATCH 079/101] raise protocol version to 32 make it easier to spot unpatched servers --- rsync.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rsync.h b/rsync.h index b9a7101a7..9be1297bd 100644 --- a/rsync.h +++ b/rsync.h @@ -111,7 +111,7 @@ /* Update this if you make incompatible changes and ALSO update the * SUBPROTOCOL_VERSION if it is not a final (official) release. */ -#define PROTOCOL_VERSION 31 +#define PROTOCOL_VERSION 32 /* This is used when working on a new protocol version or for any unofficial * protocol tweaks. It should be a non-zero value for each pre-release repo From 9dc31473bad35fc7880ec0afd028f1d8bcc3b66c Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 18 Dec 2024 09:08:24 +1100 Subject: [PATCH 080/101] change version to 3.4.0 --- version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.h b/version.h index c6515f689..60dc938e2 100644 --- a/version.h +++ b/version.h @@ -1,2 +1,2 @@ -#define RSYNC_VERSION "3.3.1dev" +#define RSYNC_VERSION "3.4.0" #define MAINTAINER_TZ_OFFSET -7.0 From 870b7d96dc19fa766831c82c331306358f7212e4 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 18 Dec 2024 09:20:33 +1100 Subject: [PATCH 081/101] update NEWS for 3.4.0 --- NEWS.md | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/NEWS.md b/NEWS.md index 8864d6d74..b983097a0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,10 +1,30 @@ -# NEWS for rsync 3.3.1 (UNRELEASED) +# NEWS for rsync 3.4.0 (14th Jan 2025) + +Release 3.4.0 is a security release that fixes a number of important vulnerabilities. + +Many thanks to Simon Scannell, Pedro Gallegos, and Jasiel Spelman at +Google Cloud Vulnerability Research and Aleksei Gorban (Loqpa) for +discovering these vulnerabilities and working with the rsync project +to develop and test fixes. + +For more details on the vulnerabilities please see the CERT report +https://kb.cert.org/vuls/id/952657 ## Changes in this version: ### SECURITY FIXES: -- Fixed a buffer overflow when the sum2 digest algorithm is SHA1. +- CVE-2024-12084 - Heap Buffer Overflow in Checksum Parsing. + +- CVE-2024-12085 - Info Leak via uninitialized Stack contents defeats ASLR. + +- CVE-2024-12086 - Server leaks arbitrary client files. + +- CVE-2024-12087 - Server can make client write files outside of destination directory using symbolic links. + +- CVE-2024-12088 - --safe-links Bypass. + +- CVE-2024-12747 - symlink race condition. ### BUG FIXES: @@ -12,6 +32,8 @@ - Fixed an incorrect extern variable's type that caused an ACL issue on macOS. +- Fixed IPv6 configure check + ### INTERNAL: - Updated included popt to version 1.19. @@ -22,8 +44,9 @@ - Improved packaging/var-checker to identify variable type issues. ------------------------------------------------------------------------------- +- added FreeBSD and Solaris CI builds +------------------------------------------------------------------------------ # NEWS for rsync 3.3.0 (6 Apr 2024) ## Changes in this version: From 7f79682732788d255b7809beff8a8f826690c58f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 15 Jan 2025 05:41:07 +1100 Subject: [PATCH 082/101] NEWS: update protocol version table --- NEWS.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/NEWS.md b/NEWS.md index b983097a0..4f18bc761 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,19 +1,24 @@ -# NEWS for rsync 3.4.0 (14th Jan 2025) +# NEWS for rsync 3.4.0 (15 Jan 2025) Release 3.4.0 is a security release that fixes a number of important vulnerabilities. -Many thanks to Simon Scannell, Pedro Gallegos, and Jasiel Spelman at -Google Cloud Vulnerability Research and Aleksei Gorban (Loqpa) for -discovering these vulnerabilities and working with the rsync project -to develop and test fixes. - For more details on the vulnerabilities please see the CERT report https://kb.cert.org/vuls/id/952657 ## Changes in this version: +### PROTOCOL NUMBER: + + - The protocol number was changed to 32 to make it easier for + administrators to check their servers have been updated + ### SECURITY FIXES: +Many thanks to Simon Scannell, Pedro Gallegos, and Jasiel Spelman at +Google Cloud Vulnerability Research and Aleksei Gorban (Loqpa) for +discovering these vulnerabilities and working with the rsync project +to develop and test fixes. + - CVE-2024-12084 - Heap Buffer Overflow in Checksum Parsing. - CVE-2024-12085 - Info Leak via uninitialized Stack contents defeats ASLR. @@ -4811,7 +4816,7 @@ https://kb.cert.org/vuls/id/952657 | RELEASE DATE | VER. | DATE OF COMMIT\* | PROTOCOL | |--------------|--------|------------------|-------------| -| ?? Nov 2024 | 3.3.1 | | 31 | +| 15 Jan 2025 | 3.4.0 | | 32 | | 06 Apr 2024 | 3.3.0 | | 31 | | 20 Oct 2022 | 3.2.7 | | 31 | | 09 Sep 2022 | 3.2.6 | | 31 | From 0fd29b6bcb7a36233a700f6af0bd15473cfabe84 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 15 Jan 2025 05:50:22 +1100 Subject: [PATCH 083/101] packaging: adjust release script remove auto-edit of NEWS.md --- packaging/release-rsync | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/release-rsync b/packaging/release-rsync index a00bedbca..755a38a01 100755 --- a/packaging/release-rsync +++ b/packaging/release-rsync @@ -202,7 +202,7 @@ About to: '%define srcdir': srcdir, } - tweak_files = 'version.h rsync.h NEWS.md'.split() + tweak_files = 'version.h rsync.h'.split() tweak_files += glob.glob('packaging/*.spec') tweak_files += glob.glob('packaging/*/*.spec') From e3ee0e7319eb4250ddb76b716510fd20441da329 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 15 Jan 2025 05:53:23 +1100 Subject: [PATCH 084/101] Preparing for release of 3.4.0 [buildall] --- latest-year.h | 2 +- packaging/lsb/rsync.spec | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/latest-year.h b/latest-year.h index f978fb8b2..f0f7d5201 100644 --- a/latest-year.h +++ b/latest-year.h @@ -1 +1 @@ -#define LATEST_YEAR "2024" +#define LATEST_YEAR "2025" diff --git a/packaging/lsb/rsync.spec b/packaging/lsb/rsync.spec index 10385a396..294715f7e 100644 --- a/packaging/lsb/rsync.spec +++ b/packaging/lsb/rsync.spec @@ -1,6 +1,6 @@ Summary: A fast, versatile, remote (and local) file-copying tool Name: rsync -Version: 3.3.0 +Version: 3.4.0 %define fullversion %{version} Release: 1 %define srcdir src @@ -79,8 +79,8 @@ rm -rf $RPM_BUILD_ROOT %dir /etc/rsync-ssl/certs %changelog -* Sat Apr 06 2024 Wayne Davison -Released 3.3.0. +* Wed Jan 15 2025 Wayne Davison +Released 3.4.0. * Fri Mar 21 2008 Wayne Davison Added installation of /etc/xinetd.d/rsync file and some commented-out From a6312e60c95e5ebb5764eaf18eb07be23420ebc6 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Tue, 14 Jan 2025 13:09:33 -0800 Subject: [PATCH 085/101] Force rsync group when uploading files. --- packaging/samba-rsync | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/samba-rsync b/packaging/samba-rsync index 8691846a0..b291b276d 100755 --- a/packaging/samba-rsync +++ b/packaging/samba-rsync @@ -121,4 +121,4 @@ fi cd "$SRC_DIR" || exit 1 echo "Copying files from $SRC_DIR to $RSYNC_SAMBA_HOST ..." -do_rsync -aivOHP --del -f._$FILT . "$RSYNC_SAMBA_HOST:$DEST_DIR/" +do_rsync -aivOHP --chown=:rsync --del -f._$FILT . "$RSYNC_SAMBA_HOST:$DEST_DIR/" From dacadd53a9e16ad1cad4a902b9de2d0c19f196ee Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 15 Jan 2025 08:20:12 +1100 Subject: [PATCH 086/101] update maintainer address use rsync.project@gmail.com --- SECURITY.md | 3 ++- packaging/lsb/rsync.spec | 6 +----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index c24357413..f390ff9f0 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -9,4 +9,5 @@ help backporting fixes into an older release, feel free to ask. Email your vulnerability information to rsync's maintainer: - Wayne Davison + Rsync Project + diff --git a/packaging/lsb/rsync.spec b/packaging/lsb/rsync.spec index 294715f7e..4771de3e4 100644 --- a/packaging/lsb/rsync.spec +++ b/packaging/lsb/rsync.spec @@ -79,9 +79,5 @@ rm -rf $RPM_BUILD_ROOT %dir /etc/rsync-ssl/certs %changelog -* Wed Jan 15 2025 Wayne Davison +* Wed Jan 15 2025 Rsync Project Released 3.4.0. - -* Fri Mar 21 2008 Wayne Davison -Added installation of /etc/xinetd.d/rsync file and some commented-out -lines that demonstrate how to use the rsync-patches tar file. From 996af4a79f9afe4d7158ecdd87c78cee382c6b39 Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Wed, 15 Jan 2025 15:10:24 +0100 Subject: [PATCH 087/101] Fix FLAG_GOT_DIR_FLIST collission with FLAG_HLINKED fixes commit 688f5c379a43 (Refuse a duplicate dirlist.) Fixes: https://github.com/RsyncProject/rsync/issues/702 Fixes: https://github.com/RsyncProject/rsync/issues/697 --- rsync.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rsync.h b/rsync.h index 9be1297bd..479ac4848 100644 --- a/rsync.h +++ b/rsync.h @@ -84,7 +84,6 @@ #define FLAG_DUPLICATE (1<<4) /* sender */ #define FLAG_MISSING_DIR (1<<4) /* generator */ #define FLAG_HLINKED (1<<5) /* receiver/generator (checked on all types) */ -#define FLAG_GOT_DIR_FLIST (1<<5)/* sender/receiver/generator - dir_flist only */ #define FLAG_HLINK_FIRST (1<<6) /* receiver/generator (w/FLAG_HLINKED) */ #define FLAG_IMPLIED_DIR (1<<6) /* sender/receiver/generator (dirs only) */ #define FLAG_HLINK_LAST (1<<7) /* receiver/generator */ @@ -93,6 +92,7 @@ #define FLAG_SKIP_GROUP (1<<10) /* receiver/generator */ #define FLAG_TIME_FAILED (1<<11)/* generator */ #define FLAG_MOD_NSEC (1<<12) /* sender/receiver/generator */ +#define FLAG_GOT_DIR_FLIST (1<<13)/* sender/receiver/generator - dir_flist only */ /* These flags are passed to functions but not stored. */ From 81ead9e70c7b9ee1bf3d1df09ace7df95934c5b8 Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Wed, 15 Jan 2025 15:48:04 +0100 Subject: [PATCH 088/101] Fix use-after-free in generator full_fname() will free the return value in the next call so we need to duplicate it before passing it to rsyserr. Fixes: https://github.com/RsyncProject/rsync/issues/704 --- generator.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/generator.c b/generator.c index 3f13bb959..b56fa569a 100644 --- a/generator.c +++ b/generator.c @@ -2041,8 +2041,12 @@ int atomic_create(struct file_struct *file, char *fname, const char *slnk, const if (!skip_atomic) { if (do_rename(tmpname, fname) < 0) { + char *full_tmpname = strdup(full_fname(tmpname)); + if (full_tmpname == NULL) + out_of_memory("atomic_create"); rsyserr(FERROR_XFER, errno, "rename %s -> \"%s\" failed", - full_fname(tmpname), full_fname(fname)); + full_tmpname, full_fname(fname)); + free(full_tmpname); do_unlink(tmpname); return 0; } From dc34990b2ef475280b899abead0ef4a809d0175a Mon Sep 17 00:00:00 2001 From: Rodrigo OSORIO Date: Wed, 15 Jan 2025 10:32:48 +0100 Subject: [PATCH 089/101] Test send a single directory with -H enabled Ensure this still working after 3.4.0 breakage https://github.com/RsyncProject/rsync/issues/702 --- testsuite/hardlinks.test | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/testsuite/hardlinks.test b/testsuite/hardlinks.test index af2ea4088..68fd2701c 100644 --- a/testsuite/hardlinks.test +++ b/testsuite/hardlinks.test @@ -77,5 +77,11 @@ rm -rf "$todir" $RSYNC -aHivv --debug=HLINK5 "$name1" "$todir/" diff $diffopt "$name1" "$todir" || test_fail "solo copy of name1 failed" +# Make sure there's nothing wrong with sending a single directory with -H +# enabled (this has broken in 3.4.0 so far, so we need this test). +rm -rf "$fromdir" "$todir" +makepath "$fromdir/sym" "$todir" +checkit "$RSYNC -aH '$fromdir/sym' '$todir'" "$fromdir" "$todir" + # The script would have aborted on error, so getting here means we've won. exit 0 From 68e9add76a7b354354220f0b3fbf5c8d8da99230 Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Wed, 15 Jan 2025 15:59:17 +0100 Subject: [PATCH 090/101] Fix build on ancient glibc without openat(AT_FDCWD Fixes: https://github.com/RsyncProject/rsync/issues/701 --- syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/syscall.c b/syscall.c index 8cea2900d..34a9bba08 100644 --- a/syscall.c +++ b/syscall.c @@ -734,7 +734,7 @@ int secure_relative_open(const char *basedir, const char *relpath, int flags, mo return -1; } -#if !defined(O_NOFOLLOW) || !defined(O_DIRECTORY) +#if !defined(O_NOFOLLOW) || !defined(O_DIRECTORY) || !defined(AT_FDCWD) // really old system, all we can do is live with the risks if (!basedir) { return open(relpath, flags, mode); From 8d6da040e5f538f21464e7ec1dccb13a1ce8e838 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 16 Jan 2025 07:09:12 +1100 Subject: [PATCH 091/101] popt: remove dependency on alloca --- popt/findme.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/popt/findme.c b/popt/findme.c index ac4cbaed2..49fc9f6f0 100644 --- a/popt/findme.c +++ b/popt/findme.c @@ -25,12 +25,15 @@ const char * findProgramPath(const char * argv0) if (path == NULL) return NULL; bufsize = strlen(path) + 1; - start = pathbuf = alloca(bufsize); + start = pathbuf = malloc(bufsize); if (pathbuf == NULL) return NULL; /* XXX can't happen */ strlcpy(pathbuf, path, bufsize); bufsize += sizeof "/" - 1 + strlen(argv0); buf = malloc(bufsize); - if (buf == NULL) return NULL; /* XXX can't happen */ + if (buf == NULL) { + free(pathbuf); + return NULL; /* XXX can't happen */ + } chptr = NULL; /*@-branchstate@*/ @@ -39,8 +42,10 @@ const char * findProgramPath(const char * argv0) *chptr = '\0'; snprintf(buf, bufsize, "%s/%s", start, argv0); - if (!access(buf, X_OK)) + if (!access(buf, X_OK)) { + free(pathbuf); return buf; + } if (chptr) start = chptr + 1; @@ -49,6 +54,7 @@ const char * findProgramPath(const char * argv0) } while (start && *start); /*@=branchstate@*/ + free(pathbuf); free(buf); return NULL; From 494879b8199e26225298006a9295c8c5dda5e77e Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 16 Jan 2025 07:37:28 +1100 Subject: [PATCH 092/101] update NEWS.md for 3.4.1 --- NEWS.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/NEWS.md b/NEWS.md index 4f18bc761..c36b1f6df 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,24 @@ +# NEWS for rsync 3.4.1 (16 Jan 2025) + +Release 3.4.1 is a fix for regressions introduced in 3.4.0 + +## Changes in this version: + +### BUG FIXES: + + - fixed handling of -H flag with conflict in internal flag values + + - fixed a user after free in logging of failed rename + + - fixed build on systems without openat() + + - removed dependency on alloca() in bundled popt + +### DEVELOPER RELATED: + + - fix to permissions handling in the developer release script + +------------------------------------------------------------------------------ # NEWS for rsync 3.4.0 (15 Jan 2025) Release 3.4.0 is a security release that fixes a number of important vulnerabilities. @@ -4816,6 +4837,7 @@ to develop and test fixes. | RELEASE DATE | VER. | DATE OF COMMIT\* | PROTOCOL | |--------------|--------|------------------|-------------| +| 16 Jan 2025 | 3.4.1 | | 32 | | 15 Jan 2025 | 3.4.0 | | 32 | | 06 Apr 2024 | 3.3.0 | | 31 | | 20 Oct 2022 | 3.2.7 | | 31 | From 3305a7a063ab0167cab5bf7029da53abaa9fdb6e Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 16 Jan 2025 07:49:23 +1100 Subject: [PATCH 093/101] Preparing for release of 3.4.1 [buildall] --- packaging/lsb/rsync.spec | 6 +++--- version.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packaging/lsb/rsync.spec b/packaging/lsb/rsync.spec index 4771de3e4..845b188a9 100644 --- a/packaging/lsb/rsync.spec +++ b/packaging/lsb/rsync.spec @@ -1,6 +1,6 @@ Summary: A fast, versatile, remote (and local) file-copying tool Name: rsync -Version: 3.4.0 +Version: 3.4.1 %define fullversion %{version} Release: 1 %define srcdir src @@ -79,5 +79,5 @@ rm -rf $RPM_BUILD_ROOT %dir /etc/rsync-ssl/certs %changelog -* Wed Jan 15 2025 Rsync Project -Released 3.4.0. +* Thu Jan 16 2025 Rsync Project +Released 3.4.1. diff --git a/version.h b/version.h index 60dc938e2..e54a4adad 100644 --- a/version.h +++ b/version.h @@ -1,2 +1,2 @@ -#define RSYNC_VERSION "3.4.0" +#define RSYNC_VERSION "3.4.1" #define MAINTAINER_TZ_OFFSET -7.0 From 14f33837dc007ab68d6bff5a6ebc79742ef2148d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 16 Jan 2025 08:17:30 +1100 Subject: [PATCH 094/101] fixed build error on ia64 NonStop it treats missing prototype as an error, not warning --- popt/findme.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/popt/findme.c b/popt/findme.c index 49fc9f6f0..406d66b21 100644 --- a/popt/findme.c +++ b/popt/findme.c @@ -9,6 +9,10 @@ #include "system.h" #include "findme.h" +#ifndef HAVE_STRLCPY +size_t strlcpy(char *d, const char *s, size_t bufsize); +#endif + const char * findProgramPath(const char * argv0) { char * path = getenv("PATH"); From 7cff121ec8e198d7e27aa87410a17521c48a02e7 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Wed, 15 Jan 2025 22:01:42 -0800 Subject: [PATCH 095/101] Start 3.4.2dev going. --- NEWS.md | 15 ++++++++++++++- version.h | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index c36b1f6df..96608cf94 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,13 @@ +# NEWS for rsync 3.4.2 (UNRELEASED) + +## Changes in this version: + +### BUG FIXES: + +- ... + +------------------------------------------------------------------------------ + # NEWS for rsync 3.4.1 (16 Jan 2025) Release 3.4.1 is a fix for regressions introduced in 3.4.0 @@ -19,6 +29,7 @@ Release 3.4.1 is a fix for regressions introduced in 3.4.0 - fix to permissions handling in the developer release script ------------------------------------------------------------------------------ + # NEWS for rsync 3.4.0 (15 Jan 2025) Release 3.4.0 is a security release that fixes a number of important vulnerabilities. @@ -73,6 +84,7 @@ to develop and test fixes. - added FreeBSD and Solaris CI builds ------------------------------------------------------------------------------ + # NEWS for rsync 3.3.0 (6 Apr 2024) ## Changes in this version: @@ -4837,8 +4849,9 @@ to develop and test fixes. | RELEASE DATE | VER. | DATE OF COMMIT\* | PROTOCOL | |--------------|--------|------------------|-------------| +| ?? ??? 2025 | 3.4.2 | | 32 | | 16 Jan 2025 | 3.4.1 | | 32 | -| 15 Jan 2025 | 3.4.0 | | 32 | +| 15 Jan 2025 | 3.4.0 | 15 Jan 2025 | 32 | | 06 Apr 2024 | 3.3.0 | | 31 | | 20 Oct 2022 | 3.2.7 | | 31 | | 09 Sep 2022 | 3.2.6 | | 31 | diff --git a/version.h b/version.h index e54a4adad..7f18570de 100644 --- a/version.h +++ b/version.h @@ -1,2 +1,2 @@ -#define RSYNC_VERSION "3.4.1" +#define RSYNC_VERSION "3.4.2dev" #define MAINTAINER_TZ_OFFSET -7.0 From 353506bc51a87e8df2ea12289786689ff9d44d14 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Wed, 15 Jan 2025 22:19:33 -0800 Subject: [PATCH 096/101] Improve interior dashes in long options. Improve the backslash-adding code in md-convert to affect dashes in the interior of long options. Perhaps fixes #686. --- md-convert | 2 ++ 1 file changed, 2 insertions(+) diff --git a/md-convert b/md-convert index 5fd63a76d..fb2bc993f 100755 --- a/md-convert +++ b/md-convert @@ -120,6 +120,7 @@ TZ_RE = re.compile(r'^#define\s+MAINTAINER_TZ_OFFSET\s+(-?\d+(\.\d+)?)', re.M) VAR_REF_RE = re.compile(r'\$\{(\w+)\}') VERSION_RE = re.compile(r' (\d[.\d]+)[, ]') BIN_CHARS_RE = re.compile(r'[\1-\7]+') +LONG_OPT_DASH_RE = re.compile(r'(--\w[-\w]+)') SPACE_DOUBLE_DASH_RE = re.compile(r'\s--(\s)') NON_SPACE_SINGLE_DASH_RE = re.compile(r'(^|\W)-') WHITESPACE_RE = re.compile(r'\s') @@ -540,6 +541,7 @@ class TransformHtml(HTMLParser): if st.in_pre: html = htmlify(txt) else: + txt = LONG_OPT_DASH_RE.sub(lambda x: x.group(1).replace('-', NBR_DASH[0]), txt) txt = SPACE_DOUBLE_DASH_RE.sub(NBR_SPACE[0] + r'--\1', txt).replace('--', NBR_DASH[0]*2) txt = NON_SPACE_SINGLE_DASH_RE.sub(r'\1' + NBR_DASH[0], txt) html = htmlify(txt) From 788ecbe5ea952bbe1498c654506264a0c4bf0ef5 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Wed, 15 Jan 2025 22:29:17 -0800 Subject: [PATCH 097/101] Don't edit copyright year values anymore. --- packaging/year-tweak | 56 +------------------------------------------- 1 file changed, 1 insertion(+), 55 deletions(-) diff --git a/packaging/year-tweak b/packaging/year-tweak index 69d2f2ff9..8a7fb98e4 100755 --- a/packaging/year-tweak +++ b/packaging/year-tweak @@ -7,9 +7,6 @@ import sys, os, re, argparse, subprocess from datetime import datetime -MAINTAINER_NAME = 'Wayne Davison' -MAINTAINER_SUF = ' ' + MAINTAINER_NAME + "\n" - def main(): latest_year = '2000' @@ -22,10 +19,6 @@ def main(): m = argparse.Namespace(**m.groupdict()) if m.year > latest_year: latest_year = m.year - if m.fn.startswith('zlib/') or m.fn.startswith('popt/'): - continue - if re.search(r'\.(c|h|sh|test)$', m.fn): - maybe_edit_copyright_year(m.fn, m.year) proc.communicate() fn = 'latest-year.h' @@ -39,55 +32,8 @@ def main(): fh.write(txt) -def maybe_edit_copyright_year(fn, year): - opening_lines = [ ] - copyright_line = None - - with open(fn, 'r', encoding='utf-8') as fh: - for lineno, line in enumerate(fh): - opening_lines.append(line) - if lineno > 3 and not re.search(r'\S', line): - break - m = re.match(r'^(?P
.*Copyright\s+\S+\s+)(?P\d\d\d\d(?:-\d\d\d\d)?(,\s+\d\d\d\d)*)(?P.+)', line)
-            if not m:
-                continue
-            copyright_line = argparse.Namespace(**m.groupdict())
-            copyright_line.lineno = len(opening_lines)
-            copyright_line.is_maintainer_line = MAINTAINER_NAME in copyright_line.suf
-            copyright_line.txt = line
-            if copyright_line.is_maintainer_line:
-                break
-
-        if not copyright_line:
-            return
-
-        if copyright_line.is_maintainer_line:
-            cyears = copyright_line.year.split('-')
-            if year == cyears[0]:
-                cyears = [ year ]
-            else:
-                cyears = [ cyears[0], year ]
-            txt = copyright_line.pre + '-'.join(cyears) + MAINTAINER_SUF
-            if txt == copyright_line.txt:
-                return
-            opening_lines[copyright_line.lineno - 1] = txt
-        else:
-            if fn.startswith('lib/') or fn.startswith('testsuite/'):
-                return
-            txt = copyright_line.pre + year + MAINTAINER_SUF
-            opening_lines[copyright_line.lineno - 1] += txt
-
-        remaining_txt = fh.read()
-
-    print(f"Updating {fn} with year {year}")
-
-    with open(fn, 'w', encoding='utf-8') as fh:
-        fh.write(''.join(opening_lines))
-        fh.write(remaining_txt)
-
-
 if __name__ == '__main__':
-    parser = argparse.ArgumentParser(description="Grab the year of last mod for our c & h files and make sure the Copyright comment is up-to-date.")
+    parser = argparse.ArgumentParser(description="Grab the year of the last mod for our c & h files and make sure the LATEST_YEAR value is accurate.")
     args = parser.parse_args()
     main()
 

From 89b847393f53e24c38097153fc8568b85d07289c Mon Sep 17 00:00:00 2001
From: Wayne Davison 
Date: Wed, 15 Jan 2025 22:36:29 -0800
Subject: [PATCH 098/101] Fix python deprecation warning.

---
 support/git-set-file-times | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/support/git-set-file-times b/support/git-set-file-times
index e06f07370..601248b90 100755
--- a/support/git-set-file-times
+++ b/support/git-set-file-times
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 
 import os, re, argparse, subprocess
-from datetime import datetime
+from datetime import datetime, UTC
 
 NULL_COMMIT_RE = re.compile(r'\0\0commit [a-f0-9]{40}$|\0$')
 
@@ -74,7 +74,7 @@ def print_line(fn, mtime, commit_time):
     if args.list > 1:
         ts = str(commit_time).rjust(10)
     else:
-        ts = datetime.utcfromtimestamp(commit_time).strftime("%Y-%m-%d %H:%M:%S")
+        ts = datetime.fromtimestamp(commit_time, UTC).strftime("%Y-%m-%d %H:%M:%S")
     chg = '.' if mtime == commit_time else '*'
     print(chg, ts, fn)
 

From fcfdd36054db18c12a85d9f42365f93c04247637 Mon Sep 17 00:00:00 2001
From: Wayne Davison 
Date: Wed, 15 Jan 2025 23:24:26 -0800
Subject: [PATCH 099/101] Update MAINTAINER_TZ_OFFSET on release.

This also fixes a string with \s that wasn't a r'...' string.
---
 packaging/release-rsync | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/packaging/release-rsync b/packaging/release-rsync
index 755a38a01..2d1486b8d 100755
--- a/packaging/release-rsync
+++ b/packaging/release-rsync
@@ -38,12 +38,16 @@ def main():
     if not os.path.isfile('packaging/release-rsync'):
         die('You must run this script from the top of your rsync checkout.')
 
-    now = datetime.now()
+    now = datetime.now().astimezone() # Requires python 3.6 or later
     cl_today = now.strftime('* %a %b %d %Y')
     year = now.strftime('%Y')
     ztoday = now.strftime('%d %b %Y')
     today = ztoday.lstrip('0')
 
+    # The MAINTAINER_TZ_OFFSET is a float number of hours vs UTC. It can start with '-' but not '+'.
+    tz_now = now.strftime('%z')
+    tz_num = tz_now[0:1].replace('+', '') + str(float(tz_now[1:3]) + float(tz_now[3:]) / 60)
+
     curdir = os.getcwd()
 
     signal.signal(signal.SIGINT, signal_handler)
@@ -213,6 +217,9 @@ About to:
             x_re = re.compile(r'^(#define RSYNC_VERSION).*', re.M)
             msg = f"Unable to update RSYNC_VERSION in {fn}"
             txt = replace_or_die(x_re, r'\1 "%s"' % version, txt, msg)
+            x_re = re.compile(r'^(#define MAINTAINER_TZ_OFFSET).*', re.M)
+            msg = f"Unable to update MAINTAINER_TZ_OFFSET in {fn}"
+            txt = replace_or_die(x_re, r'\1 ' + tz_num, txt, msg)
         elif '.spec' in fn:
             for var, val in specvars.items():
                 x_re = re.compile(r'^%s .*' % re.escape(var), re.M)
@@ -220,7 +227,7 @@ About to:
             x_re = re.compile(r'^\* \w\w\w \w\w\w \d\d \d\d\d\d (.*)', re.M)
             txt = replace_or_die(x_re, r'%s \1' % cl_today, txt, f"Unable to update ChangeLog header in {fn}")
         elif fn == 'rsync.h':
-            x_re = re.compile('(#define\s+SUBPROTOCOL_VERSION)\s+(\d+)')
+            x_re = re.compile(r'(#define\s+SUBPROTOCOL_VERSION)\s+(\d+)')
             repl = lambda m: m[1] + ' ' + ('0' if not pre or not proto_changed else '1' if m[2] == '0' else m[2])
             txt = replace_or_die(x_re, repl, txt, f"Unable to find SUBPROTOCOL_VERSION define in {fn}")
         elif fn == 'NEWS.md':

From 23d9ead5af0249babf241c5917ea2b22c2754bcb Mon Sep 17 00:00:00 2001
From: Alan Coopersmith 
Date: Wed, 15 Jan 2025 13:17:38 -0800
Subject: [PATCH 100/101] popt: remove obsolete findme.c & findme.h

popt 1.14 merged these into popt.c but the import into rsync
missed removing them.

Fixes: https://github.com/RsyncProject/rsync/issues/710

Signed-off-by: Alan Coopersmith 
---
 Makefile.in   |  2 +-
 popt/findme.c | 65 ---------------------------------------------------
 popt/findme.h | 20 ----------------
 3 files changed, 1 insertion(+), 86 deletions(-)
 delete mode 100644 popt/findme.c
 delete mode 100644 popt/findme.h

diff --git a/Makefile.in b/Makefile.in
index 7c75c2617..6340403be 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -49,7 +49,7 @@ OBJS2=options.o io.o compat.o hlink.o token.o uidlist.o socket.o hashtable.o \
 	usage.o fileio.o batch.o clientname.o chmod.o acls.o xattrs.o
 OBJS3=progress.o pipe.o @MD5_ASM@ @ROLL_SIMD@ @ROLL_ASM@
 DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
-popt_OBJS=popt/findme.o  popt/popt.o  popt/poptconfig.o \
+popt_OBJS= popt/popt.o  popt/poptconfig.o \
 	popt/popthelp.o popt/poptparse.o popt/poptint.o
 OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) @BUILD_ZLIB@ @BUILD_POPT@
 
diff --git a/popt/findme.c b/popt/findme.c
deleted file mode 100644
index 406d66b21..000000000
--- a/popt/findme.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/** \ingroup popt
- * \file popt/findme.c
- */
-
-/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
-   file accompanying popt source distributions, available from 
-   ftp://ftp.rpm.org/pub/rpm/dist. */
-
-#include "system.h"
-#include "findme.h"
-
-#ifndef HAVE_STRLCPY
-size_t strlcpy(char *d, const char *s, size_t bufsize);
-#endif
-
-const char * findProgramPath(const char * argv0)
-{
-    char * path = getenv("PATH");
-    char * pathbuf;
-    char * start, * chptr;
-    char * buf;
-    size_t bufsize;
-
-    if (argv0 == NULL) return NULL;	/* XXX can't happen */
-    /* If there is a / in the argv[0], it has to be an absolute path */
-    if (strchr(argv0, '/'))
-	return xstrdup(argv0);
-
-    if (path == NULL) return NULL;
-
-    bufsize = strlen(path) + 1;
-    start = pathbuf = malloc(bufsize);
-    if (pathbuf == NULL) return NULL;	/* XXX can't happen */
-    strlcpy(pathbuf, path, bufsize);
-    bufsize += sizeof "/" - 1 + strlen(argv0);
-    buf = malloc(bufsize);
-    if (buf == NULL) {
-	    free(pathbuf);
-	    return NULL;	/* XXX can't happen */
-    }
-
-    chptr = NULL;
-    /*@-branchstate@*/
-    do {
-	if ((chptr = strchr(start, ':')))
-	    *chptr = '\0';
-	snprintf(buf, bufsize, "%s/%s", start, argv0);
-
-	if (!access(buf, X_OK)) {
-	    free(pathbuf);
-	    return buf;
-	}
-
-	if (chptr) 
-	    start = chptr + 1;
-	else
-	    start = NULL;
-    } while (start && *start);
-    /*@=branchstate@*/
-
-    free(pathbuf);
-    free(buf);
-
-    return NULL;
-}
diff --git a/popt/findme.h b/popt/findme.h
deleted file mode 100644
index a016b867e..000000000
--- a/popt/findme.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/** \ingroup popt
- * \file popt/findme.h
- */
-
-/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
-   file accompanying popt source distributions, available from 
-   ftp://ftp.rpm.org/pub/rpm/dist. */
-
-#ifndef H_FINDME
-#define H_FINDME
-
-/**
- * Return absolute path to executable by searching PATH.
- * @param argv0		name of executable
- * @return		(malloc'd) absolute path to executable (or NULL)
- */
-/*@null@*/ const char * findProgramPath(/*@null@*/ const char * argv0)
-	/*@*/;
-
-#endif

From 9994933c8ccf7ead27c81fe4ce2eb4e08af20c7f Mon Sep 17 00:00:00 2001
From: Wayne Davison 
Date: Tue, 11 Feb 2025 13:37:12 -0800
Subject: [PATCH 101/101] Test on ubuntu-latest.

---
 .github/workflows/ubuntu-build.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/ubuntu-build.yml b/.github/workflows/ubuntu-build.yml
index 9deb935af..5efadce5b 100644
--- a/.github/workflows/ubuntu-build.yml
+++ b/.github/workflows/ubuntu-build.yml
@@ -16,7 +16,7 @@ on:
 
 jobs:
   test:
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-latest
     name: Test rsync on Ubuntu
     steps:
     - uses: actions/checkout@v4