CLI tool
kristapsdz/openrsync avatar
kristapsdz/openrsync

openrsync: an ISC licensed rsync implementation written in C

BSD-licensed implementation of rsync

940 stars41 forksCISC

At a glance

What is it?
openrsync reimplements rsync under an ISC licence, speaks protocol 27 against a modern rsync, and deliberately accepts only a subset of rsync's command-line arguments, which makes it a plausible fit for OpenBSD and a poor fit for an rsync feature marathon.
Who is it for?
openrsync suits an OpenBSD shop, or a Linux shop that wants a small C implementation of the rsync protocol, and that is content to live inside the subset of flags the tool accepts. It is the wrong tool for a pipeline that depends on rsync filters, daemon mode options or any other behaviour outside that subset, and it is the wrong dependency for a product that needs a stable tagged release, since the repository publishes no releases at all.
Can I use it commercially?
Yes. ISC is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 85 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A protocol 27 implementation under the ISC licence

openrsync is an implementation of rsync with a BSD, specifically ISC, licence. The compatibility target is stated precisely: it works with a modern rsync, with 3.1.3 used for testing, and any implementation supporting protocol 27 will do.

The licence is the headline for many adopters. The ISC licence here is short and permissive. The catch is in the next sentence of the introduction: the tool accepts only a subset of rsync's command-line arguments. You get the protocol without the entire option surface, which turns an adoption decision into a question about which rsync features your scripts actually use.

The officially supported operating system is OpenBSD, though the project states it will compile and run on other UNIX systems and refers to a Portability section for details. Portability problems are directed to a separate configure repository, which is a sensible split: the build system lives apart from the protocol implementation.

The origin story explains the shape of the code. openrsync was initially written as part of an RPKI validator project for OpenBSD, funded by several organisations, and it has had significant commits from OpenBSD project developers. Internally it also provides a portable implementation of humanize_number and a skeleton implementation of sbuf, which is a hint at the low level C style the codebase uses.

Building it is configure, make and one library

The installation section is short because the project does not hide behind a package manager. On an up to date UNIX system you download the sources and run the configure script, then make, then install:

bash
% ./configure
% make
# make install

Extra flags, such as LDFLAGS, are passed as arguments to ./configure. The install step places the openrsync utility and its manual pages, and the README is explicit that an existing rsync installation can stay where it is because the two will not collide in any way.

Two build requirements are worth noting before you start. You will currently require the zlib library to build, and on some systems, Linux mostly, the build currently requires BSD make, which is usually installed as bmake. The Makefile in the repository confirms the shape of this, with the link line pulling in zlib through pkg-config and falling back to the plain -lz flag when pkg-config cannot answer. There is no autoconf generated script to fight with, since the repository ships its own configure program, and the Makefile includes Makefile.configure along with an optional Makefile.local for local overrides. Upgrading is the same three commands run again, and removing the installation is make uninstall.

Talking to a server with --rsync-path

Because the tool can act as either the client or the server side of a transfer, the interesting part for an administrator is running it against a remote host. The README gives the two invocations for using openrsync as a server:

bash
% rsync --rsync-path=openrsync src/* dst
% openrsync --rsync-path=openrsync src/* dst

The first line is stock rsync on the left talking to openrsync on the right, the second is the same relationship with the roles of the local binaries reversed. The --rsync-path option tells the remote side which program to run, which is how a stock rsync client ends up talking to an openrsync server.

The warning that follows is the part that will cost you an afternoon if you skip it. If you want openrsync and rsync to interact, it is important to use command line flags available on both. A flag that only one of the two understands is not a portability feature, it is a divergence, and the manual page is the place to check which flags are shared.

The documentation position is deliberate and unusual. The canonical documentation for openrsync is its manual pages: rsync(5) and rsyncd(5) for protocol details, and openrsync(1) for utility documentation. The README even points out that those protocol manpages contain everything required to write your own rsync implementation, which makes the project a reference for protocol work and not only a file copying tool.

Sorting the file list is what makes order independent transfer work

The algorithm section of the README explains the rsync algorithm by reference to the technical report by Andrew Tridgell and Paul Mackerras, and to Tridgell's PhD thesis, and it points out that a thorough description lives there rather than in the source. What follows is an introduction for developers, and the README marks it as non canonical.

The structure has two components. The sender manages the source files, the receiver manages the destination, and which one is remote depends on the direction of the invocation:

bash
% openrsync -lrtp remote:foo/bar ~/baz/xyzzy
% openrsync -lrtp ~/foo/bar remote:baz/xyzzy

The hinge is the file list of names and metadata such as mode and mtime, generated by the sender and shared with the receiver, with the sharing implemented in flist.c. Both sides then independently sort the entries by the lexicographical order of the filenames. That sorting is what allows the file list to be sent and received out of order, and it preserves a directory first order, so directories are processed before the files they contain. Once sorted, both sides can refer to a file entry by its position in the sorted array.

After the receiver has read the list, it iterates through each file and passes information to the sender, which may send back instructions to update the file. The receiver lives in receiver.c, the sender in sender.c, and a great deal of the block exchange happens in blocks.c. The other files in the top level list map onto the same structure: client.c and server.c for the two sides of a session, flist.c and fmap.c for the file map, hash.c, rules.c and rmatch.c for matching, and md4.c for the checksum.

Block exchange treats directories and symlinks differently

The block exchange sequence is not the same for every kind of entry, and this is where the protocol details in the source and the manual pages matter more than the README.

For symbolic links, the information the receiver needs is already encoded in the file list metadata. The symlink is updated to point to the correct target and no update is requested from the sender. For directories, the directory is created if it does not already exist, again with no update requested from the sender. Only regular files go through the full block exchange, where the sender waits to receive a request for an update or an end of sequence message, and once a request arrives it scans for new blocks to send to the receiver.

When the block exchange completes, the files are all up to date. The overall point of the design is that only the parts of a file that differ are transmitted, which is the property that makes rsync worth choosing over a plain copy over a slow link.

Two implementation details in the repository are worth flagging for anyone reading the source. The Makefile has explicit conditionals for FreeBSD, linking the system sbuf and util libraries and defining HAVE_SBUF and HAVE_HUMANIZE_NUMBER, with a comment noting that Darwin has these functions on newer builds but not all, so the compat one is used unless the configure step is told otherwise. The md4.c file is the checksum implementation, which is part of the protocol rather than a local choice, since the checksum has to match what the other end computes.

Two regression suites, and what they need to run

The project has two regression systems under active development. The first is functional tests, which run openrsync through a variety of scenarios and check its output, and they run against the stock rsync as well, which is the interesting part because that comparison is the compatibility test. The second is unit tests, which test specific functions in the source.

Both need extra tools. The functional tests require jot, compress and truncate, and the unit tests require cunit. The Makefile wires the optional dependencies through pkg-config with fallbacks:

text
REGRESS_CU  = regress/cunit/print_7_or_8_bit
	      regress/cunit/log_format_type

Running everything is one target, and each suite has its own:

bash
% make regress
% make regress_functional
% make regress_cunit

The repository layout supports this, with a regress directory at the top level, a tests.c file, a configure program, and a Makefile that starts from a .PHONY regress target and includes Makefile.configure and an optional Makefile.local. For a project that reimplements a network protocol, having a suite that compares behaviour against the reference implementation is the part that gives you confidence in a subset implementation, and it is also the fastest way for a new adopter to find out which of their existing scripts would break.

Where openrsync stops being the right answer

Three boundaries are visible in the documentation itself.

The first is the option subset. Only a subset of rsync's command-line arguments is accepted, and the fix for a script that relies on something outside that subset is to change the script. For a one-off file copy from a shell prompt, that is a non-issue. For a backup pipeline that has grown filter rules, daemon mode options and archive flag habits over ten years, it is a migration.

The second is release engineering. The repository publishes no GitHub releases, so there is no tagged artefact, no changelog of version points and no upgrade note to read. The last push was on 2026-07-30, and the README says the main branch is being actively developed, so the code moves, but you are tracking a moving branch rather than a version series. For a tool that is likely to end up in a base image or a package, that is a packaging problem you have to solve yourself, and the configure program and Makefile are what you would package.

The third is divergence. Apple put a large amount of labour into a local fork of openrsync, and the README says the effort to merge that code back into the project is still underway. The licence field on the repository says ISC, and a LICENSE.md file sits at the top level, so redistribution is straightforward on licence terms, but the fork means the code you find in an operating system vendor's package tree may not match the code here.

Editorial conclusion

openrsync suits an OpenBSD shop, or a Linux shop that wants a small C implementation of the rsync protocol, and that is content to live inside the subset of flags the tool accepts. It is the wrong tool for a pipeline that depends on rsync filters, daemon mode options or any other behaviour outside that subset, and it is the wrong dependency for a product that needs a stable tagged release, since the repository publishes no releases at all. Before you commit, run make regress against the stock rsync for your scenarios, check the openrsync(1) manual page for the exact flag list, and plan for the divergence that the Apple fork already creates.

Frequently asked questions

What is openrsync and how is it different from rsync?

openrsync is a reimplementation of rsync written in C under an ISC licence, speaking protocol 27 so it interoperates with a modern rsync, with 3.1.3 used for testing. The difference is scope: it accepts only a subset of rsync's command-line arguments.

How do I build and install openrsync?

On an up to date UNIX system you run ./configure, then make, then make install, and you can pass extra flags such as LDFLAGS as arguments to ./configure. The build requires zlib, and on some systems, Linux mostly, it currently requires BSD make, usually installed as bmake.

Can openrsync work with a stock rsync installation?

Yes. The README says it is ok to have an installation of rsync at the same time because the two will not collide, and it shows how to point one at the other with the --rsync-path option. When the two interact you should use command line flags available on both.

How do I run the openrsync test suite?

Use make regress for both suites, or make regress_functional and make regress_cunit for one each. The functional tests require jot, compress and truncate, and the unit tests require cunit.

Where is the documentation for the rsync protocol details?

The canonical documentation for openrsync is its manual pages, with rsync(5) and rsyncd(5) covering protocol details and openrsync(1) covering utility usage. The README notes that the protocol manpages contain what is required to write your own rsync implementation.

Official sources

  1. Issues
  2. kristapsdz/openrsync on GitHub
  3. License: ISC
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/kristapsdz-openrsync.svg)](https://hysenlabs.com/projects/kristapsdz-openrsync)

Was this useful?