got-portable-0.101/0000775000175100017510000000000014644145571007672 5got-portable-0.101/Makefile.am0000664000175100017510000002327714644144735011662 # When creating a distribution tarball, make sure we enable all current # configure flags so that no files are missing. This is irrespective of # whether the end-user will enable this; this step is here so that all the # relevant files are included in the distribution. AM_DISTCHECK_CONFIGURE_FLAGS= --enable-cvg SUBDIRS = compat \ gitwrapper \ got \ gotadmin \ gotctl \ gotd \ gotsh \ gotwebd \ libexec \ template \ tog # -portable: re-enable once upstream is happy: cvg # TODO: gotd gotsh template if CVG_ENABLED SUBDIRS += cvg endif include $(top_builddir)/Makefile.common EXTRA_DIST = CHANGES \ CHANGELOG \ LICENCE \ README.portable \ regress \ util/got-portable-ver.sh LDADD = $(LIBOBJS) if HOST_FREEBSD LDADD += -lmd LIBS += -lmd endif LIBS += -lm $(zlib_LIBS) $(libbsd_LIBS) $(libmd_LIBS) AM_CPPFLAGS += $(libbsd_CFLAGS) $(libmd_CFLAGS) TEST_TARGETS=compat regress-delta regress-deltify regress-fetch regress-idset \ regress-path regress-tog regress-cmdline GOT_TEST_ROOT=/tmp .PHONY: compat compat: $(MAKE) -C compat tests: $(TEST_TARGETS) regress-cmdline: (export PLATFORM=@PLATFORM@; \ cd $(top_builddir)/regress/cmdline || exit $$?; \ ./checkout.sh -q -r "$(GOT_TEST_ROOT)"; \ ./update.sh -q -r "$(GOT_TEST_ROOT)"; \ ./status.sh -q -r "$(GOT_TEST_ROOT)"; \ ./log.sh -q -r "$(GOT_TEST_ROOT)"; \ ./add.sh -q -r "$(GOT_TEST_ROOT)"; \ ./rm.sh -q -r "$(GOT_TEST_ROOT)"; \ ./diff.sh -q -r "$(GOT_TEST_ROOT)"; \ ./blame.sh -q -r "$(GOT_TEST_ROOT)"; \ ./branch.sh -q -r "$(GOT_TEST_ROOT)"; \ ./tag.sh -q -r "$(GOT_TEST_ROOT)"; \ ./ref.sh -q -r "$(GOT_TEST_ROOT)"; \ ./commit.sh -q -r "$(GOT_TEST_ROOT)"; \ ./revert.sh -q -r "$(GOT_TEST_ROOT)"; \ ./cherrypick.sh -q -r "$(GOT_TEST_ROOT)"; \ ./backout.sh -q -r "$(GOT_TEST_ROOT)"; \ ./rebase.sh -q -r "$(GOT_TEST_ROOT)"; \ ./import.sh -q -r "$(GOT_TEST_ROOT)"; \ ./histedit.sh -q -r "$(GOT_TEST_ROOT)"; \ ./integrate.sh -q -r "$(GOT_TEST_ROOT)"; \ ./merge.sh -q -r "$(GOT_TEST_ROOT)"; \ ./stage.sh -q -r "$(GOT_TEST_ROOT)"; \ ./unstage.sh -q -r "$(GOT_TEST_ROOT)"; \ ./cat.sh -q -r "$(GOT_TEST_ROOT)"; \ ./clone.sh -q -r "$(GOT_TEST_ROOT)"; \ ./fetch.sh -q -r "$(GOT_TEST_ROOT)"; \ ./send.sh -q -r "$(GOT_TEST_ROOT)"; \ ./tree.sh -q -r "$(GOT_TEST_ROOT)"; \ ./patch.sh -q -r "$(GOT_TEST_ROOT)" \ ./pack.sh -q -r "$(GOT_TEST_ROOT)"; \ ./cleanup.sh -q -r "$(GOT_TEST_ROOT)") regress-delta: $(CC) $(DEFS) $(AM_CFLAGS) $(AM_CPPFLAGS) \ -o $(top_builddir)/regress/delta/delta_test \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/regress/delta/delta_test.c \ -L$(top_builddir)/compat -lopenbsd-compat $(LIBS) && \ $(top_builddir)/regress/delta/delta_test regress-deltify: $(CC) $(DEFS) $(AM_CFLAGS) $(AM_CPPFLAGS) \ -o $(top_builddir)/regress/deltify/deltify_test \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/regress/deltify/deltify_test.c \ -L$(top_builddir)/compat -lopenbsd-compat $(LIBS) && \ $(top_builddir)/regress/deltify/deltify_test regress-fetch: $(CC) $(DEFS) $(AM_CFLAGS) $(AM_CPPFLAGS) \ -o $(top_builddir)/regress/fetch/fetch_test \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fetch.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/regress/fetch/fetch_test.c \ -L$(top_builddir)/compat -lopenbsd-compat $(LIBS) -lm && \ $(top_builddir)/regress/fetch/fetch_test regress-idset: $(CC) $(DEFS) $(AM_CFLAGS) $(AM_CPPFLAGS) \ -o $(top_builddir)/regress/idset/idset_test \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fetch.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/regress/idset/idset_test.c \ -L$(top_builddir)/compat -lopenbsd-compat $(LIBS) && \ $(top_builddir)/regress/idset/idset_test regress-path: $(CC) $(DEFS) $(AM_CFLAGS) $(AM_CPPFLAGS) \ -o $(top_builddir)/regress/path/path_test \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fetch.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/regress/path/path_test.c \ -L$(top_builddir)/compat -lopenbsd-compat $(LIBS) && \ $(top_builddir)/regress/path/path_test regress-tog: (cd $(top_builddir)/regress/tog || exit $$?; \ ./log.sh -q -r "$(GOT_TEST_ROOT)"); got-portable-0.101/util/0000775000175100017510000000000014644145570010646 5got-portable-0.101/util/got-portable-ver.sh0000775000175100017510000000075514644145512014321 #!/bin/sh # # got-portable-ver: emits the version of got which is building. # If this is a release build, then the tag name is chomped # to remove extraneous git information. # # If it's a developer build, it's left as-is. # # Intended to be called from configure.ac (via autogen.sh) GOT_RELEASE=yes GOT_PORTABLE_VER=0.101 [ -d ".git" -a "$GOT_RELEASE" = "no" ] || { echo "$GOT_PORTABLE_VER" ; exit ; } git describe --always --dirty 2>/dev/null || \ echo "$GOT_PORTABLE_VER" got-portable-0.101/README.portable0000664000175100017510000002363514644144735012313 README.portable =============== This is the portable version of got[1] (Game of Trees), using autotools to provide the library checks required for GoT's dependencies. The following operating systems are supported: * FreeBSD * NetBSD * DragonFlyBSD * MacOS * Linux DEPENDENCIES ============ Note that the names of these libraries are indicative only; the names might vary. Linux: * `libncurses` (for tog(1)) * `libbsd` (BSD's arc4random routines) * `libmd` (SHA256 routines) * `libuuid` (for UUID generation) * `libz` (for Z compression) * `pkg-config` (for searching libraries) * `bison` (for configuration file grammar) * `libevent` (for gotwebd) * `libtls` (may be known as `libretls`) FreeBSD: * `automake` * `pkgconf` * `libretls` * `libevent` (for gotwebd) NetBSD: * `automake` * `libuuid` * `ncuresesw` * `libevent` (for gotwebd) * `libretls` DragonFlyBSD: * `automake` * `pkgconf` * `openssl` * `libevent` (for gotwebd) * `libretls` Darwin (MacOS): * `automake` * `bison` * `pkg-config` * `ncurses` * `openssl` * `ossp-uuid` * `libevent` (for gotwebd) * `libretls` TESTS (REGRESS) =============== To run the test suite: ``` $ make tests ``` Dependencies ============ * ed NOTE: THIS ONLY WORKS AFTER `make install` DUE TO HOW PATHS TO LIBEXEC HELPERS ARE HARD-CODED INTO THE BINARIES. INSTALLATION ============ ``` $ ./autogen.sh $ ./configure && make $ sudo make install ``` INSTALLING AND PACKAGING GITWRAPPER =================================== The gotd server has an optional companion tool called gitwrapper. A gotd server can be used without gitwrapper in the following cases: 1) The Git client's user account has gotsh configured as its login shell. 2) The Git client's user account sees gotsh installed under the names git-receive-pack and git-upload-pack, and these appear in $PATH before the corresponding Git binaries if Git is also installed. Setting up the user's $PATH in this way can require the use of SetEnv in sshd_config. The above cases can be too restrictive. For example, users who have regular shell access to the system may expect to be able to serve Git repositories from their home directories while also accessing repositories served by gotd. Once gitwrapper has been installed correctly it provides an out-of-the box experience where both gotd and Git "just work". However, this will require coordination with the system's Git installation and/or distribution package because the names of two specific Git programs will be overlapping: git-upload-pack and git-receive-pack If the gitwrapper tool will be used then it must replace git-receive-pack and git-upload-pack in /usr/bin. This is usually achieved by replacing the regular Git binaries in /usr/bin with symlinks to gitwrapper: ``` -rwxr-xr-x 1 root root 1019928 Aug 24 00:16 /usr/bin/gitwrapper lrwxrwxrwx 1 root root 10 Aug 20 12:40 /usr/bin/git-receive-pack -> gitwrapper lrwxrwxrwx 1 root root 10 Aug 20 12:40 /usr/bin/git-upload-pack -> gitwrapper ``` The Git binaries remain available in Git's libexec directory, which is set when Git gets compiled. On Debian it defaults to /usr/lib/git-core. This same path must be given to Got's configure script at build time to allow gitwrapper to find Git's binaries: ``` ./configure --with-gitwrapper-git-libexec-path=/usr/lib/git-core ``` Once gitwrapper is found in /usr/bin under the names git-receive-pack and git-upload-pack, any Git repositories listed in /etc/gotd.conf will be automatically served by gotd, and any Git repositories not listed in /etc/gotd.conf will be automatically served by regular Git's git-upload-pack and git-receive-pack. The client's login shell or $PATH no longer matter, and a peaceful co-existence of gotd and Git is possible. We recommend that distribution packagers take appropriate steps to package gitwrapper as a required dependency of gotd. It is also possible to install gitwrapper without installing gotd. As long as /etc/gotd.conf does not exist or no repositories are listed in /etc/gotd.conf there will be no visible change in run-time behaviour for Git users since gitwrapper will simply run the standard Git tools. In the OpenBSD ports tree both the regular git package and the gotd package are depending on gitwrapper, and the git package no longer installs the git-receive-pack and git-upload-pack programs in /usr/local/bin. BRANCHES + SUBMITTING PATCHES ============================= `got-portable` has two key branches: * `main` which tracks got upstream untainted. * `portable` which provides the portable version of GoT based from code on `main` Patches for portable code fixes should be based from the `portable` branch and sent to the mailing list for review [2] or sent to me directly (see CONTACT). Portable-specific patches should have a shortlog in the form of: ``` portable: AREA: description ``` Where `AREA` relates to the change in question (for example, `regress`, `libexec`, etc). In some cases, this can be omitted if it's a generic change. This helps to delineate `-portable` changes from upstream `got`. The read-only Github repository also runs CI checks using Cirrus-CI on Linux and FreeBSD. SYNCING UPSTREAM CHANGES WITH PORTABLE ====================================== The `-portable` GoT repository uses the following workflow: ``` Github (gh) GoT (upstream) ^ ^ | | | | | | | | +--------> GoT-portable <------+ ``` Here, `got-portable` is a clone of the `-portable` repository, locally on disk. There are two remotes set up within that repository, via `git-remote`: * `upstream` -- which points to the official GoT repository; * `gh` -- which points to the mirrored `-portable` repository so that CI can be run for cross-platform/test purposes [3] * `origin` -- our cloned copy from `-portable` Within the `-portable` repository are two key branches (there may be other topic branches which represent on-going work): * `main` -- this is the branch that tracks (without modification) those changes from `upstream`. This branch is continually reset to `upstream/main` whenever changes occur. * `portable` -- this is the *default* branch of the `-portable` repository which contains portable-specific changes to make `GoT` compile across different OSes. When updating `-portable` from upstream changes, the following actions happen: 1. Changes from `upstream` are fetched. If there are no new changes, there's nothing else to do. 2. Changes from `gh` are fetch so that the result can be pushed out to `gh`. 3. The difference between the local copy of `main` and `origin/main` is used to represent the set of commits which have *NOT* yet been merged to `-portable`. 4. A topic-branch called `syncup` is created from the HEAD of the `portable` branch to hold the to-be-cherry-picked commits from step 3. 5. These commits are then cherry-picked to the `syncup` branch. 6. If there's any conflicts, they must be resolved. 7. Once done, a sanity build is done in-situ to check there's nothing amiss. 8. If that succeeds, the `syncup` branch is merged to `portable` and pushed to `gh` for verification against CI. 9. If that fails, fixes continue and pushed up to `gh` as required. 10. Once happy, both the `main` and `portable` branches can be merged to `origin`. These steps are encapsulated in a script within `-portable`. [Link](../maintscripts/sync-upstream.sh) RELEASING A NEW VERSION ======================= Release for `-portable` try and align as close to upstream GoT as much as possible, even on the same day where that can happen. That being said, sometimes a release of `-portable` might happen outside of that cadence, where a `-portable`-specific issue needs addressing, for example. Before creating a new release, check the version of GoT as found in `util/got-portable-ver.sh` -- as `GOT_PORTABLE_VER`: ``` GOT_PORTABLE_VER=0.75 ``` Here, the *to be released* version of `got-portable` will be `0.75`. Typically, this version is incremented directly after a release, such that there's no need to change this value. The only exception would be if there were an out-of-band release to `-portable`. In such cases, that would take the form: ``` 0.75.1 ``` Where the suffix of `1`, `2`, etc., can be used to denote any sub-releases from the `0.75` version. The variable `GOT_RELEASE` needs be changed to `yes` so that the GOT_PORTABLE_VER is asserted correctly. Once the version is verified, the following should be run from the `portable` branch -- and the repository should not have any outstanding modifications to the source: ``` make clean ; ./autogen && ./configure && make distcheck ``` If this succeeds, the tarball is in the CWD, as: `got-portable-VERSION.tar.gz` This can then be copied to the `got-www` repository and uploaded, along with changing a couple of HTML pages therein to represent the new released version. Additionally, the CHANGELOG file can be copied to the `got-www` and committed. Once all of that has been done, the repository should be tagged to indicate the release, hence: ``` git tag -a 0.75 ``` This can then be pushed out to `gh` and `origin`. After that point, the version of `GOT_PORTABLE_VER` in `util/got-portable-ver.sh` should be changed to the next version, and `GOT_RELEASE` should be setg back to `no`. TODO ==== * configure.ac should start defining AC_ENABLE arguments to allow for finer-grained control of where to search for includes/libraries, etc. * review the compat/ code. Some of those functions are probably picked up in libbsd, so we should drop such implementations from compat/ where there's overlap between libbsd and what's natively available. CONTACT ======= Thomas Adam
thomas_adam (#gameoftrees on irc.libera.chat) [1] https://gameoftrees.org
[2] https://lists.openbsd.org/cgi-bin/mj_wwwusr?user=&passw=&func=lists-long-full&extra=gameoftrees [3] https://github.com/ThomasAdam/got-portable got-portable-0.101/compat/0000775000175100017510000000000014644145570011154 5got-portable-0.101/compat/freezero.c0000664000175100017510000000172414644144735013067 /* * Copyright (c) 2017 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include void freezero(void *ptr, size_t size) { if (ptr != NULL) { memset(ptr, 0, size); free(ptr); } } got-portable-0.101/compat/siphash.h0000664000175100017510000000652014644144735012711 /*- * Copyright (c) 2013 Andre Oppermann * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $OpenBSD: siphash.h,v 1.3 2015/02/20 11:51:03 tedu Exp $ */ /* * SipHash is a family of pseudorandom functions (a.k.a. keyed hash functions) * optimized for speed on short messages returning a 64bit hash/digest value. * * The number of rounds is defined during the initialization: * SipHash24_Init() for the fast and resonable strong version * SipHash48_Init() for the strong version (half as fast) * * struct SIPHASH_CTX ctx; * SipHash24_Init(&ctx); * SipHash_SetKey(&ctx, "16bytes long key"); * SipHash_Update(&ctx, pointer_to_string, length_of_string); * SipHash_Final(output, &ctx); */ #ifndef _SIPHASH_H_ #define _SIPHASH_H_ #define SIPHASH_BLOCK_LENGTH 8 #define SIPHASH_KEY_LENGTH 16 #define SIPHASH_DIGEST_LENGTH 8 typedef struct _SIPHASH_CTX { uint64_t v[4]; uint8_t buf[SIPHASH_BLOCK_LENGTH]; uint32_t bytes; } SIPHASH_CTX; typedef struct { uint64_t k0; uint64_t k1; } SIPHASH_KEY; void SipHash_Init(SIPHASH_CTX *, const SIPHASH_KEY *); void SipHash_Update(SIPHASH_CTX *, int, int, const void *, size_t); uint64_t SipHash_End(SIPHASH_CTX *, int, int); void SipHash_Final(void *, SIPHASH_CTX *, int, int); uint64_t SipHash(const SIPHASH_KEY *, int, int, const void *, size_t); #define SipHash24_Init(_c, _k) SipHash_Init((_c), (_k)) #define SipHash24_Update(_c, _p, _l) SipHash_Update((_c), 2, 4, (_p), (_l)) #define SipHash24_End(_d) SipHash_End((_d), 2, 4) #define SipHash24_Final(_d, _c) SipHash_Final((_d), (_c), 2, 4) #define SipHash24(_k, _p, _l) SipHash((_k), 2, 4, (_p), (_l)) #define SipHash48_Init(_c, _k) SipHash_Init((_c), (_k)) #define SipHash48_Update(_c, _p, _l) SipHash_Update((_c), 4, 8, (_p), (_l)) #define SipHash48_End(_d) SipHash_End((_d), 4, 8) #define SipHash48_Final(_d, _c) SipHash_Final((_d), (_c), 4, 8) #define SipHash48(_k, _p, _l) SipHash((_k), 4, 8, (_p), (_l)) #endif /* _SIPHASH_H_ */ got-portable-0.101/compat/uuid.c0000664000175100017510000000444514644144735012217 /* * Copyright (c) 2002,2005 Marcel Moolenaar * Copyright (c) 2002 Hiten Mahesh Pandya * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "got_compat.h" int32_t uuid_equal(struct uuid* a, struct uuid* b, uint32_t* unused) { return (uuid_compare(*(uuid_t *)a, *(uuid_t *)b) == 0); } int32_t uuid_is_nil(struct uuid* uuid, uint32_t* unused) { return uuid_is_null(*(uuid_t *)uuid); } void uuid_create(uuid_t *uuid, uint32_t* status) { *status = uuid_s_ok; return uuid_generate(*(uuid_t *)uuid); } void uuid_create_nil(struct uuid* uuid, uint32_t* unused) { return uuid_clear(*(uuid_t *)uuid); } void uuid_from_string(const char* s, uuid_t *uuid, uint32_t *status) { *status = uuid_parse(s, *(uuid_t *)uuid); } void uuid_to_string(uuid_t *uuid, char** s, uint32_t *status) { *s = malloc(36 + 1); /* 36 byte uuid plus '\0' */ if (*s == NULL) { fprintf(stderr, "uuid_to_string: fatal: malloc\n"); exit (1); } uuid_unparse(*(uuid_t *)uuid, *s); *status = uuid_s_ok; } got-portable-0.101/compat/Makefile.am0000664000175100017510000000315014644144735013131 noinst_LIBRARIES = libopenbsd-compat.a include $(top_builddir)/Makefile.common LDADD = $(libbsd_LIBS) AM_CPPFLAGS += $(libbsd_CFLAGS) libopenbsd_compat_a_SOURCES = \ asprintf.c \ fmt_scaled.c \ freezero.c \ getdtablecount.c \ getprogname.c \ merge.c \ reallocarray.c \ recallocarray.c \ strndup.c \ strnlen.c \ strsep.c \ strtonum.c \ imsg.h \ tree.h # For MacOS, don't build the compat versions of strl{cat,cpy}, but do for all # other systems. if !HOST_DARWIN libopenbsd_compat_a_SOURCES += strlcat.c strlcpy.c endif if HOST_DARWIN libopenbsd_compat_a_SOURCES += uuid.c bsd-poll.c bsd-poll.h endif if !HAVE_GETOPT libopenbsd_compat_a_SOURCES += getopt.c endif if !HAVE_B64 libopenbsd_compat_a_SOURCES += base64.c LDADD += $(libresolv_LIBS) endif if !HAVE_CLOSEFROM libopenbsd_compat_a_SOURCES += closefrom.c endif if HOST_NETBSD libopenbsd_compat_a_SOURCES += bsd-poll.c bsd-poll.h endif if HOST_LINUX libopenbsd_compat_a_SOURCES += uuid.c endif if HAVE_LINUX_LANDLOCK libopenbsd_compat_a_SOURCES += landlock.c endif if !HAVE_SIPHASH libopenbsd_compat_a_SOURCES += siphash.c siphash.h endif if !HAVE_SETPROCTITLE libopenbsd_compat_a_SOURCES += setproctitle.c endif if !HAVE_IMSG libopenbsd_compat_a_SOURCES += imsg-buffer.c imsg.c endif if !HOST_DARWIN # Fake an assigment here. It does nothing, but you cannot have consecutive # nested if statements in Makefiles, so we have to do something here, even if # it's a dummy assignment. NOTING=something if !HAVE_SHA2 libopenbsd_compat_a_SOURCES += sha2.c sha2.h endif endif EXTRA_DIST = \ $(top_srcdir)/include/got_compat.h \ imsg.h \ tree.h \ bsd-poll.h got-portable-0.101/compat/bsd-poll.h0000664000175100017510000000411614644144735012765 /* $OpenBSD: poll.h,v 1.11 2003/12/10 23:10:08 millert Exp $ */ /* * Copyright (c) 1996 Theo de Raadt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* OPENBSD ORIGINAL: sys/sys/poll.h */ #ifndef _COMPAT_POLL_H_ #define _COMPAT_POLL_H_ #include #include #include #include #include #ifndef HAVE_STRUCT_POLLFD_FD #define POLLIN 0x0001 #define POLLPRI 0x0002 #define POLLOUT 0x0004 #define POLLERR 0x0008 #define POLLHUP 0x0010 #define POLLNVAL 0x0020 #if 0 /* the following are currently not implemented */ #define POLLRDNORM 0x0040 #define POLLNORM POLLRDNORM #define POLLWRNORM POLLOUT #define POLLRDBAND 0x0080 #define POLLWRBAND 0x0100 #endif #endif /* !HAVE_STRUCT_POLLFD_FD */ typedef unsigned int nfds_t; int ppoll(struct pollfd *, nfds_t, const struct timespec *, const sigset_t *); #endif /* !_COMPAT_POLL_H_ */ got-portable-0.101/compat/strsep.c0000664000175100017510000000472314644144735012570 /* $OpenBSD: strsep.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */ /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include /* * Get next token from string *stringp, where tokens are possibly-empty * strings separated by characters from delim. * * Writes NULs into the string at *stringp to end tokens. * delim need not remain constant from call to call. * On return, *stringp points past the last NUL written (if there might * be further tokens), or is NULL (if there are definitely no more tokens). * * If *stringp is NULL, strsep returns NULL. */ char * strsep(char **stringp, const char *delim) { char *s; const char *spanp; int c, sc; char *tok; if ((s = *stringp) == NULL) return (NULL); for (tok = s;;) { c = *s++; spanp = delim; do { if ((sc = *spanp++) == c) { if (c == 0) s = NULL; else s[-1] = 0; *stringp = s; return (tok); } } while (sc != 0); } /* NOTREACHED */ } got-portable-0.101/compat/strlcat.c0000664000175100017510000000322314644144735012716 /* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include /* * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters * will be copied. Always NUL terminates (unless siz <= strlen(dst)). * Returns strlen(src) + MIN(siz, strlen(initial dst)). * If retval >= siz, truncation occurred. */ size_t strlcat(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = siz - dlen; if (n == 0) return(dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; return(dlen + (s - src)); /* count does not include NUL */ } got-portable-0.101/compat/closefrom.c0000664000175100017510000000550314644144735013236 /* * Copyright (c) 2004-2005 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef HAVE_CLOSEFROM #include #include #include #include #ifdef HAVE_FCNTL_H # include #endif #include #include #include #include #include #ifdef HAVE_DIRENT_H # include # define NAMLEN(dirent) strlen((dirent)->d_name) #else # define dirent direct # define NAMLEN(dirent) (dirent)->d_namlen # ifdef HAVE_SYS_NDIR_H # include # endif # ifdef HAVE_SYS_DIR_H # include # endif # ifdef HAVE_NDIR_H # include # endif #endif #ifndef OPEN_MAX # define OPEN_MAX 256 #endif #if 0 __unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $"; #endif /* lint */ /* * Close all file descriptors greater than or equal to lowfd. */ #ifdef HAVE_FCNTL_CLOSEM void closefrom(int lowfd) { (void) fcntl(lowfd, F_CLOSEM, 0); } #else void closefrom(int lowfd) { long fd, maxfd; #if defined(HAVE_DIRFD) && defined(HAVE_PROC_PID) char fdpath[PATH_MAX], *endp; struct dirent *dent; DIR *dirp; int len; /* Check for a /proc/$$/fd directory. */ len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid()); if (len > 0 && (size_t)len <= sizeof(fdpath) && (dirp = opendir(fdpath))) { while ((dent = readdir(dirp)) != NULL) { fd = strtol(dent->d_name, &endp, 10); if (dent->d_name != endp && *endp == '\0' && fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp)) (void) close((int) fd); } (void) closedir(dirp); } else #endif { /* * Fall back on sysconf() or getdtablesize(). We avoid checking * resource limits since it is possible to open a file descriptor * and then drop the rlimit such that it is below the open fd. */ #ifdef HAVE_SYSCONF maxfd = sysconf(_SC_OPEN_MAX); #else maxfd = getdtablesize(); #endif /* HAVE_SYSCONF */ if (maxfd < 0) maxfd = OPEN_MAX; for (fd = lowfd; fd < maxfd; fd++) (void) close((int) fd); } } #endif /* !HAVE_FCNTL_CLOSEM */ #endif /* HAVE_CLOSEFROM */ got-portable-0.101/compat/sha2.c0000664000175100017510000006735314644144735012115 /* $OpenBSD: sha2.c,v 1.28 2019/07/23 12:35:22 dtucker Exp $ */ /* * FILE: sha2.c * AUTHOR: Aaron D. Gifford * * Copyright (c) 2000-2001, Aaron D. Gifford * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $From: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $ */ /* OPENBSD ORIGINAL: lib/libc/hash/sha2.c */ #include #include "got_compat.h" #define DEF_WEAK(x) void __ssh_compat_weak_##x(void) #if !defined(HAVE_SHA256UPDATE) || !defined(HAVE_SHA384UPDATE) || \ !defined(HAVE_SHA512UPDATE) /* no-op out, similar to DEF_WEAK but only needed here */ #define MAKE_CLONE(x, y) void __ssh_compat_make_clone_##x_##y(void) /* * UNROLLED TRANSFORM LOOP NOTE: * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform * loop version for the hash transform rounds (defined using macros * later in this file). Either define on the command line, for example: * * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c * * or define below: * * #define SHA2_UNROLL_TRANSFORM * */ #ifndef SHA2_SMALL #if defined(__amd64__) || defined(__i386__) #define SHA2_UNROLL_TRANSFORM #endif #endif /*** SHA-224/256/384/512 Machine Architecture Definitions *****************/ /* * BYTE_ORDER NOTE: * * Please make sure that your system defines BYTE_ORDER. If your * architecture is little-endian, make sure it also defines * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are * equivalent. * * If your system does not define the above, then you can do so by * hand like this: * * #define LITTLE_ENDIAN 1234 * #define BIG_ENDIAN 4321 * * And for little-endian machines, add: * * #define BYTE_ORDER LITTLE_ENDIAN * * Or for big-endian machines: * * #define BYTE_ORDER BIG_ENDIAN * * The FreeBSD machine this was written on defines BYTE_ORDER * appropriately by including (which in turn includes * where the appropriate definitions are actually * made). */ #if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) #error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN #endif /*** SHA-224/256/384/512 Various Length Definitions ***********************/ /* NOTE: Most of these are in sha2.h */ #define SHA224_SHORT_BLOCK_LENGTH (SHA224_BLOCK_LENGTH - 8) #define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) #define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16) #define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) /*** ENDIAN SPECIFIC COPY MACROS **************************************/ #define BE_8_TO_32(dst, cp) do { \ (dst) = (u_int32_t)(cp)[3] | ((u_int32_t)(cp)[2] << 8) | \ ((u_int32_t)(cp)[1] << 16) | ((u_int32_t)(cp)[0] << 24); \ } while(0) #define BE_8_TO_64(dst, cp) do { \ (dst) = (u_int64_t)(cp)[7] | ((u_int64_t)(cp)[6] << 8) | \ ((u_int64_t)(cp)[5] << 16) | ((u_int64_t)(cp)[4] << 24) | \ ((u_int64_t)(cp)[3] << 32) | ((u_int64_t)(cp)[2] << 40) | \ ((u_int64_t)(cp)[1] << 48) | ((u_int64_t)(cp)[0] << 56); \ } while (0) #define BE_64_TO_8(cp, src) do { \ (cp)[0] = (src) >> 56; \ (cp)[1] = (src) >> 48; \ (cp)[2] = (src) >> 40; \ (cp)[3] = (src) >> 32; \ (cp)[4] = (src) >> 24; \ (cp)[5] = (src) >> 16; \ (cp)[6] = (src) >> 8; \ (cp)[7] = (src); \ } while (0) #define BE_32_TO_8(cp, src) do { \ (cp)[0] = (src) >> 24; \ (cp)[1] = (src) >> 16; \ (cp)[2] = (src) >> 8; \ (cp)[3] = (src); \ } while (0) /* * Macro for incrementally adding the unsigned 64-bit integer n to the * unsigned 128-bit integer (represented using a two-element array of * 64-bit words): */ #define ADDINC128(w,n) do { \ (w)[0] += (u_int64_t)(n); \ if ((w)[0] < (n)) { \ (w)[1]++; \ } \ } while (0) /*** THE SIX LOGICAL FUNCTIONS ****************************************/ /* * Bit shifting and rotation (used by the six SHA-XYZ logical functions: * * NOTE: The naming of R and S appears backwards here (R is a SHIFT and * S is a ROTATION) because the SHA-224/256/384/512 description document * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this * same "backwards" definition. */ /* Shift-right (used in SHA-224, SHA-256, SHA-384, and SHA-512): */ #define R(b,x) ((x) >> (b)) /* 32-bit Rotate-right (used in SHA-224 and SHA-256): */ #define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) /* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ #define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) /* Two of six logical functions used in SHA-224, SHA-256, SHA-384, and SHA-512: */ #define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) #define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) /* Four of six logical functions used in SHA-224 and SHA-256: */ #define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) #define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) #define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) #define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) /* Four of six logical functions used in SHA-384 and SHA-512: */ #define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) #define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) #define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) #define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) /*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ /* Hash constant words K for SHA-224 and SHA-256: */ static const u_int32_t K256[64] = { 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL }; /* Initial hash value H for SHA-256: */ static const u_int32_t sha256_initial_hash_value[8] = { 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL, 0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL }; #if 0 /* Hash constant words K for SHA-384 and SHA-512: */ static const u_int64_t K512[80] = { 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL }; /* Initial hash value H for SHA-512 */ static const u_int64_t sha512_initial_hash_value[8] = { 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL }; #if !defined(SHA2_SMALL) /* Initial hash value H for SHA-224: */ static const u_int32_t sha224_initial_hash_value[8] = { 0xc1059ed8UL, 0x367cd507UL, 0x3070dd17UL, 0xf70e5939UL, 0xffc00b31UL, 0x68581511UL, 0x64f98fa7UL, 0xbefa4fa4UL }; /* Initial hash value H for SHA-384 */ static const u_int64_t sha384_initial_hash_value[8] = { 0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL, 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL, 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL }; /* Initial hash value H for SHA-512-256 */ static const u_int64_t sha512_256_initial_hash_value[8] = { 0x22312194fc2bf72cULL, 0x9f555fa3c84c64c2ULL, 0x2393b86b6f53b151ULL, 0x963877195940eabdULL, 0x96283ee2a88effe3ULL, 0xbe5e1e2553863992ULL, 0x2b0199fc2c85b8aaULL, 0x0eb72ddc81c52ca2ULL }; /*** SHA-224: *********************************************************/ void SHA224Init(SHA2_CTX *context) { memcpy(context->state.st32, sha224_initial_hash_value, sizeof(sha224_initial_hash_value)); memset(context->buffer, 0, sizeof(context->buffer)); context->bitcount[0] = 0; } DEF_WEAK(SHA224Init); MAKE_CLONE(SHA224Transform, SHA256Transform); MAKE_CLONE(SHA224Update, SHA256Update); MAKE_CLONE(SHA224Pad, SHA256Pad); DEF_WEAK(SHA224Transform); DEF_WEAK(SHA224Update); DEF_WEAK(SHA224Pad); void SHA224Final(u_int8_t digest[SHA224_DIGEST_LENGTH], SHA2_CTX *context) { SHA224Pad(context); #if BYTE_ORDER == LITTLE_ENDIAN int i; /* Convert TO host byte order */ for (i = 0; i < 7; i++) BE_32_TO_8(digest + i * 4, context->state.st32[i]); #else memcpy(digest, context->state.st32, SHA224_DIGEST_LENGTH); #endif explicit_bzero(context, sizeof(*context)); } DEF_WEAK(SHA224Final); #endif /* !defined(SHA2_SMALL) */ #endif /* 0 */ /*** SHA-256: *********************************************************/ void SHA256Init(SHA2_CTX *context) { memcpy(context->state.st32, sha256_initial_hash_value, sizeof(sha256_initial_hash_value)); memset(context->buffer, 0, sizeof(context->buffer)); context->bitcount[0] = 0; } DEF_WEAK(SHA256Init); #ifdef SHA2_UNROLL_TRANSFORM /* Unrolled SHA-256 round macros: */ #define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) do { \ BE_8_TO_32(W256[j], data); \ data += 4; \ T1 = (h) + Sigma1_256((e)) + Ch((e), (f), (g)) + K256[j] + W256[j]; \ (d) += T1; \ (h) = T1 + Sigma0_256((a)) + Maj((a), (b), (c)); \ j++; \ } while(0) #define ROUND256(a,b,c,d,e,f,g,h) do { \ s0 = W256[(j+1)&0x0f]; \ s0 = sigma0_256(s0); \ s1 = W256[(j+14)&0x0f]; \ s1 = sigma1_256(s1); \ T1 = (h) + Sigma1_256((e)) + Ch((e), (f), (g)) + K256[j] + \ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ (d) += T1; \ (h) = T1 + Sigma0_256((a)) + Maj((a), (b), (c)); \ j++; \ } while(0) void SHA256Transform(u_int32_t state[8], const u_int8_t data[SHA256_BLOCK_LENGTH]) { u_int32_t a, b, c, d, e, f, g, h, s0, s1; u_int32_t T1, W256[16]; int j; /* Initialize registers with the prev. intermediate value */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; f = state[5]; g = state[6]; h = state[7]; j = 0; do { /* Rounds 0 to 15 (unrolled): */ ROUND256_0_TO_15(a,b,c,d,e,f,g,h); ROUND256_0_TO_15(h,a,b,c,d,e,f,g); ROUND256_0_TO_15(g,h,a,b,c,d,e,f); ROUND256_0_TO_15(f,g,h,a,b,c,d,e); ROUND256_0_TO_15(e,f,g,h,a,b,c,d); ROUND256_0_TO_15(d,e,f,g,h,a,b,c); ROUND256_0_TO_15(c,d,e,f,g,h,a,b); ROUND256_0_TO_15(b,c,d,e,f,g,h,a); } while (j < 16); /* Now for the remaining rounds up to 63: */ do { ROUND256(a,b,c,d,e,f,g,h); ROUND256(h,a,b,c,d,e,f,g); ROUND256(g,h,a,b,c,d,e,f); ROUND256(f,g,h,a,b,c,d,e); ROUND256(e,f,g,h,a,b,c,d); ROUND256(d,e,f,g,h,a,b,c); ROUND256(c,d,e,f,g,h,a,b); ROUND256(b,c,d,e,f,g,h,a); } while (j < 64); /* Compute the current intermediate hash value */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; state[5] += f; state[6] += g; state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = 0; } #else /* SHA2_UNROLL_TRANSFORM */ void SHA256Transform(u_int32_t state[8], const u_int8_t data[SHA256_BLOCK_LENGTH]) { u_int32_t a, b, c, d, e, f, g, h, s0, s1; u_int32_t T1, T2, W256[16]; int j; /* Initialize registers with the prev. intermediate value */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; f = state[5]; g = state[6]; h = state[7]; j = 0; do { BE_8_TO_32(W256[j], data); data += 4; /* Apply the SHA-256 compression function to update a..h */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; T2 = Sigma0_256(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 16); do { /* Part of the message block expansion: */ s0 = W256[(j+1)&0x0f]; s0 = sigma0_256(s0); s1 = W256[(j+14)&0x0f]; s1 = sigma1_256(s1); /* Apply the SHA-256 compression function to update a..h */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); T2 = Sigma0_256(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 64); /* Compute the current intermediate hash value */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; state[5] += f; state[6] += g; state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = T2 = 0; } #endif /* SHA2_UNROLL_TRANSFORM */ DEF_WEAK(SHA256Transform); void SHA256Update(SHA2_CTX *context, const u_int8_t *data, size_t len) { u_int64_t freespace, usedspace; /* Calling with no data is valid (we do nothing) */ if (len == 0) return; usedspace = (context->bitcount[0] >> 3) % SHA256_BLOCK_LENGTH; if (usedspace > 0) { /* Calculate how much free space is available in the buffer */ freespace = SHA256_BLOCK_LENGTH - usedspace; if (len >= freespace) { /* Fill the buffer completely and process it */ memcpy(&context->buffer[usedspace], data, freespace); context->bitcount[0] += freespace << 3; len -= freespace; data += freespace; SHA256Transform(context->state.st32, context->buffer); } else { /* The buffer is not yet full */ memcpy(&context->buffer[usedspace], data, len); context->bitcount[0] += (u_int64_t)len << 3; /* Clean up: */ usedspace = freespace = 0; return; } } while (len >= SHA256_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ SHA256Transform(context->state.st32, data); context->bitcount[0] += SHA256_BLOCK_LENGTH << 3; len -= SHA256_BLOCK_LENGTH; data += SHA256_BLOCK_LENGTH; } if (len > 0) { /* There's left-overs, so save 'em */ memcpy(context->buffer, data, len); context->bitcount[0] += len << 3; } /* Clean up: */ usedspace = freespace = 0; } DEF_WEAK(SHA256Update); void SHA256Pad(SHA2_CTX *context) { unsigned int usedspace; usedspace = (context->bitcount[0] >> 3) % SHA256_BLOCK_LENGTH; if (usedspace > 0) { /* Begin padding with a 1 bit: */ context->buffer[usedspace++] = 0x80; if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { /* Set-up for the last transform: */ memset(&context->buffer[usedspace], 0, SHA256_SHORT_BLOCK_LENGTH - usedspace); } else { if (usedspace < SHA256_BLOCK_LENGTH) { memset(&context->buffer[usedspace], 0, SHA256_BLOCK_LENGTH - usedspace); } /* Do second-to-last transform: */ SHA256Transform(context->state.st32, context->buffer); /* Prepare for last transform: */ memset(context->buffer, 0, SHA256_SHORT_BLOCK_LENGTH); } } else { /* Set-up for the last transform: */ memset(context->buffer, 0, SHA256_SHORT_BLOCK_LENGTH); /* Begin padding with a 1 bit: */ *context->buffer = 0x80; } /* Store the length of input data (in bits) in big endian format: */ BE_64_TO_8(&context->buffer[SHA256_SHORT_BLOCK_LENGTH], context->bitcount[0]); /* Final transform: */ SHA256Transform(context->state.st32, context->buffer); /* Clean up: */ usedspace = 0; } DEF_WEAK(SHA256Pad); void SHA256Final(u_int8_t digest[SHA256_DIGEST_LENGTH], SHA2_CTX *context) { SHA256Pad(context); #if BYTE_ORDER == LITTLE_ENDIAN int i; /* Convert TO host byte order */ for (i = 0; i < 8; i++) BE_32_TO_8(digest + i * 4, context->state.st32[i]); #else memcpy(digest, context->state.st32, SHA256_DIGEST_LENGTH); #endif explicit_bzero(context, sizeof(*context)); } DEF_WEAK(SHA256Final); #if 0 /*** SHA-512: *********************************************************/ void SHA512Init(SHA2_CTX *context) { memcpy(context->state.st64, sha512_initial_hash_value, sizeof(sha512_initial_hash_value)); memset(context->buffer, 0, sizeof(context->buffer)); context->bitcount[0] = context->bitcount[1] = 0; } DEF_WEAK(SHA512Init); #ifdef SHA2_UNROLL_TRANSFORM /* Unrolled SHA-512 round macros: */ #define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) do { \ BE_8_TO_64(W512[j], data); \ data += 8; \ T1 = (h) + Sigma1_512((e)) + Ch((e), (f), (g)) + K512[j] + W512[j]; \ (d) += T1; \ (h) = T1 + Sigma0_512((a)) + Maj((a), (b), (c)); \ j++; \ } while(0) #define ROUND512(a,b,c,d,e,f,g,h) do { \ s0 = W512[(j+1)&0x0f]; \ s0 = sigma0_512(s0); \ s1 = W512[(j+14)&0x0f]; \ s1 = sigma1_512(s1); \ T1 = (h) + Sigma1_512((e)) + Ch((e), (f), (g)) + K512[j] + \ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ (d) += T1; \ (h) = T1 + Sigma0_512((a)) + Maj((a), (b), (c)); \ j++; \ } while(0) void SHA512Transform(u_int64_t state[8], const u_int8_t data[SHA512_BLOCK_LENGTH]) { u_int64_t a, b, c, d, e, f, g, h, s0, s1; u_int64_t T1, W512[16]; int j; /* Initialize registers with the prev. intermediate value */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; f = state[5]; g = state[6]; h = state[7]; j = 0; do { /* Rounds 0 to 15 (unrolled): */ ROUND512_0_TO_15(a,b,c,d,e,f,g,h); ROUND512_0_TO_15(h,a,b,c,d,e,f,g); ROUND512_0_TO_15(g,h,a,b,c,d,e,f); ROUND512_0_TO_15(f,g,h,a,b,c,d,e); ROUND512_0_TO_15(e,f,g,h,a,b,c,d); ROUND512_0_TO_15(d,e,f,g,h,a,b,c); ROUND512_0_TO_15(c,d,e,f,g,h,a,b); ROUND512_0_TO_15(b,c,d,e,f,g,h,a); } while (j < 16); /* Now for the remaining rounds up to 79: */ do { ROUND512(a,b,c,d,e,f,g,h); ROUND512(h,a,b,c,d,e,f,g); ROUND512(g,h,a,b,c,d,e,f); ROUND512(f,g,h,a,b,c,d,e); ROUND512(e,f,g,h,a,b,c,d); ROUND512(d,e,f,g,h,a,b,c); ROUND512(c,d,e,f,g,h,a,b); ROUND512(b,c,d,e,f,g,h,a); } while (j < 80); /* Compute the current intermediate hash value */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; state[5] += f; state[6] += g; state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = 0; } #else /* SHA2_UNROLL_TRANSFORM */ void SHA512Transform(u_int64_t state[8], const u_int8_t data[SHA512_BLOCK_LENGTH]) { u_int64_t a, b, c, d, e, f, g, h, s0, s1; u_int64_t T1, T2, W512[16]; int j; /* Initialize registers with the prev. intermediate value */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; f = state[5]; g = state[6]; h = state[7]; j = 0; do { BE_8_TO_64(W512[j], data); data += 8; /* Apply the SHA-512 compression function to update a..h */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; T2 = Sigma0_512(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 16); do { /* Part of the message block expansion: */ s0 = W512[(j+1)&0x0f]; s0 = sigma0_512(s0); s1 = W512[(j+14)&0x0f]; s1 = sigma1_512(s1); /* Apply the SHA-512 compression function to update a..h */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); T2 = Sigma0_512(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 80); /* Compute the current intermediate hash value */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; state[5] += f; state[6] += g; state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = T2 = 0; } #endif /* SHA2_UNROLL_TRANSFORM */ DEF_WEAK(SHA512Transform); void SHA512Update(SHA2_CTX *context, const u_int8_t *data, size_t len) { size_t freespace, usedspace; /* Calling with no data is valid (we do nothing) */ if (len == 0) return; usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; if (usedspace > 0) { /* Calculate how much free space is available in the buffer */ freespace = SHA512_BLOCK_LENGTH - usedspace; if (len >= freespace) { /* Fill the buffer completely and process it */ memcpy(&context->buffer[usedspace], data, freespace); ADDINC128(context->bitcount, freespace << 3); len -= freespace; data += freespace; SHA512Transform(context->state.st64, context->buffer); } else { /* The buffer is not yet full */ memcpy(&context->buffer[usedspace], data, len); ADDINC128(context->bitcount, len << 3); /* Clean up: */ usedspace = freespace = 0; return; } } while (len >= SHA512_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ SHA512Transform(context->state.st64, data); ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); len -= SHA512_BLOCK_LENGTH; data += SHA512_BLOCK_LENGTH; } if (len > 0) { /* There's left-overs, so save 'em */ memcpy(context->buffer, data, len); ADDINC128(context->bitcount, len << 3); } /* Clean up: */ usedspace = freespace = 0; } DEF_WEAK(SHA512Update); void SHA512Pad(SHA2_CTX *context) { unsigned int usedspace; usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; if (usedspace > 0) { /* Begin padding with a 1 bit: */ context->buffer[usedspace++] = 0x80; if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { /* Set-up for the last transform: */ memset(&context->buffer[usedspace], 0, SHA512_SHORT_BLOCK_LENGTH - usedspace); } else { if (usedspace < SHA512_BLOCK_LENGTH) { memset(&context->buffer[usedspace], 0, SHA512_BLOCK_LENGTH - usedspace); } /* Do second-to-last transform: */ SHA512Transform(context->state.st64, context->buffer); /* And set-up for the last transform: */ memset(context->buffer, 0, SHA512_BLOCK_LENGTH - 2); } } else { /* Prepare for final transform: */ memset(context->buffer, 0, SHA512_SHORT_BLOCK_LENGTH); /* Begin padding with a 1 bit: */ *context->buffer = 0x80; } /* Store the length of input data (in bits) in big endian format: */ BE_64_TO_8(&context->buffer[SHA512_SHORT_BLOCK_LENGTH], context->bitcount[1]); BE_64_TO_8(&context->buffer[SHA512_SHORT_BLOCK_LENGTH + 8], context->bitcount[0]); /* Final transform: */ SHA512Transform(context->state.st64, context->buffer); /* Clean up: */ usedspace = 0; } DEF_WEAK(SHA512Pad); void SHA512Final(u_int8_t digest[SHA512_DIGEST_LENGTH], SHA2_CTX *context) { SHA512Pad(context); #if BYTE_ORDER == LITTLE_ENDIAN int i; /* Convert TO host byte order */ for (i = 0; i < 8; i++) BE_64_TO_8(digest + i * 8, context->state.st64[i]); #else memcpy(digest, context->state.st64, SHA512_DIGEST_LENGTH); #endif explicit_bzero(context, sizeof(*context)); } DEF_WEAK(SHA512Final); #if !defined(SHA2_SMALL) /*** SHA-384: *********************************************************/ void SHA384Init(SHA2_CTX *context) { memcpy(context->state.st64, sha384_initial_hash_value, sizeof(sha384_initial_hash_value)); memset(context->buffer, 0, sizeof(context->buffer)); context->bitcount[0] = context->bitcount[1] = 0; } DEF_WEAK(SHA384Init); MAKE_CLONE(SHA384Transform, SHA512Transform); MAKE_CLONE(SHA384Update, SHA512Update); MAKE_CLONE(SHA384Pad, SHA512Pad); DEF_WEAK(SHA384Transform); DEF_WEAK(SHA384Update); DEF_WEAK(SHA384Pad); /* Equivalent of MAKE_CLONE (which is a no-op) for SHA384 funcs */ void SHA384Transform(u_int64_t state[8], const u_int8_t data[SHA512_BLOCK_LENGTH]) { SHA512Transform(state, data); } void SHA384Update(SHA2_CTX *context, const u_int8_t *data, size_t len) { SHA512Update(context, data, len); } void SHA384Pad(SHA2_CTX *context) { SHA512Pad(context); } void SHA384Final(u_int8_t digest[SHA384_DIGEST_LENGTH], SHA2_CTX *context) { SHA384Pad(context); #if BYTE_ORDER == LITTLE_ENDIAN int i; /* Convert TO host byte order */ for (i = 0; i < 6; i++) BE_64_TO_8(digest + i * 8, context->state.st64[i]); #else memcpy(digest, context->state.st64, SHA384_DIGEST_LENGTH); #endif /* Zero out state data */ explicit_bzero(context, sizeof(*context)); } DEF_WEAK(SHA384Final); /*** SHA-512/256: *********************************************************/ void SHA512_256Init(SHA2_CTX *context) { memcpy(context->state.st64, sha512_256_initial_hash_value, sizeof(sha512_256_initial_hash_value)); memset(context->buffer, 0, sizeof(context->buffer)); context->bitcount[0] = context->bitcount[1] = 0; } DEF_WEAK(SHA512_256Init); MAKE_CLONE(SHA512_256Transform, SHA512Transform); MAKE_CLONE(SHA512_256Update, SHA512Update); MAKE_CLONE(SHA512_256Pad, SHA512Pad); DEF_WEAK(SHA512_256Transform); DEF_WEAK(SHA512_256Update); DEF_WEAK(SHA512_256Pad); void SHA512_256Final(u_int8_t digest[SHA512_256_DIGEST_LENGTH], SHA2_CTX *context) { SHA512_256Pad(context); #if BYTE_ORDER == LITTLE_ENDIAN int i; /* Convert TO host byte order */ for (i = 0; i < 4; i++) BE_64_TO_8(digest + i * 8, context->state.st64[i]); #else memcpy(digest, context->state.st64, SHA512_256_DIGEST_LENGTH); #endif /* Zero out state data */ explicit_bzero(context, sizeof(*context)); } DEF_WEAK(SHA512_256Final); #endif /* !defined(SHA2_SMALL) */ #endif /* 0 */ #endif /* HAVE_SHA{256,384,512}UPDATE */ got-portable-0.101/compat/recallocarray.c0000664000175100017510000000452414644144735014072 /* $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $ */ /* * Copyright (c) 2008, 2017 Otto Moerbeek * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include /* * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW */ #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) void * recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size) { size_t oldsize, newsize; void *newptr; if (ptr == NULL) return calloc(newnmemb, size); if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && newnmemb > 0 && SIZE_MAX / newnmemb < size) { errno = ENOMEM; return NULL; } newsize = newnmemb * size; if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && oldnmemb > 0 && SIZE_MAX / oldnmemb < size) { errno = EINVAL; return NULL; } oldsize = oldnmemb * size; /* * Don't bother too much if we're shrinking just a bit, * we do not shrink for series of small steps, oh well. */ if (newsize <= oldsize) { size_t d = oldsize - newsize; if (d < oldsize / 2 && d < (size_t)getpagesize()) { memset((char *)ptr + newsize, 0, d); return ptr; } } newptr = malloc(newsize); if (newptr == NULL) return NULL; if (newsize > oldsize) { memcpy(newptr, ptr, oldsize); memset((char *)newptr + oldsize, 0, newsize - oldsize); } else memcpy(newptr, ptr, newsize); #ifdef __APPLE__ memset_s(ptr, oldsize, 0, oldsize); #elif defined(__NetBSD__) explicit_memset(ptr, oldsize, 0); #else explicit_bzero(ptr, oldsize); #endif free(ptr); return newptr; } got-portable-0.101/compat/getprogname.c0000664000175100017510000000224214644144735013552 /* * Copyright (c) 2016 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME) const char * getprogname(void) { return (program_invocation_short_name); } #elif defined(HAVE___PROGNAME) const char * getprogname(void) { extern char *__progname; return (__progname); } #else const char * getprogname(void) { return ("got"); } #endif got-portable-0.101/compat/strlcpy.c0000664000175100017510000000304414644144735012743 /* $OpenBSD: strlcpy.c,v 1.10 2005/08/08 08:05:37 espie Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t strlcpy(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0 && --n != 0) { do { if ((*d++ = *s++) == 0) break; } while (--n != 0); } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } got-portable-0.101/compat/tree.h0000664000175100017510000006106414644144735012215 /* $OpenBSD: tree.h,v 1.13 2011/07/09 00:19:45 pirofti Exp $ */ /* * Copyright 2002 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SYS_TREE_H_ #define _SYS_TREE_H_ /* * This file defines data structures for different types of trees: * splay trees and red-black trees. * * A splay tree is a self-organizing data structure. Every operation * on the tree causes a splay to happen. The splay moves the requested * node to the root of the tree and partly rebalances it. * * This has the benefit that request locality causes faster lookups as * the requested nodes move to the top of the tree. On the other hand, * every lookup causes memory writes. * * The Balance Theorem bounds the total access time for m operations * and n inserts on an initially empty tree as O((m + n)lg n). The * amortized cost for a sequence of m accesses to a splay tree is O(lg n); * * A red-black tree is a binary search tree with the node color as an * extra attribute. It fulfills a set of conditions: * - every search path from the root to a leaf consists of the * same number of black nodes, * - each red node (except for the root) has a black parent, * - each leaf node is black. * * Every operation on a red-black tree is bounded as O(lg n). * The maximum height of a red-black tree is 2lg (n+1). */ #define SPLAY_HEAD(name, type) \ struct name { \ struct type *sph_root; /* root of the tree */ \ } #define SPLAY_INITIALIZER(root) \ { NULL } #define SPLAY_INIT(root) do { \ (root)->sph_root = NULL; \ } while (0) #define SPLAY_ENTRY(type) \ struct { \ struct type *spe_left; /* left element */ \ struct type *spe_right; /* right element */ \ } #define SPLAY_LEFT(elm, field) (elm)->field.spe_left #define SPLAY_RIGHT(elm, field) (elm)->field.spe_right #define SPLAY_ROOT(head) (head)->sph_root #define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) /* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ #define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ (head)->sph_root = tmp; \ } while (0) #define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ SPLAY_LEFT(tmp, field) = (head)->sph_root; \ (head)->sph_root = tmp; \ } while (0) #define SPLAY_LINKLEFT(head, tmp, field) do { \ SPLAY_LEFT(tmp, field) = (head)->sph_root; \ tmp = (head)->sph_root; \ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ } while (0) #define SPLAY_LINKRIGHT(head, tmp, field) do { \ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ tmp = (head)->sph_root; \ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ } while (0) #define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ } while (0) /* Generates prototypes and inline functions */ #define SPLAY_PROTOTYPE(name, type, field, cmp) \ void name##_SPLAY(struct name *, struct type *); \ void name##_SPLAY_MINMAX(struct name *, int); \ struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ \ /* Finds the node with the same key as elm */ \ static __inline struct type * \ name##_SPLAY_FIND(struct name *head, struct type *elm) \ { \ if (SPLAY_EMPTY(head)) \ return(NULL); \ name##_SPLAY(head, elm); \ if ((cmp)(elm, (head)->sph_root) == 0) \ return (head->sph_root); \ return (NULL); \ } \ \ static __inline struct type * \ name##_SPLAY_NEXT(struct name *head, struct type *elm) \ { \ name##_SPLAY(head, elm); \ if (SPLAY_RIGHT(elm, field) != NULL) { \ elm = SPLAY_RIGHT(elm, field); \ while (SPLAY_LEFT(elm, field) != NULL) { \ elm = SPLAY_LEFT(elm, field); \ } \ } else \ elm = NULL; \ return (elm); \ } \ \ static __inline struct type * \ name##_SPLAY_MIN_MAX(struct name *head, int val) \ { \ name##_SPLAY_MINMAX(head, val); \ return (SPLAY_ROOT(head)); \ } /* Main splay operation. * Moves node close to the key of elm to top */ #define SPLAY_GENERATE(name, type, field, cmp) \ struct type * \ name##_SPLAY_INSERT(struct name *head, struct type *elm) \ { \ if (SPLAY_EMPTY(head)) { \ SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ } else { \ int __comp; \ name##_SPLAY(head, elm); \ __comp = (cmp)(elm, (head)->sph_root); \ if(__comp < 0) { \ SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ SPLAY_RIGHT(elm, field) = (head)->sph_root; \ SPLAY_LEFT((head)->sph_root, field) = NULL; \ } else if (__comp > 0) { \ SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ SPLAY_LEFT(elm, field) = (head)->sph_root; \ SPLAY_RIGHT((head)->sph_root, field) = NULL; \ } else \ return ((head)->sph_root); \ } \ (head)->sph_root = (elm); \ return (NULL); \ } \ \ struct type * \ name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ { \ struct type *__tmp; \ if (SPLAY_EMPTY(head)) \ return (NULL); \ name##_SPLAY(head, elm); \ if ((cmp)(elm, (head)->sph_root) == 0) { \ if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ } else { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ name##_SPLAY(head, elm); \ SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ } \ return (elm); \ } \ return (NULL); \ } \ \ void \ name##_SPLAY(struct name *head, struct type *elm) \ { \ struct type __node, *__left, *__right, *__tmp; \ int __comp; \ \ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ __left = __right = &__node; \ \ while ((__comp = (cmp)(elm, (head)->sph_root))) { \ if (__comp < 0) { \ __tmp = SPLAY_LEFT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if ((cmp)(elm, __tmp) < 0){ \ SPLAY_ROTATE_RIGHT(head, __tmp, field); \ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKLEFT(head, __right, field); \ } else if (__comp > 0) { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if ((cmp)(elm, __tmp) > 0){ \ SPLAY_ROTATE_LEFT(head, __tmp, field); \ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKRIGHT(head, __left, field); \ } \ } \ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ } \ \ /* Splay with either the minimum or the maximum element \ * Used to find minimum or maximum element in tree. \ */ \ void name##_SPLAY_MINMAX(struct name *head, int __comp) \ { \ struct type __node, *__left, *__right, *__tmp; \ \ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ __left = __right = &__node; \ \ while (1) { \ if (__comp < 0) { \ __tmp = SPLAY_LEFT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if (__comp < 0){ \ SPLAY_ROTATE_RIGHT(head, __tmp, field); \ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKLEFT(head, __right, field); \ } else if (__comp > 0) { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if (__comp > 0) { \ SPLAY_ROTATE_LEFT(head, __tmp, field); \ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKRIGHT(head, __left, field); \ } \ } \ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ } #define SPLAY_NEGINF -1 #define SPLAY_INF 1 #define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) #define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) #define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) #define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) #define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) #define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) #define SPLAY_FOREACH(x, name, head) \ for ((x) = SPLAY_MIN(name, head); \ (x) != NULL; \ (x) = SPLAY_NEXT(name, head, x)) /* Macros that define a red-black tree */ #define RB_HEAD(name, type) \ struct name { \ struct type *rbh_root; /* root of the tree */ \ } #define RB_INITIALIZER(root) \ { NULL } #define RB_INIT(root) do { \ (root)->rbh_root = NULL; \ } while (0) #define RB_BLACK 0 #define RB_RED 1 #define RB_ENTRY(type) \ struct { \ struct type *rbe_left; /* left element */ \ struct type *rbe_right; /* right element */ \ struct type *rbe_parent; /* parent element */ \ int rbe_color; /* node color */ \ } #define RB_LEFT(elm, field) (elm)->field.rbe_left #define RB_RIGHT(elm, field) (elm)->field.rbe_right #define RB_PARENT(elm, field) (elm)->field.rbe_parent #define RB_COLOR(elm, field) (elm)->field.rbe_color #define RB_ROOT(head) (head)->rbh_root #define RB_EMPTY(head) (RB_ROOT(head) == NULL) #define RB_SET(elm, parent, field) do { \ RB_PARENT(elm, field) = parent; \ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ RB_COLOR(elm, field) = RB_RED; \ } while (0) #define RB_SET_BLACKRED(black, red, field) do { \ RB_COLOR(black, field) = RB_BLACK; \ RB_COLOR(red, field) = RB_RED; \ } while (0) #ifndef RB_AUGMENT #define RB_AUGMENT(x) do {} while (0) #endif #define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ (tmp) = RB_RIGHT(elm, field); \ if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ } \ RB_AUGMENT(elm); \ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ else \ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ } else \ (head)->rbh_root = (tmp); \ RB_LEFT(tmp, field) = (elm); \ RB_PARENT(elm, field) = (tmp); \ RB_AUGMENT(tmp); \ if ((RB_PARENT(tmp, field))) \ RB_AUGMENT(RB_PARENT(tmp, field)); \ } while (0) #define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ (tmp) = RB_LEFT(elm, field); \ if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ } \ RB_AUGMENT(elm); \ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ else \ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ } else \ (head)->rbh_root = (tmp); \ RB_RIGHT(tmp, field) = (elm); \ RB_PARENT(elm, field) = (tmp); \ RB_AUGMENT(tmp); \ if ((RB_PARENT(tmp, field))) \ RB_AUGMENT(RB_PARENT(tmp, field)); \ } while (0) /* Generates prototypes and inline functions */ #define RB_PROTOTYPE(name, type, field, cmp) \ RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) #define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static) #define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \ attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ attr struct type *name##_RB_REMOVE(struct name *, struct type *); \ attr struct type *name##_RB_INSERT(struct name *, struct type *); \ attr struct type *name##_RB_FIND(struct name *, struct type *); \ attr struct type *name##_RB_NFIND(struct name *, struct type *); \ attr struct type *name##_RB_NEXT(struct type *); \ attr struct type *name##_RB_PREV(struct type *); \ attr struct type *name##_RB_MINMAX(struct name *, int); \ \ /* Main rb operation. * Moves node close to the key of elm to top */ #define RB_GENERATE(name, type, field, cmp) \ RB_GENERATE_INTERNAL(name, type, field, cmp,) #define RB_GENERATE_STATIC(name, type, field, cmp) \ RB_GENERATE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static) #define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ attr void \ name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ { \ struct type *parent, *gparent, *tmp; \ while ((parent = RB_PARENT(elm, field)) && \ RB_COLOR(parent, field) == RB_RED) { \ gparent = RB_PARENT(parent, field); \ if (parent == RB_LEFT(gparent, field)) { \ tmp = RB_RIGHT(gparent, field); \ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ RB_COLOR(tmp, field) = RB_BLACK; \ RB_SET_BLACKRED(parent, gparent, field);\ elm = gparent; \ continue; \ } \ if (RB_RIGHT(parent, field) == elm) { \ RB_ROTATE_LEFT(head, parent, tmp, field);\ tmp = parent; \ parent = elm; \ elm = tmp; \ } \ RB_SET_BLACKRED(parent, gparent, field); \ RB_ROTATE_RIGHT(head, gparent, tmp, field); \ } else { \ tmp = RB_LEFT(gparent, field); \ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ RB_COLOR(tmp, field) = RB_BLACK; \ RB_SET_BLACKRED(parent, gparent, field);\ elm = gparent; \ continue; \ } \ if (RB_LEFT(parent, field) == elm) { \ RB_ROTATE_RIGHT(head, parent, tmp, field);\ tmp = parent; \ parent = elm; \ elm = tmp; \ } \ RB_SET_BLACKRED(parent, gparent, field); \ RB_ROTATE_LEFT(head, gparent, tmp, field); \ } \ } \ RB_COLOR(head->rbh_root, field) = RB_BLACK; \ } \ \ attr void \ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ { \ struct type *tmp; \ while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ elm != RB_ROOT(head)) { \ if (RB_LEFT(parent, field) == elm) { \ tmp = RB_RIGHT(parent, field); \ if (RB_COLOR(tmp, field) == RB_RED) { \ RB_SET_BLACKRED(tmp, parent, field); \ RB_ROTATE_LEFT(head, parent, tmp, field);\ tmp = RB_RIGHT(parent, field); \ } \ if ((RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ RB_COLOR(tmp, field) = RB_RED; \ elm = parent; \ parent = RB_PARENT(elm, field); \ } else { \ if (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ struct type *oleft; \ if ((oleft = RB_LEFT(tmp, field)))\ RB_COLOR(oleft, field) = RB_BLACK;\ RB_COLOR(tmp, field) = RB_RED; \ RB_ROTATE_RIGHT(head, tmp, oleft, field);\ tmp = RB_RIGHT(parent, field); \ } \ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ RB_COLOR(parent, field) = RB_BLACK; \ if (RB_RIGHT(tmp, field)) \ RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ RB_ROTATE_LEFT(head, parent, tmp, field);\ elm = RB_ROOT(head); \ break; \ } \ } else { \ tmp = RB_LEFT(parent, field); \ if (RB_COLOR(tmp, field) == RB_RED) { \ RB_SET_BLACKRED(tmp, parent, field); \ RB_ROTATE_RIGHT(head, parent, tmp, field);\ tmp = RB_LEFT(parent, field); \ } \ if ((RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ RB_COLOR(tmp, field) = RB_RED; \ elm = parent; \ parent = RB_PARENT(elm, field); \ } else { \ if (RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ struct type *oright; \ if ((oright = RB_RIGHT(tmp, field)))\ RB_COLOR(oright, field) = RB_BLACK;\ RB_COLOR(tmp, field) = RB_RED; \ RB_ROTATE_LEFT(head, tmp, oright, field);\ tmp = RB_LEFT(parent, field); \ } \ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ RB_COLOR(parent, field) = RB_BLACK; \ if (RB_LEFT(tmp, field)) \ RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ RB_ROTATE_RIGHT(head, parent, tmp, field);\ elm = RB_ROOT(head); \ break; \ } \ } \ } \ if (elm) \ RB_COLOR(elm, field) = RB_BLACK; \ } \ \ attr struct type * \ name##_RB_REMOVE(struct name *head, struct type *elm) \ { \ struct type *child, *parent, *old = elm; \ int color; \ if (RB_LEFT(elm, field) == NULL) \ child = RB_RIGHT(elm, field); \ else if (RB_RIGHT(elm, field) == NULL) \ child = RB_LEFT(elm, field); \ else { \ struct type *left; \ elm = RB_RIGHT(elm, field); \ while ((left = RB_LEFT(elm, field))) \ elm = left; \ child = RB_RIGHT(elm, field); \ parent = RB_PARENT(elm, field); \ color = RB_COLOR(elm, field); \ if (child) \ RB_PARENT(child, field) = parent; \ if (parent) { \ if (RB_LEFT(parent, field) == elm) \ RB_LEFT(parent, field) = child; \ else \ RB_RIGHT(parent, field) = child; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = child; \ if (RB_PARENT(elm, field) == old) \ parent = elm; \ (elm)->field = (old)->field; \ if (RB_PARENT(old, field)) { \ if (RB_LEFT(RB_PARENT(old, field), field) == old)\ RB_LEFT(RB_PARENT(old, field), field) = elm;\ else \ RB_RIGHT(RB_PARENT(old, field), field) = elm;\ RB_AUGMENT(RB_PARENT(old, field)); \ } else \ RB_ROOT(head) = elm; \ RB_PARENT(RB_LEFT(old, field), field) = elm; \ if (RB_RIGHT(old, field)) \ RB_PARENT(RB_RIGHT(old, field), field) = elm; \ if (parent) { \ left = parent; \ do { \ RB_AUGMENT(left); \ } while ((left = RB_PARENT(left, field))); \ } \ goto color; \ } \ parent = RB_PARENT(elm, field); \ color = RB_COLOR(elm, field); \ if (child) \ RB_PARENT(child, field) = parent; \ if (parent) { \ if (RB_LEFT(parent, field) == elm) \ RB_LEFT(parent, field) = child; \ else \ RB_RIGHT(parent, field) = child; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = child; \ color: \ if (color == RB_BLACK) \ name##_RB_REMOVE_COLOR(head, parent, child); \ return (old); \ } \ \ /* Inserts a node into the RB tree */ \ attr struct type * \ name##_RB_INSERT(struct name *head, struct type *elm) \ { \ struct type *tmp; \ struct type *parent = NULL; \ int comp = 0; \ tmp = RB_ROOT(head); \ while (tmp) { \ parent = tmp; \ comp = (cmp)(elm, parent); \ if (comp < 0) \ tmp = RB_LEFT(tmp, field); \ else if (comp > 0) \ tmp = RB_RIGHT(tmp, field); \ else \ return (tmp); \ } \ RB_SET(elm, parent, field); \ if (parent != NULL) { \ if (comp < 0) \ RB_LEFT(parent, field) = elm; \ else \ RB_RIGHT(parent, field) = elm; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = elm; \ name##_RB_INSERT_COLOR(head, elm); \ return (NULL); \ } \ \ /* Finds the node with the same key as elm */ \ attr struct type * \ name##_RB_FIND(struct name *head, struct type *elm) \ { \ struct type *tmp = RB_ROOT(head); \ int comp; \ while (tmp) { \ comp = cmp(elm, tmp); \ if (comp < 0) \ tmp = RB_LEFT(tmp, field); \ else if (comp > 0) \ tmp = RB_RIGHT(tmp, field); \ else \ return (tmp); \ } \ return (NULL); \ } \ \ /* Finds the first node greater than or equal to the search key */ \ attr struct type * \ name##_RB_NFIND(struct name *head, struct type *elm) \ { \ struct type *tmp = RB_ROOT(head); \ struct type *res = NULL; \ int comp; \ while (tmp) { \ comp = cmp(elm, tmp); \ if (comp < 0) { \ res = tmp; \ tmp = RB_LEFT(tmp, field); \ } \ else if (comp > 0) \ tmp = RB_RIGHT(tmp, field); \ else \ return (tmp); \ } \ return (res); \ } \ \ /* ARGSUSED */ \ attr struct type * \ name##_RB_NEXT(struct type *elm) \ { \ if (RB_RIGHT(elm, field)) { \ elm = RB_RIGHT(elm, field); \ while (RB_LEFT(elm, field)) \ elm = RB_LEFT(elm, field); \ } else { \ if (RB_PARENT(elm, field) && \ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ elm = RB_PARENT(elm, field); \ else { \ while (RB_PARENT(elm, field) && \ (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ elm = RB_PARENT(elm, field); \ elm = RB_PARENT(elm, field); \ } \ } \ return (elm); \ } \ \ /* ARGSUSED */ \ attr struct type * \ name##_RB_PREV(struct type *elm) \ { \ if (RB_LEFT(elm, field)) { \ elm = RB_LEFT(elm, field); \ while (RB_RIGHT(elm, field)) \ elm = RB_RIGHT(elm, field); \ } else { \ if (RB_PARENT(elm, field) && \ (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ elm = RB_PARENT(elm, field); \ else { \ while (RB_PARENT(elm, field) && \ (elm == RB_LEFT(RB_PARENT(elm, field), field)))\ elm = RB_PARENT(elm, field); \ elm = RB_PARENT(elm, field); \ } \ } \ return (elm); \ } \ \ attr struct type * \ name##_RB_MINMAX(struct name *head, int val) \ { \ struct type *tmp = RB_ROOT(head); \ struct type *parent = NULL; \ while (tmp) { \ parent = tmp; \ if (val < 0) \ tmp = RB_LEFT(tmp, field); \ else \ tmp = RB_RIGHT(tmp, field); \ } \ return (parent); \ } #define RB_NEGINF -1 #define RB_INF 1 #define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) #define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) #define RB_FIND(name, x, y) name##_RB_FIND(x, y) #define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) #define RB_NEXT(name, x, y) name##_RB_NEXT(y) #define RB_PREV(name, x, y) name##_RB_PREV(y) #define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) #define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) #define RB_FOREACH(x, name, head) \ for ((x) = RB_MIN(name, head); \ (x) != NULL; \ (x) = name##_RB_NEXT(x)) #define RB_FOREACH_SAFE(x, name, head, y) \ for ((x) = RB_MIN(name, head); \ ((x) != NULL) && ((y) = name##_RB_NEXT(x), 1); \ (x) = (y)) #define RB_FOREACH_REVERSE(x, name, head) \ for ((x) = RB_MAX(name, head); \ (x) != NULL; \ (x) = name##_RB_PREV(x)) #define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ for ((x) = RB_MAX(name, head); \ ((x) != NULL) && ((y) = name##_RB_PREV(x), 1); \ (x) = (y)) #endif /* _SYS_TREE_H_ */ got-portable-0.101/compat/strndup.c0000664000175100017510000000223214644144735012740 /* $OpenBSD: strndup.c,v 1.2 2015/08/31 02:53:57 guenther Exp $ */ /* * Copyright (c) 2010 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include char * strndup(const char *str, size_t maxlen) { char *copy; size_t len; len = strnlen(str, maxlen); copy = malloc(len + 1); if (copy != NULL) { (void)memcpy(copy, str, len); copy[len] = '\0'; } return copy; } got-portable-0.101/compat/asprintf.c0000664000175100017510000000300114644144735013062 /* * Copyright (c) 2006 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include int vasprintf(char **, const char *, va_list); int asprintf(char **ret, const char *fmt, ...) { va_list ap; int n; va_start(ap, fmt); n = vasprintf(ret, fmt, ap); va_end(ap); return (n); } int vasprintf(char **ret, const char *fmt, va_list ap) { int n; va_list ap2; va_copy(ap2, ap); if ((n = vsnprintf(NULL, 0, fmt, ap)) < 0) goto error; *ret = malloc(n + 1); if (*ret == NULL) errx(1, "vasprintf: malloc failed"); if ((n = vsnprintf(*ret, n + 1, fmt, ap2)) < 0) { free(*ret); goto error; } va_end(ap2); return (n); error: va_end(ap2); *ret = NULL; return (-1); } got-portable-0.101/compat/strnlen.c0000664000175100017510000000206414644144735012731 /* $OpenBSD: strnlen.c,v 1.8 2016/10/16 17:37:39 dtucker Exp $ */ /* * Copyright (c) 2010 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include size_t strnlen(const char *str, size_t maxlen) { const char *cp; for (cp = str; maxlen != 0 && *cp != '\0'; cp++, maxlen--) ; return (size_t)(cp - str); } got-portable-0.101/compat/landlock.c0000664000175100017510000000711614644144735013036 /* * Copyright (c) 2021 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include "got_compat.h" /* * What's the deal with landlock? While distro with linux >= 5.13 * have the struct declarations, libc wrappers are missing. The * sample landlock code provided by the authors includes these "shims" * in their example for the landlock API until libc provides them. */ #ifndef landlock_create_ruleset static inline int landlock_create_ruleset(const struct landlock_ruleset_attr *attr, size_t size, __u32 flags) { return syscall(__NR_landlock_create_ruleset, attr, size, flags); } #endif #ifndef landlock_add_rule static inline int landlock_add_rule(int ruleset_fd, enum landlock_rule_type type, const void *attr, __u32 flags) { return syscall(__NR_landlock_add_rule, ruleset_fd, type, attr, flags); } #endif #ifndef landlock_restrict_self static inline int landlock_restrict_self(int ruleset_fd, __u32 flags) { return syscall(__NR_landlock_restrict_self, ruleset_fd, flags); } #endif /* * Maybe we should ship with a full copy of the linux headers because * you never know... */ #ifndef LANDLOCK_ACCESS_FS_REFER #define LANDLOCK_ACCESS_FS_REFER (1ULL << 13) #endif #ifndef LANDLOCK_ACCESS_FS_TRUNCATE #define LANDLOCK_ACCESS_FS_TRUNCATE (1ULL << 14) #endif /* * Revoke any fs access. */ int landlock_no_fs(void) { struct landlock_ruleset_attr rattr = { /* * List all capabilities currently defined by landlock. * Failure in doing so will implicitly allow those actions * (i.e. omitting READ_FILE will allow to read _any_ file.) */ .handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR | LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_REMOVE_DIR | LANDLOCK_ACCESS_FS_REMOVE_FILE | LANDLOCK_ACCESS_FS_MAKE_CHAR | LANDLOCK_ACCESS_FS_MAKE_DIR | LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_MAKE_SOCK | LANDLOCK_ACCESS_FS_MAKE_FIFO | LANDLOCK_ACCESS_FS_MAKE_BLOCK | LANDLOCK_ACCESS_FS_MAKE_SYM | LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_TRUNCATE, }; int fd, abi, saved_errno; if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) return -1; abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION); if (abi == -1) { /* this kernel doesn't have landlock built in */ if (errno == ENOSYS || errno == EOPNOTSUPP) return 0; return -1; } if (abi < 2) rattr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER; if (abi < 3) rattr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE; fd = landlock_create_ruleset(&rattr, sizeof(rattr), 0); if (fd == -1) return -1; if (landlock_restrict_self(fd, 0)) { saved_errno = errno; close(fd); errno = saved_errno; return -1; } close(fd); return 0; } got-portable-0.101/compat/merge.c0000664000175100017510000002165314644144735012350 /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Peter McIlroy. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include /* * Hybrid exponential search/linear search merge sort with hybrid * natural/pairwise first pass. Requires about .3% more comparisons * for random data than LSMS with pairwise first pass alone. * It works for objects as small as two bytes. */ #define NATURAL #define THRESHOLD 16 /* Best choice for natural merge cut-off. */ /* #define NATURAL to get hybrid natural merge. * (The default is pairwise merging.) */ #include #include #include #include #include "got_compat.h" static void setup(unsigned char *, unsigned char *, size_t, size_t, int (*)(const void *, const void *)); static void insertionsort(unsigned char *, size_t, size_t, int (*)(const void *, const void *)); #define ISIZE sizeof(int) #define PSIZE sizeof(unsigned char *) #define ICOPY_LIST(src, dst, last) \ do \ *(int*)dst = *(int*)src, src += ISIZE, dst += ISIZE; \ while(src < last) #define ICOPY_ELT(src, dst, i) \ do \ *(int*) dst = *(int*) src, src += ISIZE, dst += ISIZE; \ while (i -= ISIZE) #define CCOPY_LIST(src, dst, last) \ do \ *dst++ = *src++; \ while (src < last) #define CCOPY_ELT(src, dst, i) \ do \ *dst++ = *src++; \ while (i -= 1) /* * Find the next possible pointer head. (Trickery for forcing an array * to do double duty as a linked list when objects do not align with word * boundaries. */ /* Assumption: PSIZE is a power of 2. */ #define EVAL(p) (unsigned char **) \ ((unsigned char *)0 + \ (((unsigned char *)p + PSIZE - 1 - \ (unsigned char *)0) & ~(PSIZE - 1))) /* * Arguments are as for qsort. */ int mergesort(void *base, size_t nmemb, size_t size, int (*cmp)(const void *, const void *)) { size_t i; int sense; int big, iflag; unsigned char *f1, *f2, *t, *b, *tp2, *q, *l1, *l2; unsigned char *list2, *list1, *p2, *p, *last, **p1; if (size < PSIZE / 2) { /* Pointers must fit into 2 * size. */ errno = EINVAL; return (-1); } if (nmemb == 0) return (0); /* * XXX * Stupid subtraction for the Cray. */ iflag = 0; if (!(size % ISIZE) && !(((char *)base - (char *)0) % ISIZE)) iflag = 1; if ((list2 = malloc(nmemb * size + PSIZE)) == NULL) return (-1); list1 = base; setup(list1, list2, nmemb, size, cmp); last = list2 + nmemb * size; i = big = 0; while (*EVAL(list2) != last) { l2 = list1; p1 = EVAL(list1); for (tp2 = p2 = list2; p2 != last; p1 = EVAL(l2)) { p2 = *EVAL(p2); f1 = l2; f2 = l1 = list1 + (p2 - list2); if (p2 != last) p2 = *EVAL(p2); l2 = list1 + (p2 - list2); while (f1 < l1 && f2 < l2) { if ((*cmp)(f1, f2) <= 0) { q = f2; b = f1, t = l1; sense = -1; } else { q = f1; b = f2, t = l2; sense = 0; } if (!big) { /* here i = 0 */ while ((b += size) < t && cmp(q, b) >sense) if (++i == 6) { big = 1; goto EXPONENTIAL; } } else { EXPONENTIAL: for (i = size; ; i <<= 1) if ((p = (b + i)) >= t) { if ((p = t - size) > b && (*cmp)(q, p) <= sense) t = p; else b = p; break; } else if ((*cmp)(q, p) <= sense) { t = p; if (i == size) big = 0; goto FASTCASE; } else b = p; while (t > b+size) { i = (((t - b) / size) >> 1) * size; if ((*cmp)(q, p = b + i) <= sense) t = p; else b = p; } goto COPY; FASTCASE: while (i > size) if ((*cmp)(q, p = b + (i >>= 1)) <= sense) t = p; else b = p; COPY: b = t; } i = size; if (q == f1) { if (iflag) { ICOPY_LIST(f2, tp2, b); ICOPY_ELT(f1, tp2, i); } else { CCOPY_LIST(f2, tp2, b); CCOPY_ELT(f1, tp2, i); } } else { if (iflag) { ICOPY_LIST(f1, tp2, b); ICOPY_ELT(f2, tp2, i); } else { CCOPY_LIST(f1, tp2, b); CCOPY_ELT(f2, tp2, i); } } } if (f2 < l2) { if (iflag) ICOPY_LIST(f2, tp2, l2); else CCOPY_LIST(f2, tp2, l2); } else if (f1 < l1) { if (iflag) ICOPY_LIST(f1, tp2, l1); else CCOPY_LIST(f1, tp2, l1); } *p1 = l2; } tp2 = list1; /* swap list1, list2 */ list1 = list2; list2 = tp2; last = list2 + nmemb*size; } if (base == list2) { memmove(list2, list1, nmemb*size); list2 = list1; } free(list2); return (0); } #define swap(a, b) { \ s = b; \ i = size; \ do { \ tmp = *a; *a++ = *s; *s++ = tmp; \ } while (--i); \ a -= size; \ } #define reverse(bot, top) { \ s = top; \ do { \ i = size; \ do { \ tmp = *bot; *bot++ = *s; *s++ = tmp; \ } while (--i); \ s -= size2; \ } while(bot < s); \ } /* * Optional hybrid natural/pairwise first pass. Eats up list1 in runs of * increasing order, list2 in a corresponding linked list. Checks for runs * when THRESHOLD/2 pairs compare with same sense. (Only used when NATURAL * is defined. Otherwise simple pairwise merging is used.) */ static void setup(unsigned char *list1, unsigned char *list2, size_t n, size_t size, int (*cmp)(const void *, const void *)) { int i, length, size2, tmp, sense; unsigned char *f1, *f2, *s, *l2, *last, *p2; size2 = size*2; if (n <= 5) { insertionsort(list1, n, size, cmp); *EVAL(list2) = (unsigned char*) list2 + n*size; return; } /* * Avoid running pointers out of bounds; limit n to evens * for simplicity. */ i = 4 + (n & 1); insertionsort(list1 + (n - i) * size, i, size, cmp); last = list1 + size * (n - i); *EVAL(list2 + (last - list1)) = list2 + n * size; #ifdef NATURAL p2 = list2; f1 = list1; sense = (cmp(f1, f1 + size) > 0); for (; f1 < last; sense = !sense) { length = 2; /* Find pairs with same sense. */ for (f2 = f1 + size2; f2 < last; f2 += size2) { if ((cmp(f2, f2+ size) > 0) != sense) break; length += 2; } if (length < THRESHOLD) { /* Pairwise merge */ do { p2 = *EVAL(p2) = f1 + size2 - list1 + list2; if (sense > 0) swap (f1, f1 + size); } while ((f1 += size2) < f2); } else { /* Natural merge */ l2 = f2; for (f2 = f1 + size2; f2 < l2; f2 += size2) { if ((cmp(f2-size, f2) > 0) != sense) { p2 = *EVAL(p2) = f2 - list1 + list2; if (sense > 0) reverse(f1, f2-size); f1 = f2; } } if (sense > 0) reverse (f1, f2-size); f1 = f2; if (f2 < last || cmp(f2 - size, f2) > 0) p2 = *EVAL(p2) = f2 - list1 + list2; else p2 = *EVAL(p2) = list2 + n*size; } } #else /* pairwise merge only. */ for (f1 = list1, p2 = list2; f1 < last; f1 += size2) { p2 = *EVAL(p2) = p2 + size2; if (cmp (f1, f1 + size) > 0) swap(f1, f1 + size); } #endif /* NATURAL */ } /* * This is to avoid out-of-bounds addresses in sorting the * last 4 elements. */ static void insertionsort(unsigned char *a, size_t n, size_t size, int (*cmp)(const void *, const void *)) { unsigned char *ai, *s, *t, *u, tmp; int i; for (ai = a+size; --n >= 1; ai += size) for (t = ai; t > a; t -= size) { u = t - size; if (cmp(u, t) <= 0) break; swap(u, t); } } got-portable-0.101/compat/imsg.h0000664000175100017510000001225514644144735012213 /* $OpenBSD: imsg.h,v 1.8 2023/12/12 15:47:41 claudio Exp $ */ /* * Copyright (c) 2023 Claudio Jeker * Copyright (c) 2006, 2007 Pierre-Yves Ritschard * Copyright (c) 2006, 2007, 2008 Reyk Floeter * Copyright (c) 2003, 2004 Henning Brauer * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _IMSG_H_ #define _IMSG_H_ #include #define IBUF_READ_SIZE 65535 #define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) #define MAX_IMSGSIZE 16384 struct ibuf { TAILQ_ENTRY(ibuf) entry; unsigned char *buf; size_t size; size_t max; size_t wpos; size_t rpos; int fd; }; struct msgbuf { TAILQ_HEAD(, ibuf) bufs; uint32_t queued; int fd; }; struct ibuf_read { unsigned char buf[IBUF_READ_SIZE]; unsigned char *rptr; size_t wpos; }; struct imsg_fd; struct imsgbuf { TAILQ_HEAD(, imsg_fd) fds; struct ibuf_read r; struct msgbuf w; int fd; pid_t pid; }; #define IMSGF_HASFD 1 struct imsg_hdr { uint32_t type; uint16_t len; uint16_t flags; uint32_t peerid; uint32_t pid; }; struct imsg { struct imsg_hdr hdr; int fd; void *data; struct ibuf *buf; }; struct iovec; /* imsg-buffer.c */ struct ibuf *ibuf_open(size_t); struct ibuf *ibuf_dynamic(size_t, size_t); int ibuf_add(struct ibuf *, const void *, size_t); int ibuf_add_buf(struct ibuf *, const struct ibuf *); int ibuf_add_ibuf(struct ibuf *, const struct ibuf *); int ibuf_add_zero(struct ibuf *, size_t); int ibuf_add_n8(struct ibuf *, uint64_t); int ibuf_add_n16(struct ibuf *, uint64_t); int ibuf_add_n32(struct ibuf *, uint64_t); int ibuf_add_n64(struct ibuf *, uint64_t); int ibuf_add_h16(struct ibuf *, uint64_t); int ibuf_add_h32(struct ibuf *, uint64_t); int ibuf_add_h64(struct ibuf *, uint64_t); void *ibuf_reserve(struct ibuf *, size_t); void *ibuf_seek(struct ibuf *, size_t, size_t); int ibuf_set(struct ibuf *, size_t, const void *, size_t); int ibuf_set_n8(struct ibuf *, size_t, uint64_t); int ibuf_set_n16(struct ibuf *, size_t, uint64_t); int ibuf_set_n32(struct ibuf *, size_t, uint64_t); int ibuf_set_n64(struct ibuf *, size_t, uint64_t); int ibuf_set_h16(struct ibuf *, size_t, uint64_t); int ibuf_set_h32(struct ibuf *, size_t, uint64_t); int ibuf_set_h64(struct ibuf *, size_t, uint64_t); void *ibuf_data(const struct ibuf *); size_t ibuf_size(const struct ibuf *); size_t ibuf_left(const struct ibuf *); int ibuf_truncate(struct ibuf *, size_t); void ibuf_rewind(struct ibuf *); void ibuf_close(struct msgbuf *, struct ibuf *); void ibuf_from_buffer(struct ibuf *, void *, size_t); void ibuf_from_ibuf(struct ibuf *, const struct ibuf *); int ibuf_get(struct ibuf *, void *, size_t); int ibuf_get_ibuf(struct ibuf *, size_t, struct ibuf *); int ibuf_get_n8(struct ibuf *, uint8_t *); int ibuf_get_n16(struct ibuf *, uint16_t *); int ibuf_get_n32(struct ibuf *, uint32_t *); int ibuf_get_n64(struct ibuf *, uint64_t *); int ibuf_get_h16(struct ibuf *, uint16_t *); int ibuf_get_h32(struct ibuf *, uint32_t *); int ibuf_get_h64(struct ibuf *, uint64_t *); int ibuf_skip(struct ibuf *, size_t); void ibuf_free(struct ibuf *); int ibuf_fd_avail(struct ibuf *); int ibuf_fd_get(struct ibuf *); void ibuf_fd_set(struct ibuf *, int); int ibuf_write(struct msgbuf *); void msgbuf_init(struct msgbuf *); void msgbuf_clear(struct msgbuf *); uint32_t msgbuf_queuelen(struct msgbuf *); int msgbuf_write(struct msgbuf *); /* imsg.c */ void imsg_init(struct imsgbuf *, int); ssize_t imsg_read(struct imsgbuf *); ssize_t imsg_get(struct imsgbuf *, struct imsg *); int imsg_get_ibuf(struct imsg *, struct ibuf *); int imsg_get_data(struct imsg *, void *, size_t); int imsg_get_fd(struct imsg *); uint32_t imsg_get_id(struct imsg *); size_t imsg_get_len(struct imsg *); pid_t imsg_get_pid(struct imsg *); uint32_t imsg_get_type(struct imsg *); int imsg_forward(struct imsgbuf *, struct imsg *); int imsg_compose(struct imsgbuf *, uint32_t, uint32_t, pid_t, int, const void *, size_t); int imsg_composev(struct imsgbuf *, uint32_t, uint32_t, pid_t, int, const struct iovec *, int); int imsg_compose_ibuf(struct imsgbuf *, uint32_t, uint32_t, pid_t, struct ibuf *); struct ibuf *imsg_create(struct imsgbuf *, uint32_t, uint32_t, pid_t, size_t); int imsg_add(struct ibuf *, const void *, size_t); void imsg_close(struct imsgbuf *, struct ibuf *); void imsg_free(struct imsg *); int imsg_flush(struct imsgbuf *); void imsg_clear(struct imsgbuf *); #endif got-portable-0.101/compat/bsd-poll.c0000664000175100017510000000620614644144735012762 /* * Copyright (c) 2004, 2005, 2007 Darren Tucker (dtucker at zip com au). * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_SYS_SELECT_H # include #endif #include #include #include #include "bsd-poll.h" #ifndef MAX #define MAX(_a,_b) ((_a) > (_b) ? (_a) : (_b)) #endif #ifndef howmany #define howmany(x,y) (((x)+((y)-1))/(y)) #endif /* * A minimal implementation of ppoll(2), built on top of pselect(2). * * Only supports POLLIN, POLLOUT and POLLPRI flags in pfd.events and * revents. Notably POLLERR, POLLHUP and POLLNVAL are not supported. * * Supports pfd.fd = -1 meaning "unused" although it's not standard. */ int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmoutp, const sigset_t *sigmask) { nfds_t i; int saved_errno, ret, fd, maxfd = 0; fd_set *readfds = NULL, *writefds = NULL, *exceptfds = NULL; size_t nmemb; for (i = 0; i < nfds; i++) { fd = fds[i].fd; if (fd != -1 && fd >= FD_SETSIZE) { errno = EINVAL; return -1; } maxfd = MAX(maxfd, fd); } nmemb = howmany(maxfd + 1 , NFDBITS); if ((readfds = calloc(nmemb, sizeof(fd_mask))) == NULL || (writefds = calloc(nmemb, sizeof(fd_mask))) == NULL || (exceptfds = calloc(nmemb, sizeof(fd_mask))) == NULL) { saved_errno = ENOMEM; ret = -1; goto out; } /* populate event bit vectors for the events we're interested in */ for (i = 0; i < nfds; i++) { fd = fds[i].fd; if (fd == -1) continue; if (fds[i].events & POLLIN) FD_SET(fd, readfds); if (fds[i].events & POLLOUT) FD_SET(fd, writefds); if (fds[i].events & POLLPRI) FD_SET(fd, exceptfds); } ret = pselect(maxfd + 1, readfds, writefds, exceptfds, tmoutp, sigmask); saved_errno = errno; /* scan through select results and set poll() flags */ for (i = 0; i < nfds; i++) { fd = fds[i].fd; fds[i].revents = 0; if (fd == -1) continue; if (FD_ISSET(fd, readfds)) fds[i].revents |= POLLIN; if (FD_ISSET(fd, writefds)) fds[i].revents |= POLLOUT; if (FD_ISSET(fd, exceptfds)) fds[i].revents |= POLLPRI; } out: free(readfds); free(writefds); free(exceptfds); if (ret == -1) errno = saved_errno; return ret; } #if 0 int poll(struct pollfd *fds, nfds_t nfds, int timeout) { struct timespec ts, *tsp = NULL; /* poll timeout is msec, ppoll is timespec (sec + nsec) */ if (timeout >= 0) { ts.tv_sec = timeout / 1000; ts.tv_nsec = (timeout % 1000) * 1000000; tsp = &ts; } return ppoll(fds, nfds, tsp, NULL); } #endif got-portable-0.101/compat/imsg-buffer.c0000664000175100017510000003005214644144735013450 /* $OpenBSD: imsg-buffer.c,v 1.18 2023/12/12 15:47:41 claudio Exp $ */ /* * Copyright (c) 2023 Claudio Jeker * Copyright (c) 2003, 2004 Henning Brauer * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "imsg.h" static int ibuf_realloc(struct ibuf *, size_t); static void ibuf_enqueue(struct msgbuf *, struct ibuf *); static void ibuf_dequeue(struct msgbuf *, struct ibuf *); static void msgbuf_drain(struct msgbuf *, size_t); struct ibuf * ibuf_open(size_t len) { struct ibuf *buf; if (len == 0) { errno = EINVAL; return (NULL); } if ((buf = calloc(1, sizeof(struct ibuf))) == NULL) return (NULL); if ((buf->buf = calloc(len, 1)) == NULL) { free(buf); return (NULL); } buf->size = buf->max = len; buf->fd = -1; return (buf); } struct ibuf * ibuf_dynamic(size_t len, size_t max) { struct ibuf *buf; if (max == 0 || max < len) { errno = EINVAL; return (NULL); } if ((buf = calloc(1, sizeof(struct ibuf))) == NULL) return (NULL); if (len > 0) { if ((buf->buf = calloc(len, 1)) == NULL) { free(buf); return (NULL); } } buf->size = len; buf->max = max; buf->fd = -1; return (buf); } static int ibuf_realloc(struct ibuf *buf, size_t len) { unsigned char *b; /* on static buffers max is eq size and so the following fails */ if (len > SIZE_MAX - buf->wpos || buf->wpos + len > buf->max) { errno = ERANGE; return (-1); } b = recallocarray(buf->buf, buf->size, buf->wpos + len, 1); if (b == NULL) return (-1); buf->buf = b; buf->size = buf->wpos + len; return (0); } void * ibuf_reserve(struct ibuf *buf, size_t len) { void *b; if (len > SIZE_MAX - buf->wpos || buf->max == 0) { errno = ERANGE; return (NULL); } if (buf->wpos + len > buf->size) if (ibuf_realloc(buf, len) == -1) return (NULL); b = buf->buf + buf->wpos; buf->wpos += len; return (b); } int ibuf_add(struct ibuf *buf, const void *data, size_t len) { void *b; if ((b = ibuf_reserve(buf, len)) == NULL) return (-1); memcpy(b, data, len); return (0); } int ibuf_add_ibuf(struct ibuf *buf, const struct ibuf *from) { return ibuf_add(buf, ibuf_data(from), ibuf_size(from)); } /* remove after tree is converted */ int ibuf_add_buf(struct ibuf *buf, const struct ibuf *from) { return ibuf_add_ibuf(buf, from); } int ibuf_add_n8(struct ibuf *buf, uint64_t value) { uint8_t v; if (value > UINT8_MAX) { errno = EINVAL; return (-1); } v = value; return ibuf_add(buf, &v, sizeof(v)); } int ibuf_add_n16(struct ibuf *buf, uint64_t value) { uint16_t v; if (value > UINT16_MAX) { errno = EINVAL; return (-1); } v = htobe16(value); return ibuf_add(buf, &v, sizeof(v)); } int ibuf_add_n32(struct ibuf *buf, uint64_t value) { uint32_t v; if (value > UINT32_MAX) { errno = EINVAL; return (-1); } v = htobe32(value); return ibuf_add(buf, &v, sizeof(v)); } int ibuf_add_n64(struct ibuf *buf, uint64_t value) { value = htobe64(value); return ibuf_add(buf, &value, sizeof(value)); } int ibuf_add_h16(struct ibuf *buf, uint64_t value) { uint16_t v; if (value > UINT16_MAX) { errno = EINVAL; return (-1); } v = value; return ibuf_add(buf, &v, sizeof(v)); } int ibuf_add_h32(struct ibuf *buf, uint64_t value) { uint32_t v; if (value > UINT32_MAX) { errno = EINVAL; return (-1); } v = value; return ibuf_add(buf, &v, sizeof(v)); } int ibuf_add_h64(struct ibuf *buf, uint64_t value) { return ibuf_add(buf, &value, sizeof(value)); } int ibuf_add_zero(struct ibuf *buf, size_t len) { void *b; if ((b = ibuf_reserve(buf, len)) == NULL) return (-1); memset(b, 0, len); return (0); } void * ibuf_seek(struct ibuf *buf, size_t pos, size_t len) { /* only allow seeking between rpos and wpos */ if (ibuf_size(buf) < pos || SIZE_MAX - pos < len || ibuf_size(buf) < pos + len) { errno = ERANGE; return (NULL); } return (buf->buf + buf->rpos + pos); } int ibuf_set(struct ibuf *buf, size_t pos, const void *data, size_t len) { void *b; if ((b = ibuf_seek(buf, pos, len)) == NULL) return (-1); memcpy(b, data, len); return (0); } int ibuf_set_n8(struct ibuf *buf, size_t pos, uint64_t value) { uint8_t v; if (value > UINT8_MAX) { errno = EINVAL; return (-1); } v = value; return (ibuf_set(buf, pos, &v, sizeof(v))); } int ibuf_set_n16(struct ibuf *buf, size_t pos, uint64_t value) { uint16_t v; if (value > UINT16_MAX) { errno = EINVAL; return (-1); } v = htobe16(value); return (ibuf_set(buf, pos, &v, sizeof(v))); } int ibuf_set_n32(struct ibuf *buf, size_t pos, uint64_t value) { uint32_t v; if (value > UINT32_MAX) { errno = EINVAL; return (-1); } v = htobe32(value); return (ibuf_set(buf, pos, &v, sizeof(v))); } int ibuf_set_n64(struct ibuf *buf, size_t pos, uint64_t value) { value = htobe64(value); return (ibuf_set(buf, pos, &value, sizeof(value))); } int ibuf_set_h16(struct ibuf *buf, size_t pos, uint64_t value) { uint16_t v; if (value > UINT16_MAX) { errno = EINVAL; return (-1); } v = value; return (ibuf_set(buf, pos, &v, sizeof(v))); } int ibuf_set_h32(struct ibuf *buf, size_t pos, uint64_t value) { uint32_t v; if (value > UINT32_MAX) { errno = EINVAL; return (-1); } v = value; return (ibuf_set(buf, pos, &v, sizeof(v))); } int ibuf_set_h64(struct ibuf *buf, size_t pos, uint64_t value) { return (ibuf_set(buf, pos, &value, sizeof(value))); } void * ibuf_data(const struct ibuf *buf) { return (buf->buf + buf->rpos); } size_t ibuf_size(const struct ibuf *buf) { return (buf->wpos - buf->rpos); } size_t ibuf_left(const struct ibuf *buf) { if (buf->max == 0) return (0); return (buf->max - buf->wpos); } int ibuf_truncate(struct ibuf *buf, size_t len) { if (ibuf_size(buf) >= len) { buf->wpos = buf->rpos + len; return (0); } if (buf->max == 0) { /* only allow to truncate down */ errno = ERANGE; return (-1); } return ibuf_add_zero(buf, len - ibuf_size(buf)); } void ibuf_rewind(struct ibuf *buf) { buf->rpos = 0; } void ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf) { ibuf_enqueue(msgbuf, buf); } void ibuf_from_buffer(struct ibuf *buf, void *data, size_t len) { memset(buf, 0, sizeof(*buf)); buf->buf = data; buf->size = buf->wpos = len; buf->fd = -1; } void ibuf_from_ibuf(struct ibuf *buf, const struct ibuf *from) { ibuf_from_buffer(buf, ibuf_data(from), ibuf_size(from)); } int ibuf_get(struct ibuf *buf, void *data, size_t len) { if (ibuf_size(buf) < len) { errno = EBADMSG; return (-1); } memcpy(data, ibuf_data(buf), len); buf->rpos += len; return (0); } int ibuf_get_ibuf(struct ibuf *buf, size_t len, struct ibuf *new) { if (ibuf_size(buf) < len) { errno = EBADMSG; return (-1); } ibuf_from_buffer(new, ibuf_data(buf), len); buf->rpos += len; return (0); } int ibuf_get_n8(struct ibuf *buf, uint8_t *value) { return ibuf_get(buf, value, sizeof(*value)); } int ibuf_get_n16(struct ibuf *buf, uint16_t *value) { int rv; rv = ibuf_get(buf, value, sizeof(*value)); *value = be16toh(*value); return (rv); } int ibuf_get_n32(struct ibuf *buf, uint32_t *value) { int rv; rv = ibuf_get(buf, value, sizeof(*value)); *value = be32toh(*value); return (rv); } int ibuf_get_n64(struct ibuf *buf, uint64_t *value) { int rv; rv = ibuf_get(buf, value, sizeof(*value)); *value = be64toh(*value); return (rv); } int ibuf_get_h16(struct ibuf *buf, uint16_t *value) { return ibuf_get(buf, value, sizeof(*value)); } int ibuf_get_h32(struct ibuf *buf, uint32_t *value) { return ibuf_get(buf, value, sizeof(*value)); } int ibuf_get_h64(struct ibuf *buf, uint64_t *value) { return ibuf_get(buf, value, sizeof(*value)); } int ibuf_skip(struct ibuf *buf, size_t len) { if (ibuf_size(buf) < len) { errno = EBADMSG; return (-1); } buf->rpos += len; return (0); } void ibuf_free(struct ibuf *buf) { if (buf == NULL) return; if (buf->max == 0) /* if buf lives on the stack */ abort(); /* abort before causing more harm */ if (buf->fd != -1) close(buf->fd); freezero(buf->buf, buf->size); free(buf); } int ibuf_fd_avail(struct ibuf *buf) { return (buf->fd != -1); } int ibuf_fd_get(struct ibuf *buf) { int fd; fd = buf->fd; buf->fd = -1; return (fd); } void ibuf_fd_set(struct ibuf *buf, int fd) { if (buf->max == 0) /* if buf lives on the stack */ abort(); /* abort before causing more harm */ if (buf->fd != -1) close(buf->fd); buf->fd = fd; } int ibuf_write(struct msgbuf *msgbuf) { struct iovec iov[IOV_MAX]; struct ibuf *buf; unsigned int i = 0; ssize_t n; memset(&iov, 0, sizeof(iov)); TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { if (i >= IOV_MAX) break; iov[i].iov_base = ibuf_data(buf); iov[i].iov_len = ibuf_size(buf); i++; } again: if ((n = writev(msgbuf->fd, iov, i)) == -1) { if (errno == EINTR) goto again; if (errno == ENOBUFS) errno = EAGAIN; return (-1); } if (n == 0) { /* connection closed */ errno = 0; return (0); } msgbuf_drain(msgbuf, n); return (1); } void msgbuf_init(struct msgbuf *msgbuf) { msgbuf->queued = 0; msgbuf->fd = -1; TAILQ_INIT(&msgbuf->bufs); } static void msgbuf_drain(struct msgbuf *msgbuf, size_t n) { struct ibuf *buf, *next; for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; buf = next) { next = TAILQ_NEXT(buf, entry); if (n >= ibuf_size(buf)) { n -= ibuf_size(buf); ibuf_dequeue(msgbuf, buf); } else { buf->rpos += n; n = 0; } } } void msgbuf_clear(struct msgbuf *msgbuf) { struct ibuf *buf; while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL) ibuf_dequeue(msgbuf, buf); } int msgbuf_write(struct msgbuf *msgbuf) { struct iovec iov[IOV_MAX]; struct ibuf *buf, *buf0 = NULL; unsigned int i = 0; ssize_t n; struct msghdr msg; struct cmsghdr *cmsg; union { struct cmsghdr hdr; char buf[CMSG_SPACE(sizeof(int))]; } cmsgbuf; memset(&iov, 0, sizeof(iov)); memset(&msg, 0, sizeof(msg)); memset(&cmsgbuf, 0, sizeof(cmsgbuf)); TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { if (i >= IOV_MAX) break; if (i > 0 && buf->fd != -1) break; iov[i].iov_base = ibuf_data(buf); iov[i].iov_len = ibuf_size(buf); i++; if (buf->fd != -1) buf0 = buf; } msg.msg_iov = iov; msg.msg_iovlen = i; if (buf0 != NULL) { msg.msg_control = (caddr_t)&cmsgbuf.buf; msg.msg_controllen = sizeof(cmsgbuf.buf); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; *(int *)CMSG_DATA(cmsg) = buf0->fd; } again: if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) { if (errno == EINTR) goto again; if (errno == ENOBUFS) errno = EAGAIN; return (-1); } if (n == 0) { /* connection closed */ errno = 0; return (0); } /* * assumption: fd got sent if sendmsg sent anything * this works because fds are passed one at a time */ if (buf0 != NULL) { close(buf0->fd); buf0->fd = -1; } msgbuf_drain(msgbuf, n); return (1); } uint32_t msgbuf_queuelen(struct msgbuf *msgbuf) { return (msgbuf->queued); } static void ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf) { if (buf->max == 0) /* if buf lives on the stack */ abort(); /* abort before causing more harm */ TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry); msgbuf->queued++; } static void ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf) { TAILQ_REMOVE(&msgbuf->bufs, buf, entry); msgbuf->queued--; ibuf_free(buf); } got-portable-0.101/compat/base64.c0000664000175100017510000002430014644144735012325 /* $OpenBSD: base64.c,v 1.8 2015/01/16 16:48:51 deraadt Exp $ */ /* * Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * Portions Copyright (c) 1995 by International Business Machines, Inc. * * International Business Machines, Inc. (hereinafter called IBM) grants * permission under its copyrights to use, copy, modify, and distribute this * Software with or without fee, provided that the above copyright notice and * all paragraphs of this notice appear in all copies, and that the name of IBM * not be used in connection with the marketing of any product incorporating * the Software or modifications thereof, without specific, written prior * permission. * * To the extent it has a right to do so, IBM grants an immunity from suit * under its patents, if any, for the use, sale or manufacture of products to * the extent that such products are used for performing Domain Name System * dynamic updates in TCP/IP networks by means of the Software. No immunity is * granted for any product per se or for any other function of any product. * * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char Pad64 = '='; /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) The following encoding technique is taken from RFC 1521 by Borenstein and Freed. It is reproduced here in a slightly edited form for convenience. A 65-character subset of US-ASCII is used, enabling 6 bits to be represented per printable character. (The extra 65th character, "=", is used to signify a special processing function.) The encoding process represents 24-bit groups of input bits as output strings of 4 encoded characters. Proceeding from left to right, a 24-bit input group is formed by concatenating 3 8-bit input groups. These 24 bits are then treated as 4 concatenated 6-bit groups, each of which is translated into a single digit in the base64 alphabet. Each 6-bit group is used as an index into an array of 64 printable characters. The character referenced by the index is placed in the output string. Table 1: The Base64 Alphabet Value Encoding Value Encoding Value Encoding Value Encoding 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w (pad) = 15 P 32 g 49 x 16 Q 33 h 50 y Special processing is performed if fewer than 24 bits are available at the end of the data being encoded. A full encoding quantum is always completed at the end of a quantity. When fewer than 24 input bits are available in an input group, zero bits are added (on the right) to form an integral number of 6-bit groups. Padding at the end of the data is performed using the '=' character. Since all base64 input is an integral number of octets, only the ------------------------------------------------- following cases can arise: (1) the final quantum of encoding input is an integral multiple of 24 bits; here, the final unit of encoded output will be an integral multiple of 4 characters with no "=" padding, (2) the final quantum of encoding input is exactly 8 bits; here, the final unit of encoded output will be two characters followed by two "=" padding characters, or (3) the final quantum of encoding input is exactly 16 bits; here, the final unit of encoded output will be three characters followed by one "=" padding character. */ int b64_ntop(src, srclength, target, targsize) u_char const *src; size_t srclength; char *target; size_t targsize; { size_t datalength = 0; u_char input[3]; u_char output[4]; int i; while (2 < srclength) { input[0] = *src++; input[1] = *src++; input[2] = *src++; srclength -= 3; output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); output[3] = input[2] & 0x3f; if (datalength + 4 > targsize) return (-1); target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; target[datalength++] = Base64[output[2]]; target[datalength++] = Base64[output[3]]; } /* Now we worry about padding. */ if (0 != srclength) { /* Get what's left. */ input[0] = input[1] = input[2] = '\0'; for (i = 0; i < srclength; i++) input[i] = *src++; output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); if (datalength + 4 > targsize) return (-1); target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; if (srclength == 1) target[datalength++] = Pad64; else target[datalength++] = Base64[output[2]]; target[datalength++] = Pad64; } if (datalength >= targsize) return (-1); target[datalength] = '\0'; /* Returned value doesn't count \0. */ return (datalength); } /* skips all whitespace anywhere. converts characters, four at a time, starting at (or after) src from base - 64 numbers into three 8 bit bytes in the target area. it returns the number of data bytes stored at the target, or -1 on error. */ int b64_pton(src, target, targsize) char const *src; u_char *target; size_t targsize; { int tarindex, state, ch; u_char nextbyte; char *pos; state = 0; tarindex = 0; while ((ch = (unsigned char)*src++) != '\0') { if (isspace(ch)) /* Skip whitespace anywhere. */ continue; if (ch == Pad64) break; pos = strchr(Base64, ch); if (pos == 0) /* A non-base64 character. */ return (-1); switch (state) { case 0: if (target) { if (tarindex >= targsize) return (-1); target[tarindex] = (pos - Base64) << 2; } state = 1; break; case 1: if (target) { if (tarindex >= targsize) return (-1); target[tarindex] |= (pos - Base64) >> 4; nextbyte = ((pos - Base64) & 0x0f) << 4; if (tarindex + 1 < targsize) target[tarindex+1] = nextbyte; else if (nextbyte) return (-1); } tarindex++; state = 2; break; case 2: if (target) { if (tarindex >= targsize) return (-1); target[tarindex] |= (pos - Base64) >> 2; nextbyte = ((pos - Base64) & 0x03) << 6; if (tarindex + 1 < targsize) target[tarindex+1] = nextbyte; else if (nextbyte) return (-1); } tarindex++; state = 3; break; case 3: if (target) { if (tarindex >= targsize) return (-1); target[tarindex] |= (pos - Base64); } tarindex++; state = 0; break; } } /* * We are done decoding Base-64 chars. Let's see if we ended * on a byte boundary, and/or with erroneous trailing characters. */ if (ch == Pad64) { /* We got a pad char. */ ch = (unsigned char)*src++; /* Skip it, get next. */ switch (state) { case 0: /* Invalid = in first position */ case 1: /* Invalid = in second position */ return (-1); case 2: /* Valid, means one byte of info */ /* Skip any number of spaces. */ for (; ch != '\0'; ch = (unsigned char)*src++) if (!isspace(ch)) break; /* Make sure there is another trailing = sign. */ if (ch != Pad64) return (-1); ch = (unsigned char)*src++; /* Skip the = */ /* Fall through to "single trailing =" case. */ /* FALLTHROUGH */ case 3: /* Valid, means two bytes of info */ /* * We know this char is an =. Is there anything but * whitespace after it? */ for (; ch != '\0'; ch = (unsigned char)*src++) if (!isspace(ch)) return (-1); /* * Now make sure for cases 2 and 3 that the "extra" * bits that slopped past the last full byte were * zeros. If we don't check them, they become a * subliminal channel. */ if (target && tarindex < targsize && target[tarindex] != 0) return (-1); } } else { /* * We ended by seeing the end of the string. Make sure we * have no partial bytes lying around. */ if (state != 0) return (-1); } return (tarindex); } got-portable-0.101/compat/getopt.c0000664000175100017510000000716514644144735012555 /* * Copyright (c) 1987, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* OPENBSD ORIGINAL: lib/libc/stdlib/getopt.c */ #include "got_compat.h" #include #include #include int BSDopterr = 1, /* if error message should be printed */ BSDoptind = 1, /* index into parent argv vector */ BSDoptopt, /* character checked for validity */ BSDoptreset; /* reset getopt */ char *BSDoptarg; /* argument associated with option */ #define BADCH (int)'?' #define BADARG (int)':' #define EMSG "" /* * getopt -- * Parse argc/argv argument vector. */ int BSDgetopt(int nargc, char *const *nargv, const char *ostr) { static const char *place = EMSG; /* option letter processing */ char *oli; /* option letter list index */ if (ostr == NULL) return (-1); if (BSDoptreset || !*place) { /* update scanning pointer */ BSDoptreset = 0; if (BSDoptind >= nargc || *(place = nargv[BSDoptind]) != '-') { place = EMSG; return (-1); } if (place[1] && *++place == '-') { /* found "--" */ if (place[1]) return (BADCH); ++BSDoptind; place = EMSG; return (-1); } } /* option letter okay? */ if ((BSDoptopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, BSDoptopt))) { /* * if the user didn't specify '-' as an option, * assume it means -1. */ if (BSDoptopt == (int)'-') return (-1); if (!*place) ++BSDoptind; if (BSDopterr && *ostr != ':') (void)fprintf(stderr, "%s: unknown option -- %c\n", getprogname(), BSDoptopt); return (BADCH); } if (*++oli != ':') { /* don't need argument */ BSDoptarg = NULL; if (!*place) ++BSDoptind; } else { /* need an argument */ if (*place) /* no white space */ BSDoptarg = (char *)place; else if (nargc <= ++BSDoptind) { /* no arg */ place = EMSG; if (*ostr == ':') return (BADARG); if (BSDopterr) (void)fprintf(stderr, "%s: option requires an argument -- %c\n", getprogname(), BSDoptopt); return (BADCH); } else /* white space */ BSDoptarg = nargv[BSDoptind]; place = EMSG; ++BSDoptind; } return (BSDoptopt); /* dump back option letter */ } got-portable-0.101/compat/siphash.c0000664000175100017510000001204114644144735012677 /* $OpenBSD: siphash.c,v 1.8 2019/01/20 03:53:47 bcook Exp $ */ /*- * Copyright (c) 2013 Andre Oppermann * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * SipHash is a family of PRFs SipHash-c-d where the integer parameters c and d * are the number of compression rounds and the number of finalization rounds. * A compression round is identical to a finalization round and this round * function is called SipRound. Given a 128-bit key k and a (possibly empty) * byte string m, SipHash-c-d returns a 64-bit value SipHash-c-d(k; m). * * Implemented from the paper "SipHash: a fast short-input PRF", 2012.09.18, * by Jean-Philippe Aumasson and Daniel J. Bernstein, * Permanent Document ID b9a943a805fbfc6fde808af9fc0ecdfa * https://131002.net/siphash/siphash.pdf * https://131002.net/siphash/ */ #include #include #include "siphash.h" #include "got_compat.h" static void SipHash_CRounds(SIPHASH_CTX *, int); static void SipHash_Rounds(SIPHASH_CTX *, int); void SipHash_Init(SIPHASH_CTX *ctx, const SIPHASH_KEY *key) { uint64_t k0, k1; k0 = le64toh(key->k0); k1 = le64toh(key->k1); ctx->v[0] = 0x736f6d6570736575ULL ^ k0; ctx->v[1] = 0x646f72616e646f6dULL ^ k1; ctx->v[2] = 0x6c7967656e657261ULL ^ k0; ctx->v[3] = 0x7465646279746573ULL ^ k1; memset(ctx->buf, 0, sizeof(ctx->buf)); ctx->bytes = 0; } void SipHash_Update(SIPHASH_CTX *ctx, int rc, int rf, const void *src, size_t len) { const uint8_t *ptr = src; size_t left, used; if (len == 0) return; used = ctx->bytes % sizeof(ctx->buf); ctx->bytes += len; if (used > 0) { left = sizeof(ctx->buf) - used; if (len >= left) { memcpy(&ctx->buf[used], ptr, left); SipHash_CRounds(ctx, rc); len -= left; ptr += left; } else { memcpy(&ctx->buf[used], ptr, len); return; } } while (len >= sizeof(ctx->buf)) { memcpy(ctx->buf, ptr, sizeof(ctx->buf)); SipHash_CRounds(ctx, rc); len -= sizeof(ctx->buf); ptr += sizeof(ctx->buf); } if (len > 0) memcpy(ctx->buf, ptr, len); } void SipHash_Final(void *dst, SIPHASH_CTX *ctx, int rc, int rf) { uint64_t r; r = htole64(SipHash_End(ctx, rc, rf)); memcpy(dst, &r, sizeof r); } uint64_t SipHash_End(SIPHASH_CTX *ctx, int rc, int rf) { uint64_t r; size_t left, used; used = ctx->bytes % sizeof(ctx->buf); left = sizeof(ctx->buf) - used; memset(&ctx->buf[used], 0, left - 1); ctx->buf[7] = ctx->bytes; SipHash_CRounds(ctx, rc); ctx->v[2] ^= 0xff; SipHash_Rounds(ctx, rf); r = (ctx->v[0] ^ ctx->v[1]) ^ (ctx->v[2] ^ ctx->v[3]); #ifdef __APPLE__ memset_s(ctx, sizeof(*ctx), 0, sizeof(*ctx)); #elif defined(__NetBSD__) explicit_memset(ctx, sizeof(*ctx), 0); #else explicit_bzero(ctx, sizeof(*ctx)); #endif return (r); } uint64_t SipHash(const SIPHASH_KEY *key, int rc, int rf, const void *src, size_t len) { SIPHASH_CTX ctx; SipHash_Init(&ctx, key); SipHash_Update(&ctx, rc, rf, src, len); return (SipHash_End(&ctx, rc, rf)); } #define SIP_ROTL(x, b) ((x) << (b)) | ( (x) >> (64 - (b))) static void SipHash_Rounds(SIPHASH_CTX *ctx, int rounds) { while (rounds--) { ctx->v[0] += ctx->v[1]; ctx->v[2] += ctx->v[3]; ctx->v[1] = SIP_ROTL(ctx->v[1], 13); ctx->v[3] = SIP_ROTL(ctx->v[3], 16); ctx->v[1] ^= ctx->v[0]; ctx->v[3] ^= ctx->v[2]; ctx->v[0] = SIP_ROTL(ctx->v[0], 32); ctx->v[2] += ctx->v[1]; ctx->v[0] += ctx->v[3]; ctx->v[1] = SIP_ROTL(ctx->v[1], 17); ctx->v[3] = SIP_ROTL(ctx->v[3], 21); ctx->v[1] ^= ctx->v[2]; ctx->v[3] ^= ctx->v[0]; ctx->v[2] = SIP_ROTL(ctx->v[2], 32); } } static void SipHash_CRounds(SIPHASH_CTX *ctx, int rounds) { uint64_t m = le64toh(*(uint64_t *)ctx->buf); ctx->v[3] ^= m; SipHash_Rounds(ctx, rounds); ctx->v[0] ^= m; } got-portable-0.101/compat/Makefile.in0000664000175100017510000006163214644145543013151 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ # For MacOS, don't build the compat versions of strl{cat,cpy}, but do for all # other systems. @HOST_DARWIN_FALSE@am__append_1 = strlcat.c strlcpy.c @HOST_DARWIN_TRUE@am__append_2 = uuid.c bsd-poll.c bsd-poll.h @HAVE_GETOPT_FALSE@am__append_3 = getopt.c @HAVE_B64_FALSE@am__append_4 = base64.c @HAVE_B64_FALSE@am__append_5 = $(libresolv_LIBS) @HAVE_CLOSEFROM_FALSE@am__append_6 = closefrom.c @HOST_NETBSD_TRUE@am__append_7 = bsd-poll.c bsd-poll.h @HOST_LINUX_TRUE@am__append_8 = uuid.c @HAVE_LINUX_LANDLOCK_TRUE@am__append_9 = landlock.c @HAVE_SIPHASH_FALSE@am__append_10 = siphash.c siphash.h @HAVE_SETPROCTITLE_FALSE@am__append_11 = setproctitle.c @HAVE_IMSG_FALSE@am__append_12 = imsg-buffer.c imsg.c @HAVE_SHA2_FALSE@@HOST_DARWIN_FALSE@am__append_13 = sha2.c sha2.h subdir = compat ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libopenbsd_compat_a_AR = $(AR) $(ARFLAGS) libopenbsd_compat_a_LIBADD = am__libopenbsd_compat_a_SOURCES_DIST = asprintf.c fmt_scaled.c \ freezero.c getdtablecount.c getprogname.c merge.c \ reallocarray.c recallocarray.c strndup.c strnlen.c strsep.c \ strtonum.c imsg.h tree.h strlcat.c strlcpy.c uuid.c bsd-poll.c \ bsd-poll.h getopt.c base64.c closefrom.c landlock.c siphash.c \ siphash.h setproctitle.c imsg-buffer.c imsg.c sha2.c sha2.h @HOST_DARWIN_FALSE@am__objects_1 = strlcat.$(OBJEXT) strlcpy.$(OBJEXT) @HOST_DARWIN_TRUE@am__objects_2 = uuid.$(OBJEXT) bsd-poll.$(OBJEXT) @HAVE_GETOPT_FALSE@am__objects_3 = getopt.$(OBJEXT) @HAVE_B64_FALSE@am__objects_4 = base64.$(OBJEXT) @HAVE_CLOSEFROM_FALSE@am__objects_5 = closefrom.$(OBJEXT) @HOST_NETBSD_TRUE@am__objects_6 = bsd-poll.$(OBJEXT) @HOST_LINUX_TRUE@am__objects_7 = uuid.$(OBJEXT) @HAVE_LINUX_LANDLOCK_TRUE@am__objects_8 = landlock.$(OBJEXT) @HAVE_SIPHASH_FALSE@am__objects_9 = siphash.$(OBJEXT) @HAVE_SETPROCTITLE_FALSE@am__objects_10 = setproctitle.$(OBJEXT) @HAVE_IMSG_FALSE@am__objects_11 = imsg-buffer.$(OBJEXT) imsg.$(OBJEXT) @HAVE_SHA2_FALSE@@HOST_DARWIN_FALSE@am__objects_12 = sha2.$(OBJEXT) am_libopenbsd_compat_a_OBJECTS = asprintf.$(OBJEXT) \ fmt_scaled.$(OBJEXT) freezero.$(OBJEXT) \ getdtablecount.$(OBJEXT) getprogname.$(OBJEXT) merge.$(OBJEXT) \ reallocarray.$(OBJEXT) recallocarray.$(OBJEXT) \ strndup.$(OBJEXT) strnlen.$(OBJEXT) strsep.$(OBJEXT) \ strtonum.$(OBJEXT) $(am__objects_1) $(am__objects_2) \ $(am__objects_3) $(am__objects_4) $(am__objects_5) \ $(am__objects_6) $(am__objects_7) $(am__objects_8) \ $(am__objects_9) $(am__objects_10) $(am__objects_11) \ $(am__objects_12) libopenbsd_compat_a_OBJECTS = $(am_libopenbsd_compat_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/asprintf.Po ./$(DEPDIR)/base64.Po \ ./$(DEPDIR)/bsd-poll.Po ./$(DEPDIR)/closefrom.Po \ ./$(DEPDIR)/fmt_scaled.Po ./$(DEPDIR)/freezero.Po \ ./$(DEPDIR)/getdtablecount.Po ./$(DEPDIR)/getopt.Po \ ./$(DEPDIR)/getprogname.Po ./$(DEPDIR)/imsg-buffer.Po \ ./$(DEPDIR)/imsg.Po ./$(DEPDIR)/landlock.Po \ ./$(DEPDIR)/merge.Po ./$(DEPDIR)/reallocarray.Po \ ./$(DEPDIR)/recallocarray.Po ./$(DEPDIR)/setproctitle.Po \ ./$(DEPDIR)/sha2.Po ./$(DEPDIR)/siphash.Po \ ./$(DEPDIR)/strlcat.Po ./$(DEPDIR)/strlcpy.Po \ ./$(DEPDIR)/strndup.Po ./$(DEPDIR)/strnlen.Po \ ./$(DEPDIR)/strsep.Po ./$(DEPDIR)/strtonum.Po \ ./$(DEPDIR)/uuid.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libopenbsd_compat_a_SOURCES) DIST_SOURCES = $(am__libopenbsd_compat_a_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(libbsd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ noinst_LIBRARIES = libopenbsd-compat.a LDADD = $(libbsd_LIBS) $(am__append_5) libopenbsd_compat_a_SOURCES = asprintf.c fmt_scaled.c freezero.c \ getdtablecount.c getprogname.c merge.c reallocarray.c \ recallocarray.c strndup.c strnlen.c strsep.c strtonum.c imsg.h \ tree.h $(am__append_1) $(am__append_2) $(am__append_3) \ $(am__append_4) $(am__append_6) $(am__append_7) \ $(am__append_8) $(am__append_9) $(am__append_10) \ $(am__append_11) $(am__append_12) $(am__append_13) # Fake an assigment here. It does nothing, but you cannot have consecutive # nested if statements in Makefiles, so we have to do something here, even if # it's a dummy assignment. @HOST_DARWIN_FALSE@NOTING = something EXTRA_DIST = \ $(top_srcdir)/include/got_compat.h \ imsg.h \ tree.h \ bsd-poll.h all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign compat/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign compat/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libopenbsd-compat.a: $(libopenbsd_compat_a_OBJECTS) $(libopenbsd_compat_a_DEPENDENCIES) $(EXTRA_libopenbsd_compat_a_DEPENDENCIES) $(AM_V_at)-rm -f libopenbsd-compat.a $(AM_V_AR)$(libopenbsd_compat_a_AR) libopenbsd-compat.a $(libopenbsd_compat_a_OBJECTS) $(libopenbsd_compat_a_LIBADD) $(AM_V_at)$(RANLIB) libopenbsd-compat.a mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asprintf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base64.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bsd-poll.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/closefrom.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fmt_scaled.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/freezero.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getdtablecount.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getprogname.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imsg-buffer.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imsg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/landlock.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/merge.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reallocarray.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/recallocarray.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/setproctitle.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha2.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/siphash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strlcat.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strlcpy.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strndup.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strnlen.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strtonum.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uuid.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am distclean: distclean-am -rm -f ./$(DEPDIR)/asprintf.Po -rm -f ./$(DEPDIR)/base64.Po -rm -f ./$(DEPDIR)/bsd-poll.Po -rm -f ./$(DEPDIR)/closefrom.Po -rm -f ./$(DEPDIR)/fmt_scaled.Po -rm -f ./$(DEPDIR)/freezero.Po -rm -f ./$(DEPDIR)/getdtablecount.Po -rm -f ./$(DEPDIR)/getopt.Po -rm -f ./$(DEPDIR)/getprogname.Po -rm -f ./$(DEPDIR)/imsg-buffer.Po -rm -f ./$(DEPDIR)/imsg.Po -rm -f ./$(DEPDIR)/landlock.Po -rm -f ./$(DEPDIR)/merge.Po -rm -f ./$(DEPDIR)/reallocarray.Po -rm -f ./$(DEPDIR)/recallocarray.Po -rm -f ./$(DEPDIR)/setproctitle.Po -rm -f ./$(DEPDIR)/sha2.Po -rm -f ./$(DEPDIR)/siphash.Po -rm -f ./$(DEPDIR)/strlcat.Po -rm -f ./$(DEPDIR)/strlcpy.Po -rm -f ./$(DEPDIR)/strndup.Po -rm -f ./$(DEPDIR)/strnlen.Po -rm -f ./$(DEPDIR)/strsep.Po -rm -f ./$(DEPDIR)/strtonum.Po -rm -f ./$(DEPDIR)/uuid.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/asprintf.Po -rm -f ./$(DEPDIR)/base64.Po -rm -f ./$(DEPDIR)/bsd-poll.Po -rm -f ./$(DEPDIR)/closefrom.Po -rm -f ./$(DEPDIR)/fmt_scaled.Po -rm -f ./$(DEPDIR)/freezero.Po -rm -f ./$(DEPDIR)/getdtablecount.Po -rm -f ./$(DEPDIR)/getopt.Po -rm -f ./$(DEPDIR)/getprogname.Po -rm -f ./$(DEPDIR)/imsg-buffer.Po -rm -f ./$(DEPDIR)/imsg.Po -rm -f ./$(DEPDIR)/landlock.Po -rm -f ./$(DEPDIR)/merge.Po -rm -f ./$(DEPDIR)/reallocarray.Po -rm -f ./$(DEPDIR)/recallocarray.Po -rm -f ./$(DEPDIR)/setproctitle.Po -rm -f ./$(DEPDIR)/sha2.Po -rm -f ./$(DEPDIR)/siphash.Po -rm -f ./$(DEPDIR)/strlcat.Po -rm -f ./$(DEPDIR)/strlcpy.Po -rm -f ./$(DEPDIR)/strndup.Po -rm -f ./$(DEPDIR)/strnlen.Po -rm -f ./$(DEPDIR)/strsep.Po -rm -f ./$(DEPDIR)/strtonum.Po -rm -f ./$(DEPDIR)/uuid.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-noinstLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/compat/imsg.c0000664000175100017510000002131514644144735012203 /* $OpenBSD: imsg.c,v 1.23 2023/12/12 15:47:41 claudio Exp $ */ /* * Copyright (c) 2023 Claudio Jeker * Copyright (c) 2003, 2004 Henning Brauer * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include "got_compat.h" #include "imsg.h" struct imsg_fd { TAILQ_ENTRY(imsg_fd) entry; int fd; }; int imsg_fd_overhead = 0; static int imsg_dequeue_fd(struct imsgbuf *); void imsg_init(struct imsgbuf *imsgbuf, int fd) { msgbuf_init(&imsgbuf->w); memset(&imsgbuf->r, 0, sizeof(imsgbuf->r)); imsgbuf->fd = fd; imsgbuf->w.fd = fd; imsgbuf->pid = getpid(); TAILQ_INIT(&imsgbuf->fds); } ssize_t imsg_read(struct imsgbuf *imsgbuf) { struct msghdr msg; struct cmsghdr *cmsg; union { struct cmsghdr hdr; char buf[CMSG_SPACE(sizeof(int) * 1)]; } cmsgbuf; struct iovec iov; ssize_t n = -1; int fd; struct imsg_fd *ifd; memset(&msg, 0, sizeof(msg)); memset(&cmsgbuf, 0, sizeof(cmsgbuf)); iov.iov_base = imsgbuf->r.buf + imsgbuf->r.wpos; iov.iov_len = sizeof(imsgbuf->r.buf) - imsgbuf->r.wpos; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = &cmsgbuf.buf; msg.msg_controllen = sizeof(cmsgbuf.buf); if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) return (-1); again: if (getdtablecount() + imsg_fd_overhead + (int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int)) >= getdtablesize()) { errno = EAGAIN; free(ifd); return (-1); } if ((n = recvmsg(imsgbuf->fd, &msg, 0)) == -1) { if (errno == EINTR) goto again; goto fail; } imsgbuf->r.wpos += n; for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { int i; int j; /* * We only accept one file descriptor. Due to C * padding rules, our control buffer might contain * more than one fd, and we must close them. */ j = ((char *)cmsg + cmsg->cmsg_len - (char *)CMSG_DATA(cmsg)) / sizeof(int); for (i = 0; i < j; i++) { fd = ((int *)CMSG_DATA(cmsg))[i]; if (ifd != NULL) { ifd->fd = fd; TAILQ_INSERT_TAIL(&imsgbuf->fds, ifd, entry); ifd = NULL; } else close(fd); } } /* we do not handle other ctl data level */ } fail: free(ifd); return (n); } ssize_t imsg_get(struct imsgbuf *imsgbuf, struct imsg *imsg) { struct imsg m; size_t av, left, datalen; av = imsgbuf->r.wpos; if (IMSG_HEADER_SIZE > av) return (0); memcpy(&m.hdr, imsgbuf->r.buf, sizeof(m.hdr)); if (m.hdr.len < IMSG_HEADER_SIZE || m.hdr.len > MAX_IMSGSIZE) { errno = ERANGE; return (-1); } if (m.hdr.len > av) return (0); m.fd = -1; m.buf = NULL; m.data = NULL; datalen = m.hdr.len - IMSG_HEADER_SIZE; imsgbuf->r.rptr = imsgbuf->r.buf + IMSG_HEADER_SIZE; if (datalen != 0) { if ((m.buf = ibuf_open(datalen)) == NULL) return (-1); if (ibuf_add(m.buf, imsgbuf->r.rptr, datalen) == -1) { /* this should never fail */ ibuf_free(m.buf); return (-1); } m.data = ibuf_data(m.buf); } if (m.hdr.flags & IMSGF_HASFD) m.fd = imsg_dequeue_fd(imsgbuf); if (m.hdr.len < av) { left = av - m.hdr.len; memmove(&imsgbuf->r.buf, imsgbuf->r.buf + m.hdr.len, left); imsgbuf->r.wpos = left; } else imsgbuf->r.wpos = 0; *imsg = m; return (datalen + IMSG_HEADER_SIZE); } int imsg_get_ibuf(struct imsg *imsg, struct ibuf *ibuf) { if (imsg->buf == NULL) { errno = EBADMSG; return (-1); } return ibuf_get_ibuf(imsg->buf, ibuf_size(imsg->buf), ibuf); } int imsg_get_data(struct imsg *imsg, void *data, size_t len) { if (len == 0) { errno = EINVAL; return (-1); } if (imsg->buf == NULL || ibuf_size(imsg->buf) != len) { errno = EBADMSG; return (-1); } return ibuf_get(imsg->buf, data, len); } int imsg_get_fd(struct imsg *imsg) { int fd = imsg->fd; imsg->fd = -1; return fd; } uint32_t imsg_get_id(struct imsg *imsg) { return (imsg->hdr.peerid); } size_t imsg_get_len(struct imsg *imsg) { if (imsg->buf == NULL) return 0; return ibuf_size(imsg->buf); } pid_t imsg_get_pid(struct imsg *imsg) { return (imsg->hdr.pid); } uint32_t imsg_get_type(struct imsg *imsg) { return (imsg->hdr.type); } int imsg_compose(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid, int fd, const void *data, size_t datalen) { struct ibuf *wbuf; if ((wbuf = imsg_create(imsgbuf, type, id, pid, datalen)) == NULL) return (-1); if (imsg_add(wbuf, data, datalen) == -1) return (-1); ibuf_fd_set(wbuf, fd); imsg_close(imsgbuf, wbuf); return (1); } int imsg_composev(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid, int fd, const struct iovec *iov, int iovcnt) { struct ibuf *wbuf; int i; size_t datalen = 0; for (i = 0; i < iovcnt; i++) datalen += iov[i].iov_len; if ((wbuf = imsg_create(imsgbuf, type, id, pid, datalen)) == NULL) return (-1); for (i = 0; i < iovcnt; i++) if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1) return (-1); ibuf_fd_set(wbuf, fd); imsg_close(imsgbuf, wbuf); return (1); } /* * Enqueue imsg with payload from ibuf buf. fd passing is not possible * with this function. */ int imsg_compose_ibuf(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid, struct ibuf *buf) { struct ibuf *hdrbuf = NULL; struct imsg_hdr hdr; int save_errno; if (ibuf_size(buf) + IMSG_HEADER_SIZE > MAX_IMSGSIZE) { errno = ERANGE; goto fail; } hdr.type = type; hdr.len = ibuf_size(buf) + IMSG_HEADER_SIZE; hdr.flags = 0; hdr.peerid = id; if ((hdr.pid = pid) == 0) hdr.pid = imsgbuf->pid; if ((hdrbuf = ibuf_open(IMSG_HEADER_SIZE)) == NULL) goto fail; if (imsg_add(hdrbuf, &hdr, sizeof(hdr)) == -1) goto fail; ibuf_close(&imsgbuf->w, hdrbuf); ibuf_close(&imsgbuf->w, buf); return (1); fail: save_errno = errno; ibuf_free(buf); ibuf_free(hdrbuf); errno = save_errno; return (-1); } /* * Forward imsg to another channel. Any attached fd is closed. */ int imsg_forward(struct imsgbuf *imsgbuf, struct imsg *msg) { struct ibuf *wbuf; size_t len = 0; if (msg->fd != -1) { close(msg->fd); msg->fd = -1; } if (msg->buf != NULL) { ibuf_rewind(msg->buf); len = ibuf_size(msg->buf); } if ((wbuf = imsg_create(imsgbuf, msg->hdr.type, msg->hdr.peerid, msg->hdr.pid, len)) == NULL) return (-1); if (msg->buf != NULL) { if (ibuf_add_buf(wbuf, msg->buf) == -1) { ibuf_free(wbuf); return (-1); } } imsg_close(imsgbuf, wbuf); return (1); } struct ibuf * imsg_create(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid, size_t datalen) { struct ibuf *wbuf; struct imsg_hdr hdr; datalen += IMSG_HEADER_SIZE; if (datalen > MAX_IMSGSIZE) { errno = ERANGE; return (NULL); } hdr.type = type; hdr.flags = 0; hdr.peerid = id; if ((hdr.pid = pid) == 0) hdr.pid = imsgbuf->pid; if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) { return (NULL); } if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1) return (NULL); return (wbuf); } int imsg_add(struct ibuf *msg, const void *data, size_t datalen) { if (datalen) if (ibuf_add(msg, data, datalen) == -1) { ibuf_free(msg); return (-1); } return (datalen); } void imsg_close(struct imsgbuf *imsgbuf, struct ibuf *msg) { struct imsg_hdr *hdr; hdr = (struct imsg_hdr *)msg->buf; hdr->flags &= ~IMSGF_HASFD; if (ibuf_fd_avail(msg)) hdr->flags |= IMSGF_HASFD; hdr->len = ibuf_size(msg); ibuf_close(&imsgbuf->w, msg); } void imsg_free(struct imsg *imsg) { ibuf_free(imsg->buf); } static int imsg_dequeue_fd(struct imsgbuf *imsgbuf) { int fd; struct imsg_fd *ifd; if ((ifd = TAILQ_FIRST(&imsgbuf->fds)) == NULL) return (-1); fd = ifd->fd; TAILQ_REMOVE(&imsgbuf->fds, ifd, entry); free(ifd); return (fd); } int imsg_flush(struct imsgbuf *imsgbuf) { while (imsgbuf->w.queued) if (msgbuf_write(&imsgbuf->w) <= 0) return (-1); return (0); } void imsg_clear(struct imsgbuf *imsgbuf) { int fd; msgbuf_clear(&imsgbuf->w); while ((fd = imsg_dequeue_fd(imsgbuf)) != -1) close(fd); } got-portable-0.101/compat/setproctitle.c0000664000175100017510000000261014644144735013762 /* * Copyright (c) 2016 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include "got_compat.h" #if defined(HAVE_PRCTL) && defined(HAVE_PR_SET_NAME) #include void setproctitle(const char *fmt, ...) { char title[16], name[16], *cp; va_list ap; int used; va_start(ap, fmt); vsnprintf(title, sizeof title, fmt, ap); va_end(ap); used = snprintf(name, sizeof name, "%s: %s", getprogname(), title); if (used >= (int)sizeof name) { cp = strrchr(name, ' '); if (cp != NULL) *cp = '\0'; } prctl(PR_SET_NAME, name); } #else void setproctitle(__unused const char *fmt, ...) { } #endif got-portable-0.101/compat/sha2.h0000664000175100017510000001670214644144735012112 /* $OpenBSD: sha2.h,v 1.10 2016/09/03 17:00:29 tedu Exp $ */ /* * FILE: sha2.h * AUTHOR: Aaron D. Gifford * * Copyright (c) 2000-2001, Aaron D. Gifford * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $From: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $ */ /* OPENBSD ORIGINAL: include/sha2.h */ #ifndef _SSHSHA2_H #define _SSHSHA2_H #if !defined(HAVE_SHA256UPDATE) /*** SHA-256/384/512 Various Length Definitions ***********************/ #define SHA224_BLOCK_LENGTH 64 #define SHA224_DIGEST_LENGTH 28 #define SHA224_DIGEST_STRING_LENGTH (SHA224_DIGEST_LENGTH * 2 + 1) #define SHA256_BLOCK_LENGTH 64 #define SHA256_DIGEST_LENGTH 32 #define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) #define SHA384_BLOCK_LENGTH 128 #define SHA384_DIGEST_LENGTH 48 #define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) #define SHA512_BLOCK_LENGTH 128 #define SHA512_DIGEST_LENGTH 64 #define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) #define SHA512_256_BLOCK_LENGTH 128 #define SHA512_256_DIGEST_LENGTH 32 #define SHA512_256_DIGEST_STRING_LENGTH (SHA512_256_DIGEST_LENGTH * 2 + 1) /*** SHA-224/256/384/512 Context Structure *******************************/ typedef struct _SHA2_CTX { union { u_int32_t st32[8]; u_int64_t st64[8]; } state; u_int64_t bitcount[2]; u_int8_t buffer[SHA512_BLOCK_LENGTH]; } SHA2_CTX; #if 0 __BEGIN_DECLS void SHA224Init(SHA2_CTX *); void SHA224Transform(u_int32_t state[8], const u_int8_t [SHA224_BLOCK_LENGTH]); void SHA224Update(SHA2_CTX *, const u_int8_t *, size_t) __attribute__((__bounded__(__string__,2,3))); void SHA224Pad(SHA2_CTX *); void SHA224Final(u_int8_t [SHA224_DIGEST_LENGTH], SHA2_CTX *) __attribute__((__bounded__(__minbytes__,1,SHA224_DIGEST_LENGTH))); char *SHA224End(SHA2_CTX *, char *) __attribute__((__bounded__(__minbytes__,2,SHA224_DIGEST_STRING_LENGTH))); char *SHA224File(const char *, char *) __attribute__((__bounded__(__minbytes__,2,SHA224_DIGEST_STRING_LENGTH))); char *SHA224FileChunk(const char *, char *, off_t, off_t) __attribute__((__bounded__(__minbytes__,2,SHA224_DIGEST_STRING_LENGTH))); char *SHA224Data(const u_int8_t *, size_t, char *) __attribute__((__bounded__(__string__,1,2))) __attribute__((__bounded__(__minbytes__,3,SHA224_DIGEST_STRING_LENGTH))); #endif /* 0 */ #ifndef HAVE_SHA256UPDATE void SHA256Init(SHA2_CTX *); void SHA256Transform(u_int32_t state[8], const u_int8_t [SHA256_BLOCK_LENGTH]); void SHA256Update(SHA2_CTX *, const u_int8_t *, size_t) __attribute__((__bounded__(__string__,2,3))); void SHA256Pad(SHA2_CTX *); void SHA256Final(u_int8_t [SHA256_DIGEST_LENGTH], SHA2_CTX *) __attribute__((__bounded__(__minbytes__,1,SHA256_DIGEST_LENGTH))); char *SHA256End(SHA2_CTX *, char *) __attribute__((__bounded__(__minbytes__,2,SHA256_DIGEST_STRING_LENGTH))); char *SHA256File(const char *, char *) __attribute__((__bounded__(__minbytes__,2,SHA256_DIGEST_STRING_LENGTH))); char *SHA256FileChunk(const char *, char *, off_t, off_t) __attribute__((__bounded__(__minbytes__,2,SHA256_DIGEST_STRING_LENGTH))); char *SHA256Data(const u_int8_t *, size_t, char *) __attribute__((__bounded__(__string__,1,2))) __attribute__((__bounded__(__minbytes__,3,SHA256_DIGEST_STRING_LENGTH))); #endif /* HAVE_SHA256UPDATE */ #if 0 void SHA384Init(SHA2_CTX *); void SHA384Transform(u_int64_t state[8], const u_int8_t [SHA384_BLOCK_LENGTH]); void SHA384Update(SHA2_CTX *, const u_int8_t *, size_t) __attribute__((__bounded__(__string__,2,3))); void SHA384Pad(SHA2_CTX *); void SHA384Final(u_int8_t [SHA384_DIGEST_LENGTH], SHA2_CTX *) __attribute__((__bounded__(__minbytes__,1,SHA384_DIGEST_LENGTH))); char *SHA384End(SHA2_CTX *, char *) __attribute__((__bounded__(__minbytes__,2,SHA384_DIGEST_STRING_LENGTH))); char *SHA384File(const char *, char *) __attribute__((__bounded__(__minbytes__,2,SHA384_DIGEST_STRING_LENGTH))); char *SHA384FileChunk(const char *, char *, off_t, off_t) __attribute__((__bounded__(__minbytes__,2,SHA384_DIGEST_STRING_LENGTH))); char *SHA384Data(const u_int8_t *, size_t, char *) __attribute__((__bounded__(__string__,1,2))) __attribute__((__bounded__(__minbytes__,3,SHA384_DIGEST_STRING_LENGTH))); void SHA512Init(SHA2_CTX *); void SHA512Transform(u_int64_t state[8], const u_int8_t [SHA512_BLOCK_LENGTH]); void SHA512Update(SHA2_CTX *, const u_int8_t *, size_t) __attribute__((__bounded__(__string__,2,3))); void SHA512Pad(SHA2_CTX *); void SHA512Final(u_int8_t [SHA512_DIGEST_LENGTH], SHA2_CTX *) __attribute__((__bounded__(__minbytes__,1,SHA512_DIGEST_LENGTH))); char *SHA512End(SHA2_CTX *, char *) __attribute__((__bounded__(__minbytes__,2,SHA512_DIGEST_STRING_LENGTH))); char *SHA512File(const char *, char *) __attribute__((__bounded__(__minbytes__,2,SHA512_DIGEST_STRING_LENGTH))); char *SHA512FileChunk(const char *, char *, off_t, off_t) __attribute__((__bounded__(__minbytes__,2,SHA512_DIGEST_STRING_LENGTH))); char *SHA512Data(const u_int8_t *, size_t, char *) __attribute__((__bounded__(__string__,1,2))) __attribute__((__bounded__(__minbytes__,3,SHA512_DIGEST_STRING_LENGTH))); void SHA512_256Init(SHA2_CTX *); void SHA512_256Transform(u_int64_t state[8], const u_int8_t [SHA512_256_BLOCK_LENGTH]); void SHA512_256Update(SHA2_CTX *, const u_int8_t *, size_t) __attribute__((__bounded__(__string__,2,3))); void SHA512_256Pad(SHA2_CTX *); void SHA512_256Final(u_int8_t [SHA512_256_DIGEST_LENGTH], SHA2_CTX *) __attribute__((__bounded__(__minbytes__,1,SHA512_256_DIGEST_LENGTH))); char *SHA512_256End(SHA2_CTX *, char *) __attribute__((__bounded__(__minbytes__,2,SHA512_256_DIGEST_STRING_LENGTH))); char *SHA512_256File(const char *, char *) __attribute__((__bounded__(__minbytes__,2,SHA512_256_DIGEST_STRING_LENGTH))); char *SHA512_256FileChunk(const char *, char *, off_t, off_t) __attribute__((__bounded__(__minbytes__,2,SHA512_256_DIGEST_STRING_LENGTH))); char *SHA512_256Data(const u_int8_t *, size_t, char *) __attribute__((__bounded__(__string__,1,2))) __attribute__((__bounded__(__minbytes__,3,SHA512_256_DIGEST_STRING_LENGTH))); __END_DECLS #endif /* 0 */ #endif /* HAVE_SHA256UPDATE */ #endif /* _SSHSHA2_H */ got-portable-0.101/compat/strtonum.c0000664000175100017510000000335114644144735013137 /* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */ /* * Copyright (c) 2004 Ted Unangst and Todd Miller * All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #define INVALID 1 #define TOOSMALL 2 #define TOOLARGE 3 long long strtonum(const char *numstr, long long minval, long long maxval, const char **errstrp) { long long ll = 0; char *ep; int error = 0; struct errval { const char *errstr; int err; } ev[4] = { { NULL, 0 }, { "invalid", EINVAL }, { "too small", ERANGE }, { "too large", ERANGE }, }; ev[0].err = errno; errno = 0; if (minval > maxval) error = INVALID; else { ll = strtoll(numstr, &ep, 10); if (numstr == ep || *ep != '\0') error = INVALID; else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) error = TOOSMALL; else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) error = TOOLARGE; } if (errstrp != NULL) *errstrp = ev[error].errstr; errno = ev[error].err; if (error) ll = 0; return (ll); } got-portable-0.101/compat/fmt_scaled.c0000664000175100017510000001455614644144735013356 /* * Copyright (c) 2001, 2002, 2003 Ian F. Darwin. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * fmt_scaled: Format numbers scaled for human comprehension * scan_scaled: Scan numbers in this format. * * "Human-readable" output uses 4 digits max, and puts a unit suffix at * the end. Makes output compact and easy-to-read esp. on huge disks. * Formatting code was originally in OpenBSD "df", converted to library routine. * Scanning code written for OpenBSD libutil. */ #include #include #include #include #include #include #include "got_compat.h" typedef enum { NONE = 0, KILO = 1, MEGA = 2, GIGA = 3, TERA = 4, PETA = 5, EXA = 6 } unit_type; /* These three arrays MUST be in sync! XXX make a struct */ static unit_type units[] = { NONE, KILO, MEGA, GIGA, TERA, PETA, EXA }; static char scale_chars[] = "BKMGTPE"; static long long scale_factors[] = { 1LL, 1024LL, 1024LL*1024, 1024LL*1024*1024, 1024LL*1024*1024*1024, 1024LL*1024*1024*1024*1024, 1024LL*1024*1024*1024*1024*1024, }; #define SCALE_LENGTH (sizeof(units)/sizeof(units[0])) #define MAX_DIGITS (SCALE_LENGTH * 3) /* XXX strlen(sprintf("%lld", -1)? */ /* Convert the given input string "scaled" into numeric in "result". * Return 0 on success, -1 and errno set on error. */ int scan_scaled(char *scaled, long long *result) { char *p = scaled; int sign = 0; unsigned int i, ndigits = 0, fract_digits = 0; long long scale_fact = 1, whole = 0, fpart = 0; /* Skip leading whitespace */ while (isascii(*p) && isspace(*p)) ++p; /* Then at most one leading + or - */ while (*p == '-' || *p == '+') { if (*p == '-') { if (sign) { errno = EINVAL; return -1; } sign = -1; ++p; } else if (*p == '+') { if (sign) { errno = EINVAL; return -1; } sign = +1; ++p; } } /* Main loop: Scan digits, find decimal point, if present. * We don't allow exponentials, so no scientific notation * (but note that E for Exa might look like e to some!). * Advance 'p' to end, to get scale factor. */ for (; isascii(*p) && (isdigit(*p) || *p=='.'); ++p) { if (*p == '.') { if (fract_digits > 0) { /* oops, more than one '.' */ errno = EINVAL; return -1; } fract_digits = 1; continue; } i = (*p) - '0'; /* whew! finally a digit we can use */ if (fract_digits > 0) { if (fract_digits >= MAX_DIGITS-1) /* ignore extra fractional digits */ continue; fract_digits++; /* for later scaling */ fpart *= 10; fpart += i; } else { /* normal digit */ if (++ndigits >= MAX_DIGITS) { errno = ERANGE; return -1; } whole *= 10; whole += i; } } if (sign) { whole *= sign; fpart *= sign; } /* If no scale factor given, we're done. fraction is discarded. */ if (!*p) { *result = whole; return 0; } /* Validate scale factor, and scale whole and fraction by it. */ for (i = 0; i < SCALE_LENGTH; i++) { /* Are we there yet? */ if (*p == scale_chars[i] || *p == tolower(scale_chars[i])) { /* If it ends with alphanumerics after the scale char, bad. */ if (isalnum(*(p+1))) { errno = EINVAL; return -1; } scale_fact = scale_factors[i]; /* scale whole part */ whole *= scale_fact; /* truncate fpart so it does't overflow. * then scale fractional part. */ while (fpart >= LLONG_MAX / scale_fact) { fpart /= 10; fract_digits--; } fpart *= scale_fact; if (fract_digits > 0) { for (i = 0; i < fract_digits -1; i++) fpart /= 10; } whole += fpart; *result = whole; return 0; } } errno = ERANGE; return -1; } /* Format the given "number" into human-readable form in "result". * Result must point to an allocated buffer of length FMT_SCALED_STRSIZE. * Return 0 on success, -1 and errno set if error. */ int fmt_scaled(long long number, char *result) { long long abval, fract = 0; unsigned int i; unit_type unit = NONE; abval = llabs(number); /* Not every negative long long has a positive representation. * Also check for numbers that are just too darned big to format */ if (abval < 0 || abval / 1024 >= scale_factors[SCALE_LENGTH-1]) { errno = ERANGE; return -1; } /* scale whole part; get unscaled fraction */ for (i = 0; i < SCALE_LENGTH; i++) { if (abval/1024 < scale_factors[i]) { unit = units[i]; fract = (i == 0) ? 0 : abval % scale_factors[i]; number /= scale_factors[i]; if (i > 0) fract /= scale_factors[i - 1]; break; } } fract = (10 * fract + 512) / 1024; /* if the result would be >= 10, round main number */ if (fract == 10) { if (number >= 0) number++; else number--; fract = 0; } if (number == 0) strlcpy(result, "0B", FMT_SCALED_STRSIZE); else if (unit == NONE || number >= 100 || number <= -100) { if (fract >= 5) { if (number >= 0) number++; else number--; } (void)snprintf(result, FMT_SCALED_STRSIZE, "%lld%c", number, scale_chars[unit]); } else (void)snprintf(result, FMT_SCALED_STRSIZE, "%lld.%1lld%c", number, fract, scale_chars[unit]); return 0; } got-portable-0.101/compat/err.c0000664000175100017510000000335114644144735012034 /* * Copyright (c) 2021 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include static void vwarn_impl(const char*, va_list); static void vwarnx_impl(const char*, va_list); static void vwarn_impl(const char *fmt, va_list ap) { fprintf(stderr, "%s: ", getprogname()); vfprintf(stderr, fmt, ap); fprintf(stderr, ": %s\n", strerror(errno)); } static void vwarnx_impl(const char *fmt, va_list ap) { fprintf(stderr, "%s: ", getprogname()); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); } void err(int ret, const char *fmt, ...) { va_list ap; va_start(ap, fmt); vwarn_impl(fmt, ap); va_end(ap); exit(ret); } void errx(int ret, const char *fmt, ...) { va_list ap; va_start(ap, fmt); vwarnx_impl(fmt, ap); va_end(ap); exit(ret); } void warn(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vwarn_impl(fmt, ap); va_end(ap); } void warnx(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vwarnx_impl(fmt, ap); va_end(ap); } got-portable-0.101/compat/reallocarray.c0000664000175100017510000000255414644144735013730 /* $OpenBSD: reallocarray.c,v 1.3 2015/09/13 08:31:47 guenther Exp $ */ /* * Copyright (c) 2008 Otto Moerbeek * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include "got_compat.h" /* * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW */ #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) void * reallocarray(void *optr, size_t nmemb, size_t size) { if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && nmemb > 0 && SIZE_MAX / nmemb < size) { errno = ENOMEM; return NULL; } return realloc(optr, size * nmemb); } got-portable-0.101/compat/getdtablecount.c0000664000175100017510000000242514644144735014251 /* * Copyright (c) 2017 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include void fatal(const char *, ...); void fatalx(const char *, ...); #ifdef HAVE_PROC_PID int getdtablecount(void) { char path[PATH_MAX]; glob_t g; int n = 0; if (snprintf(path, sizeof path, "/proc/%ld/fd/*", (long)getpid()) < 0) { fprintf(stderr, "snprintf overflow"); exit (1); } if (glob(path, 0, NULL, &g) == 0) n = g.gl_pathc; globfree(&g); return (n); } #else int getdtablecount(void) { return (0); } #endif got-portable-0.101/TODO0000664000175100017510000001104414644143345010277 got: - Teach 'got merge' to merge changes into an arbitrary subdirectory of the work tree. This would be nice for merging vendor branches. Say you have a branch 'llvm-12' which intially contains a 12.0 release tree as published by the LLVM project, added to the repository with a command such as 'got import -b llvm-12'. On the main branch we would want to merge files from the llvm-12 branch into /usr/src/gnu/llvm instead of the root directory checked out at /usr/src. The next LLVM release 12.1 would later be committed onto the llvm-12 branch and then merged into main at /usr/src/gnu/llvm in the same way. - When a clone fails the HEAD symref will always point to "refs/heads/main" (ie. the internal default HEAD symref of Got). Resuming a failed clone with 'got fetch' is supposed to work. To make this easier, if the HEAD symref points to a non-existent reference it should be updated by 'got fetch' to match the HEAD symref sent by the server. - If invoked in a work tree, got fetch could default to fetching the work tree's current branch, instead of fetching the remote repository's HEAD. - 'got patch' should be able to detect an already applied patch. - 'got patch' should ideally do more passes if a patch doesn't apply and try fancy things (like ignoring context and whitespaces) only in later passes. - investigate whether it's worth for 'got patch' to memory-map the files to edit. (c.f. Plan A / Plan B in Larry' patch.) - when fetching pack files got should verify that the requested branch tips are present in the pack file sent by the server, before making this pack file visible to readers of the repository - enforce that log messages are encoded in either ASCII or UTF-8; this mostly matters for -portable since OpenBSD doesn't provide other locales - by default, deny rebasing of commits that exist in refs/remotes or refs/tags tog: - make 'tog log' respond to key presses while 'loading...' history; loading can be slow for paths in a deep history if the path has not been changed very often, and 'tog log' blocks far too long in this case - make it possible to view the contents of tag objects - verify signed tag objects - make it possible to toggle the parent to diff against in merge commits gotwebd: - fix COMMITS page for paths that were deleted and/or re-added to the repository. One way would be not to let the commit graph filter paths. As an additional optimization we could keep a tailq or the object-id set for everything traversed in the repo to have fast reverse-lookups. (has the additional requirement to invalidate it when the reference timestamp changes) - reply with 404 on some kind of errors ('reference not found' for sure, maybe also tree entry not found?) - support category grouping a-la gitweb/cgit with the gitweb.category config option or via the "category" file in the root of the repo. - consider changing the URL scheme to avoid so many query parameters gotd: - ensure all error messages are propagated to clients before disconnecting, there are probably still some cases where such error reporting is skipped - client connection timeout handling needs to be checked by regress tests, and is likely in need of improvement - implement stress-tests to observe and fix misbehaviour under load - listener's fd-reserve limit needs to be reviewed and perhaps adjusted - implement pre-commit checks (in lieu of hook scripts): 1. deny branch history rewriting ('got send -f') via gotd.conf [done] 2. allow/deny creation/deletion of references via gotd.conf 3. deny modifications within a given reference namespace via gotd.conf [done] 4. entirely hide a given reference namespace from clients via gotd.conf 5. allow/deny addition of binary files to a repo via gotd.conf 6. enforce a particular blob size limit via gotd.conf 7. optionally reject merge commits via gotd.conf - implement post-commit-event libexec handlers (in lieu of hook scripts): 1. commit email notification, plaintext smtp to localhost port 25 [done] 2. general-purpose HTTP(s) GET/POST request as commit notification [done] 3. perform the equivalent of 'got send' to another repository - keep track of available repository disk space and fail gracefully when uploaded pack files would fill up the disk too much, keeping a reserve - reuse packed non-delta objects directly (without re-deltification) for speed gotadmin: - add support for generating git-fast-export streams from a repository - add support for importing git-fast-export streams into a repository - speed up 'gotadmin pack -a' is too slow on repositories with many pack files got-portable-0.101/gitwrapper/0000775000175100017510000000000014644145570012055 5got-portable-0.101/gitwrapper/Makefile.am0000664000175100017510000000147414644144735014041 bin_PROGRAMS = gitwrapper include $(top_builddir)/Makefile.common AM_CPPFLAGS += -I$(top_builddir)/gotd AM_CPPFLAGS += -DGITWRAPPER_GIT_LIBEXEC_DIR='"@GITWRAPPER_LIBEXEC_PATHC@"' CLEANFILES = parse.h gitwrapper_SOURCES = gitwrapper.c \ $(top_srcdir)/gotd/parse.y \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/log.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/reference_parse.c gitwrapper_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = gitwrapper.1 man1_MANS = gitwrapper.1 LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(libbsd_LIBS) \ $(libuuid_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(libbsd_CFLAGS) $(libuuid_CFLAGS) $(libevent_CFLAGS) got-portable-0.101/gitwrapper/gitwrapper.10000644000175100017510000000736314644143163014246 .\" .\" Copyright (c) 2023 Stefan Sperling .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt GITWRAPPER 1 .Os .Sh NAME .Nm gitwrapper .Nd invoke an appropriate Git repository server .Sh SYNOPSIS .Nm Fl c Sq Cm git-receive-pack Ar repository-path .Nm Fl c Sq Cm git-upload-pack Ar repository-path .Sh DESCRIPTION At one time, the only Git repository server software easily available was built into .Xr git-upload-pack 1 and .Xr git-receive-pack 1 which are part of the .Xr git 1 suite. As a result of this, most Git client implementations had the path and calling conventions expected by .Xr git 1 compiled in. .Pp Times have changed, however. On a modern system, the administrator may wish to use one of several available Git repository servers, such as .Xr gotd 8 . .Pp It would be difficult to modify all Git client software typically available on a system, so most of the authors of alternative Git servers have written their programs so that they use the same calling conventions as .Xr git-upload-pack 1 and .Xr git-receive-pack 1 and may be put into place in their stead. .Pp Although having drop-in replacements for .Xr git-upload-pack 1 and .Xr git-receive-pack 1 helps in installing alternative Git servers, it essentially makes the configuration of the system depend on hard installing new programs in .Pa /usr . This leads to configuration problems for many administrators, since they may wish to install a new Git server without altering the system provided .Pa /usr . (This may be, for example, to avoid having upgrade problems when a new version of the system is installed over the old.) They may also have a shared .Pa /usr among several machines, and may wish to avoid placing implicit configuration information in a read-only .Pa /usr . .Pp The .Nm program is designed to replace .Xr git-upload-pack 1 and .Xr git-receive-pack 1 and to invoke an appropriate Git server based on configuration information placed in .Xr gotd.conf 5 . This permits the administrator to configure which Git server is to be invoked on the system at run-time. Git repositories which are listed in .Xr gotd.conf 5 and exist on the filesystem will be served by .Xr gotsh 1 . Any other Git repositories will be served by .Xr git-upload-pack 1 and .Xr git-receive-pack 1 as found in Git's .Pa libexec directory, which is .Pa /usr/local/libexec/git/ by default on .Ox . .Sh ENVIRONMENT .Bl -tag -width GOTD_CONF_PATH .It Ev GOTD_CONF_PATH Set the path to the configuration file for .Xr gotd 8 . If not specified, the default path .Pa /etc/gotd.conf will be used. .El .Sh FILES Configuration for .Xr gotd 8 is kept in .Pa /etc/gotd.conf . .Pp .Pa git-upload-pack and .Pa git-receive-pack are typically set up as a symlink to .Nm which is not usually invoked on its own. .Sh SEE ALSO .Xr got 1 , .Xr gotd.conf 5 , .Xr gotd 8 , .Xr mailwrapper 8 .Sh AUTHORS .An Stefan Sperling Aq Mt stsp@openbsd.org .Sh BUGS The entire reason this program exists is a crock. Instead, a command for invoking a Git server should be standardized or the Git protocol should be changed to make the path to the program discoverable by Git clients. got-portable-0.101/gitwrapper/Makefile.in0000664000175100017510000006671014644145543014054 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = gitwrapper$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = gitwrapper ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" PROGRAMS = $(bin_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_gitwrapper_OBJECTS = gitwrapper.$(OBJEXT) \ $(top_builddir)/gotd/parse.$(OBJEXT) \ $(top_builddir)/lib/dial.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/log.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/reference_parse.$(OBJEXT) gitwrapper_OBJECTS = $(am_gitwrapper_OBJECTS) gitwrapper_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/gotd/$(DEPDIR)/parse.Po \ $(top_builddir)/lib/$(DEPDIR)/dial.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/log.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po \ ./$(DEPDIR)/gitwrapper.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \ -e s/c++$$/h++/ -e s/c$$/h/ YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS) AM_V_YACC = $(am__v_YACC_@AM_V@) am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@) am__v_YACC_0 = @echo " YACC " $@; am__v_YACC_1 = YLWRAP = $(top_srcdir)/etc/ylwrap SOURCES = $(gitwrapper_SOURCES) DIST_SOURCES = $(gitwrapper_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } man1dir = $(mandir)/man1 NROFF = nroff MANS = $(man1_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp \ $(top_srcdir)/etc/ylwrap $(top_srcdir)/gotd/parse.c DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_builddir)/gotd \ -DGITWRAPPER_GIT_LIBEXEC_DIR='"@GITWRAPPER_LIBEXEC_PATHC@"' \ $(libbsd_CFLAGS) $(libuuid_CFLAGS) $(libevent_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ CLEANFILES = parse.h gitwrapper_SOURCES = gitwrapper.c \ $(top_srcdir)/gotd/parse.y \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/log.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/reference_parse.c gitwrapper_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = gitwrapper.1 man1_MANS = gitwrapper.1 LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(libbsd_LIBS) \ $(libuuid_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj .y $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gitwrapper/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign gitwrapper/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) $(top_builddir)/gotd/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/gotd @: > $(top_builddir)/gotd/$(am__dirstamp) $(top_builddir)/gotd/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/gotd/$(DEPDIR) @: > $(top_builddir)/gotd/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/gotd/parse.$(OBJEXT): \ $(top_builddir)/gotd/$(am__dirstamp) \ $(top_builddir)/gotd/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: > $(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: > $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/dial.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/log.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) gitwrapper$(EXEEXT): $(gitwrapper_OBJECTS) $(gitwrapper_DEPENDENCIES) $(EXTRA_gitwrapper_DEPENDENCIES) @rm -f gitwrapper$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gitwrapper_OBJECTS) $(gitwrapper_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/gotd/*.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/gotd/$(DEPDIR)/parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/dial.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/log.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gitwrapper.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .y.c: $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE) install-man1: $(man1_MANS) @$(NORMAL_INSTALL) @list1='$(man1_MANS)'; \ list2=''; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list='$(man1_MANS)'; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(MANS) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(top_builddir)/gotd/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/gotd/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/gotd/$(am__dirstamp)" || rm -f $(top_builddir)/gotd/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -rm -f $(top_srcdir)/gotd/parse.c clean: clean-am clean-am: clean-binPROGRAMS clean-generic mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/gotd/$(DEPDIR)/parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/dial.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/log.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f ./$(DEPDIR)/gitwrapper.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/gotd/$(DEPDIR)/parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/dial.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/log.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f ./$(DEPDIR)/gitwrapper.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-man uninstall-man: uninstall-man1 .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-binPROGRAMS clean-generic cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-binPROGRAMS install-data install-data-am \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-man1 install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-man uninstall-man1 .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/gitwrapper/gitwrapper.c0000664000175100017510000001262114644144735014331 /* * Copyright (c) 2023 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Resolve path namespace conflicts for git-upload-pack and git-receive-pack. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_lib_dial.h" #include "gotd.h" #include "log.h" #ifndef GITWRAPPER_GIT_LIBEXEC_DIR #define GITWRAPPER_GIT_LIBEXEC_DIR "/usr/local/libexec/git" #endif #ifndef GITWRAPPER_MY_SERVER_PROG #define GITWRAPPER_MY_SERVER_PROG "gotsh" #endif __dead static void usage(void) { fprintf(stderr, "usage: %s -c '%s|%s repository-path'\n", getprogname(), GOT_DIAL_CMD_SEND, GOT_DIAL_CMD_FETCH); exit(1); } /* * Unveil the specific programs we want to start and hide everything else. * This is important to limit the impact of our "exec" pledge. */ static const struct got_error * apply_unveil(const char *myserver) { const char *fetchcmd = GITWRAPPER_GIT_LIBEXEC_DIR "/" \ GOT_DIAL_CMD_FETCH; const char *sendcmd = GITWRAPPER_GIT_LIBEXEC_DIR "/" \ GOT_DIAL_CMD_SEND; #ifdef PROFILE if (unveil("gmon.out", "rwc") != 0) return got_error_from_errno2("unveil", "gmon.out"); #endif if (unveil(fetchcmd, "x") != 0 && errno != ENOENT) return got_error_from_errno2("unveil", fetchcmd); if (unveil(sendcmd, "x") != 0 && errno != ENOENT) return got_error_from_errno2("unveil", sendcmd); if (myserver && unveil(myserver, "x") != 0 && errno != ENOENT) return got_error_from_errno2("unveil", myserver); if (unveil(NULL, NULL) != 0) return got_error_from_errno("unveil"); return NULL; } int main(int argc, char *argv[]) { const struct got_error *error; const char *confpath = NULL; char *command = NULL, *repo_name = NULL; /* for matching gotd.conf */ char *myserver = NULL; const char *repo_path = NULL; /* as passed on the command line */ const char *relpath; char *gitcommand = NULL; struct gotd gotd; struct gotd_repo *repo = NULL; log_init(1, LOG_USER); /* Log to stderr. */ #ifndef PROFILE if (pledge("stdio rpath exec unveil", NULL) == -1) err(1, "pledge"); #endif /* * Look up our own server program in PATH so we can unveil(2) it. * This call only errors out upon memory allocation failure. * If the program cannot be found then myserver will be set to NULL. */ error = got_path_find_prog(&myserver, GITWRAPPER_MY_SERVER_PROG); if (error) goto done; /* * Run parse_config() before unveil(2) because parse_config() * checks whether repository paths exist on disk. * Parsing errors and warnings will be logged to stderr. * Upon failure we will run Git's native tooling so do not * bother checking for errors here. */ confpath = getenv("GOTD_CONF_PATH"); if (confpath == NULL) confpath = GOTD_CONF_PATH; parse_config(confpath, PROC_GITWRAPPER, &gotd); error = apply_unveil(myserver); if (error) goto done; #ifndef PROFILE if (pledge("stdio exec", NULL) == -1) err(1, "pledge"); #endif if (strcmp(getprogname(), GOT_DIAL_CMD_SEND) == 0 || strcmp(getprogname(), GOT_DIAL_CMD_FETCH) == 0) { if (argc != 2) usage(); command = strdup(getprogname()); if (command == NULL) { error = got_error_from_errno("strdup"); goto done; } repo_path = argv[1]; relpath = argv[1]; while (relpath[0] == '/') relpath++; repo_name = strdup(relpath); if (repo_name == NULL) { error = got_error_from_errno("strdup"); goto done; } } else { if (argc != 3 || strcmp(argv[1], "-c") != 0) usage(); repo_path = argv[2]; error = got_dial_parse_command(&command, &repo_name, repo_path); if (error && error->code == GOT_ERR_BAD_PACKET) usage(); if (error) goto done; } repo = gotd_find_repo_by_name(repo_name, &gotd.repos); /* * Invoke our custom Git server if the repository was found * in gotd.conf. Otherwise invoke native git(1) tooling. */ if (repo) { if (myserver == NULL) { error = got_error_fmt(GOT_ERR_NO_PROG, "cannot run '%s'", GITWRAPPER_MY_SERVER_PROG); goto done; } execl(myserver, command, repo_name, (char *)NULL); error = got_error_from_errno2("execl", myserver); } else { if (asprintf(&gitcommand, "%s/%s", GITWRAPPER_GIT_LIBEXEC_DIR, command) == -1) { error = got_error_from_errno("asprintf"); goto done; } execl(gitcommand, gitcommand, repo_path, (char *)NULL); error = got_error_from_errno2("execl", gitcommand); } done: free(command); free(repo_name); free(myserver); free(gitcommand); if (error) { fprintf(stderr, "%s: %s\n", getprogname(), error->msg); return 1; } return 0; } got-portable-0.101/template/0000775000175100017510000000000014644145571011505 5got-portable-0.101/template/Makefile.am0000664000175100017510000000023514644144735013462 noinst_PROGRAMS = template include $(top_builddir)/Makefile.common template_SOURCES = template.c \ parse.y EXTRA_DIST = got_compat.h LDADD = $(LIBOBJS) got-portable-0.101/template/compile0000755000175100017510000001635014644145542013004 #! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1999-2021 Free Software Foundation, Inc. # Written by Tom Tromey . # # 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 # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN* | MSYS*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/* | msys/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: got-portable-0.101/template/tmpl.h0000644000175100017510000000302314644143163012541 /* * Copyright (c) 2022 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef TMPL_H #define TMPL_H struct template; typedef int (*tmpl_write)(void *, const void *, size_t); struct template { void *tp_arg; char *tp_tmp; tmpl_write tp_write; char *tp_buf; size_t tp_len; size_t tp_cap; }; int tp_write(struct template *, const char *, size_t); int tp_writes(struct template *, const char *); int tp_writef(struct template *, const char *, ...) __attribute__((__format__ (printf, 2, 3))); int tp_urlescape(struct template *, const char *); int tp_htmlescape(struct template *, const char *); int tp_write_htmlescape(struct template *, const char *, size_t); struct template *template(void *, tmpl_write, char *, size_t); int template_flush(struct template *); void template_free(struct template *); #endif got-portable-0.101/template/missing0000755000175100017510000001533614644145542013030 #! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1996-2021 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # 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 # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=https://www.perl.org/ flex_URL=https://github.com/westes/flex gnu_software_URL=https://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: got-portable-0.101/template/parse.c0000644000175100017510000017473514644145561012721 /* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. 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 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 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output, and Bison version. */ #define YYBISON 30802 /* Bison version string. */ #define YYBISON_VERSION "3.8.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* First part of user prologue. */ #line 24 "parse.y" #include #include #include #include #include #include #include #include #include #include "got_compat.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); static struct file { TAILQ_ENTRY(file) entry; FILE *stream; char *name; size_t ungetpos; size_t ungetsize; unsigned char *ungetbuf; int eof_reached; int lineno; int errors; } *file, *topfile; int parse(FILE *, const char *); struct file *pushfile(const char *, int); int popfile(void); int yyparse(void); int yylex(void); int yyerror(const char *, ...) __attribute__((__format__ (printf, 1, 2))) __attribute__((__nonnull__ (1))); int kw_cmp(const void *, const void *); int lookup(char *); int igetc(void); int lgetc(int); void lungetc(int); int findeol(void); void dbg(void); void printq(const char *); extern int nodebug; static FILE *fp; static int block; static int in_define; static int errors; static int lastline = -1; typedef struct { union { char *string; } v; int lineno; } YYSTYPE; #line 138 "parse.c" # ifndef YY_CAST # ifdef __cplusplus # define YY_CAST(Type, Val) static_cast (Val) # define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) # else # define YY_CAST(Type, Val) ((Type) (Val)) # define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) # endif # endif # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # else # define YY_NULLPTR ((void*)0) # endif # endif /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yydebug; #endif /* Token kinds. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { YYEMPTY = -2, YYEOF = 0, /* "end of file" */ YYerror = 256, /* error */ YYUNDEF = 257, /* "invalid token" */ DEFINE = 258, /* DEFINE */ ELSE = 259, /* ELSE */ END = 260, /* END */ ERROR = 261, /* ERROR */ FINALLY = 262, /* FINALLY */ FOR = 263, /* FOR */ IF = 264, /* IF */ INCLUDE = 265, /* INCLUDE */ PRINTF = 266, /* PRINTF */ RENDER = 267, /* RENDER */ TQFOREACH = 268, /* TQFOREACH */ UNSAFE = 269, /* UNSAFE */ URLESCAPE = 270, /* URLESCAPE */ WHILE = 271, /* WHILE */ STRING = 272 /* STRING */ }; typedef enum yytokentype yytoken_kind_t; #endif /* Token kinds. */ #define YYEMPTY -2 #define YYEOF 0 #define YYerror 256 #define YYUNDEF 257 #define DEFINE 258 #define ELSE 259 #define END 260 #define ERROR 261 #define FINALLY 262 #define FOR 263 #define IF 264 #define INCLUDE 265 #define PRINTF 266 #define RENDER 267 #define TQFOREACH 268 #define UNSAFE 269 #define URLESCAPE 270 #define WHILE 271 #define STRING 272 /* Value type. */ extern YYSTYPE yylval; int yyparse (void); /* Symbol kind. */ enum yysymbol_kind_t { YYSYMBOL_YYEMPTY = -2, YYSYMBOL_YYEOF = 0, /* "end of file" */ YYSYMBOL_YYerror = 1, /* error */ YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ YYSYMBOL_DEFINE = 3, /* DEFINE */ YYSYMBOL_ELSE = 4, /* ELSE */ YYSYMBOL_END = 5, /* END */ YYSYMBOL_ERROR = 6, /* ERROR */ YYSYMBOL_FINALLY = 7, /* FINALLY */ YYSYMBOL_FOR = 8, /* FOR */ YYSYMBOL_IF = 9, /* IF */ YYSYMBOL_INCLUDE = 10, /* INCLUDE */ YYSYMBOL_PRINTF = 11, /* PRINTF */ YYSYMBOL_RENDER = 12, /* RENDER */ YYSYMBOL_TQFOREACH = 13, /* TQFOREACH */ YYSYMBOL_UNSAFE = 14, /* UNSAFE */ YYSYMBOL_URLESCAPE = 15, /* URLESCAPE */ YYSYMBOL_WHILE = 16, /* WHILE */ YYSYMBOL_STRING = 17, /* STRING */ YYSYMBOL_18_ = 18, /* '!' */ YYSYMBOL_19_ = 19, /* '{' */ YYSYMBOL_20_ = 20, /* '}' */ YYSYMBOL_21_ = 21, /* '|' */ YYSYMBOL_YYACCEPT = 22, /* $accept */ YYSYMBOL_grammar = 23, /* grammar */ YYSYMBOL_include = 24, /* include */ YYSYMBOL_verbatim = 25, /* verbatim */ YYSYMBOL_verbatim1 = 26, /* verbatim1 */ YYSYMBOL_verbatims = 27, /* verbatims */ YYSYMBOL_raw = 28, /* raw */ YYSYMBOL_block = 29, /* block */ YYSYMBOL_define = 30, /* define */ YYSYMBOL_body = 31, /* body */ YYSYMBOL_special = 32, /* special */ YYSYMBOL_printf = 33, /* printf */ YYSYMBOL_34_1 = 34, /* $@1 */ YYSYMBOL_printfargs = 35, /* printfargs */ YYSYMBOL_if = 36, /* if */ YYSYMBOL_endif = 37, /* endif */ YYSYMBOL_elsif = 38, /* elsif */ YYSYMBOL_else = 39, /* else */ YYSYMBOL_loop = 40, /* loop */ YYSYMBOL_41_2 = 41, /* $@2 */ YYSYMBOL_42_3 = 42, /* $@3 */ YYSYMBOL_43_4 = 43, /* $@4 */ YYSYMBOL_end = 44, /* end */ YYSYMBOL_finally = 45, /* finally */ YYSYMBOL_46_5 = 46, /* $@5 */ YYSYMBOL_nstring = 47, /* nstring */ YYSYMBOL_string = 48, /* string */ YYSYMBOL_stringy = 49 /* stringy */ }; typedef enum yysymbol_kind_t yysymbol_kind_t; #ifdef short # undef short #endif /* On compilers that do not define __PTRDIFF_MAX__ etc., make sure and (if available) are included so that the code can choose integer types of a good width. */ #ifndef __PTRDIFF_MAX__ # include /* INFRINGES ON USER NAME SPACE */ # if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YY_STDINT_H # endif #endif /* Narrow types that promote to a signed type and that can represent a signed or unsigned integer of at least N bits. In tables they can save space and decrease cache pressure. Promoting to a signed type helps avoid bugs in integer arithmetic. */ #ifdef __INT_LEAST8_MAX__ typedef __INT_LEAST8_TYPE__ yytype_int8; #elif defined YY_STDINT_H typedef int_least8_t yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef __INT_LEAST16_MAX__ typedef __INT_LEAST16_TYPE__ yytype_int16; #elif defined YY_STDINT_H typedef int_least16_t yytype_int16; #else typedef short yytype_int16; #endif /* Work around bug in HP-UX 11.23, which defines these macros incorrectly for preprocessor constants. This workaround can likely be removed in 2023, as HPE has promised support for HP-UX 11.23 (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of . */ #ifdef __hpux # undef UINT_LEAST8_MAX # undef UINT_LEAST16_MAX # define UINT_LEAST8_MAX 255 # define UINT_LEAST16_MAX 65535 #endif #if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ typedef __UINT_LEAST8_TYPE__ yytype_uint8; #elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ && UINT_LEAST8_MAX <= INT_MAX) typedef uint_least8_t yytype_uint8; #elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX typedef unsigned char yytype_uint8; #else typedef short yytype_uint8; #endif #if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ typedef __UINT_LEAST16_TYPE__ yytype_uint16; #elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ && UINT_LEAST16_MAX <= INT_MAX) typedef uint_least16_t yytype_uint16; #elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX typedef unsigned short yytype_uint16; #else typedef int yytype_uint16; #endif #ifndef YYPTRDIFF_T # if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ # define YYPTRDIFF_T __PTRDIFF_TYPE__ # define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ # elif defined PTRDIFF_MAX # ifndef ptrdiff_t # include /* INFRINGES ON USER NAME SPACE */ # endif # define YYPTRDIFF_T ptrdiff_t # define YYPTRDIFF_MAXIMUM PTRDIFF_MAX # else # define YYPTRDIFF_T long # define YYPTRDIFF_MAXIMUM LONG_MAX # endif #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned # endif #endif #define YYSIZE_MAXIMUM \ YY_CAST (YYPTRDIFF_T, \ (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ ? YYPTRDIFF_MAXIMUM \ : YY_CAST (YYSIZE_T, -1))) #define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) /* Stored state numbers (used for stacks). */ typedef yytype_int8 yy_state_t; /* State numbers in computations. */ typedef int yy_state_fast_t; #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE_PURE # if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) # else # define YY_ATTRIBUTE_PURE # endif #endif #ifndef YY_ATTRIBUTE_UNUSED # if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) # else # define YY_ATTRIBUTE_UNUSED # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YY_USE(E) ((void) (E)) #else # define YY_USE(E) /* empty */ #endif /* Suppress an incorrect diagnostic about yylval being uninitialized. */ #if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ # if __GNUC__ * 100 + __GNUC_MINOR__ < 407 # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") # else # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # endif # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ # define YY_IGNORE_USELESS_CAST_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") # define YY_IGNORE_USELESS_CAST_END \ _Pragma ("GCC diagnostic pop") #endif #ifndef YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_END #endif #define YY_ASSERT(E) ((void) (0 && (E))) #if !defined yyoverflow /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* !defined yyoverflow */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yy_state_t yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYPTRDIFF_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / YYSIZEOF (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYPTRDIFF_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 98 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 22 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 28 /* YYNRULES -- Number of rules. */ #define YYNRULES 53 /* YYNSTATES -- Number of states. */ #define YYNSTATES 100 /* YYMAXUTOK -- Last valid token kind. */ #define YYMAXUTOK 272 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM as returned by yylex, with out-of-bounds checking. */ #define YYTRANSLATE(YYX) \ (0 <= (YYX) && (YYX) <= YYMAXUTOK \ ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ : YYSYMBOL_YYUNDEF) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex. */ static const yytype_int8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 18, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 19, 21, 20, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { 0, 99, 99, 100, 101, 102, 103, 106, 121, 128, 129, 138, 139, 142, 153, 159, 166, 177, 178, 179, 180, 183, 189, 190, 191, 192, 200, 208, 218, 218, 232, 233, 239, 246, 247, 248, 251, 258, 264, 264, 270, 270, 279, 279, 287, 290, 290, 296, 302, 305, 311, 314, 315, 321 }; #endif /** Accessing symbol of state STATE. */ #define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) #if YYDEBUG || 0 /* The user-facing name of the symbol whose (internal) number is YYSYMBOL. No bounds checking. */ static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "\"end of file\"", "error", "\"invalid token\"", "DEFINE", "ELSE", "END", "ERROR", "FINALLY", "FOR", "IF", "INCLUDE", "PRINTF", "RENDER", "TQFOREACH", "UNSAFE", "URLESCAPE", "WHILE", "STRING", "'!'", "'{'", "'}'", "'|'", "$accept", "grammar", "include", "verbatim", "verbatim1", "verbatims", "raw", "block", "define", "body", "special", "printf", "$@1", "printfargs", "if", "endif", "elsif", "else", "loop", "$@2", "$@3", "$@4", "end", "finally", "$@5", "nstring", "string", "stringy", YY_NULLPTR }; static const char * yysymbol_name (yysymbol_kind_t yysymbol) { return yytname[yysymbol]; } #endif #define YYPACT_NINF (-33) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) #define YYTABLE_NINF (-1) #define yytable_value_is_error(Yyn) \ 0 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int8 yypact[] = { -33, 11, -33, -33, 22, -33, 15, -33, -33, -33, -33, -33, 2, 33, 5, -33, -33, 33, 31, 37, 51, -33, -33, -33, -33, -33, -33, -33, 36, -33, -33, -33, -33, 45, 46, -12, -12, -33, 33, 52, -12, 23, 8, 65, -33, -33, -33, -12, -12, 53, 54, -33, 55, 63, 61, -33, 17, 29, -33, -33, -33, -33, -33, -33, -33, -33, -33, -7, -33, 71, -33, 69, 72, -3, 8, 30, 75, -33, -33, -33, 76, -33, -33, -33, -12, -33, -33, 74, -33, -33, 30, -33, 30, 77, -33, -33, -33, -33, 30, -33 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_int8 yydefact[] = { 2, 0, 1, 6, 0, 9, 0, 3, 4, 5, 17, 7, 0, 0, 0, 10, 8, 50, 0, 48, 0, 18, 19, 20, 22, 17, 24, 14, 0, 13, 49, 16, 47, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 15, 44, 45, 51, 0, 0, 0, 30, 0, 0, 0, 27, 0, 0, 23, 17, 17, 33, 11, 52, 53, 38, 32, 0, 21, 0, 42, 0, 0, 0, 0, 0, 46, 17, 31, 29, 0, 17, 25, 26, 0, 37, 35, 0, 34, 12, 0, 40, 0, 0, 39, 17, 43, 36, 0, 41 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { -33, -33, -33, 1, -33, -33, -33, -33, -33, -24, -33, -33, -33, -33, -33, -2, -33, -33, -33, -33, -33, -33, -14, -33, -33, 79, -10, -32 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { 0, 1, 7, 21, 12, 76, 22, 9, 10, 14, 23, 24, 51, 67, 25, 58, 59, 60, 26, 77, 95, 81, 61, 28, 62, 29, 41, 49 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int8 yytable[] = { 27, 42, 8, 18, 50, 47, 84, 30, 54, 48, 78, 2, 3, 79, 44, 63, 64, 85, 13, 15, 16, 4, 19, 5, 20, 19, 5, 57, 52, 5, 6, 71, 72, 73, 33, 74, 75, 35, 36, 11, 37, 38, 39, 55, 56, 40, 17, 19, 5, 87, 17, 31, 93, 90, 19, 43, 33, 92, 34, 35, 36, 88, 37, 38, 39, 45, 46, 40, 17, 53, 33, 98, 86, 65, 66, 68, 94, 89, 96, 33, 69, 70, 35, 36, 99, 37, 38, 39, 80, 82, 40, 17, 83, 5, 0, 0, 91, 97, 32 }; static const yytype_int8 yycheck[] = { 14, 25, 1, 13, 36, 17, 9, 17, 40, 21, 17, 0, 1, 20, 28, 47, 48, 20, 3, 17, 18, 10, 17, 18, 19, 17, 18, 19, 38, 18, 19, 14, 15, 4, 5, 59, 60, 8, 9, 17, 11, 12, 13, 20, 21, 16, 17, 17, 18, 19, 17, 20, 84, 77, 17, 19, 5, 81, 7, 8, 9, 75, 11, 12, 13, 20, 20, 16, 17, 17, 5, 95, 74, 20, 20, 20, 90, 76, 92, 5, 17, 20, 8, 9, 98, 11, 12, 13, 17, 20, 16, 17, 20, 18, -1, -1, 20, 20, 19 }; /* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of state STATE-NUM. */ static const yytype_int8 yystos[] = { 0, 23, 0, 1, 10, 18, 19, 24, 25, 29, 30, 17, 26, 3, 31, 17, 18, 17, 48, 17, 19, 25, 28, 32, 33, 36, 40, 44, 45, 47, 48, 20, 47, 5, 7, 8, 9, 11, 12, 13, 16, 48, 31, 19, 44, 20, 20, 17, 21, 49, 49, 34, 48, 17, 49, 20, 21, 19, 37, 38, 39, 44, 46, 49, 49, 20, 20, 35, 20, 17, 20, 14, 15, 4, 31, 31, 27, 41, 17, 20, 17, 43, 20, 20, 9, 20, 37, 19, 44, 25, 31, 20, 31, 49, 44, 42, 44, 20, 31, 44 }; /* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ static const yytype_int8 yyr1[] = { 0, 22, 23, 23, 23, 23, 23, 24, 25, 26, 26, 27, 27, 28, 29, 29, 30, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 34, 33, 35, 35, 36, 37, 37, 37, 38, 39, 41, 40, 42, 40, 43, 40, 44, 46, 45, 47, 47, 48, 48, 49, 49, 49 }; /* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ static const yytype_int8 yyr2[] = { 0, 2, 0, 2, 2, 2, 2, 2, 3, 0, 2, 0, 2, 1, 3, 4, 4, 0, 2, 2, 2, 4, 1, 3, 1, 5, 5, 3, 0, 5, 0, 2, 4, 1, 3, 3, 5, 3, 0, 7, 0, 9, 0, 7, 3, 0, 5, 2, 1, 2, 1, 1, 2, 2 }; enum { YYENOMEM = -2 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYNOMEM goto yyexhaustedlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Backward compatibility with an undocumented macro. Use YYerror or YYUNDEF. */ #define YYERRCODE YYUNDEF /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Kind, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*-----------------------------------. | Print this symbol's value on YYO. | `-----------------------------------*/ static void yy_symbol_value_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) { FILE *yyoutput = yyo; YY_USE (yyoutput); if (!yyvaluep) return; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /*---------------------------. | Print this symbol on YYO. | `---------------------------*/ static void yy_symbol_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) { YYFPRINTF (yyo, "%s %s (", yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); yy_symbol_value_print (yyo, yykind, yyvaluep); YYFPRINTF (yyo, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, int yyrule) { int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), &yyvsp[(yyi + 1) - (yynrhs)]); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, Rule); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) ((void) 0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, yysymbol_kind_t yykind, YYSTYPE *yyvaluep) { YY_USE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /* Lookahead token kind. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*----------. | yyparse. | `----------*/ int yyparse (void) { yy_state_fast_t yystate = 0; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus = 0; /* Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* Their size. */ YYPTRDIFF_T yystacksize = YYINITDEPTH; /* The state stack: array, bottom, top. */ yy_state_t yyssa[YYINITDEPTH]; yy_state_t *yyss = yyssa; yy_state_t *yyssp = yyss; /* The semantic value stack: array, bottom, top. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; YYSTYPE *yyvsp = yyvs; int yyn; /* The return value of yyparse. */ int yyresult; /* Lookahead symbol kind. */ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; YYDPRINTF ((stderr, "Starting parse\n")); yychar = YYEMPTY; /* Cause a token to be read. */ goto yysetstate; /*------------------------------------------------------------. | yynewstate -- push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; /*--------------------------------------------------------------------. | yysetstate -- set current state (the top of the stack) to yystate. | `--------------------------------------------------------------------*/ yysetstate: YYDPRINTF ((stderr, "Entering state %d\n", yystate)); YY_ASSERT (0 <= yystate && yystate < YYNSTATES); YY_IGNORE_USELESS_CAST_BEGIN *yyssp = YY_CAST (yy_state_t, yystate); YY_IGNORE_USELESS_CAST_END YY_STACK_PRINT (yyss, yyssp); if (yyss + yystacksize - 1 <= yyssp) #if !defined yyoverflow && !defined YYSTACK_RELOCATE YYNOMEM; #else { /* Get the current used size of the three stacks, in elements. */ YYPTRDIFF_T yysize = yyssp - yyss + 1; # if defined yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ yy_state_t *yyss1 = yyss; YYSTYPE *yyvs1 = yyvs; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * YYSIZEOF (*yyssp), &yyvs1, yysize * YYSIZEOF (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } # else /* defined YYSTACK_RELOCATE */ /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) YYNOMEM; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yy_state_t *yyss1 = yyss; union yyalloc *yyptr = YY_CAST (union yyalloc *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); if (! yyptr) YYNOMEM; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YY_IGNORE_USELESS_CAST_BEGIN YYDPRINTF ((stderr, "Stack size increased to %ld\n", YY_CAST (long, yystacksize))); YY_IGNORE_USELESS_CAST_END if (yyss + yystacksize - 1 <= yyssp) YYABORT; } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token\n")); yychar = yylex (); } if (yychar <= YYEOF) { yychar = YYEOF; yytoken = YYSYMBOL_YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else if (yychar == YYerror) { /* The scanner already issued an error message, process directly to error recovery. But do not keep the error token as lookahead, it is too special and may lead us to an endless loop in error recovery. */ yychar = YYUNDEF; yytoken = YYSYMBOL_YYerror; goto yyerrlab1; } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Discard the shifted token. */ yychar = YYEMPTY; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 6: /* grammar: grammar error */ #line 103 "parse.y" { file->errors++; } #line 1297 "parse.c" break; case 7: /* include: INCLUDE STRING */ #line 106 "parse.y" { struct file *nfile; if ((nfile = pushfile((yyvsp[0].v.string), 0)) == NULL) { yyerror("failed to include file %s", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); file = nfile; lungetc('\n'); } #line 1315 "parse.c" break; case 8: /* verbatim: '!' verbatim1 '!' */ #line 121 "parse.y" { if (in_define) { /* TODO: check template status and exit in case */ } } #line 1325 "parse.c" break; case 10: /* verbatim1: verbatim1 STRING */ #line 129 "parse.y" { if (*(yyvsp[0].v.string) != '\0') { dbg(); fprintf(fp, "%s\n", (yyvsp[0].v.string)); } free((yyvsp[0].v.string)); } #line 1337 "parse.c" break; case 13: /* raw: nstring */ #line 142 "parse.y" { dbg(); fprintf(fp, "if ((tp_ret = tp_write(tp, "); printq((yyvsp[0].v.string)); fprintf(fp, ", %zu)) == -1) goto err;\n", strlen((yyvsp[0].v.string))); free((yyvsp[0].v.string)); } #line 1351 "parse.c" break; case 14: /* block: define body end */ #line 153 "parse.y" { fputs("err:\n", fp); fputs("return tp_ret;\n", fp); fputs("}\n", fp); in_define = 0; } #line 1362 "parse.c" break; case 15: /* block: define body finally end */ #line 159 "parse.y" { fputs("return tp_ret;\n", fp); fputs("}\n", fp); in_define = 0; } #line 1372 "parse.c" break; case 16: /* define: '{' DEFINE string '}' */ #line 166 "parse.y" { in_define = 1; dbg(); fprintf(fp, "int\n%s\n{\n", (yyvsp[-1].v.string)); fputs("int tp_ret = 0;\n", fp); free((yyvsp[-1].v.string)); } #line 1386 "parse.c" break; case 21: /* special: '{' RENDER string '}' */ #line 183 "parse.y" { dbg(); fprintf(fp, "if ((tp_ret = %s) == -1) goto err;\n", (yyvsp[-1].v.string)); free((yyvsp[-1].v.string)); } #line 1397 "parse.c" break; case 23: /* special: if body endif */ #line 190 "parse.y" { fputs("}\n", fp); } #line 1403 "parse.c" break; case 25: /* special: '{' string '|' UNSAFE '}' */ #line 192 "parse.y" { dbg(); fprintf(fp, "if ((tp_ret = tp_writes(tp, %s)) == -1)\n", (yyvsp[-3].v.string)); fputs("goto err;\n", fp); free((yyvsp[-3].v.string)); } #line 1416 "parse.c" break; case 26: /* special: '{' string '|' URLESCAPE '}' */ #line 200 "parse.y" { dbg(); fprintf(fp, "if ((tp_ret = tp_urlescape(tp, %s)) == -1)\n", (yyvsp[-3].v.string)); fputs("goto err;\n", fp); free((yyvsp[-3].v.string)); } #line 1429 "parse.c" break; case 27: /* special: '{' string '}' */ #line 208 "parse.y" { dbg(); fprintf(fp, "if ((tp_ret = tp_htmlescape(tp, %s)) == -1)\n", (yyvsp[-1].v.string)); fputs("goto err;\n", fp); free((yyvsp[-1].v.string)); } #line 1442 "parse.c" break; case 28: /* $@1: %empty */ #line 218 "parse.y" { dbg(); fprintf(fp, "if (asprintf(&tp->tp_tmp, "); } #line 1451 "parse.c" break; case 29: /* printf: '{' PRINTF $@1 printfargs '}' */ #line 221 "parse.y" { fputs(") == -1)\n", fp); fputs("goto err;\n", fp); fputs("if ((tp_ret = tp_htmlescape(tp, tp->tp_tmp)) " "== -1)\n", fp); fputs("goto err;\n", fp); fputs("free(tp->tp_tmp);\n", fp); fputs("tp->tp_tmp = NULL;\n", fp); } #line 1465 "parse.c" break; case 31: /* printfargs: printfargs STRING */ #line 233 "parse.y" { fprintf(fp, " %s", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); } #line 1474 "parse.c" break; case 32: /* if: '{' IF stringy '}' */ #line 239 "parse.y" { dbg(); fprintf(fp, "if (%s) {\n", (yyvsp[-1].v.string)); free((yyvsp[-1].v.string)); } #line 1484 "parse.c" break; case 36: /* elsif: '{' ELSE IF stringy '}' */ #line 251 "parse.y" { dbg(); fprintf(fp, "} else if (%s) {\n", (yyvsp[-1].v.string)); free((yyvsp[-1].v.string)); } #line 1494 "parse.c" break; case 37: /* else: '{' ELSE '}' */ #line 258 "parse.y" { dbg(); fputs("} else {\n", fp); } #line 1503 "parse.c" break; case 38: /* $@2: %empty */ #line 264 "parse.y" { fprintf(fp, "for (%s) {\n", (yyvsp[-1].v.string)); free((yyvsp[-1].v.string)); } #line 1512 "parse.c" break; case 39: /* loop: '{' FOR stringy '}' $@2 body end */ #line 267 "parse.y" { fputs("}\n", fp); } #line 1520 "parse.c" break; case 40: /* $@3: %empty */ #line 270 "parse.y" { fprintf(fp, "TAILQ_FOREACH(%s, %s, %s) {\n", (yyvsp[-3].v.string), (yyvsp[-2].v.string), (yyvsp[-1].v.string)); free((yyvsp[-3].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[-1].v.string)); } #line 1532 "parse.c" break; case 41: /* loop: '{' TQFOREACH STRING STRING STRING '}' $@3 body end */ #line 276 "parse.y" { fputs("}\n", fp); } #line 1540 "parse.c" break; case 42: /* $@4: %empty */ #line 279 "parse.y" { fprintf(fp, "while (%s) {\n", (yyvsp[-1].v.string)); free((yyvsp[-1].v.string)); } #line 1549 "parse.c" break; case 43: /* loop: '{' WHILE stringy '}' $@4 body end */ #line 282 "parse.y" { fputs("}\n", fp); } #line 1557 "parse.c" break; case 45: /* $@5: %empty */ #line 290 "parse.y" { dbg(); fputs("err:\n", fp); } #line 1566 "parse.c" break; case 47: /* nstring: STRING nstring */ #line 296 "parse.y" { if (asprintf(&(yyval.v.string), "%s%s", (yyvsp[-1].v.string), (yyvsp[0].v.string)) == -1) err(1, "asprintf"); free((yyvsp[-1].v.string)); free((yyvsp[0].v.string)); } #line 1577 "parse.c" break; case 49: /* string: STRING string */ #line 305 "parse.y" { if (asprintf(&(yyval.v.string), "%s %s", (yyvsp[-1].v.string), (yyvsp[0].v.string)) == -1) err(1, "asprintf"); free((yyvsp[-1].v.string)); free((yyvsp[0].v.string)); } #line 1588 "parse.c" break; case 52: /* stringy: STRING stringy */ #line 315 "parse.y" { if (asprintf(&(yyval.v.string), "%s %s", (yyvsp[-1].v.string), (yyvsp[0].v.string)) == -1) err(1, "asprintf"); free((yyvsp[-1].v.string)); free((yyvsp[0].v.string)); } #line 1599 "parse.c" break; case 53: /* stringy: '|' stringy */ #line 321 "parse.y" { if (asprintf(&(yyval.v.string), "|%s", (yyvsp[0].v.string)) == -1) err(1, "asprintf"); free((yyvsp[0].v.string)); } #line 1609 "parse.c" break; #line 1613 "parse.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; *++yyvsp = yyval; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ { const int yylhs = yyr1[yyn] - YYNTOKENS; const int yyi = yypgoto[yylhs] + *yyssp; yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp ? yytable[yyi] : yydefgoto[yylhs]); } goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; yyerror (YY_("syntax error")); } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (0) YYERROR; ++yynerrs; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ /* Pop stack until we find a state that shifts the error token. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYSYMBOL_YYerror; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", YY_ACCESSING_SYMBOL (yystate), yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturnlab; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturnlab; /*-----------------------------------------------------------. | yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | `-----------------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; goto yyreturnlab; /*----------------------------------------------------------. | yyreturnlab -- parsing is finished, clean up and return. | `----------------------------------------------------------*/ yyreturnlab: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", YY_ACCESSING_SYMBOL (+*yyssp), yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif return yyresult; } #line 328 "parse.y" struct keywords { const char *k_name; int k_val; }; int yyerror(const char *fmt, ...) { va_list ap; char *msg; file->errors++; va_start(ap, fmt); if (vasprintf(&msg, fmt, ap) == -1) err(1, "yyerror vasprintf"); va_end(ap); fprintf(stderr, "%s:%d: %s\n", file->name, yylval.lineno, msg); free(msg); return (0); } int kw_cmp(const void *k, const void *e) { return (strcmp(k, ((const struct keywords *)e)->k_name)); } int lookup(char *s) { /* this has to be sorted always */ static const struct keywords keywords[] = { { "define", DEFINE }, { "else", ELSE }, { "end", END }, { "finally", FINALLY }, { "for", FOR }, { "if", IF }, { "include", INCLUDE }, { "printf", PRINTF }, { "render", RENDER }, { "tailq-foreach", TQFOREACH }, { "unsafe", UNSAFE }, { "urlescape", URLESCAPE }, { "while", WHILE }, }; const struct keywords *p; p = bsearch(s, keywords, nitems(keywords), sizeof(keywords[0]), kw_cmp); if (p) return (p->k_val); else return (STRING); } #define START_EXPAND 1 #define DONE_EXPAND 2 static int expanding; int igetc(void) { int c; while (1) { if (file->ungetpos > 0) c = file->ungetbuf[--file->ungetpos]; else c = getc(file->stream); if (c == START_EXPAND) expanding = 1; else if (c == DONE_EXPAND) expanding = 0; else break; } return (c); } int lgetc(int quotec) { int c; if (quotec) { if ((c = igetc()) == EOF) { yyerror("reached end of filewhile parsing " "quoted string"); if (file == topfile || popfile() == EOF) return (EOF); return (quotec); } return (c); } c = igetc(); if (c == '\t' || c == ' ') { /* Compress blanks to a sigle space. */ do { c = getc(file->stream); } while (c == '\t' || c == ' '); ungetc(c, file->stream); c = ' '; } if (c == EOF) { /* * Fake EOL when hit EOF for the first time. This gets line * count right if last line in included file is syntactically * invalid and has no newline. */ if (file->eof_reached == 0) { file->eof_reached = 1; return ('\n'); } while (c == EOF) { if (file == topfile || popfile() == EOF) return (EOF); c = igetc(); } } return (c); } void lungetc(int c) { if (c == EOF) return; if (file->ungetpos >= file->ungetsize) { void *p = reallocarray(file->ungetbuf, file->ungetsize, 2); if (p == NULL) err(1, "reallocarray"); file->ungetbuf = p; file->ungetsize *= 2; } file->ungetbuf[file->ungetpos++] = c; } int findeol(void) { int c; /* skip to either EOF or the first real EOL */ while (1) { c = lgetc(0); if (c == '\n') { file->lineno++; break; } if (c == EOF) break; } return (ERROR); } int yylex(void) { char buf[8096]; char *p = buf; int c; int token; int starting = 0; int ending = 0; int quote = 0; if (!in_define && block == 0) { while ((c = lgetc(0)) != '{' && c != EOF) { if (c == '\n') file->lineno++; } if (c == EOF) return (0); newblock: c = lgetc(0); if (c == '{' || c == '!') { if (c == '{') block = '}'; else block = c; return (c); } if (c == '\n') file->lineno++; } while ((c = lgetc(0)) == ' ' || c == '\t' || c == '\n') { if (c == '\n') file->lineno++; } if (c == EOF) { yyerror("unterminated block"); return (0); } yylval.lineno = file->lineno; if (block != 0 && c == block) { if ((c = lgetc(0)) == '}') { if (block == '!') { block = 0; return ('!'); } block = 0; return ('}'); } lungetc(c); c = block; } if (in_define && block == 0) { if (c == '{') goto newblock; do { if (starting) { if (c == '!' || c == '{') { lungetc(c); lungetc('{'); break; } starting = 0; lungetc(c); c = '{'; } else if (c == '{') { starting = 1; continue; } else if (c == '\n') break; *p++ = c; if ((size_t)(p - buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } } while ((c = lgetc(0)) != EOF); *p = '\0'; if (c == EOF) { yyerror("unterminated block"); return (0); } if (c == '\n') file->lineno++; if ((yylval.v.string = strdup(buf)) == NULL) err(1, "strdup"); return (STRING); } if (block == '!') { do { if (ending) { if (c == '}') { lungetc(c); lungetc(block); break; } ending = 0; lungetc(c); c = block; } else if (c == '!') { ending = 1; continue; } else if (c == '\n') break; *p++ = c; if ((size_t)(p - buf) >= sizeof(buf)) { yyerror("line too long"); return (findeol()); } } while ((c = lgetc(0)) != EOF); *p = '\0'; if (c == EOF) { yyerror("unterminated block"); return (0); } if (c == '\n') file->lineno++; if ((yylval.v.string = strdup(buf)) == NULL) err(1, "strdup"); return (STRING); } if (c == '|') return (c); do { if (!quote && isspace((unsigned char)c)) break; if (c == '"') quote = !quote; if (!quote && c == '|') { lungetc(c); break; } if (ending) { if (c == '}') { lungetc(c); lungetc('}'); break; } ending = 0; lungetc(c); c = block; } else if (!quote && c == '}') { ending = 1; continue; } *p++ = c; if ((size_t)(p - buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } } while ((c = lgetc(0)) != EOF); *p = '\0'; if (c == EOF) { yyerror(quote ? "unterminated quote" : "unterminated block"); return (0); } if (c == '\n') file->lineno++; if ((token = lookup(buf)) == STRING) if ((yylval.v.string = strdup(buf)) == NULL) err(1, "strdup"); return (token); } struct file * pushfile(const char *name, int secret) { struct file *nfile; if ((nfile = calloc(1, sizeof(*nfile))) == NULL) err(1, "calloc"); if ((nfile->name = strdup(name)) == NULL) err(1, "strdup"); if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { warn("can't open %s", nfile->name); free(nfile->name); free(nfile); return (NULL); } nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0; nfile->ungetsize = 16; nfile->ungetbuf = malloc(nfile->ungetsize); if (nfile->ungetbuf == NULL) err(1, "malloc"); TAILQ_INSERT_TAIL(&files, nfile, entry); return (nfile); } int popfile(void) { struct file *prev; if ((prev = TAILQ_PREV(file, files, entry)) != NULL) prev->errors += file->errors; TAILQ_REMOVE(&files, file, entry); fclose(file->stream); free(file->name); free(file->ungetbuf); free(file); file = prev; return (file ? 0 : EOF); } int parse(FILE *outfile, const char *filename) { fp = outfile; if ((file = pushfile(filename, 0)) == 0) return (-1); topfile = file; yyparse(); errors = file->errors; popfile(); return (errors ? -1 : 0); } void dbg(void) { if (nodebug) return; if (yylval.lineno == lastline + 1) { lastline = yylval.lineno; return; } lastline = yylval.lineno; fprintf(fp, "#line %d ", yylval.lineno); printq(file->name); putc('\n', fp); } void printq(const char *str) { putc('"', fp); for (; *str; ++str) { if (*str == '"') putc('\\', fp); putc(*str, fp); } putc('"', fp); } got-portable-0.101/template/configure0000775000175100017510000063000714644145542013340 #! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71 for template 1.0. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="as_nop=: if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes else $as_nop as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$as_shell as_have_required=yes if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null then : break 2 fi fi done;; esac as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes fi fi if test "x$CONFIG_SHELL" != x then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : printf "%s\n" "$0: This script requires a shell more modern than all" printf "%s\n" "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and op@openbsd.org $0: about your system, including any error possibly output $0: before this message. Then install a modern shell, or $0: manually run the script under such a shell if you do $0: have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='template' PACKAGE_TARNAME='template' PACKAGE_VERSION='1.0' PACKAGE_STRING='template 1.0' PACKAGE_BUGREPORT='op@openbsd.org' PACKAGE_URL='' ac_config_libobj_dir=../compat # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_c_list= ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS AM_LDFLAGS AM_CFLAGS AM_CPPFLAGS LIBOBJS LIBBSD_LIBS LIBBSD_CFLAGS PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG YFLAGS YACC am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC HOSTCFLAGS HOSTCC AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V CSCOPE ETAGS CTAGS am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL am__quote' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_dependency_tracking ' ac_precious_vars='build_alias host_alias target_alias HOSTCC HOSTCFLAGS CC CFLAGS LDFLAGS LIBS CPPFLAGS YACC YFLAGS PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR LIBBSD_CFLAGS LIBBSD_LIBS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures template 1.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/template] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of template 1.0:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build Some influential environment variables: HOSTCC The C compiler on the host. HOSTCFLAGS CFLAGS for the host compiler CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory YACC The `Yet Another Compiler Compiler' implementation to use. Defaults to the first program found out of: `bison -y', `byacc', `yacc'. YFLAGS The list of arguments that will be passed by default to $YACC. This script will default YFLAGS to the empty string to avoid a default value of `-d' given by some make applications. PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path LIBBSD_CFLAGS C compiler flags for LIBBSD, overriding pkg-config LIBBSD_LIBS linker flags for LIBBSD, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF template configure 1.0 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. */ #include #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main (void) { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR # ------------------------------------------------------------------ # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR # accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR. ac_fn_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack as_decl_name=`echo $2|sed 's/ *(.*//'` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 printf %s "checking whether $as_decl_name is declared... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` eval ac_save_FLAGS=\$$6 as_fn_append $6 " $5" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { #ifndef $as_decl_name #ifdef __cplusplus (void) $as_decl_use; #else (void) $as_decl_name; #endif #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext eval $6=\$ac_save_FLAGS fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_check_decl ac_configure_args_raw= for ac_arg do case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done case $ac_configure_args_raw in *$as_nl*) ac_safe_unquote= ;; *) ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by template $as_me 1.0, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Sanitize IFS. IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && printf "%s\n" "$as_me: caught signal $ac_signal" printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi for ac_site_file in $ac_site_files do case $ac_site_file in #( */*) : ;; #( *) : ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' /* Does the compiler advertise C89 conformance? Do not test the value of __STDC__, because some compilers set it to 0 while being otherwise adequately conformant. */ #if !defined __STDC__ # error "Compiler does not advertise C89 conformance" #endif #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated as an "x". The following induces an error, until -std is added to get proper ANSI mode. Curiously \x00 != x always comes out true, for an array size at least. It is necessary to write \x00 == 0 to get something that is true only with -std. */ int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) '\''x'\'' int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), int, int);' # Test code for whether the C compiler supports C89 (body of main). ac_c_conftest_c89_main=' ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); ' # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' // Does the compiler advertise C99 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare // FILE and stderr. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK #error "your preprocessor is broken" #endif #if BIG_OK #else #error "your preprocessor is broken" #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case '\''s'\'': // string str = va_arg (args_copy, const char *); break; case '\''d'\'': // int number = va_arg (args_copy, int); break; case '\''f'\'': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; } ' # Test code for whether the C compiler supports C99 (body of main). ac_c_conftest_c99_main=' // Check bool. _Bool success = false; success |= (argc != 0); // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[0] = argv[0][0]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' || dynamic_array[ni.number - 1] != 543); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' // Does the compiler advertise C11 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ' # Test code for whether the C compiler supports C11 (body of main). ac_c_conftest_c11_main=' _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); v1.i = 2; v1.w.k = 5; ok |= v1.i != 5; ' # Test code for whether the C compiler supports C11 (complete). ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} ${ac_c_conftest_c11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} ${ac_c_conftest_c11_main} return ok; } " # Test code for whether the C compiler supports C99 (complete). ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} return ok; } " # Test code for whether the C compiler supports C89 (complete). ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} return ok; } " as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" as_fn_append ac_header_c_list " wchar.h wchar_h HAVE_WCHAR_H" as_fn_append ac_header_c_list " minix/config.h minix_config_h HAVE_MINIX_CONFIG_H" # Auxiliary files required by this configure script. ac_aux_files="compile missing install-sh" # Locations in which to look for auxiliary files. ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." # Search for a directory containing all of the required auxiliary files, # $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. # If we don't find one directory that contains all the files we need, # we report the set of missing files from the *first* directory in # $ac_aux_dir_candidates and give up. ac_missing_aux_files="" ac_first_candidate=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in $ac_aux_dir_candidates do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 ac_aux_dir_found=yes ac_install_sh= for ac_aux in $ac_aux_files do # As a special case, if "install-sh" is required, that requirement # can be satisfied by any of "install-sh", "install.sh", or "shtool", # and $ac_install_sh is set appropriately for whichever one is found. if test x"$ac_aux" = x"install-sh" then if test -f "${as_dir}install-sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 ac_install_sh="${as_dir}install-sh -c" elif test -f "${as_dir}install.sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 ac_install_sh="${as_dir}install.sh -c" elif test -f "${as_dir}shtool"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 ac_install_sh="${as_dir}shtool install -c" else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} install-sh" else break fi fi else if test -f "${as_dir}${ac_aux}"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" else break fi fi fi done if test "$ac_aux_dir_found" = yes; then ac_aux_dir="$as_dir" break fi ac_first_candidate=false as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. if test -f "${ac_aux_dir}config.guess"; then ac_config_guess="$SHELL ${ac_aux_dir}config.guess" fi if test -f "${ac_aux_dir}config.sub"; then ac_config_sub="$SHELL ${ac_aux_dir}config.sub" fi if test -f "$ac_aux_dir/configure"; then ac_configure="$SHELL ${ac_aux_dir}configure" fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu am__api_version='1.16' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 printf %s "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test ${ac_cv_path_install+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac # Account for fact that we put trailing slashes in our PATH walk. case $as_dir in #(( ./ | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test ${ac_cv_path_install+y}; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 printf "%s\n" "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 printf %s "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`printf "%s\n" "$program_transform_name" | sed "$ac_script"` # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` if test x"${MISSING+set}" != xset; then MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 printf "%s\n" "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 printf "%s\n" "$STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 printf "%s\n" "$ac_ct_STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 printf %s "checking for a race-free mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if test ${ac_cv_path_mkdir+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir ('*'coreutils) '* | \ 'BusyBox '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test ${ac_cv_path_mkdir+y}; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 printf "%s\n" "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AWK+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 printf "%s\n" "$AWK" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AWK" && break done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval test \${ac_cv_prog_make_${ac_make}_set+y} then : printf %s "(cached) " >&6 else $as_nop cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } SET_MAKE= else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. if test ${enable_silent_rules+y} then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 printf %s "checking whether $am_make supports nested variables... " >&6; } if test ${am_cv_make_support_nested_variables+y} then : printf %s "(cached) " >&6 else $as_nop if printf "%s\n" 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 printf "%s\n" "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='template' VERSION='1.0' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h printf "%s\n" "#define VERSION \"$VERSION\"" >>confdefs.h # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # Variables for tags utilities; see am/tags.am if test -z "$CTAGS"; then CTAGS=ctags fi if test -z "$ETAGS"; then ETAGS=etags fi if test -z "$CSCOPE"; then CSCOPE=cscope fi # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 fi fi DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } case $?:`cat confinc.out 2>/dev/null` in #( '0:this is the am__doit target') : case $s in #( BSD) : am__include='.include' am__quote='"' ;; #( *) : am__include='include' am__quote='' ;; esac ;; #( *) : ;; esac if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 printf "%s\n" "${_am_result}" >&6; } # Check whether --enable-dependency-tracking was given. if test ${enable_dependency_tracking+y} then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 printf %s "checking whether the C compiler works... " >&6; } ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else $as_nop ac_file='' fi if test -z "$ac_file" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else $as_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 printf %s "checking whether $CC understands -c and -o together... " >&6; } if test ${am_cv_prog_cc_c_o+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 printf %s "checking dependency style of $depcc... " >&6; } if test ${am_cv_CC_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 else $as_nop if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 printf "%s\n" "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi ac_header= ac_cache= for ac_item in $ac_header_c_list do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then printf "%s\n" "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then ac_cache=$ac_item else ac_header=$ac_item fi done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 printf %s "checking whether it is safe to define __EXTENSIONS__... " >&6; } if test ${ac_cv_safe_to_define___extensions__+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # define __EXTENSIONS__ 1 $ac_includes_default int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_safe_to_define___extensions__=yes else $as_nop ac_cv_safe_to_define___extensions__=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 printf "%s\n" "$ac_cv_safe_to_define___extensions__" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether _XOPEN_SOURCE should be defined" >&5 printf %s "checking whether _XOPEN_SOURCE should be defined... " >&6; } if test ${ac_cv_should_define__xopen_source+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_should_define__xopen_source=no if test $ac_cv_header_wchar_h = yes then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include mbstate_t x; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _XOPEN_SOURCE 500 #include mbstate_t x; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_should_define__xopen_source=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_should_define__xopen_source" >&5 printf "%s\n" "$ac_cv_should_define__xopen_source" >&6; } printf "%s\n" "#define _ALL_SOURCE 1" >>confdefs.h printf "%s\n" "#define _DARWIN_C_SOURCE 1" >>confdefs.h printf "%s\n" "#define _GNU_SOURCE 1" >>confdefs.h printf "%s\n" "#define _HPUX_ALT_XOPEN_SOCKET_API 1" >>confdefs.h printf "%s\n" "#define _NETBSD_SOURCE 1" >>confdefs.h printf "%s\n" "#define _OPENBSD_SOURCE 1" >>confdefs.h printf "%s\n" "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_BFP_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_DFP_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_LIB_EXT2__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_MATH_SPEC_FUNCS__ 1" >>confdefs.h printf "%s\n" "#define _TANDEM_SOURCE 1" >>confdefs.h if test $ac_cv_header_minix_config_h = yes then : MINIX=yes printf "%s\n" "#define _MINIX 1" >>confdefs.h printf "%s\n" "#define _POSIX_SOURCE 1" >>confdefs.h printf "%s\n" "#define _POSIX_1_SOURCE 2" >>confdefs.h else $as_nop MINIX= fi if test $ac_cv_safe_to_define___extensions__ = yes then : printf "%s\n" "#define __EXTENSIONS__ 1" >>confdefs.h fi if test $ac_cv_should_define__xopen_source = yes then : printf "%s\n" "#define _XOPEN_SOURCE 500" >>confdefs.h fi # When CFLAGS isn't set at this stage and gcc is detected by the macro below, # autoconf will automatically use CFLAGS="-O2 -g". Prevent that by using an # empty default. : ${CFLAGS=""} # Save user CPPFLAGS, CFLAGS and LDFLAGS. We need to change them because # AC_CHECK_HEADER doesn't give us any other way to update the include # paths. But for Makefile.am we want to use AM_CPPFLAGS and friends. SAVED_CFLAGS="$CFLAGS" test -n "$HOSTCC" && export CC="$HOSTCC" test -n "$HOSTCFLAGS" && export CFLAGS="$SAVED_CFLAGS $HOSTCFLAGS" YACC_OVERRIDE=yes ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 printf %s "checking whether $CC understands -c and -o together... " >&6; } if test ${am_cv_prog_cc_c_o+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 printf %s "checking dependency style of $depcc... " >&6; } if test ${am_cv_CC_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 else $as_nop if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 printf "%s\n" "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi if test -z "$YACC"; then YACC_OVERRIDE="no" for ac_prog in 'bison -y' byacc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_YACC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$YACC"; then ac_cv_prog_YACC="$YACC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_YACC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi YACC=$ac_cv_prog_YACC if test -n "$YACC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 printf "%s\n" "$YACC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$YACC" && break done test -n "$YACC" || YACC="yacc" fi if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_PKG_CONFIG+y} then : printf %s "(cached) " >&6 else $as_nop case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 printf "%s\n" "$PKG_CONFIG" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} then : printf %s "(cached) " >&6 else $as_nop case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 printf "%s\n" "$ac_pt_PKG_CONFIG" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 printf %s "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } PKG_CONFIG="" fi fi pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libbsd-overlay" >&5 printf %s "checking for libbsd-overlay... " >&6; } if test -n "$LIBBSD_CFLAGS"; then pkg_cv_LIBBSD_CFLAGS="$LIBBSD_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libbsd-overlay\""; } >&5 ($PKG_CONFIG --exists --print-errors "libbsd-overlay") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBBSD_CFLAGS=`$PKG_CONFIG --cflags "libbsd-overlay" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBBSD_LIBS"; then pkg_cv_LIBBSD_LIBS="$LIBBSD_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libbsd-overlay\""; } >&5 ($PKG_CONFIG --exists --print-errors "libbsd-overlay") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBBSD_LIBS=`$PKG_CONFIG --libs "libbsd-overlay" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBBSD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libbsd-overlay" 2>&1` else LIBBSD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libbsd-overlay" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBBSD_PKG_ERRORS" >&5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: libbsd not found" >&5 printf "%s\n" "$as_me: libbsd not found" >&6;} elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: libbsd not found" >&5 printf "%s\n" "$as_me: libbsd not found" >&6;} else LIBBSD_CFLAGS=$pkg_cv_LIBBSD_CFLAGS LIBBSD_LIBS=$pkg_cv_LIBBSD_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } AM_CFLAGS="$LIBBSD_CFLAGS $AM_CFLAGS" CFLAGS="$AM_CFLAGS $SAVED_CFLAGS" LIBS="$LIBBSD_LIBS $LIBS" printf "%s\n" "#define HAVE_LIBBSD 1" >>confdefs.h fi AM_CPPFLAGS="$CFLAGS" ac_fn_c_check_func "$LINENO" "asprintf" "ac_cv_func_asprintf" if test "x$ac_cv_func_asprintf" = xyes then : printf "%s\n" "#define HAVE_ASPRINTF 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" asprintf.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS asprintf.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "err" "ac_cv_func_err" if test "x$ac_cv_func_err" = xyes then : printf "%s\n" "#define HAVE_ERR 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" err.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS err.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "getprogname" "ac_cv_func_getprogname" if test "x$ac_cv_func_getprogname" = xyes then : printf "%s\n" "#define HAVE_GETPROGNAME 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" getprogname.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS getprogname.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "reallocarray" "ac_cv_func_reallocarray" if test "x$ac_cv_func_reallocarray" = xyes then : printf "%s\n" "#define HAVE_REALLOCARRAY 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" reallocarray.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS reallocarray.$ac_objext" ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5 printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; } if test ${ac_cv_c_undeclared_builtin_options+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_CFLAGS=$CFLAGS ac_cv_c_undeclared_builtin_options='cannot detect' for ac_arg in '' -fno-builtin; do CFLAGS="$ac_save_CFLAGS $ac_arg" # This test program should *not* compile successfully. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { (void) strchr; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop # This test program should compile successfully. # No library function is consistently available on # freestanding implementations, so test against a dummy # declaration. Include always-available headers on the # off chance that they somehow elicit warnings. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include extern void ac_decl (int, char *); int main (void) { (void) ac_decl (0, (char *) 0); (void) ac_decl; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : if test x"$ac_arg" = x then : ac_cv_c_undeclared_builtin_options='none needed' else $as_nop ac_cv_c_undeclared_builtin_options=$ac_arg fi break fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done CFLAGS=$ac_save_CFLAGS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; } case $ac_cv_c_undeclared_builtin_options in #( 'cannot detect') : { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot make $CC report undeclared builtins See \`config.log' for more details" "$LINENO" 5; } ;; #( 'none needed') : ac_c_undeclared_builtin_options='' ;; #( *) : ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;; esac ac_fn_check_decl "$LINENO" "TAILQ_REMOVE" "ac_cv_have_decl_TAILQ_REMOVE" "#include " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_TAILQ_REMOVE" = xyes then : else $as_nop as_fn_error $? "\"*** sys/queue.h is missing key defines ***\"" "$LINENO" 5 fi CPPFLAGS="$SAVED_CPPFLAGS" CFLAGS="$SAVED_CFLAGS" LDFLAGS="$SAVED_LDFLAGS" ac_config_files="$ac_config_files Makefile Makefile.common:Makefile.common.in" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 printf %s "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5 printf "%s\n" "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by template $as_me 1.0, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Configuration commands: $config_commands Report bugs to ." _ACEOF ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ template config.status 1.0 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX printf "%s\n" "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "Makefile.common") CONFIG_FILES="$CONFIG_FILES Makefile.common:Makefile.common.in" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :C) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 printf "%s\n" "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. case $CONFIG_FILES in #( *\'*) : eval set x "$CONFIG_FILES" ;; #( *) : set x $CONFIG_FILES ;; #( *) : ;; esac shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`printf "%s\n" "$am_mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`$as_dirname -- "$am_mf" || $as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$am_mf" : 'X\(//\)[^/]' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$am_mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` am_filepart=`$as_basename -- "$am_mf" || $as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$am_mf" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` { echo "$as_me:$LINENO: cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles" >&5 (cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } || am_rc=$? done if test $am_rc -ne 0; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE=\"gmake\" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking). See \`config.log' for more details" "$LINENO" 5; } fi { am_dirpart=; unset am_dirpart;} { am_filepart=; unset am_filepart;} { am_mf=; unset am_mf;} { am_rc=; unset am_rc;} rm -f conftest-deps.mk } ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi got-portable-0.101/template/template.c0000664000175100017510000000371614644144735013414 /* * Copyright (c) 2022 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include "got_compat.h" int parse(FILE *, const char *); int nodebug; static void __dead usage(void) { fprintf(stderr, "usage: %s [-G] [-o out] [file ...]\n", getprogname()); exit(1); } int main(int argc, char **argv) { FILE *fp = stdout; const char *out = NULL; int ch, i; while ((ch = getopt(argc, argv, "Go:")) != -1) { switch (ch) { case 'G': nodebug = 1; break; case 'o': out = optarg; break; default: usage(); } } argc -= optind; argv += optind; if (out && (fp = fopen(out, "w")) == NULL) err(1, "can't open %s", out); if (out && unveil(out, "wc") == -1) err(1, "unveil %s", out); if (unveil("/", "r") == -1) err(1, "unveil /"); if (pledge(out ? "stdio rpath cpath" : "stdio rpath", NULL) == -1) err(1, "pledge"); if (argc == 0) { nodebug = 1; if (parse(fp, "/dev/stdin") == -1) goto err; } else { for (i = 0; i < argc; ++i) if (parse(fp, argv[i]) == -1) goto err; } if (ferror(fp)) goto err; if (fclose(fp) == -1) { fp = NULL; goto err; } return (0); err: if (fp) fclose(fp); if (out && unlink(out) == -1) err(1, "unlink %s", out); return (1); } got-portable-0.101/template/depcomp0000755000175100017510000005602014644145542013001 #! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2018-03-07.03; # UTC # Copyright (C) 1999-2021 Free Software Foundation, Inc. # 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 # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: got-portable-0.101/template/Makefile.in0000664000175100017510000006130714644145542013477 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : noinst_PROGRAMS = template$(EXEEXT) subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__configure_deps) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = Makefile.common CONFIG_CLEAN_VPATH_FILES = PROGRAMS = $(noinst_PROGRAMS) LIBOBJDIR = ../compat/ am__dirstamp = $(am__leading_dot)dirstamp am_template_OBJECTS = template.$(OBJEXT) parse.$(OBJEXT) template_OBJECTS = $(am_template_OBJECTS) template_LDADD = $(LDADD) template_DEPENDENCIES = $(LIBOBJS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ../compat/$(DEPDIR)/asprintf.Po \ ../compat/$(DEPDIR)/err.Po ../compat/$(DEPDIR)/getprogname.Po \ ../compat/$(DEPDIR)/reallocarray.Po ./$(DEPDIR)/parse.Po \ ./$(DEPDIR)/template.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \ -e s/c++$$/h++/ -e s/c$$/h/ YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS) AM_V_YACC = $(am__v_YACC_@AM_V@) am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@) am__v_YACC_0 = @echo " YACC " $@; am__v_YACC_1 = YLWRAP = $(top_srcdir)/ylwrap SOURCES = $(template_SOURCES) DIST_SOURCES = $(template_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` AM_RECURSIVE_TARGETS = cscope am__DIST_COMMON = $(srcdir)/Makefile.common.in $(srcdir)/Makefile.in \ $(top_srcdir)/../compat/asprintf.c \ $(top_srcdir)/../compat/err.c \ $(top_srcdir)/../compat/getprogname.c \ $(top_srcdir)/../compat/reallocarray.c compile depcomp \ install-sh missing parse.c ylwrap DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip # Exists only to be overridden by the user if desired. AM_DISTCHECK_DVI_TARGET = dvi distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ HOSTCC = @HOSTCC@ HOSTCFLAGS = @HOSTCFLAGS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ template_SOURCES = template.c \ parse.y EXTRA_DIST = got_compat.h LDADD = $(LIBOBJS) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj .y am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): Makefile.common: $(top_builddir)/config.status $(srcdir)/Makefile.common.in cd $(top_builddir) && $(SHELL) ./config.status $@ clean-noinstPROGRAMS: -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) ../compat/$(am__dirstamp): @$(MKDIR_P) ../compat/ @: > ../compat/$(am__dirstamp) ../compat/asprintf.$(OBJEXT): ../compat/$(am__dirstamp) ../compat/err.$(OBJEXT): ../compat/$(am__dirstamp) ../compat/getprogname.$(OBJEXT): ../compat/$(am__dirstamp) ../compat/reallocarray.$(OBJEXT): ../compat/$(am__dirstamp) template$(EXEEXT): $(template_OBJECTS) $(template_DEPENDENCIES) $(EXTRA_template_DEPENDENCIES) @rm -f template$(EXEEXT) $(AM_V_CCLD)$(LINK) $(template_OBJECTS) $(template_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@../compat/$(DEPDIR)/asprintf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../compat/$(DEPDIR)/err.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../compat/$(DEPDIR)/getprogname.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../compat/$(DEPDIR)/reallocarray.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/template.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .y.c: $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-zstd: distdir tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ *.tar.zst*) \ zstd -dc $(distdir).tar.zst | $(am__untar) ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build/sub \ && ../../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: -rm -f ../compat/asprintf.$(OBJEXT) -rm -f ../compat/err.$(OBJEXT) -rm -f ../compat/getprogname.$(OBJEXT) -rm -f ../compat/reallocarray.$(OBJEXT) clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -rm -f ../compat/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -rm -f parse.c clean: clean-am clean-am: clean-generic clean-noinstPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f ../compat/$(DEPDIR)/asprintf.Po -rm -f ../compat/$(DEPDIR)/err.Po -rm -f ../compat/$(DEPDIR)/getprogname.Po -rm -f ../compat/$(DEPDIR)/reallocarray.Po -rm -f ./$(DEPDIR)/parse.Po -rm -f ./$(DEPDIR)/template.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f ../compat/$(DEPDIR)/asprintf.Po -rm -f ../compat/$(DEPDIR)/err.Po -rm -f ../compat/$(DEPDIR)/getprogname.Po -rm -f ../compat/$(DEPDIR)/reallocarray.Po -rm -f ./$(DEPDIR)/parse.Po -rm -f ./$(DEPDIR)/template.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles am--refresh check \ check-am clean clean-cscope clean-generic clean-noinstPROGRAMS \ cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ dist-zstd distcheck distclean distclean-compile \ distclean-generic distclean-tags distcleancheck distdir \ distuninstallcheck dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/template/tmpl.c0000664000175100017510000000654714644144735012562 /* * Copyright (c) 2022 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include "got_compat.h" #include "tmpl.h" int tp_write(struct template *tp, const char *str, size_t len) { size_t avail; while (len > 0) { avail = tp->tp_cap - tp->tp_len; if (avail == 0) { if (template_flush(tp) == -1) return (-1); avail = tp->tp_cap; } if (len < avail) avail = len; memcpy(tp->tp_buf + tp->tp_len, str, avail); tp->tp_len += avail; str += avail; len -= avail; } return (0); } int tp_writes(struct template *tp, const char *str) { return (tp_write(tp, str, strlen(str))); } int tp_writef(struct template *tp, const char *fmt, ...) { va_list ap; char *str; int r; va_start(ap, fmt); r = vasprintf(&str, fmt, ap); va_end(ap); if (r == -1) return (-1); r = tp_write(tp, str, r); free(str); return (r); } int tp_urlescape(struct template *tp, const char *str) { int r; char tmp[4]; if (str == NULL) return (0); for (; *str; ++str) { if (iscntrl((unsigned char)*str) || isspace((unsigned char)*str) || *str == '\'' || *str == '"' || *str == '\\') { r = snprintf(tmp, sizeof(tmp), "%%%2X", *str); if (r < 0 || (size_t)r >= sizeof(tmp)) return (0); if (tp_write(tp, tmp, r) == -1) return (-1); } else { if (tp_write(tp, str, 1) == -1) return (-1); } } return (0); } static inline int htmlescape(struct template *tp, char c) { switch (c) { case '<': return tp_write(tp, "<", 4); case '>': return tp_write(tp, ">", 4); case '&': return tp_write(tp, "&", 5); case '"': return tp_write(tp, """, 6); case '\'': return tp_write(tp, "'", 6); default: return tp_write(tp, &c, 1); } } int tp_htmlescape(struct template *tp, const char *str) { if (str == NULL) return (0); for (; *str; ++str) { if (htmlescape(tp, *str) == -1) return (-1); } return (0); } int tp_write_htmlescape(struct template *tp, const char *str, size_t len) { size_t i; for (i = 0; i < len; ++i) { if (htmlescape(tp, str[i]) == -1) return (-1); } return (0); } struct template * template(void *arg, tmpl_write writefn, char *buf, size_t siz) { struct template *tp; if ((tp = calloc(1, sizeof(*tp))) == NULL) return (NULL); tp->tp_arg = arg; tp->tp_write = writefn; tp->tp_buf = buf; tp->tp_cap = siz; return (tp); } int template_flush(struct template *tp) { if (tp->tp_len == 0) return (0); if (tp->tp_write(tp->tp_arg, tp->tp_buf, tp->tp_len) == -1) return (-1); tp->tp_len = 0; return (0); } void template_free(struct template *tp) { free(tp->tp_tmp); free(tp); } got-portable-0.101/template/configure.ac0000664000175100017510000000302314644144735013712 AC_INIT([template], 1.0, [op@openbsd.org]) AC_CONFIG_LIBOBJ_DIR(../compat) AM_INIT_AUTOMAKE([foreign subdir-objects]) AC_ARG_VAR(HOSTCC, [The C compiler on the host.]) AC_ARG_VAR(HOSTCFLAGS, [CFLAGS for the host compiler]) AC_USE_SYSTEM_EXTENSIONS # When CFLAGS isn't set at this stage and gcc is detected by the macro below, # autoconf will automatically use CFLAGS="-O2 -g". Prevent that by using an # empty default. : ${CFLAGS=""} # Save user CPPFLAGS, CFLAGS and LDFLAGS. We need to change them because # AC_CHECK_HEADER doesn't give us any other way to update the include # paths. But for Makefile.am we want to use AM_CPPFLAGS and friends. SAVED_CFLAGS="$CFLAGS" test -n "$HOSTCC" && export CC="$HOSTCC" test -n "$HOSTCFLAGS" && export CFLAGS="$SAVED_CFLAGS $HOSTCFLAGS" YACC_OVERRIDE=yes AC_PROG_CC if test -z "$YACC"; then YACC_OVERRIDE="no" AC_PROG_YACC fi PKG_PROG_PKG_CONFIG PKG_CHECK_MODULES(LIBBSD, libbsd-overlay, [ AM_CFLAGS="$LIBBSD_CFLAGS $AM_CFLAGS" CFLAGS="$AM_CFLAGS $SAVED_CFLAGS" LIBS="$LIBBSD_LIBS $LIBS" AC_DEFINE(HAVE_LIBBSD) ], [AC_MSG_NOTICE([libbsd not found])]) AM_CPPFLAGS="$CFLAGS" AC_REPLACE_FUNCS([ \ asprintf \ err \ getprogname \ reallocarray \ ]) AC_CHECK_DECL([TAILQ_REMOVE], [], [AC_MSG_ERROR("*** sys/queue.h is missing key defines ***")], [#include ]) AC_SUBST(AM_CPPFLAGS) CPPFLAGS="$SAVED_CPPFLAGS" AC_SUBST(AM_CFLAGS) CFLAGS="$SAVED_CFLAGS" AC_SUBST(AM_LDFLAGS) LDFLAGS="$SAVED_LDFLAGS" AC_CONFIG_FILES([Makefile Makefile.common:Makefile.common.in ]) AC_OUTPUT got-portable-0.101/template/install-sh0000755000175100017510000003577614644145542013447 #!/bin/sh # install - install a program, script, or datafile scriptversion=2020-11-14.01; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. tab=' ' nl=' ' IFS=" $tab$nl" # Set DOITPROG to "echo" to test this script. doit=${DOITPROG-} doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_mkdir= # Desired mode of installed file. mode=0755 # Create dirs (including intermediate dirs) using mode 755. # This is like GNU 'install' as of coreutils 8.32 (2020). mkdir_umask=22 backupsuffix= chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -p pass -p to $cpprog. -s $stripprog installed files. -S SUFFIX attempt to back up existing files, with suffix SUFFIX. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG By default, rm is invoked with -f; when overridden with RMPROG, it's up to you to specify -f if you want it. If -S is not specified, no backups are attempted. Email bug reports to bug-automake@gnu.org. Automake home page: https://www.gnu.org/software/automake/ " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -p) cpprog="$cpprog -p";; -s) stripcmd=$stripprog;; -S) backupsuffix="$2" shift;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? # Don't chown directories that already exist. if test $dstdir_status = 0; then chowncmd="" fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dstbase=`basename "$src"` case $dst in */) dst=$dst$dstbase;; *) dst=$dst/$dstbase;; esac dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi case $dstdir in */) dstdirslash=$dstdir;; *) dstdirslash=$dstdir/;; esac obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false # The $RANDOM variable is not portable (e.g., dash). Use it # here however when possible just to lower collision chance. tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap ' ret=$? rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null exit $ret ' 0 # Because "mkdir -p" follows existing symlinks and we likely work # directly in world-writeable /tmp, make sure that the '$tmpdir' # directory is successfully created first before we actually test # 'mkdir -p'. if (umask $mkdir_umask && $mkdirprog $mkdir_mode "$tmpdir" && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. test_tmpdir="$tmpdir/a" ls_ld_tmpdir=`ls -ld "$test_tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi trap '' 0;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac oIFS=$IFS IFS=/ set -f set fnord $dstdir shift set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=${dstdirslash}_inst.$$_ rmtmp=${dstdirslash}_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && { test -z "$stripcmd" || { # Create $dsttmp read-write so that cp doesn't create it read-only, # which would cause strip to fail. if test -z "$doit"; then : >"$dsttmp" # No need to fork-exec 'touch'. else $doit touch "$dsttmp" fi } } && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # If $backupsuffix is set, and the file being installed # already exists, attempt a backup. Don't worry if it fails, # e.g., if mv doesn't support -f. if test -n "$backupsuffix" && test -f "$dst"; then $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null fi # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: got-portable-0.101/template/parse.y0000664000175100017510000003246514644144735012744 /* * Copyright (c) 2022 Omar Polo * Copyright (c) 2007-2016 Reyk Floeter * Copyright (c) 2004, 2005 Esben Norby * Copyright (c) 2004 Ryan McBride * Copyright (c) 2002, 2003, 2004 Henning Brauer * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. * Copyright (c) 2001 Theo de Raadt. All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ %{ #include #include #include #include #include #include #include #include #include #include "got_compat.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); static struct file { TAILQ_ENTRY(file) entry; FILE *stream; char *name; size_t ungetpos; size_t ungetsize; unsigned char *ungetbuf; int eof_reached; int lineno; int errors; } *file, *topfile; int parse(FILE *, const char *); struct file *pushfile(const char *, int); int popfile(void); int yyparse(void); int yylex(void); int yyerror(const char *, ...) __attribute__((__format__ (printf, 1, 2))) __attribute__((__nonnull__ (1))); int kw_cmp(const void *, const void *); int lookup(char *); int igetc(void); int lgetc(int); void lungetc(int); int findeol(void); void dbg(void); void printq(const char *); extern int nodebug; static FILE *fp; static int block; static int in_define; static int errors; static int lastline = -1; typedef struct { union { char *string; } v; int lineno; } YYSTYPE; %} %token DEFINE ELSE END ERROR FINALLY FOR IF INCLUDE PRINTF %token RENDER TQFOREACH UNSAFE URLESCAPE WHILE %token STRING %type string nstring %type stringy %% grammar : /* empty */ | grammar include | grammar verbatim | grammar block | grammar error { file->errors++; } ; include : INCLUDE STRING { struct file *nfile; if ((nfile = pushfile($2, 0)) == NULL) { yyerror("failed to include file %s", $2); free($2); YYERROR; } free($2); file = nfile; lungetc('\n'); } ; verbatim : '!' verbatim1 '!' { if (in_define) { /* TODO: check template status and exit in case */ } } ; verbatim1 : /* empty */ | verbatim1 STRING { if (*$2 != '\0') { dbg(); fprintf(fp, "%s\n", $2); } free($2); } ; verbatims : /* empty */ | verbatims verbatim ; raw : nstring { dbg(); fprintf(fp, "if ((tp_ret = tp_write(tp, "); printq($1); fprintf(fp, ", %zu)) == -1) goto err;\n", strlen($1)); free($1); } ; block : define body end { fputs("err:\n", fp); fputs("return tp_ret;\n", fp); fputs("}\n", fp); in_define = 0; } | define body finally end { fputs("return tp_ret;\n", fp); fputs("}\n", fp); in_define = 0; } ; define : '{' DEFINE string '}' { in_define = 1; dbg(); fprintf(fp, "int\n%s\n{\n", $3); fputs("int tp_ret = 0;\n", fp); free($3); } ; body : /* empty */ | body verbatim | body raw | body special ; special : '{' RENDER string '}' { dbg(); fprintf(fp, "if ((tp_ret = %s) == -1) goto err;\n", $3); free($3); } | printf | if body endif { fputs("}\n", fp); } | loop | '{' string '|' UNSAFE '}' { dbg(); fprintf(fp, "if ((tp_ret = tp_writes(tp, %s)) == -1)\n", $2); fputs("goto err;\n", fp); free($2); } | '{' string '|' URLESCAPE '}' { dbg(); fprintf(fp, "if ((tp_ret = tp_urlescape(tp, %s)) == -1)\n", $2); fputs("goto err;\n", fp); free($2); } | '{' string '}' { dbg(); fprintf(fp, "if ((tp_ret = tp_htmlescape(tp, %s)) == -1)\n", $2); fputs("goto err;\n", fp); free($2); } ; printf : '{' PRINTF { dbg(); fprintf(fp, "if (asprintf(&tp->tp_tmp, "); } printfargs '}' { fputs(") == -1)\n", fp); fputs("goto err;\n", fp); fputs("if ((tp_ret = tp_htmlescape(tp, tp->tp_tmp)) " "== -1)\n", fp); fputs("goto err;\n", fp); fputs("free(tp->tp_tmp);\n", fp); fputs("tp->tp_tmp = NULL;\n", fp); } ; printfargs : /* empty */ | printfargs STRING { fprintf(fp, " %s", $2); free($2); } ; if : '{' IF stringy '}' { dbg(); fprintf(fp, "if (%s) {\n", $3); free($3); } ; endif : end | else body end | elsif body endif ; elsif : '{' ELSE IF stringy '}' { dbg(); fprintf(fp, "} else if (%s) {\n", $4); free($4); } ; else : '{' ELSE '}' { dbg(); fputs("} else {\n", fp); } ; loop : '{' FOR stringy '}' { fprintf(fp, "for (%s) {\n", $3); free($3); } body end { fputs("}\n", fp); } | '{' TQFOREACH STRING STRING STRING '}' { fprintf(fp, "TAILQ_FOREACH(%s, %s, %s) {\n", $3, $4, $5); free($3); free($4); free($5); } body end { fputs("}\n", fp); } | '{' WHILE stringy '}' { fprintf(fp, "while (%s) {\n", $3); free($3); } body end { fputs("}\n", fp); } ; end : '{' END '}' ; finally : '{' FINALLY '}' { dbg(); fputs("err:\n", fp); } verbatims ; nstring : STRING nstring { if (asprintf(&$$, "%s%s", $1, $2) == -1) err(1, "asprintf"); free($1); free($2); } | STRING ; string : STRING string { if (asprintf(&$$, "%s %s", $1, $2) == -1) err(1, "asprintf"); free($1); free($2); } | STRING ; stringy : STRING | STRING stringy { if (asprintf(&$$, "%s %s", $1, $2) == -1) err(1, "asprintf"); free($1); free($2); } | '|' stringy { if (asprintf(&$$, "|%s", $2) == -1) err(1, "asprintf"); free($2); } ; %% struct keywords { const char *k_name; int k_val; }; int yyerror(const char *fmt, ...) { va_list ap; char *msg; file->errors++; va_start(ap, fmt); if (vasprintf(&msg, fmt, ap) == -1) err(1, "yyerror vasprintf"); va_end(ap); fprintf(stderr, "%s:%d: %s\n", file->name, yylval.lineno, msg); free(msg); return (0); } int kw_cmp(const void *k, const void *e) { return (strcmp(k, ((const struct keywords *)e)->k_name)); } int lookup(char *s) { /* this has to be sorted always */ static const struct keywords keywords[] = { { "define", DEFINE }, { "else", ELSE }, { "end", END }, { "finally", FINALLY }, { "for", FOR }, { "if", IF }, { "include", INCLUDE }, { "printf", PRINTF }, { "render", RENDER }, { "tailq-foreach", TQFOREACH }, { "unsafe", UNSAFE }, { "urlescape", URLESCAPE }, { "while", WHILE }, }; const struct keywords *p; p = bsearch(s, keywords, nitems(keywords), sizeof(keywords[0]), kw_cmp); if (p) return (p->k_val); else return (STRING); } #define START_EXPAND 1 #define DONE_EXPAND 2 static int expanding; int igetc(void) { int c; while (1) { if (file->ungetpos > 0) c = file->ungetbuf[--file->ungetpos]; else c = getc(file->stream); if (c == START_EXPAND) expanding = 1; else if (c == DONE_EXPAND) expanding = 0; else break; } return (c); } int lgetc(int quotec) { int c; if (quotec) { if ((c = igetc()) == EOF) { yyerror("reached end of filewhile parsing " "quoted string"); if (file == topfile || popfile() == EOF) return (EOF); return (quotec); } return (c); } c = igetc(); if (c == '\t' || c == ' ') { /* Compress blanks to a sigle space. */ do { c = getc(file->stream); } while (c == '\t' || c == ' '); ungetc(c, file->stream); c = ' '; } if (c == EOF) { /* * Fake EOL when hit EOF for the first time. This gets line * count right if last line in included file is syntactically * invalid and has no newline. */ if (file->eof_reached == 0) { file->eof_reached = 1; return ('\n'); } while (c == EOF) { if (file == topfile || popfile() == EOF) return (EOF); c = igetc(); } } return (c); } void lungetc(int c) { if (c == EOF) return; if (file->ungetpos >= file->ungetsize) { void *p = reallocarray(file->ungetbuf, file->ungetsize, 2); if (p == NULL) err(1, "reallocarray"); file->ungetbuf = p; file->ungetsize *= 2; } file->ungetbuf[file->ungetpos++] = c; } int findeol(void) { int c; /* skip to either EOF or the first real EOL */ while (1) { c = lgetc(0); if (c == '\n') { file->lineno++; break; } if (c == EOF) break; } return (ERROR); } int yylex(void) { char buf[8096]; char *p = buf; int c; int token; int starting = 0; int ending = 0; int quote = 0; if (!in_define && block == 0) { while ((c = lgetc(0)) != '{' && c != EOF) { if (c == '\n') file->lineno++; } if (c == EOF) return (0); newblock: c = lgetc(0); if (c == '{' || c == '!') { if (c == '{') block = '}'; else block = c; return (c); } if (c == '\n') file->lineno++; } while ((c = lgetc(0)) == ' ' || c == '\t' || c == '\n') { if (c == '\n') file->lineno++; } if (c == EOF) { yyerror("unterminated block"); return (0); } yylval.lineno = file->lineno; if (block != 0 && c == block) { if ((c = lgetc(0)) == '}') { if (block == '!') { block = 0; return ('!'); } block = 0; return ('}'); } lungetc(c); c = block; } if (in_define && block == 0) { if (c == '{') goto newblock; do { if (starting) { if (c == '!' || c == '{') { lungetc(c); lungetc('{'); break; } starting = 0; lungetc(c); c = '{'; } else if (c == '{') { starting = 1; continue; } else if (c == '\n') break; *p++ = c; if ((size_t)(p - buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } } while ((c = lgetc(0)) != EOF); *p = '\0'; if (c == EOF) { yyerror("unterminated block"); return (0); } if (c == '\n') file->lineno++; if ((yylval.v.string = strdup(buf)) == NULL) err(1, "strdup"); return (STRING); } if (block == '!') { do { if (ending) { if (c == '}') { lungetc(c); lungetc(block); break; } ending = 0; lungetc(c); c = block; } else if (c == '!') { ending = 1; continue; } else if (c == '\n') break; *p++ = c; if ((size_t)(p - buf) >= sizeof(buf)) { yyerror("line too long"); return (findeol()); } } while ((c = lgetc(0)) != EOF); *p = '\0'; if (c == EOF) { yyerror("unterminated block"); return (0); } if (c == '\n') file->lineno++; if ((yylval.v.string = strdup(buf)) == NULL) err(1, "strdup"); return (STRING); } if (c == '|') return (c); do { if (!quote && isspace((unsigned char)c)) break; if (c == '"') quote = !quote; if (!quote && c == '|') { lungetc(c); break; } if (ending) { if (c == '}') { lungetc(c); lungetc('}'); break; } ending = 0; lungetc(c); c = block; } else if (!quote && c == '}') { ending = 1; continue; } *p++ = c; if ((size_t)(p - buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } } while ((c = lgetc(0)) != EOF); *p = '\0'; if (c == EOF) { yyerror(quote ? "unterminated quote" : "unterminated block"); return (0); } if (c == '\n') file->lineno++; if ((token = lookup(buf)) == STRING) if ((yylval.v.string = strdup(buf)) == NULL) err(1, "strdup"); return (token); } struct file * pushfile(const char *name, int secret) { struct file *nfile; if ((nfile = calloc(1, sizeof(*nfile))) == NULL) err(1, "calloc"); if ((nfile->name = strdup(name)) == NULL) err(1, "strdup"); if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { warn("can't open %s", nfile->name); free(nfile->name); free(nfile); return (NULL); } nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0; nfile->ungetsize = 16; nfile->ungetbuf = malloc(nfile->ungetsize); if (nfile->ungetbuf == NULL) err(1, "malloc"); TAILQ_INSERT_TAIL(&files, nfile, entry); return (nfile); } int popfile(void) { struct file *prev; if ((prev = TAILQ_PREV(file, files, entry)) != NULL) prev->errors += file->errors; TAILQ_REMOVE(&files, file, entry); fclose(file->stream); free(file->name); free(file->ungetbuf); free(file); file = prev; return (file ? 0 : EOF); } int parse(FILE *outfile, const char *filename) { fp = outfile; if ((file = pushfile(filename, 0)) == 0) return (-1); topfile = file; yyparse(); errors = file->errors; popfile(); return (errors ? -1 : 0); } void dbg(void) { if (nodebug) return; if (yylval.lineno == lastline + 1) { lastline = yylval.lineno; return; } lastline = yylval.lineno; fprintf(fp, "#line %d ", yylval.lineno); printq(file->name); putc('\n', fp); } void printq(const char *str) { putc('"', fp); for (; *str; ++str) { if (*str == '"') putc('\\', fp); putc(*str, fp); } putc('"', fp); } got-portable-0.101/template/got_compat.h0000664000175100017510000000263714644144735013743 /* * Copyright (c) 2022 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef COMPAT_H #define COMPAT_H #ifndef __OpenBSD__ #define pledge(s, p) (0) #define unveil(s, p) (0) #endif #ifndef __dead #define __dead __attribute__((__noreturn__)) #endif #ifndef HAVE_ASPRINTF int asprintf(char **, const char *, ...); int vasprintf(char **, const char *, va_list); #endif #ifndef HAVE_ERR __dead void err(int, const char *, ...); __dead void errx(int, const char *, ...); void warn(const char *, ...); void warnx(const char *, ...); #else # include #endif #ifndef HAVE_GETPROGNAME const char *getprogname(void); #endif #ifndef HAVE_REALLOCARRAY void *reallocarray(void *, size_t, size_t); #endif #endif got-portable-0.101/template/aclocal.m40000664000175100017510000015341214644145542013271 # generated automatically by aclocal 1.16.5 -*- Autoconf -*- # Copyright (C) 1996-2021 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.71],, [m4_warning([this file was generated for autoconf 2.71. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*- # serial 12 (pkg-config-0.29.2) dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA dnl 02111-1307, USA. dnl dnl As a special exception to the GNU General Public License, if you dnl distribute this file as part of a program that contains a dnl configuration script generated by Autoconf, you may include it under dnl the same distribution terms that you use for the rest of that dnl program. dnl PKG_PREREQ(MIN-VERSION) dnl ----------------------- dnl Since: 0.29 dnl dnl Verify that the version of the pkg-config macros are at least dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's dnl installed version of pkg-config, this checks the developer's version dnl of pkg.m4 when generating configure. dnl dnl To ensure that this macro is defined, also add: dnl m4_ifndef([PKG_PREREQ], dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) dnl dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], [m4_define([PKG_MACROS_VERSION], [0.29.2]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) dnl ---------------------------------- dnl Since: 0.16 dnl dnl Search for the pkg-config tool and set the PKG_CONFIG variable to dnl first found in the path. Checks that the version of pkg-config found dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is dnl used since that's the first version where most current features of dnl pkg-config existed. AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])dnl PKG_PROG_PKG_CONFIG dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------------------------------- dnl Since: 0.18 dnl dnl Check to see whether a particular set of modules exists. Similar to dnl PKG_CHECK_MODULES(), but does not set variables or print errors. dnl dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) dnl only at the first occurrence in configure.ac, so if the first place dnl it's called might be skipped (such as if it is within an "if", you dnl have to call PKG_CHECK_EXISTS manually AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) dnl --------------------------------------------- dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting dnl pkg_failed based on the result. m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])dnl _PKG_CONFIG dnl _PKG_SHORT_ERRORS_SUPPORTED dnl --------------------------- dnl Internal check to see if pkg-config supports short errors. AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])dnl _PKG_SHORT_ERRORS_SUPPORTED dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl -------------------------------------------------------------- dnl Since: 0.4.0 dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES might not happen, you should be sure to include an dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $2]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])dnl PKG_CHECK_MODULES dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl --------------------------------------------------------------------- dnl Since: 0.29 dnl dnl Checks for existence of MODULES and gathers its build flags with dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags dnl and VARIABLE-PREFIX_LIBS from --libs. dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to dnl include an explicit call to PKG_PROG_PKG_CONFIG in your dnl configure.ac. AC_DEFUN([PKG_CHECK_MODULES_STATIC], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl _save_PKG_CONFIG=$PKG_CONFIG PKG_CONFIG="$PKG_CONFIG --static" PKG_CHECK_MODULES($@) PKG_CONFIG=$_save_PKG_CONFIG[]dnl ])dnl PKG_CHECK_MODULES_STATIC dnl PKG_INSTALLDIR([DIRECTORY]) dnl ------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable pkgconfigdir as the location where a module dnl should install pkg-config .pc files. By default the directory is dnl $libdir/pkgconfig, but the default can be changed by passing dnl DIRECTORY. The user can override through the --with-pkgconfigdir dnl parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_INSTALLDIR dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) dnl -------------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable noarch_pkgconfigdir as the location where a dnl module should install arch-independent pkg-config .pc files. By dnl default the directory is $datadir/pkgconfig, but the default can be dnl changed by passing DIRECTORY. The user can override through the dnl --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_NOARCH_INSTALLDIR dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------- dnl Since: 0.28 dnl dnl Retrieves the value of the pkg-config variable for the given module. AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl _PKG_CONFIG([$1], [variable="][$3]["], [$2]) AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])dnl PKG_CHECK_VAR dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], dnl [DESCRIPTION], [DEFAULT]) dnl ------------------------------------------ dnl dnl Prepare a "--with-" configure option using the lowercase dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and dnl PKG_CHECK_MODULES in a single macro. AC_DEFUN([PKG_WITH_MODULES], [ m4_pushdef([with_arg], m4_tolower([$1])) m4_pushdef([description], [m4_default([$5], [build with ]with_arg[ support])]) m4_pushdef([def_arg], [m4_default([$6], [auto])]) m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) m4_case(def_arg, [yes],[m4_pushdef([with_without], [--without-]with_arg)], [m4_pushdef([with_without],[--with-]with_arg)]) AC_ARG_WITH(with_arg, AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, [AS_TR_SH([with_]with_arg)=def_arg]) AS_CASE([$AS_TR_SH([with_]with_arg)], [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], [auto],[PKG_CHECK_MODULES([$1],[$2], [m4_n([def_action_if_found]) $3], [m4_n([def_action_if_not_found]) $4])]) m4_popdef([with_arg]) m4_popdef([description]) m4_popdef([def_arg]) ])dnl PKG_WITH_MODULES dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [DESCRIPTION], [DEFAULT]) dnl ----------------------------------------------- dnl dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES dnl check._[VARIABLE-PREFIX] is exported as make variable. AC_DEFUN([PKG_HAVE_WITH_MODULES], [ PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) AM_CONDITIONAL([HAVE_][$1], [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) ])dnl PKG_HAVE_WITH_MODULES dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [DESCRIPTION], [DEFAULT]) dnl ------------------------------------------------------ dnl dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make dnl and preprocessor variable. AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], [ PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) ])dnl PKG_HAVE_DEFINE_WITH_MODULES # Copyright (C) 2002-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.16' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.16.5], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.16.5])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. AS_CASE([$CONFIG_FILES], [*\'*], [eval set x "$CONFIG_FILES"], [*], [set x $CONFIG_FILES]) shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`AS_DIRNAME(["$am_mf"])` am_filepart=`AS_BASENAME(["$am_mf"])` AM_RUN_LOG([cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles]) || am_rc=$? done if test $am_rc -ne 0; then AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE="gmake" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking).]) fi AS_UNSET([am_dirpart]) AS_UNSET([am_filepart]) AS_UNSET([am_mf]) AS_UNSET([am_rc]) rm -f conftest-deps.mk } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking is enabled. # This creates each '.Po' and '.Plo' makefile fragment that we'll need in # order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl m4_ifdef([_$0_ALREADY_INIT], [m4_fatal([$0 expanded multiple times ]m4_defn([_$0_ALREADY_INIT]))], [m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) # Variables for tags utilities; see am/tags.am if test -z "$CTAGS"; then CTAGS=ctags fi AC_SUBST([CTAGS]) if test -z "$ETAGS"; then ETAGS=etags fi AC_SUBST([ETAGS]) if test -z "$CSCOPE"; then CSCOPE=cscope fi AC_SUBST([CSCOPE]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi dnl The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check whether make has an 'include' directive that can support all # the idioms we need for our automatic dependency tracking code. AC_DEFUN([AM_MAKE_INCLUDE], [AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) AS_CASE([$?:`cat confinc.out 2>/dev/null`], ['0:this is the am__doit target'], [AS_CASE([$s], [BSD], [am__include='.include' am__quote='"'], [am__include='include' am__quote=''])]) if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* AC_MSG_RESULT([${_am_result}]) AC_SUBST([am__include])]) AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR got-portable-0.101/template/Makefile.common.in0000664000175100017510000000134214644144735014762 AM_CFLAGS += \ @AM_CFLAGS@ \ -Wunused-variable \ -Wwrite-strings # Ideally, we should be enabling further flags, but this requires upstream # changes. Leaving these here for now. # # -g -Wall -Wno-long-long -W -Wformat=2 -Wmissing-prototypes \ # -Wstrict-prototypes -Wmissing-declarations -Wwrite-strings \ # -Wshadow -Wpointer-arith -Wno-sign-compare -Wundef \ # -Wbad-function-cast -Winline -Wcast-align \ # -Wdeclaration-after-statement -Wno-pointer-sign \ # -Wno-attributes -Wno-unused-result AM_CPPFLAGS += \ @AM_CPPFLAGS@ \ -DGOT_VERSION=@VERSION@ \ -DGOT_VERSION_NUMBER=@VERSION@ \ -DGOT_LIBEXECDIR="$(libexecdir)" \ -I$(top_srcdir)/template \ -I. got-portable-0.101/template/ylwrap0000755000175100017510000001531414644145542012671 #! /bin/sh # ylwrap - wrapper for lex/yacc invocations. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1996-2021 Free Software Foundation, Inc. # # Written by Tom Tromey . # # 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 # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . get_dirname () { case $1 in */*|*\\*) printf '%s\n' "$1" | sed -e 's|\([\\/]\)[^\\/]*$|\1|';; # Otherwise, we want the empty string (not "."). esac } # guard FILE # ---------- # The CPP macro used to guard inclusion of FILE. guard () { printf '%s\n' "$1" \ | sed \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g' \ -e 's/__*/_/g' } # quote_for_sed [STRING] # ---------------------- # Return STRING (or stdin) quoted to be used as a sed pattern. quote_for_sed () { case $# in 0) cat;; 1) printf '%s\n' "$1";; esac \ | sed -e 's|[][\\.*]|\\&|g' } case "$1" in '') echo "$0: No files given. Try '$0 --help' for more information." 1>&2 exit 1 ;; --basedir) basedir=$2 shift 2 ;; -h|--h*) cat <<\EOF Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]... Wrapper for lex/yacc invocations, renaming files as desired. INPUT is the input file OUTPUT is one file PROG generates DESIRED is the file we actually want instead of OUTPUT PROGRAM is program to run ARGS are passed to PROG Any number of OUTPUT,DESIRED pairs may be used. Report bugs to . EOF exit $? ;; -v|--v*) echo "ylwrap $scriptversion" exit $? ;; esac # The input. input=$1 shift # We'll later need for a correct munging of "#line" directives. input_sub_rx=`get_dirname "$input" | quote_for_sed` case $input in [\\/]* | ?:[\\/]*) # Absolute path; do nothing. ;; *) # Relative path. Make it absolute. input=`pwd`/$input ;; esac input_rx=`get_dirname "$input" | quote_for_sed` # Since DOS filename conventions don't allow two dots, # the DOS version of Bison writes out y_tab.c instead of y.tab.c # and y_tab.h instead of y.tab.h. Test to see if this is the case. y_tab_nodot=false if test -f y_tab.c || test -f y_tab.h; then y_tab_nodot=true fi # The parser itself, the first file, is the destination of the .y.c # rule in the Makefile. parser=$1 # A sed program to s/FROM/TO/g for all the FROM/TO so that, for # instance, we rename #include "y.tab.h" into #include "parse.h" # during the conversion from y.tab.c to parse.c. sed_fix_filenames= # Also rename header guards, as Bison 2.7 for instance uses its header # guard in its implementation file. sed_fix_header_guards= while test $# -ne 0; do if test x"$1" = x"--"; then shift break fi from=$1 # Handle y_tab.c and y_tab.h output by DOS if $y_tab_nodot; then case $from in "y.tab.c") from=y_tab.c;; "y.tab.h") from=y_tab.h;; esac fi shift to=$1 shift sed_fix_filenames="${sed_fix_filenames}s|"`quote_for_sed "$from"`"|$to|g;" sed_fix_header_guards="${sed_fix_header_guards}s|"`guard "$from"`"|"`guard "$to"`"|g;" done # The program to run. prog=$1 shift # Make any relative path in $prog absolute. case $prog in [\\/]* | ?:[\\/]*) ;; *[\\/]*) prog=`pwd`/$prog ;; esac dirname=ylwrap$$ do_exit="cd '`pwd`' && rm -rf $dirname > /dev/null 2>&1;"' (exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 mkdir $dirname || exit 1 cd $dirname case $# in 0) "$prog" "$input" ;; *) "$prog" "$@" "$input" ;; esac ret=$? if test $ret -eq 0; then for from in * do to=`printf '%s\n' "$from" | sed "$sed_fix_filenames"` if test -f "$from"; then # If $2 is an absolute path name, then just use that, # otherwise prepend '../'. case $to in [\\/]* | ?:[\\/]*) target=$to;; *) target=../$to;; esac # Do not overwrite unchanged header files to avoid useless # recompilations. Always update the parser itself: it is the # destination of the .y.c rule in the Makefile. Divert the # output of all other files to a temporary file so we can # compare them to existing versions. if test $from != $parser; then realtarget=$target target=tmp-`printf '%s\n' "$target" | sed 's|.*[\\/]||g'` fi # Munge "#line" or "#" directives. Don't let the resulting # debug information point at an absolute srcdir. Use the real # output file name, not yy.lex.c for instance. Adjust the # include guards too. sed -e "/^#/!b" \ -e "s|$input_rx|$input_sub_rx|" \ -e "$sed_fix_filenames" \ -e "$sed_fix_header_guards" \ "$from" >"$target" || ret=$? # Check whether files must be updated. if test "$from" != "$parser"; then if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then echo "$to is unchanged" rm -f "$target" else echo "updating $to" mv -f "$target" "$realtarget" fi fi else # A missing file is only an error for the parser. This is a # blatant hack to let us support using "yacc -d". If -d is not # specified, don't fail when the header file is "missing". if test "$from" = "$parser"; then ret=1 fi fi done fi # Remove the directory. cd .. rm -rf $dirname exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: got-portable-0.101/configure0000775000175100017510000127564314644145543011542 #! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71 for got-portable 0.101. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="as_nop=: if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes else $as_nop as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$as_shell as_have_required=yes if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null then : break 2 fi fi done;; esac as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes fi fi if test "x$CONFIG_SHELL" != x then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : printf "%s\n" "$0: This script requires a shell more modern than all" printf "%s\n" "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and thomas@xteddy.org $0: about your system, including any error possibly output $0: before this message. Then install a modern shell, or $0: manually run the script under such a shell if you do $0: have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='got-portable' PACKAGE_TARNAME='got-portable' PACKAGE_VERSION='0.101' PACKAGE_STRING='got-portable 0.101' PACKAGE_BUGREPORT='thomas@xteddy.org' PACKAGE_URL='' ac_unique_file="lib/rcsutil.h" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_c_list= enable_option_checking=no ac_func_c_list= ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS CVG_ENABLED_FALSE CVG_ENABLED_TRUE AM_LDFLAGS AM_CFLAGS AM_CPPFLAGS libncurses_LIBS libncurses_CFLAGS LIBNCURSES_LIBS LIBNCURSES_CFLAGS LIBPANELW_LIBS LIBPANELW_CFLAGS libtls_LIBS libtls_CFLAGS LIBTLS_LIBS LIBTLS_CFLAGS libmd_LIBS libmd_CFLAGS LIBMD_LIBS LIBMD_CFLAGS libbsd_LIBS libbsd_CFLAGS LIBBSD_LIBS LIBBSD_CFLAGS zlib_LIBS zlib_CFLAGS ZLIB_LIBS ZLIB_CFLAGS libuuid_LIBS libuuid_CFLAGS LIBUUID_LIBS LIBUUID_CFLAGS LIBEVENT_LIBS LIBEVENT_CFLAGS libevent_LIBS libevent_CFLAGS LIBEVENT_CORE_LIBS LIBEVENT_CORE_CFLAGS libutil_LIBS HAVE_IMSG_FALSE HAVE_IMSG_TRUE HAVE_LINUX_LANDLOCK_FALSE HAVE_LINUX_LANDLOCK_TRUE HOST_DRAGONFLYBSD_FALSE HOST_DRAGONFLYBSD_TRUE HOST_OPENBSD_FALSE HOST_OPENBSD_TRUE HOST_NETBSD_FALSE HOST_NETBSD_TRUE HOST_DARWIN_FALSE HOST_DARWIN_TRUE HOST_LINUX_FALSE HOST_LINUX_TRUE HOST_FREEBSD_FALSE HOST_FREEBSD_TRUE PLATFORM libresolv_LIBS HAVE_B64_FALSE HAVE_B64_TRUE HAVE_CLOSEFROM_FALSE HAVE_CLOSEFROM_TRUE HAVE_SIPHASH_FALSE HAVE_SIPHASH_TRUE HAVE_SETPROCTITLE_FALSE HAVE_SETPROCTITLE_TRUE LIBOBJS HAVE_GETOPT_FALSE HAVE_GETOPT_TRUE HAVE_SHA2_FALSE HAVE_SHA2_TRUE PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG RANLIB ac_ct_AR AR YFLAGS YACC LN_S CPP GITWRAPPER_LIBEXEC_PATHC GOTD_EMPTY_PATHC subdirs host_os host_vendor host_cpu host build_os build_vendor build_cpu build am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC GOT_RELEASE AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V CSCOPE ETAGS CTAGS am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL am__quote' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_dependency_tracking enable_cvg with_gotd_empty_path with_gitwrapper_git_libexec_path ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP YACC YFLAGS PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR LIBEVENT_CORE_CFLAGS LIBEVENT_CORE_LIBS LIBEVENT_CFLAGS LIBEVENT_LIBS LIBUUID_CFLAGS LIBUUID_LIBS ZLIB_CFLAGS ZLIB_LIBS LIBBSD_CFLAGS LIBBSD_LIBS LIBMD_CFLAGS LIBMD_LIBS LIBTLS_CFLAGS LIBTLS_LIBS LIBPANELW_CFLAGS LIBPANELW_LIBS LIBNCURSES_CFLAGS LIBNCURSES_LIBS' ac_subdirs_all='template' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures got-portable 0.101 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/got-portable] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of got-portable 0.101:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build --enable-cvg EXPERIMENTAL: cvg - cvs-like-git Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-gotd-empty-path gotd empty path --with-gitwrapper-git-libexec-path git libexec path for gitwrapper Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor YACC The `Yet Another Compiler Compiler' implementation to use. Defaults to the first program found out of: `bison -y', `byacc', `yacc'. YFLAGS The list of arguments that will be passed by default to $YACC. This script will default YFLAGS to the empty string to avoid a default value of `-d' given by some make applications. PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path LIBEVENT_CORE_CFLAGS C compiler flags for LIBEVENT_CORE, overriding pkg-config LIBEVENT_CORE_LIBS linker flags for LIBEVENT_CORE, overriding pkg-config LIBEVENT_CFLAGS C compiler flags for LIBEVENT, overriding pkg-config LIBEVENT_LIBS linker flags for LIBEVENT, overriding pkg-config LIBUUID_CFLAGS C compiler flags for LIBUUID, overriding pkg-config LIBUUID_LIBS linker flags for LIBUUID, overriding pkg-config ZLIB_CFLAGS C compiler flags for ZLIB, overriding pkg-config ZLIB_LIBS linker flags for ZLIB, overriding pkg-config LIBBSD_CFLAGS C compiler flags for LIBBSD, overriding pkg-config LIBBSD_LIBS linker flags for LIBBSD, overriding pkg-config LIBMD_CFLAGS C compiler flags for LIBMD, overriding pkg-config LIBMD_LIBS linker flags for LIBMD, overriding pkg-config LIBTLS_CFLAGS C compiler flags for LIBTLS, overriding pkg-config LIBTLS_LIBS linker flags for LIBTLS, overriding pkg-config LIBPANELW_CFLAGS C compiler flags for LIBPANELW, overriding pkg-config LIBPANELW_LIBS linker flags for LIBPANELW, overriding pkg-config LIBNCURSES_CFLAGS C compiler flags for LIBNCURSES, overriding pkg-config LIBNCURSES_LIBS linker flags for LIBNCURSES, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF got-portable configure 0.101 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR # ------------------------------------------------------------------ # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR # accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR. ac_fn_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack as_decl_name=`echo $2|sed 's/ *(.*//'` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 printf %s "checking whether $as_decl_name is declared... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` eval ac_save_FLAGS=\$$6 as_fn_append $6 " $5" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { #ifndef $as_decl_name #ifdef __cplusplus (void) $as_decl_use; #else (void) $as_decl_name; #endif #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext eval $6=\$ac_save_FLAGS fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_check_decl # ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES # ---------------------------------------------------- # Tries to find if the field MEMBER exists in type AGGR, after including # INCLUDES, setting cache variable VAR accordingly. ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 printf %s "checking for $2.$3... " >&6; } if eval test \${$4+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main (void) { static $2 ac_aggr; if (ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$4=yes" else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main (void) { static $2 ac_aggr; if (sizeof ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$4=yes" else $as_nop eval "$4=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$4 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_find_intX_t LINENO BITS VAR # ----------------------------------- # Finds a signed integer type with width BITS, setting cache variable VAR # accordingly. ac_fn_c_find_intX_t () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 printf %s "checking for int$2_t... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop eval "$3=no" # Order is important - never check a type that is potentially smaller # than half of the expected target width. for ac_type in int$2_t 'int' 'long int' \ 'long long int' 'short int' 'signed char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default enum { N = $2 / 2 - 1 }; int main (void) { static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default enum { N = $2 / 2 - 1 }; int main (void) { static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop case $ac_type in #( int$2_t) : eval "$3=yes" ;; #( *) : eval "$3=\$ac_type" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if eval test \"x\$"$3"\" = x"no" then : else $as_nop break fi done fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_intX_t # ac_fn_c_find_uintX_t LINENO BITS VAR # ------------------------------------ # Finds an unsigned integer type with width BITS, setting cache variable VAR # accordingly. ac_fn_c_find_uintX_t () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 printf %s "checking for uint$2_t... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop eval "$3=no" # Order is important - never check a type that is potentially smaller # than half of the expected target width. for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : case $ac_type in #( uint$2_t) : eval "$3=yes" ;; #( *) : eval "$3=\$ac_type" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if eval test \"x\$"$3"\" = x"no" then : else $as_nop break fi done fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_uintX_t # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. */ #include #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main (void) { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_try_run LINENO # ---------------------- # Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that # executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: program exited with status $ac_status" >&5 printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run ac_configure_args_raw= for ac_arg do case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done case $ac_configure_args_raw in *$as_nl*) ac_safe_unquote= ;; *) ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by got-portable $as_me 0.101, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Sanitize IFS. IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && printf "%s\n" "$as_me: caught signal $ac_signal" printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi for ac_site_file in $ac_site_files do case $ac_site_file in #( */*) : ;; #( *) : ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' /* Does the compiler advertise C89 conformance? Do not test the value of __STDC__, because some compilers set it to 0 while being otherwise adequately conformant. */ #if !defined __STDC__ # error "Compiler does not advertise C89 conformance" #endif #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated as an "x". The following induces an error, until -std is added to get proper ANSI mode. Curiously \x00 != x always comes out true, for an array size at least. It is necessary to write \x00 == 0 to get something that is true only with -std. */ int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) '\''x'\'' int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), int, int);' # Test code for whether the C compiler supports C89 (body of main). ac_c_conftest_c89_main=' ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); ' # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' // Does the compiler advertise C99 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare // FILE and stderr. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK #error "your preprocessor is broken" #endif #if BIG_OK #else #error "your preprocessor is broken" #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case '\''s'\'': // string str = va_arg (args_copy, const char *); break; case '\''d'\'': // int number = va_arg (args_copy, int); break; case '\''f'\'': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; } ' # Test code for whether the C compiler supports C99 (body of main). ac_c_conftest_c99_main=' // Check bool. _Bool success = false; success |= (argc != 0); // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[0] = argv[0][0]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' || dynamic_array[ni.number - 1] != 543); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' // Does the compiler advertise C11 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ' # Test code for whether the C compiler supports C11 (body of main). ac_c_conftest_c11_main=' _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); v1.i = 2; v1.w.k = 5; ok |= v1.i != 5; ' # Test code for whether the C compiler supports C11 (complete). ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} ${ac_c_conftest_c11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} ${ac_c_conftest_c11_main} return ok; } " # Test code for whether the C compiler supports C99 (complete). ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} return ok; } " # Test code for whether the C compiler supports C89 (complete). ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} return ok; } " as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" as_fn_append ac_header_c_list " wchar.h wchar_h HAVE_WCHAR_H" as_fn_append ac_header_c_list " minix/config.h minix_config_h HAVE_MINIX_CONFIG_H" as_fn_append ac_header_c_list " vfork.h vfork_h HAVE_VFORK_H" as_fn_append ac_func_c_list " fork HAVE_FORK" as_fn_append ac_func_c_list " vfork HAVE_VFORK" as_fn_append ac_header_c_list " sys/param.h sys_param_h HAVE_SYS_PARAM_H" as_fn_append ac_func_c_list " getpagesize HAVE_GETPAGESIZE" # Auxiliary files required by this configure script. ac_aux_files="ar-lib config.guess config.sub compile missing install-sh" # Locations in which to look for auxiliary files. ac_aux_dir_candidates="${srcdir}/etc" # Search for a directory containing all of the required auxiliary files, # $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. # If we don't find one directory that contains all the files we need, # we report the set of missing files from the *first* directory in # $ac_aux_dir_candidates and give up. ac_missing_aux_files="" ac_first_candidate=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in $ac_aux_dir_candidates do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 ac_aux_dir_found=yes ac_install_sh= for ac_aux in $ac_aux_files do # As a special case, if "install-sh" is required, that requirement # can be satisfied by any of "install-sh", "install.sh", or "shtool", # and $ac_install_sh is set appropriately for whichever one is found. if test x"$ac_aux" = x"install-sh" then if test -f "${as_dir}install-sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 ac_install_sh="${as_dir}install-sh -c" elif test -f "${as_dir}install.sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 ac_install_sh="${as_dir}install.sh -c" elif test -f "${as_dir}shtool"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 ac_install_sh="${as_dir}shtool install -c" else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} install-sh" else break fi fi else if test -f "${as_dir}${ac_aux}"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" else break fi fi fi done if test "$ac_aux_dir_found" = yes; then ac_aux_dir="$as_dir" break fi ac_first_candidate=false as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. if test -f "${ac_aux_dir}config.guess"; then ac_config_guess="$SHELL ${ac_aux_dir}config.guess" fi if test -f "${ac_aux_dir}config.sub"; then ac_config_sub="$SHELL ${ac_aux_dir}config.sub" fi if test -f "$ac_aux_dir/configure"; then ac_configure="$SHELL ${ac_aux_dir}configure" fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu am__api_version='1.16' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 printf %s "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test ${ac_cv_path_install+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac # Account for fact that we put trailing slashes in our PATH walk. case $as_dir in #(( ./ | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test ${ac_cv_path_install+y}; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 printf "%s\n" "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 printf %s "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`printf "%s\n" "$program_transform_name" | sed "$ac_script"` # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` if test x"${MISSING+set}" != xset; then MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 printf "%s\n" "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 printf "%s\n" "$STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 printf "%s\n" "$ac_ct_STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 printf %s "checking for a race-free mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if test ${ac_cv_path_mkdir+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir ('*'coreutils) '* | \ 'BusyBox '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test ${ac_cv_path_mkdir+y}; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 printf "%s\n" "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AWK+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 printf "%s\n" "$AWK" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AWK" && break done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval test \${ac_cv_prog_make_${ac_make}_set+y} then : printf %s "(cached) " >&6 else $as_nop cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } SET_MAKE= else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. if test ${enable_silent_rules+y} then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 printf %s "checking whether $am_make supports nested variables... " >&6; } if test ${am_cv_make_support_nested_variables+y} then : printf %s "(cached) " >&6 else $as_nop if printf "%s\n" 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 printf "%s\n" "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='got-portable' VERSION='0.101' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h printf "%s\n" "#define VERSION \"$VERSION\"" >>confdefs.h # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # Variables for tags utilities; see am/tags.am if test -z "$CTAGS"; then CTAGS=ctags fi if test -z "$ETAGS"; then ETAGS=etags fi if test -z "$CSCOPE"; then CSCOPE=cscope fi # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 fi fi ac_config_headers="$ac_config_headers include/got_compat.h" printf "%s\n" "#define VERSION $VERSION" >>confdefs.h printf "%s\n" "#define GOT_VERSION VERSION" >>confdefs.h printf "%s\n" "#define GOT_VERSION_NUMBER VERSION" >>confdefs.h DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } case $?:`cat confinc.out 2>/dev/null` in #( '0:this is the am__doit target') : case $s in #( BSD) : am__include='.include' am__quote='"' ;; #( *) : am__include='include' am__quote='' ;; esac ;; #( *) : ;; esac if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 printf "%s\n" "${_am_result}" >&6; } # Check whether --enable-dependency-tracking was given. if test ${enable_dependency_tracking+y} then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 printf %s "checking whether the C compiler works... " >&6; } ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else $as_nop ac_file='' fi if test -z "$ac_file" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else $as_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 printf %s "checking whether $CC understands -c and -o together... " >&6; } if test ${am_cv_prog_cc_c_o+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 printf %s "checking dependency style of $depcc... " >&6; } if test ${am_cv_CC_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 else $as_nop if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 printf "%s\n" "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi ac_header= ac_cache= for ac_item in $ac_header_c_list do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then printf "%s\n" "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then ac_cache=$ac_item else ac_header=$ac_item fi done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 printf %s "checking whether it is safe to define __EXTENSIONS__... " >&6; } if test ${ac_cv_safe_to_define___extensions__+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # define __EXTENSIONS__ 1 $ac_includes_default int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_safe_to_define___extensions__=yes else $as_nop ac_cv_safe_to_define___extensions__=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 printf "%s\n" "$ac_cv_safe_to_define___extensions__" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether _XOPEN_SOURCE should be defined" >&5 printf %s "checking whether _XOPEN_SOURCE should be defined... " >&6; } if test ${ac_cv_should_define__xopen_source+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_should_define__xopen_source=no if test $ac_cv_header_wchar_h = yes then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include mbstate_t x; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _XOPEN_SOURCE 500 #include mbstate_t x; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_should_define__xopen_source=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_should_define__xopen_source" >&5 printf "%s\n" "$ac_cv_should_define__xopen_source" >&6; } printf "%s\n" "#define _ALL_SOURCE 1" >>confdefs.h printf "%s\n" "#define _DARWIN_C_SOURCE 1" >>confdefs.h printf "%s\n" "#define _GNU_SOURCE 1" >>confdefs.h printf "%s\n" "#define _HPUX_ALT_XOPEN_SOCKET_API 1" >>confdefs.h printf "%s\n" "#define _NETBSD_SOURCE 1" >>confdefs.h printf "%s\n" "#define _OPENBSD_SOURCE 1" >>confdefs.h printf "%s\n" "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_BFP_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_DFP_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_LIB_EXT2__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_MATH_SPEC_FUNCS__ 1" >>confdefs.h printf "%s\n" "#define _TANDEM_SOURCE 1" >>confdefs.h if test $ac_cv_header_minix_config_h = yes then : MINIX=yes printf "%s\n" "#define _MINIX 1" >>confdefs.h printf "%s\n" "#define _POSIX_SOURCE 1" >>confdefs.h printf "%s\n" "#define _POSIX_1_SOURCE 2" >>confdefs.h else $as_nop MINIX= fi if test $ac_cv_safe_to_define___extensions__ = yes then : printf "%s\n" "#define __EXTENSIONS__ 1" >>confdefs.h fi if test $ac_cv_should_define__xopen_source = yes then : printf "%s\n" "#define _XOPEN_SOURCE 500" >>confdefs.h fi # Make sure we can run config.sub. $SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 printf %s "checking build system type... " >&6; } if test ${ac_cv_build+y} then : printf %s "(cached) " >&6 else $as_nop ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 printf "%s\n" "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 printf %s "checking host system type... " >&6; } if test ${ac_cv_host+y} then : printf %s "(cached) " >&6 else $as_nop if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 printf "%s\n" "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac subdirs="$subdirs template" # Check whether --enable-cvg was given. if test ${enable_cvg+y} then : enableval=$enable_cvg; fi # Override gotd's empty_path location. # Check whether --with-gotd-empty-path was given. if test ${with_gotd_empty_path+y} then : withval=$with_gotd_empty_path; GOTD_EMPTY_PATHC=$withval fi # Override where git's libexec helpers are located for gitwrapper. # Check whether --with-gitwrapper-git-libexec-path was given. if test ${with_gitwrapper_git_libexec_path+y} then : withval=$with_gitwrapper_git_libexec_path; GITWRAPPER_LIBEXEC_PATHC=$withval fi # When CFLAGS isn't set at this stage and gcc is detected by the macro below, # autoconf will automatically use CFLAGS="-O2 -g". Prevent that by using an # empty default. : ${CFLAGS=""} # Save user CPPFLAGS, CFLAGS and LDFLAGS. We need to change them because # AC_CHECK_HEADER doesn't give us any other way to update the include # paths. But for Makefile.am we want to use AM_CPPFLAGS and friends. SAVED_CFLAGS="$CFLAGS" SAVED_CPPFLAGS="$CPPFLAGS" SAVED_LDFLAGS="$LDFLAGS" # YACC override YACC_OVERRIDE="yes" # Checks for programs. ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 printf %s "checking whether $CC understands -c and -o together... " >&6; } if test ${am_cv_prog_cc_c_o+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 printf %s "checking dependency style of $depcc... " >&6; } if test ${am_cv_CC_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 else $as_nop if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 printf "%s\n" "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 printf %s "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test ${ac_cv_prog_CPP+y} then : printf %s "(cached) " >&6 else $as_nop # Double quotes because $CC needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO" then : # Broken: success on invalid input. continue else $as_nop # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 printf "%s\n" "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO" then : # Broken: success on invalid input. continue else $as_nop # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : else $as_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 printf %s "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 printf "%s\n" "no, using $LN_S" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval test \${ac_cv_prog_make_${ac_make}_set+y} then : printf %s "(cached) " >&6 else $as_nop cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } SET_MAKE= else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi if test -z "$YACC"; then YACC_OVERRIDE="no" for ac_prog in 'bison -y' byacc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_YACC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$YACC"; then ac_cv_prog_YACC="$YACC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_YACC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi YACC=$ac_cv_prog_YACC if test -n "$YACC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 printf "%s\n" "$YACC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$YACC" && break done test -n "$YACC" || YACC="yacc" fi if test -n "$ac_tool_prefix"; then for ac_prog in ar lib "link -lib" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AR+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 printf "%s\n" "$AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar lib "link -lib" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_AR+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 printf "%s\n" "$ac_ct_AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi fi : ${AR=ar} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5 printf %s "checking the archiver ($AR) interface... " >&6; } if test ${am_cv_ar_interface+y} then : printf %s "(cached) " >&6 else $as_nop ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu am_cv_ar_interface=ar cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int some_variable = 0; _ACEOF if ac_fn_c_try_compile "$LINENO" then : am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 (eval $am_ar_try) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then am_cv_ar_interface=ar else am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 (eval $am_ar_try) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then am_cv_ar_interface=lib else am_cv_ar_interface=unknown fi fi rm -f conftest.lib libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5 printf "%s\n" "$am_cv_ar_interface" >&6; } case $am_cv_ar_interface in ar) ;; lib) # Microsoft lib, so override with the ar-lib wrapper script. # FIXME: It is wrong to rewrite AR. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__AR in this case, # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something # similar. AR="$am_aux_dir/ar-lib $AR" ;; unknown) as_fn_error $? "could not determine $AR interface" "$LINENO" 5 ;; esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 printf "%s\n" "$RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 printf "%s\n" "$ac_ct_RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_PKG_CONFIG+y} then : printf %s "(cached) " >&6 else $as_nop case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 printf "%s\n" "$PKG_CONFIG" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} then : printf %s "(cached) " >&6 else $as_nop case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 printf "%s\n" "$ac_pt_PKG_CONFIG" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 printf %s "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } PKG_CONFIG="" fi fi if test "$YACC_OVERRIDE" = "yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \"Using YACC set from environment: $YACC\"" >&5 printf "%s\n" "$as_me: \"Using YACC set from environment: $YACC\"" >&6;} fi # Checks for header files. ac_fn_c_check_header_compile "$LINENO" "fcntl.h" "ac_cv_header_fcntl_h" "$ac_includes_default" if test "x$ac_cv_header_fcntl_h" = xyes then : printf "%s\n" "#define HAVE_FCNTL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "getopt.h" "ac_cv_header_getopt_h" "$ac_includes_default" if test "x$ac_cv_header_getopt_h" = xyes then : printf "%s\n" "#define HAVE_GETOPT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "langinfo.h" "ac_cv_header_langinfo_h" "$ac_includes_default" if test "x$ac_cv_header_langinfo_h" = xyes then : printf "%s\n" "#define HAVE_LANGINFO_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "libutil.h" "ac_cv_header_libutil_h" "$ac_includes_default" if test "x$ac_cv_header_libutil_h" = xyes then : printf "%s\n" "#define HAVE_LIBUTIL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default" if test "x$ac_cv_header_limits_h" = xyes then : printf "%s\n" "#define HAVE_LIMITS_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "linux/landlock.h" "ac_cv_header_linux_landlock_h" "$ac_includes_default" if test "x$ac_cv_header_linux_landlock_h" = xyes then : printf "%s\n" "#define HAVE_LINUX_LANDLOCK_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "locale.h" "ac_cv_header_locale_h" "$ac_includes_default" if test "x$ac_cv_header_locale_h" = xyes then : printf "%s\n" "#define HAVE_LOCALE_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "netdb.h" "ac_cv_header_netdb_h" "$ac_includes_default" if test "x$ac_cv_header_netdb_h" = xyes then : printf "%s\n" "#define HAVE_NETDB_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "netinet/in.h" "ac_cv_header_netinet_in_h" "$ac_includes_default" if test "x$ac_cv_header_netinet_in_h" = xyes then : printf "%s\n" "#define HAVE_NETINET_IN_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "paths.h" "ac_cv_header_paths_h" "$ac_includes_default" if test "x$ac_cv_header_paths_h" = xyes then : printf "%s\n" "#define HAVE_PATHS_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "poll.h" "ac_cv_header_poll_h" "$ac_includes_default" if test "x$ac_cv_header_poll_h" = xyes then : printf "%s\n" "#define HAVE_POLL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sha.h" "ac_cv_header_sha_h" "$ac_includes_default" if test "x$ac_cv_header_sha_h" = xyes then : printf "%s\n" "#define HAVE_SHA_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sha1.h" "ac_cv_header_sha1_h" "$ac_includes_default" if test "x$ac_cv_header_sha1_h" = xyes then : printf "%s\n" "#define HAVE_SHA1_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sha2.h" "ac_cv_header_sha2_h" "$ac_includes_default" if test "x$ac_cv_header_sha2_h" = xyes then : printf "%s\n" "#define HAVE_SHA2_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sha256.h" "ac_cv_header_sha256_h" "$ac_includes_default" if test "x$ac_cv_header_sha256_h" = xyes then : printf "%s\n" "#define HAVE_SHA256_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "stddef.h" "ac_cv_header_stddef_h" "$ac_includes_default" if test "x$ac_cv_header_stddef_h" = xyes then : printf "%s\n" "#define HAVE_STDDEF_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "stdint.h" "ac_cv_header_stdint_h" "$ac_includes_default" if test "x$ac_cv_header_stdint_h" = xyes then : printf "%s\n" "#define HAVE_STDINT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = xyes then : printf "%s\n" "#define HAVE_STDLIB_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default" if test "x$ac_cv_header_string_h" = xyes then : printf "%s\n" "#define HAVE_STRING_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/ioctl.h" "ac_cv_header_sys_ioctl_h" "$ac_includes_default" if test "x$ac_cv_header_sys_ioctl_h" = xyes then : printf "%s\n" "#define HAVE_SYS_IOCTL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" if test "x$ac_cv_header_sys_param_h" = xyes then : printf "%s\n" "#define HAVE_SYS_PARAM_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/poll.h" "ac_cv_header_sys_poll_h" "$ac_includes_default" if test "x$ac_cv_header_sys_poll_h" = xyes then : printf "%s\n" "#define HAVE_SYS_POLL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/queue.h" "ac_cv_header_sys_queue_h" "$ac_includes_default" if test "x$ac_cv_header_sys_queue_h" = xyes then : printf "%s\n" "#define HAVE_SYS_QUEUE_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/select.h" "ac_cv_header_sys_select_h" "$ac_includes_default" if test "x$ac_cv_header_sys_select_h" = xyes then : printf "%s\n" "#define HAVE_SYS_SELECT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default" if test "x$ac_cv_header_sys_socket_h" = xyes then : printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default" if test "x$ac_cv_header_sys_time_h" = xyes then : printf "%s\n" "#define HAVE_SYS_TIME_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/tree.h" "ac_cv_header_sys_tree_h" "$ac_includes_default" if test "x$ac_cv_header_sys_tree_h" = xyes then : printf "%s\n" "#define HAVE_SYS_TREE_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "tls.h" "ac_cv_header_tls_h" "$ac_includes_default" if test "x$ac_cv_header_tls_h" = xyes then : printf "%s\n" "#define HAVE_TLS_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "util.h" "ac_cv_header_util_h" "$ac_includes_default" if test "x$ac_cv_header_util_h" = xyes then : printf "%s\n" "#define HAVE_UTIL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default" if test "x$ac_cv_header_unistd_h" = xyes then : printf "%s\n" "#define HAVE_UNISTD_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "wchar.h" "ac_cv_header_wchar_h" "$ac_includes_default" if test "x$ac_cv_header_wchar_h" = xyes then : printf "%s\n" "#define HAVE_WCHAR_H 1" >>confdefs.h fi ac_header_dirent=no for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do as_ac_Header=`printf "%s\n" "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 printf %s "checking for $ac_hdr that defines DIR... " >&6; } if eval test \${$as_ac_Header+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include <$ac_hdr> int main (void) { if ((DIR *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$as_ac_Header=yes" else $as_nop eval "$as_ac_Header=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$as_ac_Header { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } if eval test \"x\$"$as_ac_Header"\" = x"yes" then : cat >>confdefs.h <<_ACEOF #define `printf "%s\n" "HAVE_$ac_hdr" | $as_tr_cpp` 1 _ACEOF ac_header_dirent=$ac_hdr; break fi done # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 printf %s "checking for library containing opendir... " >&6; } if test ${ac_cv_search_opendir+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char opendir (); int main (void) { return opendir (); ; return 0; } _ACEOF for ac_lib in '' dir do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_opendir+y} then : break fi done if test ${ac_cv_search_opendir+y} then : else $as_nop ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 printf "%s\n" "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 printf %s "checking for library containing opendir... " >&6; } if test ${ac_cv_search_opendir+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char opendir (); int main (void) { return opendir (); ; return 0; } _ACEOF for ac_lib in '' x do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_opendir+y} then : break fi done if test ${ac_cv_search_opendir+y} then : else $as_nop ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 printf "%s\n" "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5 printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; } if test ${ac_cv_c_undeclared_builtin_options+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_CFLAGS=$CFLAGS ac_cv_c_undeclared_builtin_options='cannot detect' for ac_arg in '' -fno-builtin; do CFLAGS="$ac_save_CFLAGS $ac_arg" # This test program should *not* compile successfully. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { (void) strchr; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop # This test program should compile successfully. # No library function is consistently available on # freestanding implementations, so test against a dummy # declaration. Include always-available headers on the # off chance that they somehow elicit warnings. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include extern void ac_decl (int, char *); int main (void) { (void) ac_decl (0, (char *) 0); (void) ac_decl; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : if test x"$ac_arg" = x then : ac_cv_c_undeclared_builtin_options='none needed' else $as_nop ac_cv_c_undeclared_builtin_options=$ac_arg fi break fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done CFLAGS=$ac_save_CFLAGS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; } case $ac_cv_c_undeclared_builtin_options in #( 'cannot detect') : { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot make $CC report undeclared builtins See \`config.log' for more details" "$LINENO" 5; } ;; #( 'none needed') : ac_c_undeclared_builtin_options='' ;; #( *) : ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;; esac ac_fn_check_decl "$LINENO" "F_CLOSEM" "ac_cv_have_decl_F_CLOSEM" "#include #include " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_F_CLOSEM" = xyes then : HAVE_FCNTL_CLOSEM printf "%s\n" "#define HAVE_FCNTL_CLOSEM 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /proc/pid/fd directory" >&5 printf %s "checking for /proc/pid/fd directory... " >&6; } if test -d "/proc/$$/fd" ; then printf "%s\n" "#define HAVE_PROC_PID 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether program_invocation_short_name is defined" >&5 printf %s "checking whether program_invocation_short_name is defined... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { program_invocation_short_name = "test"; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define HAVE_PROGRAM_INVOCATION_SHORT_NAME 1" >>confdefs.h else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext # Look for prctl(PR_SET_NAME). ac_fn_check_decl "$LINENO" "PR_SET_NAME" "ac_cv_have_decl_PR_SET_NAME" "#include " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_PR_SET_NAME" = xyes then : printf "%s\n" "#define HAVE_PR_SET_NAME 1" >>confdefs.h fi if test "x$ac_cv_header_sha2_h" = xyes || \ test "x$ac_cv_header_sha256_h" = xyes; then HAVE_SHA2_TRUE= HAVE_SHA2_FALSE='#' else HAVE_SHA2_TRUE='#' HAVE_SHA2_FALSE= fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether getopt has optreset support" >&5 printf %s "checking whether getopt has optreset support... " >&6; } if test ${ac_cv_have_getopt_optreset+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { extern int optreset; optreset = 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_have_getopt_optreset="yes" else $as_nop ac_cv_have_getopt_optreset="no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_getopt_optreset" >&5 printf "%s\n" "$ac_cv_have_getopt_optreset" >&6; } if test "x$ac_cv_have_getopt_optreset" = "xyes"; then HAVE_GETOPT_TRUE= HAVE_GETOPT_FALSE='#' else HAVE_GETOPT_TRUE='#' HAVE_GETOPT_FALSE= fi if test "x$ac_cv_have_getopt_optreset" = "xyes" ; then printf "%s\n" "#define HAVE_GETOPT_OPTRESET 1" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct pollfd" "fd" "ac_cv_member_struct_pollfd_fd" " #include #ifdef HAVE_POLL_H #include #endif #ifdef HAVE_SYS_POLL_H #include #endif " if test "x$ac_cv_member_struct_pollfd_fd" = xyes then : printf "%s\n" "#define HAVE_STRUCT_POLLFD_FD 1" >>confdefs.h fi # Checks for typ edefs, structures, and compiler characteristics. ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default" if test "x$ac_cv_type__Bool" = xyes then : printf "%s\n" "#define HAVE__BOOL 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5 printf %s "checking for stdbool.h that conforms to C99... " >&6; } if test ${ac_cv_header_stdbool_h+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifndef __bool_true_false_are_defined #error "__bool_true_false_are_defined is not defined" #endif char a[__bool_true_false_are_defined == 1 ? 1 : -1]; /* Regardless of whether this is C++ or "_Bool" is a valid type name, "true" and "false" should be usable in #if expressions and integer constant expressions, and "bool" should be a valid type name. */ #if !true #error "'true' is not true" #endif #if true != 1 #error "'true' is not equal to 1" #endif char b[true == 1 ? 1 : -1]; char c[true]; #if false #error "'false' is not false" #endif #if false != 0 #error "'false' is not equal to 0" #endif char d[false == 0 ? 1 : -1]; enum { e = false, f = true, g = false * true, h = true * 256 }; char i[(bool) 0.5 == true ? 1 : -1]; char j[(bool) 0.0 == false ? 1 : -1]; char k[sizeof (bool) > 0 ? 1 : -1]; struct sb { bool s: 1; bool t; } s; char l[sizeof s.t > 0 ? 1 : -1]; /* The following fails for HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */ bool m[h]; char n[sizeof m == h * sizeof m[0] ? 1 : -1]; char o[-1 - (bool) 0 < 0 ? 1 : -1]; /* Catch a bug in an HP-UX C compiler. See https://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html https://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html */ bool p = true; bool *pp = &p; /* C 1999 specifies that bool, true, and false are to be macros, but C++ 2011 and later overrule this. */ #if __cplusplus < 201103 #ifndef bool #error "bool is not defined" #endif #ifndef false #error "false is not defined" #endif #ifndef true #error "true is not defined" #endif #endif /* If _Bool is available, repeat with it all the tests above that used bool. */ #ifdef HAVE__BOOL struct sB { _Bool s: 1; _Bool t; } t; char q[(_Bool) 0.5 == true ? 1 : -1]; char r[(_Bool) 0.0 == false ? 1 : -1]; char u[sizeof (_Bool) > 0 ? 1 : -1]; char v[sizeof t.t > 0 ? 1 : -1]; _Bool w[h]; char x[sizeof m == h * sizeof m[0] ? 1 : -1]; char y[-1 - (_Bool) 0 < 0 ? 1 : -1]; _Bool z = true; _Bool *pz = &p; #endif int main (void) { bool ps = &s; *pp |= p; *pp |= ! p; #ifdef HAVE__BOOL _Bool pt = &t; *pz |= z; *pz |= ! z; #endif /* Refer to every declared value, so they cannot be discarded as unused. */ return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !j + !k + !l + !m + !n + !o + !p + !pp + !ps #ifdef HAVE__BOOL + !q + !r + !u + !v + !w + !x + !y + !z + !pt #endif ); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_header_stdbool_h=yes else $as_nop ac_cv_header_stdbool_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5 printf "%s\n" "$ac_cv_header_stdbool_h" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 printf %s "checking for inline... " >&6; } if test ${ac_cv_c_inline+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __cplusplus typedef int foo_t; static $ac_kw foo_t static_foo (void) {return 0; } $ac_kw foo_t foo (void) {return 0; } #endif _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_inline=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext test "$ac_cv_c_inline" != no && break done fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 printf "%s\n" "$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; *) case $ac_cv_c_inline in no) ac_val=;; *) ac_val=$ac_cv_c_inline;; esac cat >>confdefs.h <<_ACEOF #ifndef __cplusplus #define inline $ac_val #endif _ACEOF ;; esac ac_fn_c_find_intX_t "$LINENO" "64" "ac_cv_c_int64_t" case $ac_cv_c_int64_t in #( no|yes) ;; #( *) printf "%s\n" "#define int64_t $ac_cv_c_int64_t" >>confdefs.h ;; esac ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" if test "x$ac_cv_type_mode_t" = xyes then : else $as_nop printf "%s\n" "#define mode_t int" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" if test "x$ac_cv_type_off_t" = xyes then : else $as_nop printf "%s\n" "#define off_t long int" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default " if test "x$ac_cv_type_pid_t" = xyes then : else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined _WIN64 && !defined __CYGWIN__ LLP64 #endif int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_pid_type='int' else $as_nop ac_pid_type='__int64' fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext printf "%s\n" "#define pid_t $ac_pid_type" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes then : else $as_nop printf "%s\n" "#define size_t unsigned int" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" if test "x$ac_cv_type_ssize_t" = xyes then : else $as_nop printf "%s\n" "#define ssize_t int" >>confdefs.h fi ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t" case $ac_cv_c_uint16_t in #( no|yes) ;; #( *) printf "%s\n" "#define uint16_t $ac_cv_c_uint16_t" >>confdefs.h ;; esac ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t" case $ac_cv_c_uint32_t in #( no|yes) ;; #( *) printf "%s\n" "#define _UINT32_T 1" >>confdefs.h printf "%s\n" "#define uint32_t $ac_cv_c_uint32_t" >>confdefs.h ;; esac ac_fn_c_find_uintX_t "$LINENO" "64" "ac_cv_c_uint64_t" case $ac_cv_c_uint64_t in #( no|yes) ;; #( *) printf "%s\n" "#define _UINT64_T 1" >>confdefs.h printf "%s\n" "#define uint64_t $ac_cv_c_uint64_t" >>confdefs.h ;; esac ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t" case $ac_cv_c_uint8_t in #( no|yes) ;; #( *) printf "%s\n" "#define _UINT8_T 1" >>confdefs.h printf "%s\n" "#define uint8_t $ac_cv_c_uint8_t" >>confdefs.h ;; esac # Check for ifgroupreq which is only available on BSD. ac_fn_c_check_type "$LINENO" "struct ifgroupreq" "ac_cv_type_struct_ifgroupreq" "$ac_includes_default" if test "x$ac_cv_type_struct_ifgroupreq" = xyes then : printf "%s\n" "#define HAVE_STRUCT_IFGROUPREQ 1" >>confdefs.h fi # Check for sockaddr_storage. On some systems, ss_len is filled out, although # this is not mandated by POSIX, and hence systems such as linux, don't have # it. ac_fn_c_check_type "$LINENO" "struct sockaddr_storage" "ac_cv_type_struct_sockaddr_storage" " #include #include " if test "x$ac_cv_type_struct_sockaddr_storage" = xyes then : printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_STORAGE 1" >>confdefs.h fi # Same thing as sockaddr_storage above, only now check if the member exists in # the struct as well. ac_fn_c_check_member "$LINENO" "struct sockaddr_storage" "ss_len" "ac_cv_member_struct_sockaddr_storage_ss_len" " #include #include #include " if test "x$ac_cv_member_struct_sockaddr_storage_ss_len" = xyes then : printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN 1" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct sockaddr" "sa_len" "ac_cv_member_struct_sockaddr_sa_len" " #include #include #include " if test "x$ac_cv_member_struct_sockaddr_sa_len" = xyes then : printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_SA_LEN 1" >>confdefs.h fi # Both checks above will result in: # # HAVE_STRUCT_SOCKADDR_AS_LEN # SS_LEN # # Either being defined or not. # Look for library needed for flock. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing flock" >&5 printf %s "checking for library containing flock... " >&6; } if test ${ac_cv_search_flock+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char flock (); int main (void) { return flock (); ; return 0; } _ACEOF for ac_lib in '' bsd do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_flock=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_flock+y} then : break fi done if test ${ac_cv_search_flock+y} then : else $as_nop ac_cv_search_flock=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_flock" >&5 printf "%s\n" "$ac_cv_search_flock" >&6; } ac_res=$ac_cv_search_flock if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi # Checks for library functions. ac_func= for ac_item in $ac_func_c_list do if test $ac_func; then ac_fn_c_check_func "$LINENO" $ac_func ac_cv_func_$ac_func if eval test \"x\$ac_cv_func_$ac_func\" = xyes; then echo "#define $ac_item 1" >> confdefs.h fi ac_func= else ac_func=$ac_item fi done if test "x$ac_cv_func_fork" = xyes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5 printf %s "checking for working fork... " >&6; } if test ${ac_cv_func_fork_works+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : ac_cv_func_fork_works=cross else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { /* By Ruediger Kuhlmann. */ return fork () < 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_fork_works=yes else $as_nop ac_cv_func_fork_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5 printf "%s\n" "$ac_cv_func_fork_works" >&6; } else ac_cv_func_fork_works=$ac_cv_func_fork fi if test "x$ac_cv_func_fork_works" = xcross; then case $host in *-*-amigaos* | *-*-msdosdjgpp*) # Override, as these systems have only a dummy fork() stub ac_cv_func_fork_works=no ;; *) ac_cv_func_fork_works=yes ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 printf "%s\n" "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} fi ac_cv_func_vfork_works=$ac_cv_func_vfork if test "x$ac_cv_func_vfork" = xyes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5 printf %s "checking for working vfork... " >&6; } if test ${ac_cv_func_vfork_works+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : ac_cv_func_vfork_works=cross else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Thanks to Paul Eggert for this test. */ $ac_includes_default #include #include #ifdef HAVE_VFORK_H # include #endif static void do_nothing (int sig) { (void) sig; } /* On some sparc systems, changes by the child to local and incoming argument registers are propagated back to the parent. The compiler is told about this with #include , but some compilers (e.g. gcc -O) don't grok . Test for this by using a static variable whose address is put into a register that is clobbered by the vfork. */ static void sparc_address_test (int arg) { static pid_t child; if (!child) { child = vfork (); if (child < 0) { perror ("vfork"); _exit(2); } if (!child) { arg = getpid(); write(-1, "", 0); _exit (arg); } } } int main (void) { pid_t parent = getpid (); pid_t child; sparc_address_test (0); /* On Solaris 2.4, changes by the child to the signal handler also munge signal handlers in the parent. To detect this, start by putting the parent's handler in a known state. */ signal (SIGTERM, SIG_DFL); child = vfork (); if (child == 0) { /* Here is another test for sparc vfork register problems. This test uses lots of local variables, at least as many local variables as main has allocated so far including compiler temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should reuse the register of parent for one of the local variables, since it will think that parent can't possibly be used any more in this routine. Assigning to the local variable will thus munge parent in the parent process. */ pid_t p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); /* Convince the compiler that p..p7 are live; otherwise, it might use the same hardware register for all 8 local variables. */ if (p != p1 || p != p2 || p != p3 || p != p4 || p != p5 || p != p6 || p != p7) _exit(1); /* Alter the child's signal handler. */ if (signal (SIGTERM, do_nothing) != SIG_DFL) _exit(1); /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent from child file descriptors. If the child closes a descriptor before it execs or exits, this munges the parent's descriptor as well. Test for this by closing stdout in the child. */ _exit(close(fileno(stdout)) != 0); } else { int status; struct stat st; while (wait(&status) != child) ; return ( /* Was there some problem with vforking? */ child < 0 /* Did the child munge the parent's signal handler? */ || signal (SIGTERM, SIG_DFL) != SIG_DFL /* Did the child fail? (This shouldn't happen.) */ || status /* Did the vfork/compiler bug occur? */ || parent != getpid() /* Did the file descriptor bug occur? */ || fstat(fileno(stdout), &st) != 0 ); } } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_vfork_works=yes else $as_nop ac_cv_func_vfork_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5 printf "%s\n" "$ac_cv_func_vfork_works" >&6; } fi; if test "x$ac_cv_func_fork_works" = xcross; then ac_cv_func_vfork_works=$ac_cv_func_vfork { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 printf "%s\n" "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} fi if test "x$ac_cv_func_vfork_works" = xyes; then printf "%s\n" "#define HAVE_WORKING_VFORK 1" >>confdefs.h else printf "%s\n" "#define vfork fork" >>confdefs.h fi if test "x$ac_cv_func_fork_works" = xyes; then printf "%s\n" "#define HAVE_WORKING_FORK 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _LARGEFILE_SOURCE value needed for large files" >&5 printf %s "checking for _LARGEFILE_SOURCE value needed for large files... " >&6; } if test ${ac_cv_sys_largefile_source+y} then : printf %s "(cached) " >&6 else $as_nop while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* for off_t */ #include int main (void) { int (*fp) (FILE *, off_t, int) = fseeko; return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_sys_largefile_source=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGEFILE_SOURCE 1 #include /* for off_t */ #include int main (void) { int (*fp) (FILE *, off_t, int) = fseeko; return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_sys_largefile_source=1; break fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext ac_cv_sys_largefile_source=unknown break done fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_source" >&5 printf "%s\n" "$ac_cv_sys_largefile_source" >&6; } case $ac_cv_sys_largefile_source in #( no | unknown) ;; *) printf "%s\n" "#define _LARGEFILE_SOURCE $ac_cv_sys_largefile_source" >>confdefs.h ;; esac rm -rf conftest* # We used to try defining _XOPEN_SOURCE=500 too, to work around a bug # in glibc 2.1.3, but that breaks too many other things. # If you want fseeko and ftello with glibc, upgrade to a fixed glibc. if test $ac_cv_sys_largefile_source != unknown; then printf "%s\n" "#define HAVE_FSEEKO 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether lstat correctly handles trailing slash" >&5 printf %s "checking whether lstat correctly handles trailing slash... " >&6; } if test ${ac_cv_func_lstat_dereferences_slashed_symlink+y} then : printf %s "(cached) " >&6 else $as_nop rm -f conftest.sym conftest.file echo >conftest.file if test "$as_ln_s" = "ln -s" && ln -s conftest.file conftest.sym; then if test "$cross_compiling" = yes then : case "$host_os" in # (( # Guess yes on glibc systems. *-gnu*) ac_cv_func_lstat_dereferences_slashed_symlink=yes ;; # If we don't know, assume the worst. *) ac_cv_func_lstat_dereferences_slashed_symlink=no ;; esac else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { struct stat sbuf; /* Linux will dereference the symlink and fail, as required by POSIX. That is better in the sense that it means we will not have to compile and use the lstat wrapper. */ return lstat ("conftest.sym/", &sbuf) == 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_lstat_dereferences_slashed_symlink=yes else $as_nop ac_cv_func_lstat_dereferences_slashed_symlink=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi else # If the `ln -s' command failed, then we probably don't even # have an lstat function. ac_cv_func_lstat_dereferences_slashed_symlink=no fi rm -f conftest.sym conftest.file fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_lstat_dereferences_slashed_symlink" >&5 printf "%s\n" "$ac_cv_func_lstat_dereferences_slashed_symlink" >&6; } test $ac_cv_func_lstat_dereferences_slashed_symlink = yes && printf "%s\n" "#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1" >>confdefs.h if test "x$ac_cv_func_lstat_dereferences_slashed_symlink" = xno; then case " $LIBOBJS " in *" lstat.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS lstat.$ac_objext" ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 printf %s "checking for GNU libc compatible malloc... " >&6; } if test ${ac_cv_func_malloc_0_nonnull+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : case "$host_os" in # (( # Guess yes on platforms where we know the result. *-gnu* | freebsd* | netbsd* | openbsd* | bitrig* \ | hpux* | solaris* | cygwin* | mingw* | msys* ) ac_cv_func_malloc_0_nonnull=yes ;; # If we don't know, assume the worst. *) ac_cv_func_malloc_0_nonnull=no ;; esac else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { void *p = malloc (0); int result = !p; free (p); return result; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_malloc_0_nonnull=yes else $as_nop ac_cv_func_malloc_0_nonnull=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 printf "%s\n" "$ac_cv_func_malloc_0_nonnull" >&6; } if test $ac_cv_func_malloc_0_nonnull = yes then : printf "%s\n" "#define HAVE_MALLOC 1" >>confdefs.h else $as_nop printf "%s\n" "#define HAVE_MALLOC 0" >>confdefs.h case " $LIBOBJS " in *" malloc.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS malloc.$ac_objext" ;; esac printf "%s\n" "#define malloc rpl_malloc" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working mmap" >&5 printf %s "checking for working mmap... " >&6; } if test ${ac_cv_func_mmap_fixed_mapped+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : case "$host_os" in # (( # Guess yes on platforms where we know the result. linux*) ac_cv_func_mmap_fixed_mapped=yes ;; # If we don't know, assume the worst. *) ac_cv_func_mmap_fixed_mapped=no ;; esac else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default /* malloc might have been renamed as rpl_malloc. */ #undef malloc /* Thanks to Mike Haertel and Jim Avera for this test. Here is a matrix of mmap possibilities: mmap private not fixed mmap private fixed at somewhere currently unmapped mmap private fixed at somewhere already mapped mmap shared not fixed mmap shared fixed at somewhere currently unmapped mmap shared fixed at somewhere already mapped For private mappings, we should verify that changes cannot be read() back from the file, nor mmap's back from the file at a different address. (There have been systems where private was not correctly implemented like the infamous i386 svr4.0, and systems where the VM page cache was not coherent with the file system buffer cache like early versions of FreeBSD and possibly contemporary NetBSD.) For shared mappings, we should conversely verify that changes get propagated back to all the places they're supposed to be. Grep wants private fixed already mapped. The main things grep needs to know about mmap are: * does it exist and is it safe to write into the mmap'd area * how to use it (BSD variants) */ #include #include /* This mess was copied from the GNU getpagesize.h. */ #ifndef HAVE_GETPAGESIZE # ifdef _SC_PAGESIZE # define getpagesize() sysconf(_SC_PAGESIZE) # else /* no _SC_PAGESIZE */ # ifdef HAVE_SYS_PARAM_H # include # ifdef EXEC_PAGESIZE # define getpagesize() EXEC_PAGESIZE # else /* no EXEC_PAGESIZE */ # ifdef NBPG # define getpagesize() NBPG * CLSIZE # ifndef CLSIZE # define CLSIZE 1 # endif /* no CLSIZE */ # else /* no NBPG */ # ifdef NBPC # define getpagesize() NBPC # else /* no NBPC */ # ifdef PAGESIZE # define getpagesize() PAGESIZE # endif /* PAGESIZE */ # endif /* no NBPC */ # endif /* no NBPG */ # endif /* no EXEC_PAGESIZE */ # else /* no HAVE_SYS_PARAM_H */ # define getpagesize() 8192 /* punt totally */ # endif /* no HAVE_SYS_PARAM_H */ # endif /* no _SC_PAGESIZE */ #endif /* no HAVE_GETPAGESIZE */ int main (void) { char *data, *data2, *data3; const char *cdata2; int i, pagesize; int fd, fd2; pagesize = getpagesize (); /* First, make a file with some known garbage in it. */ data = (char *) malloc (pagesize); if (!data) return 1; for (i = 0; i < pagesize; ++i) *(data + i) = rand (); umask (0); fd = creat ("conftest.mmap", 0600); if (fd < 0) return 2; if (write (fd, data, pagesize) != pagesize) return 3; close (fd); /* Next, check that the tail of a page is zero-filled. File must have non-zero length, otherwise we risk SIGBUS for entire page. */ fd2 = open ("conftest.txt", O_RDWR | O_CREAT | O_TRUNC, 0600); if (fd2 < 0) return 4; cdata2 = ""; if (write (fd2, cdata2, 1) != 1) return 5; data2 = (char *) mmap (0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, 0L); if (data2 == MAP_FAILED) return 6; for (i = 0; i < pagesize; ++i) if (*(data2 + i)) return 7; close (fd2); if (munmap (data2, pagesize)) return 8; /* Next, try to mmap the file at a fixed address which already has something else allocated at it. If we can, also make sure that we see the same garbage. */ fd = open ("conftest.mmap", O_RDWR); if (fd < 0) return 9; if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fd, 0L)) return 10; for (i = 0; i < pagesize; ++i) if (*(data + i) != *(data2 + i)) return 11; /* Finally, make sure that changes to the mapped area do not percolate back to the file as seen by read(). (This is a bug on some variants of i386 svr4.0.) */ for (i = 0; i < pagesize; ++i) *(data2 + i) = *(data2 + i) + 1; data3 = (char *) malloc (pagesize); if (!data3) return 12; if (read (fd, data3, pagesize) != pagesize) return 13; for (i = 0; i < pagesize; ++i) if (*(data + i) != *(data3 + i)) return 14; close (fd); free (data); free (data3); return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_mmap_fixed_mapped=yes else $as_nop ac_cv_func_mmap_fixed_mapped=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mmap_fixed_mapped" >&5 printf "%s\n" "$ac_cv_func_mmap_fixed_mapped" >&6; } if test $ac_cv_func_mmap_fixed_mapped = yes; then printf "%s\n" "#define HAVE_MMAP 1" >>confdefs.h fi rm -f conftest.mmap conftest.txt { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible realloc" >&5 printf %s "checking for GNU libc compatible realloc... " >&6; } if test ${ac_cv_func_realloc_0_nonnull+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : case "$host_os" in # (( # Guess yes on platforms where we know the result. *-gnu* | freebsd* | netbsd* | openbsd* | bitrig* \ | hpux* | solaris* | cygwin* | mingw* | msys* ) ac_cv_func_realloc_0_nonnull=yes ;; # If we don't know, assume the worst. *) ac_cv_func_realloc_0_nonnull=no ;; esac else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { void *p = realloc (0, 0); int result = !p; free (p); return result; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_realloc_0_nonnull=yes else $as_nop ac_cv_func_realloc_0_nonnull=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_realloc_0_nonnull" >&5 printf "%s\n" "$ac_cv_func_realloc_0_nonnull" >&6; } if test $ac_cv_func_realloc_0_nonnull = yes then : printf "%s\n" "#define HAVE_REALLOC 1" >>confdefs.h else $as_nop printf "%s\n" "#define HAVE_REALLOC 0" >>confdefs.h case " $LIBOBJS " in *" realloc.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS realloc.$ac_objext" ;; esac printf "%s\n" "#define realloc rpl_realloc" >>confdefs.h fi ac_fn_check_decl "$LINENO" "strerror_r" "ac_cv_have_decl_strerror_r" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_strerror_r" = xyes then : ac_have_decl=1 else $as_nop ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_STRERROR_R $ac_have_decl" >>confdefs.h if test $ac_cv_have_decl_strerror_r = yes; then # For backward compatibility's sake, define HAVE_STRERROR_R. # (We used to run AC_CHECK_FUNCS_ONCE for strerror_r, as well # as AC_CHECK_DECLS_ONCE.) printf "%s\n" "#define HAVE_STRERROR_R 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether strerror_r returns char *" >&5 printf %s "checking whether strerror_r returns char *... " >&6; } if test ${ac_cv_func_strerror_r_char_p+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_func_strerror_r_char_p=no if test $ac_cv_have_decl_strerror_r = yes; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { char buf[100]; char x = *strerror_r (0, buf, sizeof buf); char *p = strerror_r (0, buf, sizeof buf); return !p || x; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_func_strerror_r_char_p=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strerror_r_char_p" >&5 printf "%s\n" "$ac_cv_func_strerror_r_char_p" >&6; } if test $ac_cv_func_strerror_r_char_p = yes; then printf "%s\n" "#define STRERROR_R_CHAR_P 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working strnlen" >&5 printf %s "checking for working strnlen... " >&6; } if test ${ac_cv_func_strnlen_working+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : # Guess no on AIX systems, yes otherwise. case "$host_os" in aix*) ac_cv_func_strnlen_working=no;; *) ac_cv_func_strnlen_working=yes;; esac else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { #define S "foobar" #define S_LEN (sizeof S - 1) /* At least one implementation is buggy: that of AIX 4.3 would give strnlen (S, 1) == 3. */ int i; for (i = 0; i < S_LEN + 1; ++i) { int expected = i <= S_LEN ? i : S_LEN; if (strnlen (S, i) != expected) return 1; } return 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_strnlen_working=yes else $as_nop ac_cv_func_strnlen_working=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strnlen_working" >&5 printf "%s\n" "$ac_cv_func_strnlen_working" >&6; } test $ac_cv_func_strnlen_working = no && case " $LIBOBJS " in *" strnlen.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strnlen.$ac_objext" ;; esac ac_fn_c_check_func "$LINENO" "dup2" "ac_cv_func_dup2" if test "x$ac_cv_func_dup2" = xyes then : printf "%s\n" "#define HAVE_DUP2 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "flock" "ac_cv_func_flock" if test "x$ac_cv_func_flock" = xyes then : printf "%s\n" "#define HAVE_FLOCK 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "getcwd" "ac_cv_func_getcwd" if test "x$ac_cv_func_getcwd" = xyes then : printf "%s\n" "#define HAVE_GETCWD 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "localtime_r" "ac_cv_func_localtime_r" if test "x$ac_cv_func_localtime_r" = xyes then : printf "%s\n" "#define HAVE_LOCALTIME_R 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "memchr" "ac_cv_func_memchr" if test "x$ac_cv_func_memchr" = xyes then : printf "%s\n" "#define HAVE_MEMCHR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "memmove" "ac_cv_func_memmove" if test "x$ac_cv_func_memmove" = xyes then : printf "%s\n" "#define HAVE_MEMMOVE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "memset" "ac_cv_func_memset" if test "x$ac_cv_func_memset" = xyes then : printf "%s\n" "#define HAVE_MEMSET 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "mergesort" "ac_cv_func_mergesort" if test "x$ac_cv_func_mergesort" = xyes then : printf "%s\n" "#define HAVE_MERGESORT 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "mkdir" "ac_cv_func_mkdir" if test "x$ac_cv_func_mkdir" = xyes then : printf "%s\n" "#define HAVE_MKDIR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "munmap" "ac_cv_func_munmap" if test "x$ac_cv_func_munmap" = xyes then : printf "%s\n" "#define HAVE_MUNMAP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "nl_langinfo" "ac_cv_func_nl_langinfo" if test "x$ac_cv_func_nl_langinfo" = xyes then : printf "%s\n" "#define HAVE_NL_LANGINFO 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "realpath" "ac_cv_func_realpath" if test "x$ac_cv_func_realpath" = xyes then : printf "%s\n" "#define HAVE_REALPATH 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "regcomp" "ac_cv_func_regcomp" if test "x$ac_cv_func_regcomp" = xyes then : printf "%s\n" "#define HAVE_REGCOMP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "rmdir" "ac_cv_func_rmdir" if test "x$ac_cv_func_rmdir" = xyes then : printf "%s\n" "#define HAVE_RMDIR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setlocale" "ac_cv_func_setlocale" if test "x$ac_cv_func_setlocale" = xyes then : printf "%s\n" "#define HAVE_SETLOCALE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "socket" "ac_cv_func_socket" if test "x$ac_cv_func_socket" = xyes then : printf "%s\n" "#define HAVE_SOCKET 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setresgid" "ac_cv_func_setresgid" if test "x$ac_cv_func_setresgid" = xyes then : printf "%s\n" "#define HAVE_SETRESGID 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setresuid" "ac_cv_func_setresuid" if test "x$ac_cv_func_setresuid" = xyes then : printf "%s\n" "#define HAVE_SETRESUID 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setproctitle" "ac_cv_func_setproctitle" if test "x$ac_cv_func_setproctitle" = xyes then : printf "%s\n" "#define HAVE_SETPROCTITLE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strcasecmp" "ac_cv_func_strcasecmp" if test "x$ac_cv_func_strcasecmp" = xyes then : printf "%s\n" "#define HAVE_STRCASECMP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strchr" "ac_cv_func_strchr" if test "x$ac_cv_func_strchr" = xyes then : printf "%s\n" "#define HAVE_STRCHR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strcspn" "ac_cv_func_strcspn" if test "x$ac_cv_func_strcspn" = xyes then : printf "%s\n" "#define HAVE_STRCSPN 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strdup" "ac_cv_func_strdup" if test "x$ac_cv_func_strdup" = xyes then : printf "%s\n" "#define HAVE_STRDUP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strerror" "ac_cv_func_strerror" if test "x$ac_cv_func_strerror" = xyes then : printf "%s\n" "#define HAVE_STRERROR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strncasecmp" "ac_cv_func_strncasecmp" if test "x$ac_cv_func_strncasecmp" = xyes then : printf "%s\n" "#define HAVE_STRNCASECMP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strndup" "ac_cv_func_strndup" if test "x$ac_cv_func_strndup" = xyes then : printf "%s\n" "#define HAVE_STRNDUP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strrchr" "ac_cv_func_strrchr" if test "x$ac_cv_func_strrchr" = xyes then : printf "%s\n" "#define HAVE_STRRCHR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strspn" "ac_cv_func_strspn" if test "x$ac_cv_func_strspn" = xyes then : printf "%s\n" "#define HAVE_STRSPN 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strstr" "ac_cv_func_strstr" if test "x$ac_cv_func_strstr" = xyes then : printf "%s\n" "#define HAVE_STRSTR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strtol" "ac_cv_func_strtol" if test "x$ac_cv_func_strtol" = xyes then : printf "%s\n" "#define HAVE_STRTOL 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strtoul" "ac_cv_func_strtoul" if test "x$ac_cv_func_strtoul" = xyes then : printf "%s\n" "#define HAVE_STRTOUL 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "sysconf" "ac_cv_func_sysconf" if test "x$ac_cv_func_sysconf" = xyes then : printf "%s\n" "#define HAVE_SYSCONF 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "wcwidth" "ac_cv_func_wcwidth" if test "x$ac_cv_func_wcwidth" = xyes then : printf "%s\n" "#define HAVE_WCWIDTH 1" >>confdefs.h fi if test "x$ac_cv_func_setproctitle" = xyes; then HAVE_SETPROCTITLE_TRUE= HAVE_SETPROCTITLE_FALSE='#' else HAVE_SETPROCTITLE_TRUE='#' HAVE_SETPROCTITLE_FALSE= fi if test "x$ac_cv_func_sysconf" = xyes; then printf "%s\n" "#define HAVE_SYSCONF 1" >>confdefs.h fi # Siphash support. ac_fn_c_check_func "$LINENO" "SipHash" "ac_cv_func_SipHash" if test "x$ac_cv_func_SipHash" = xyes then : printf "%s\n" "#define HAVE_SIPHASH 1" >>confdefs.h fi if test "x$ac_cv_func_SipHash" = xyes; then HAVE_SIPHASH_TRUE= HAVE_SIPHASH_FALSE='#' else HAVE_SIPHASH_TRUE='#' HAVE_SIPHASH_FALSE= fi # Check for functions with a compatibility implementation. ac_fn_c_check_func "$LINENO" "asprintf" "ac_cv_func_asprintf" if test "x$ac_cv_func_asprintf" = xyes then : printf "%s\n" "#define HAVE_ASPRINTF 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" asprintf.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS asprintf.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "closefrom" "ac_cv_func_closefrom" if test "x$ac_cv_func_closefrom" = xyes then : printf "%s\n" "#define HAVE_CLOSEFROM 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" closefrom.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS closefrom.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero" if test "x$ac_cv_func_explicit_bzero" = xyes then : printf "%s\n" "#define HAVE_EXPLICIT_BZERO 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" explicit_bzero.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS explicit_bzero.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "fmt_scaled" "ac_cv_func_fmt_scaled" if test "x$ac_cv_func_fmt_scaled" = xyes then : printf "%s\n" "#define HAVE_FMT_SCALED 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" fmt_scaled.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS fmt_scaled.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "freezero" "ac_cv_func_freezero" if test "x$ac_cv_func_freezero" = xyes then : printf "%s\n" "#define HAVE_FREEZERO 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" freezero.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS freezero.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "getdtablecount" "ac_cv_func_getdtablecount" if test "x$ac_cv_func_getdtablecount" = xyes then : printf "%s\n" "#define HAVE_GETDTABLECOUNT 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" getdtablecount.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS getdtablecount.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "getline" "ac_cv_func_getline" if test "x$ac_cv_func_getline" = xyes then : printf "%s\n" "#define HAVE_GETLINE 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" getline.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS getline.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "getprogname" "ac_cv_func_getprogname" if test "x$ac_cv_func_getprogname" = xyes then : printf "%s\n" "#define HAVE_GETPROGNAME 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" getprogname.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS getprogname.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "recallocarray" "ac_cv_func_recallocarray" if test "x$ac_cv_func_recallocarray" = xyes then : printf "%s\n" "#define HAVE_RECALLOCARRAY 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" recallocarray.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS recallocarray.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "reallocarray" "ac_cv_func_reallocarray" if test "x$ac_cv_func_reallocarray" = xyes then : printf "%s\n" "#define HAVE_REALLOCARRAY 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" reallocarray.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS reallocarray.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat" if test "x$ac_cv_func_strlcat" = xyes then : printf "%s\n" "#define HAVE_STRLCAT 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" strlcat.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strlcat.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy" if test "x$ac_cv_func_strlcpy" = xyes then : printf "%s\n" "#define HAVE_STRLCPY 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" strlcpy.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strlcpy.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "strndup" "ac_cv_func_strndup" if test "x$ac_cv_func_strndup" = xyes then : printf "%s\n" "#define HAVE_STRNDUP 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" strndup.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strndup.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "strnlen" "ac_cv_func_strnlen" if test "x$ac_cv_func_strnlen" = xyes then : printf "%s\n" "#define HAVE_STRNLEN 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" strnlen.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strnlen.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "strsep" "ac_cv_func_strsep" if test "x$ac_cv_func_strsep" = xyes then : printf "%s\n" "#define HAVE_STRSEP 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" strsep.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strsep.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "strtonum" "ac_cv_func_strtonum" if test "x$ac_cv_func_strtonum" = xyes then : printf "%s\n" "#define HAVE_STRTONUM 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" strtonum.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strtonum.$ac_objext" ;; esac fi if test "x$ac_cv_func_closefrom" = xyes; then HAVE_CLOSEFROM_TRUE= HAVE_CLOSEFROM_FALSE='#' else HAVE_CLOSEFROM_TRUE='#' HAVE_CLOSEFROM_FALSE= fi # Always use our getopt because 1) glibc's doesn't enforce argument order 2) # musl does not set optarg to NULL for flags without arguments (although it is # not required to, but it is helpful) 3) there are probably other weird # implementations. case " $LIBOBJS " in *" getopt.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS getopt.$ac_objext" ;; esac # Check for b64_ntop. If we have b64_ntop, we assume b64_pton as well. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for b64_ntop" >&5 printf %s "checking for b64_ntop... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main (void) { b64_ntop(NULL, 0, NULL, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : found_b64_ntop=yes else $as_nop found_b64_ntop=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $found_b64_ntop" >&5 printf "%s\n" "$found_b64_ntop" >&6; } libresolv_LIBS="" if test "x$found_b64_ntop" = xno; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for b64_ntop with -lresolv" >&5 printf %s "checking for b64_ntop with -lresolv... " >&6; } LIBS="-lresolv" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main (void) { b64_ntop(NULL, 0, NULL, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : found_b64_ntop=yes else $as_nop found_b64_ntop=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $found_b64_ntop" >&5 printf "%s\n" "$found_b64_ntop" >&6; } libresolv_LIBS="$LIBS" fi if test "x$found_b64_ntop" = xno; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for b64_ntop with -lnetwork" >&5 printf %s "checking for b64_ntop with -lnetwork... " >&6; } LIBS="-lresolv -lnetwork" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main (void) { b64_ntop(NULL, 0, NULL, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : found_b64_ntop=yes else $as_nop found_b64_ntop=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $found_b64_ntop" >&5 printf "%s\n" "$found_b64_ntop" >&6; } libresolv_LIBS="$LIBS" fi if test "x$found_b64_ntop" = xyes; then HAVE_B64_TRUE= HAVE_B64_FALSE='#' else HAVE_B64_TRUE='#' HAVE_B64_FALSE= fi if test "x$found_b64_ntop" = xyes; then printf "%s\n" "#define HAVE_B64_NTOP 1" >>confdefs.h else case " $LIBOBJS " in *" base64.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS base64.$ac_objext" ;; esac fi # Check the platform we're compiling on. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking platform" >&5 printf %s "checking platform... " >&6; } case "$host_os" in *linux*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: linux" >&5 printf "%s\n" "linux" >&6; } PLATFORM=linux ;; *freebsd*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: freebsd" >&5 printf "%s\n" "freebsd" >&6; } PLATFORM=freebsd ;; *darwin*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: darwin" >&5 printf "%s\n" "darwin" >&6; } PLATFORM=darwin ;; *netbsd*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: netbsd" >&5 printf "%s\n" "netbsd" >&6; } PLATFORM=netbsd ;; *openbsd*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: openbsd" >&5 printf "%s\n" "openbsd" >&6; } PLATFORM=openbsd ;; *dragonfly*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: dragonfly" >&5 printf "%s\n" "dragonfly" >&6; } PLATFORM=dragonflybsd ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unknown" >&5 printf "%s\n" "unknown" >&6; } PLATFORM=unknown ;; esac if test "$PLATFORM" = "freebsd"; then HOST_FREEBSD_TRUE= HOST_FREEBSD_FALSE='#' else HOST_FREEBSD_TRUE='#' HOST_FREEBSD_FALSE= fi if test "$PLATFORM" = "linux"; then HOST_LINUX_TRUE= HOST_LINUX_FALSE='#' else HOST_LINUX_TRUE='#' HOST_LINUX_FALSE= fi if test "$PLATFORM" = "darwin"; then HOST_DARWIN_TRUE= HOST_DARWIN_FALSE='#' else HOST_DARWIN_TRUE='#' HOST_DARWIN_FALSE= fi if test "$PLATFORM" = "netbsd"; then HOST_NETBSD_TRUE= HOST_NETBSD_FALSE='#' else HOST_NETBSD_TRUE='#' HOST_NETBSD_FALSE= fi if test "$PLATFORM" = "openbsd"; then HOST_OPENBSD_TRUE= HOST_OPENBSD_FALSE='#' else HOST_OPENBSD_TRUE='#' HOST_OPENBSD_FALSE= fi if test "$PLATFORM" = "dragonflybsd"; then HOST_DRAGONFLYBSD_TRUE= HOST_DRAGONFLYBSD_FALSE='#' else HOST_DRAGONFLYBSD_TRUE='#' HOST_DRAGONFLYBSD_FALSE= fi # On OpenBSD, these functions are already defined, yet looking for them in # this way on OpenBSD breaks inclusion. # FIXME: this needs addressing. if test "x$PLATFORM" != "xopenbsd"; then ac_fn_c_check_func "$LINENO" "SHA256Update" "ac_cv_func_SHA256Update" if test "x$ac_cv_func_SHA256Update" = xyes then : printf "%s\n" "#define HAVE_SHA256UPDATE 1" >>confdefs.h fi fi # Look for yacc. if test "YACC_OVERRIDE" = "yes" && test -n "$YACC" \ && ! command -v "$YACC" >/dev/null 2>&1; then as_fn_error $? "\"yacc not found: $YACC\"" "$LINENO" 5 fi if test x"$PLATFORM" = "xdarwin"; then # Check for and/or set HOMEBREW_PREFIX. brew is a common way of # installing applications. The other is MacPorts. # # Before Apple Silicon existed (M1 onward), the paths for applications # installed via homebrew was typically /usr/local. However, with M1 # onward, this changed to a different path. # # Rather than hardcode this, check for HOMEBREW_PREFIX in the # environment if it's already set, and use it. Otherwise, check for # brew(1) and use that. If that fails, default to /usr/local # # This also means that MacPorts should continue to work. # # But with MacPorts, we should also check --prefix, and use that if it # has been supplied. # # In both cases, the variable HOMEBREW_PREFIX is used for both. HB_PREFIX="" FOUND_BISON="no" GNUBISON="" if test -z "$HOMEBREW_PREFIX" -o "$HOMEBREW_PREFIX" = "NONE"; then # HOMEBREW_PREFIX not set, check for brew(1) if command -v brew >/dev/null 2>&1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \"HOMEBREW_PREFIX set via 'brew --prefix'\"" >&5 printf "%s\n" "$as_me: \"HOMEBREW_PREFIX set via 'brew --prefix'\"" >&6;} export HOMEBREW_PREFIX="$(brew --prefix)" fi if test -z "$HOMEBREW_PREFIX" -o "$HOMEBREW_PREFIX" = "NONE" then # Default. if test -z "${prefix}" -o "${prefix}" = "NONE"; then export HOMEBREW_PREFIX="/usr/local" HB_PREFIX="/usr/local" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \"HOMEBREW_PREFIX defaulting to $HB_PREFIX\"" >&5 printf "%s\n" "$as_me: \"HOMEBREW_PREFIX defaulting to $HB_PREFIX\"" >&6;} else HB_PREFIX="$(eval echo ${prefix})" if test "$HB_PREFIX" = "NONE"; then HB_PREFIX="/opt/local" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \"HOMEBREW_PREFIX using --prefix\"" >&5 printf "%s\n" "$as_me: \"HOMEBREW_PREFIX using --prefix\"" >&6;} fi export HOMEBREW_PREFIX="$HB_PREFIX" fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \"HOMEBREW_PREFIX determined as: $HOMEBREW_PREFIX\"" >&5 printf "%s\n" "$as_me: \"HOMEBREW_PREFIX determined as: $HOMEBREW_PREFIX\"" >&6;} if test "$YACC_OVERRIDE" = "no" && \ ! test -x "${HOMEBREW_PREFIX}/opt/bison/bin/bison"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: \"*********************************************************** GNU Bison not found: ${HOMEBREW_PREFIX}/opt/bison/bin/bison *********************************************************** Falling back to checking either /usr/local or \${prefix}\" " >&5 printf "%s\n" "$as_me: WARNING: \"*********************************************************** GNU Bison not found: ${HOMEBREW_PREFIX}/opt/bison/bin/bison *********************************************************** Falling back to checking either /usr/local or \${prefix}\" " >&2;} FOUND_BISON="no" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: \"Trying ${HB_PREFIX}/opt/bison/bin/bison\"" >&5 printf "%s\n" "$as_me: WARNING: \"Trying ${HB_PREFIX}/opt/bison/bin/bison\"" >&2;} if test -x "${HB_PREFIX}/opt/bison/bin/bison"; then export HOMEBREW_PREFIX="/usr/local" FOUND_BISON="yes" GNUBISON="${HB_PREFIX}/opt/bison/bin/bison" fi if test "$FOUND_BISON" = "no"; then HB_PREFIX="/opt/local" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: \"Trying ${HB_PREFIX}/bin/bison\"" >&5 printf "%s\n" "$as_me: WARNING: \"Trying ${HB_PREFIX}/bin/bison\"" >&2;} if test -x "${HB_PREFIX}/bin/bison"; then export HOMEBREW_PREFIX="${HB_PREFIX}" GNUBISON="${HB_PREFIX}/bin/bison" FOUND_BISON="yes" fi fi else FOUND_BISON="yes" GNUBISON="${HOMEBREW_PREFIX}/opt/bison/bin/bison" fi if test "$FOUND_BISON" = "no" && test "$YACC_OVERRIDE" = "no"; then as_fn_error $? "\"*** Couldn't find GNU BISON ***\"" "$LINENO" 5 fi # Override YACC here to point to the GNU version of bison. if test "$YACC_OVERRIDE" = "yes"; then export YACC="$YACC -y" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \"Found GNU Bison as: $GNUBISON\"" >&5 printf "%s\n" "$as_me: \"Found GNU Bison as: $GNUBISON\"" >&6;} export YACC="${GNUBISON} -y" fi export LDFLAGS="-L${HOMEBREW_PREFIX}/opt/ncurses/lib -L${HOMEBREW_PREFIX}/opt/openssl@3/lib $LDFLAGS" export CPPFLAGS="-I${HOMEBREW_PREFIX}/opt/ncurses/include -I${HOMEBREW_PREFIX}/opt/openssl@3/include $CPPFLAGS" export PKG_CONFIG_PATH="${HOMEBREW_PREFIX}/opt/ncurses/lib/pkgconfig" export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:${HOMEBREW_PREFIX}/opt/openssl@3/lib/pkgconfig" fi # Landlock detection. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for landlock" >&5 printf %s "checking for landlock... " >&6; } if test "x$ac_cv_header_linux_landlock_h" = "xyes"; then HAVE_LINUX_LANDLOCK_TRUE= HAVE_LINUX_LANDLOCK_FALSE='#' else HAVE_LINUX_LANDLOCK_TRUE='#' HAVE_LINUX_LANDLOCK_FALSE= fi if test "x$ac_cv_header_linux_landlock_h" = "xyes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi # Clang sanitizers wrap reallocarray even if it isn't available on the target # system. When compiled it always returns NULL and crashes the program. To # detect this we need a more complicated test. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working reallocarray" >&5 printf %s "checking for working reallocarray... " >&6; } if test "$cross_compiling" = yes then : case " $LIBOBJS " in *" reallocarray.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS reallocarray.$ac_objext" ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { return (reallocarray(NULL, 1, 1) == NULL); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else $as_nop case " $LIBOBJS " in *" reallocarray.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS reallocarray.$ac_objext" ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working recallocarray" >&5 printf %s "checking for working recallocarray... " >&6; } if test "$cross_compiling" = yes then : case " $LIBOBJS " in *" recallocarray.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS recallocarray.$ac_objext" ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { return (recallocarray(NULL, 1, 1, 1) == NULL); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else $as_nop case " $LIBOBJS " in *" recallocarray.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS recallocarray.$ac_objext" ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi # Look for imsg_init in libutil. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing imsg_init" >&5 printf %s "checking for library containing imsg_init... " >&6; } if test ${ac_cv_search_imsg_init+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char imsg_init (); int main (void) { return imsg_init (); ; return 0; } _ACEOF for ac_lib in '' util do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_imsg_init=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_imsg_init+y} then : break fi done if test ${ac_cv_search_imsg_init+y} then : else $as_nop ac_cv_search_imsg_init=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_imsg_init" >&5 printf "%s\n" "$ac_cv_search_imsg_init" >&6; } ac_res=$ac_cv_search_imsg_init if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" found_imsg_init=yes else $as_nop found_imsg_init=no fi if test "x$found_imsg_init" = "xyes"; then HAVE_IMSG_TRUE= HAVE_IMSG_FALSE='#' else HAVE_IMSG_TRUE='#' HAVE_IMSG_FALSE= fi if test "x$found_imsg_init" = "xyes"; then printf "%s\n" "#define HAVE_IMSG 1" >>confdefs.h libutil_LIBS="$ac_cv_search_imsg_init" fi # libevent (for gotwebd). Lifted from tmux. # Look for libevent. Try libevent_core or libevent with pkg-config first then # look for the library. found_libevent=no pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libevent_core >= 2" >&5 printf %s "checking for libevent_core >= 2... " >&6; } if test -n "$LIBEVENT_CORE_CFLAGS"; then pkg_cv_LIBEVENT_CORE_CFLAGS="$LIBEVENT_CORE_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libevent_core >= 2\""; } >&5 ($PKG_CONFIG --exists --print-errors "libevent_core >= 2") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBEVENT_CORE_CFLAGS=`$PKG_CONFIG --cflags "libevent_core >= 2" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBEVENT_CORE_LIBS"; then pkg_cv_LIBEVENT_CORE_LIBS="$LIBEVENT_CORE_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libevent_core >= 2\""; } >&5 ($PKG_CONFIG --exists --print-errors "libevent_core >= 2") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBEVENT_CORE_LIBS=`$PKG_CONFIG --libs "libevent_core >= 2" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBEVENT_CORE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libevent_core >= 2" 2>&1` else LIBEVENT_CORE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libevent_core >= 2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBEVENT_CORE_PKG_ERRORS" >&5 found_libevent=no elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } found_libevent=no else LIBEVENT_CORE_CFLAGS=$pkg_cv_LIBEVENT_CORE_CFLAGS LIBEVENT_CORE_LIBS=$pkg_cv_LIBEVENT_CORE_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } libevent_CFLAGS="$LIBEVENT_CORE_CFLAGS" libevent_LIBS="$LIBEVENT_CORE_LIBS" found_libevent=yes fi if test x$found_libevent = xno; then pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libevent >= 2" >&5 printf %s "checking for libevent >= 2... " >&6; } if test -n "$LIBEVENT_CFLAGS"; then pkg_cv_LIBEVENT_CFLAGS="$LIBEVENT_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libevent >= 2\""; } >&5 ($PKG_CONFIG --exists --print-errors "libevent >= 2") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBEVENT_CFLAGS=`$PKG_CONFIG --cflags "libevent >= 2" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBEVENT_LIBS"; then pkg_cv_LIBEVENT_LIBS="$LIBEVENT_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libevent >= 2\""; } >&5 ($PKG_CONFIG --exists --print-errors "libevent >= 2") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBEVENT_LIBS=`$PKG_CONFIG --libs "libevent >= 2" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBEVENT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libevent >= 2" 2>&1` else LIBEVENT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libevent >= 2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBEVENT_PKG_ERRORS" >&5 found_libevent=no elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } found_libevent=no else LIBEVENT_CFLAGS=$pkg_cv_LIBEVENT_CFLAGS LIBEVENT_LIBS=$pkg_cv_LIBEVENT_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } libevent_CFLAGS="$LIBEVENT_CFLAGS" libevent_LIBS="$LIBEVENT_LIBS" found_libevent=yes fi fi if test x$found_libevent = xno; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing event_init" >&5 printf %s "checking for library containing event_init... " >&6; } if test ${ac_cv_search_event_init+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char event_init (); int main (void) { return event_init (); ; return 0; } _ACEOF for ac_lib in '' event_core event event-1.4 do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_event_init=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_event_init+y} then : break fi done if test ${ac_cv_search_event_init+y} then : else $as_nop ac_cv_search_event_init=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_event_init" >&5 printf "%s\n" "$ac_cv_search_event_init" >&6; } ac_res=$ac_cv_search_event_init if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" found_libevent=yes else $as_nop found_libevent=no fi if test "x$found_libevent" = "xyes"; then libevent_LIBS="$ac_cv_search_event_init" fi fi if test x$found_libevent = xno; then ac_fn_c_check_header_compile "$LINENO" "event2/event.h" "ac_cv_header_event2_event_h" "$ac_includes_default" if test "x$ac_cv_header_event2_event_h" = xyes then : printf "%s\n" "#define HAVE_EVENT2_EVENT_H 1" >>confdefs.h else $as_nop ac_fn_c_check_header_compile "$LINENO" "event.h" "ac_cv_header_event_h" "$ac_includes_default" if test "x$ac_cv_header_event_h" = xyes then : printf "%s\n" "#define HAVE_EVENT_H 0" >>confdefs.h else $as_nop found_libevent=no fi fi fi if test "x$found_libevent" = xno; then as_fn_error $? "\"libevent not found\"" "$LINENO" 5 fi ac_fn_c_check_func "$LINENO" "uuid_create" "ac_cv_func_uuid_create" if test "x$ac_cv_func_uuid_create" = xyes then : found_uuid=yes else $as_nop found_uuid=no fi # Don't define HAVE_BSD_UUID on darwin (Apple) as this breaks the BSD API. # Instead, use the UUID implementation wrapper that's in compat/ plus uuid # ossp if test "x$found_uuid" = "xyes" -a "x$PLATFORM" != "darwin"; then printf "%s\n" "#define HAVE_BSD_UUID 1" >>confdefs.h else pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uuid" >&5 printf %s "checking for uuid... " >&6; } if test -n "$LIBUUID_CFLAGS"; then pkg_cv_LIBUUID_CFLAGS="$LIBUUID_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"uuid\""; } >&5 ($PKG_CONFIG --exists --print-errors "uuid") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBUUID_CFLAGS=`$PKG_CONFIG --cflags "uuid" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBUUID_LIBS"; then pkg_cv_LIBUUID_LIBS="$LIBUUID_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"uuid\""; } >&5 ($PKG_CONFIG --exists --print-errors "uuid") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBUUID_LIBS=`$PKG_CONFIG --libs "uuid" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBUUID_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "uuid" 2>&1` else LIBUUID_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "uuid" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBUUID_PKG_ERRORS" >&5 found_libuuid=no elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } found_libuuid=no else LIBUUID_CFLAGS=$pkg_cv_LIBUUID_CFLAGS LIBUUID_LIBS=$pkg_cv_LIBUUID_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } libuuid_CFLAGS="$LIBUUID_CFLAGS" libuuid_LIBS="$LIBUUID_LIBS" found_libuuid=yes fi if test "x$found_libuuid" = "xno"; then ac_fn_c_check_header_compile "$LINENO" "uuid.h" "ac_cv_header_uuid_h" "$ac_includes_default" if test "x$ac_cv_header_uuid_h" = xyes then : found_libuuid=yes else $as_nop found_libuuid=no fi fi fi if test "x$found_libuuid" = "xno"; then as_fn_error $? "\"*** couldn't find uuid ***\"" "$LINENO" 5 fi pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for zlib" >&5 printf %s "checking for zlib... " >&6; } if test -n "$ZLIB_CFLAGS"; then pkg_cv_ZLIB_CFLAGS="$ZLIB_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib\""; } >&5 ($PKG_CONFIG --exists --print-errors "zlib") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_ZLIB_CFLAGS=`$PKG_CONFIG --cflags "zlib" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$ZLIB_LIBS"; then pkg_cv_ZLIB_LIBS="$ZLIB_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib\""; } >&5 ($PKG_CONFIG --exists --print-errors "zlib") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_ZLIB_LIBS=`$PKG_CONFIG --libs "zlib" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then ZLIB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "zlib" 2>&1` else ZLIB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "zlib" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$ZLIB_PKG_ERRORS" >&5 found_zlib=no elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } found_zlib=no else ZLIB_CFLAGS=$pkg_cv_ZLIB_CFLAGS ZLIB_LIBS=$pkg_cv_ZLIB_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } zlib_CFLAGS="$ZLIB_CFLAGS" zlib_LIBS="$ZLIB_LIBS" found_zlib=yes fi if test "x$found_zlib" = "xno"; then ac_fn_c_check_header_compile "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" if test "x$ac_cv_header_zlib_h" = xyes then : else $as_nop found_zlib=no fi fi if test "x$found_zlib" = "xno"; then as_fn_error $? "\"*** couldn't find zlib ***\"" "$LINENO" 5 fi if test "$PLATFORM" = "linux"; then pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libbsd-overlay" >&5 printf %s "checking for libbsd-overlay... " >&6; } if test -n "$LIBBSD_CFLAGS"; then pkg_cv_LIBBSD_CFLAGS="$LIBBSD_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libbsd-overlay\""; } >&5 ($PKG_CONFIG --exists --print-errors "libbsd-overlay") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBBSD_CFLAGS=`$PKG_CONFIG --cflags "libbsd-overlay" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBBSD_LIBS"; then pkg_cv_LIBBSD_LIBS="$LIBBSD_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libbsd-overlay\""; } >&5 ($PKG_CONFIG --exists --print-errors "libbsd-overlay") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBBSD_LIBS=`$PKG_CONFIG --libs "libbsd-overlay" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBBSD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libbsd-overlay" 2>&1` else LIBBSD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libbsd-overlay" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBBSD_PKG_ERRORS" >&5 as_fn_error $? "\"*** couldn't find libbsd-overlay via pkg-config\"" "$LINENO" 5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } as_fn_error $? "\"*** couldn't find libbsd-overlay via pkg-config\"" "$LINENO" 5 else LIBBSD_CFLAGS=$pkg_cv_LIBBSD_CFLAGS LIBBSD_LIBS=$pkg_cv_LIBBSD_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } libbsd_CFLAGS="$LIBBSD_CFLAGS" libbsd_LIBS="$LIBBSD_LIBS" printf "%s\n" "#define HAVE_LIBBSD 1" >>confdefs.h fi # Add LIBBSD_{CFLAGS,LIBS} to the environment here, as libbsd puts its # header files in a non-standard location, which means the overlay for # and won't be found. CFLAGS="$CFLAGS $LIBBSD_CFLAGS" LIBS="$LIBS $LIBBSD_LIBS" pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libmd" >&5 printf %s "checking for libmd... " >&6; } if test -n "$LIBMD_CFLAGS"; then pkg_cv_LIBMD_CFLAGS="$LIBMD_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libmd\""; } >&5 ($PKG_CONFIG --exists --print-errors "libmd") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBMD_CFLAGS=`$PKG_CONFIG --cflags "libmd" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBMD_LIBS"; then pkg_cv_LIBMD_LIBS="$LIBMD_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libmd\""; } >&5 ($PKG_CONFIG --exists --print-errors "libmd") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBMD_LIBS=`$PKG_CONFIG --libs "libmd" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBMD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libmd" 2>&1` else LIBMD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libmd" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBMD_PKG_ERRORS" >&5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } else LIBMD_CFLAGS=$pkg_cv_LIBMD_CFLAGS LIBMD_LIBS=$pkg_cv_LIBMD_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } libmd_CFLAGS="$LIBMD_CFLAGS" libmd_LIBS="$LIBMD_LIBS" fi CFLAGS="$CFLAGS $LIBMD_CFLAGS" LIBS="$LIBS $LIBMD_LIBS" fi # Look for a suitable queue.h. We hope libbsd is enough, but that is missing # some declarations. ac_fn_check_decl "$LINENO" "TAILQ_CONCAT" "ac_cv_have_decl_TAILQ_CONCAT" "#include " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_TAILQ_CONCAT" = xyes then : found_queue_h=yes else $as_nop found_queue_h=no fi ac_fn_check_decl "$LINENO" "TAILQ_PREV" "ac_cv_have_decl_TAILQ_PREV" "#include " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_TAILQ_PREV" = xyes then : else $as_nop found_queue_h=no fi ac_fn_check_decl "$LINENO" "TAILQ_FOREACH_SAFE" "ac_cv_have_decl_TAILQ_FOREACH_SAFE" "#include " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_TAILQ_FOREACH_SAFE" = xyes then : else $as_nop found_queue_h=no fi if test "x$found_queue_h" = xyes; then printf "%s\n" "#define HAVE_QUEUE_H 1" >>confdefs.h else as_fn_error $? "\"*** sys/queue.h missing key defines ***" "$LINENO" 5 fi ac_fn_check_decl "$LINENO" "RB_GENERATE_STATIC" "ac_cv_have_decl_RB_GENERATE_STATIC" "#include " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_RB_GENERATE_STATIC" = xyes then : found_sys_tree_h=yes else $as_nop found_sys_tree_h=no fi if test "x$PLATFORM" != "xopenbsd"; then pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libtls" >&5 printf %s "checking for libtls... " >&6; } if test -n "$LIBTLS_CFLAGS"; then pkg_cv_LIBTLS_CFLAGS="$LIBTLS_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtls\""; } >&5 ($PKG_CONFIG --exists --print-errors "libtls") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBTLS_CFLAGS=`$PKG_CONFIG --cflags "libtls" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBTLS_LIBS"; then pkg_cv_LIBTLS_LIBS="$LIBTLS_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtls\""; } >&5 ($PKG_CONFIG --exists --print-errors "libtls") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBTLS_LIBS=`$PKG_CONFIG --libs "libtls" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBTLS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libtls" 2>&1` else LIBTLS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libtls" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBTLS_PKG_ERRORS" >&5 as_fn_error $? "\"*** Couldn't find libtls ***\"" "$LINENO" 5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } as_fn_error $? "\"*** Couldn't find libtls ***\"" "$LINENO" 5 else LIBTLS_CFLAGS=$pkg_cv_LIBTLS_CFLAGS LIBTLS_LIBS=$pkg_cv_LIBTLS_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } libtls_CFLAGS="$LIBTLS_CFLAGS" libtls_LIBS="$LIBTLS_LIBS" fi fi # Look for __progname. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __progname" >&5 printf %s "checking for __progname... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include extern char *__progname; int main(void) { const char *cp = __progname; printf("%s\n", cp); exit(0); } _ACEOF if ac_fn_c_try_link "$LINENO" then : printf "%s\n" "#define HAVE___PROGNAME 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for panelw" >&5 printf %s "checking for panelw... " >&6; } if test -n "$LIBPANELW_CFLAGS"; then pkg_cv_LIBPANELW_CFLAGS="$LIBPANELW_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panelw\""; } >&5 ($PKG_CONFIG --exists --print-errors "panelw") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBPANELW_CFLAGS=`$PKG_CONFIG --cflags "panelw" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBPANELW_LIBS"; then pkg_cv_LIBPANELW_LIBS="$LIBPANELW_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panelw\""; } >&5 ($PKG_CONFIG --exists --print-errors "panelw") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBPANELW_LIBS=`$PKG_CONFIG --libs "panelw" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBPANELW_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "panelw" 2>&1` else LIBPANELW_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "panelw" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBPANELW_PKG_ERRORS" >&5 found_panel=no elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } found_panel=no else LIBPANELW_CFLAGS=$pkg_cv_LIBPANELW_CFLAGS LIBPANELW_LIBS=$pkg_cv_LIBPANELW_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } LIBPANELW_LIBS="$LIBPANELW_LIBS" found_panel=yes fi if test "x$found_panel" = "xno"; then pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gnupanelw" >&5 printf %s "checking for gnupanelw... " >&6; } if test -n "$LIBPANELW_CFLAGS"; then pkg_cv_LIBPANELW_CFLAGS="$LIBPANELW_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnupanelw\""; } >&5 ($PKG_CONFIG --exists --print-errors "gnupanelw") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBPANELW_CFLAGS=`$PKG_CONFIG --cflags "gnupanelw" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBPANELW_LIBS"; then pkg_cv_LIBPANELW_LIBS="$LIBPANELW_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnupanelw\""; } >&5 ($PKG_CONFIG --exists --print-errors "gnupanelw") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBPANELW_LIBS=`$PKG_CONFIG --libs "gnupanelw" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBPANELW_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gnupanelw" 2>&1` else LIBPANELW_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gnupanelw" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBPANELW_PKG_ERRORS" >&5 found_panel=no elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } found_panel=no else LIBPANELW_CFLAGS=$pkg_cv_LIBPANELW_CFLAGS LIBPANELW_LIBS=$pkg_cv_LIBPANELW_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } LIBPANELW_LIBS="$LIBPANELW_LIBS" found_panel=yes fi fi if test "x$found_panel" = "xno"; then pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for panel" >&5 printf %s "checking for panel... " >&6; } if test -n "$LIBPANELW_CFLAGS"; then pkg_cv_LIBPANELW_CFLAGS="$LIBPANELW_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panel\""; } >&5 ($PKG_CONFIG --exists --print-errors "panel") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBPANELW_CFLAGS=`$PKG_CONFIG --cflags "panel" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBPANELW_LIBS"; then pkg_cv_LIBPANELW_LIBS="$LIBPANELW_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panel\""; } >&5 ($PKG_CONFIG --exists --print-errors "panel") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBPANELW_LIBS=`$PKG_CONFIG --libs "panel" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBPANELW_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "panel" 2>&1` else LIBPANELW_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "panel" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBPANELW_PKG_ERRORS" >&5 found_panel=no elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } found_panel=no else LIBPANELW_CFLAGS=$pkg_cv_LIBPANELW_CFLAGS LIBPANELW_LIBS=$pkg_cv_LIBPANELW_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } LIBPANELW_LIBS="$LIBPANELW_LIBS" found_panel=yes fi fi if test "x$found_panel" = "xno"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for update_panels in -lpanelw" >&5 printf %s "checking for update_panels in -lpanelw... " >&6; } if test ${ac_cv_lib_panelw_update_panels+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpanelw -lncurses $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char update_panels (); int main (void) { return update_panels (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_panelw_update_panels=yes else $as_nop ac_cv_lib_panelw_update_panels=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_panelw_update_panels" >&5 printf "%s\n" "$ac_cv_lib_panelw_update_panels" >&6; } if test "x$ac_cv_lib_panelw_update_panels" = xyes then : printf "%s\n" "#define HAVE_LIBPANELW 1" >>confdefs.h LIBS="-lpanelw $LIBS" else $as_nop as_fn_error $? " \"*** panelw not found for ncurses. ***\"" "$LINENO" 5 fi fi pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ncursesw" >&5 printf %s "checking for ncursesw... " >&6; } if test -n "$LIBNCURSES_CFLAGS"; then pkg_cv_LIBNCURSES_CFLAGS="$LIBNCURSES_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ncursesw\""; } >&5 ($PKG_CONFIG --exists --print-errors "ncursesw") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBNCURSES_CFLAGS=`$PKG_CONFIG --cflags "ncursesw" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBNCURSES_LIBS"; then pkg_cv_LIBNCURSES_LIBS="$LIBNCURSES_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ncursesw\""; } >&5 ($PKG_CONFIG --exists --print-errors "ncursesw") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBNCURSES_LIBS=`$PKG_CONFIG --libs "ncursesw" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBNCURSES_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "ncursesw" 2>&1` else LIBNCURSES_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "ncursesw" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBNCURSES_PKG_ERRORS" >&5 found_ncurses=no elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } found_ncurses=no else LIBNCURSES_CFLAGS=$pkg_cv_LIBNCURSES_CFLAGS LIBNCURSES_LIBS=$pkg_cv_LIBNCURSES_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } found_ncurses=yes fi if test "x$found_ncurses" = xyes; then libncurses_CFLAGS="$LIBNCURSES_CFLAGS $LIBTINFO_CFLAGS $LIBPANELW_CFLAGS" libncurses_LIBS="$LIBNCURSES_LIBS $LIBTINFO_LIBS $LIBPANELW_LIBS" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing setupterm" >&5 printf %s "checking for library containing setupterm... " >&6; } if test ${ac_cv_search_setupterm+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char setupterm (); int main (void) { return setupterm (); ; return 0; } _ACEOF for ac_lib in '' found_ncurses=yes do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_setupterm=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_setupterm+y} then : break fi done if test ${ac_cv_search_setupterm+y} then : else $as_nop ac_cv_search_setupterm=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_setupterm" >&5 printf "%s\n" "$ac_cv_search_setupterm" >&6; } ac_res=$ac_cv_search_setupterm if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" found_ncurses=no fi if test "x$found_ncurses" = xyes; then ac_fn_c_check_header_compile "$LINENO" "ncurses.h" "ac_cv_header_ncurses_h" "$ac_includes_default" if test "x$ac_cv_header_ncurses_h" = xyes then : libncurses_CFLAGS="$LIBPANELW_CFLAGS $LIBPANEL_CFLAGS" libncurses_LIBS="$LIBPANELW_LIBS -lncursesw" fi fi fi if test "x$found_ncurses" = xyes; then printf "%s\n" "#define HAVE_NCURSES_H 1" >>confdefs.h else # No ncurses, try curses. ac_fn_c_check_func "$LINENO" "setupterm" "ac_cv_func_setupterm" if test "x$ac_cv_func_setupterm" = xyes then : found_curses=yes else $as_nop found_curses=no fi ac_fn_c_check_header_compile "$LINENO" "curses.h" "ac_cv_header_curses_h" "$ac_includes_default" if test "x$ac_cv_header_curses_h" = xyes then : found_curses=yes else $as_nop found_curses=no fi if test "x$found_curses" = xyes; then libncurses_CFLAGS="$LIBPANELW_CFLAGS $LIBPANEL_CFLAGS" libncurses_LIBS="$LIBPANELW_LIBS -lncursesw -lpanelw" printf "%s\n" "#define HAVE_CURSES_H 1" >>confdefs.h else as_fn_error $? "\"curses not found\"" "$LINENO" 5 fi fi # Save our CFLAGS/CPPFLAGS/LDFLAGS for the Makefile and restore the old user # variables. CPPFLAGS="$SAVED_CPPFLAGS" CFLAGS="$SAVED_CFLAGS" LDFLAGS="$SAVED_LDFLAGS" # LIBS is designed to accumulate library dependencies as checks for them are # peformed, so that this can be included directly to ld(1). # # However, this hinders the splitting up of the library dependencies so that # they're targetted just where they're needed. Flatting LIBS here ensures # that this happens appropriately. LIBS="" if test "x$enable_cvg" = xyes; then CVG_ENABLED_TRUE= CVG_ENABLED_FALSE='#' else CVG_ENABLED_TRUE='#' CVG_ENABLED_FALSE= fi ac_config_files="$ac_config_files Makefile compat/Makefile gitwrapper/Makefile got/Makefile gotadmin/Makefile gotctl/Makefile gotd/Makefile gotd/libexec/Makefile gotd/libexec/got-notify-email/Makefile gotd/libexec/got-notify-http/Makefile gotsh/Makefile gotwebd/Makefile libexec/Makefile libexec/got-fetch-http/Makefile libexec/got-fetch-pack/Makefile libexec/got-index-pack/Makefile libexec/got-read-blob/Makefile libexec/got-read-commit/Makefile libexec/got-read-gitconfig/Makefile libexec/got-read-gotconfig/Makefile libexec/got-read-object/Makefile libexec/got-read-pack/Makefile libexec/got-read-patch/Makefile libexec/got-read-tag/Makefile libexec/got-read-tree/Makefile libexec/got-send-pack/Makefile tog/Makefile Makefile.common:Makefile.common.in" if test "x$enable_cvg" = "xyes"; then ac_config_files="$ac_config_files cvg/Makefile" fi cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 printf %s "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5 printf "%s\n" "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_SHA2_TRUE}" && test -z "${HAVE_SHA2_FALSE}"; then as_fn_error $? "conditional \"HAVE_SHA2\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_GETOPT_TRUE}" && test -z "${HAVE_GETOPT_FALSE}"; then as_fn_error $? "conditional \"HAVE_GETOPT\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_SETPROCTITLE_TRUE}" && test -z "${HAVE_SETPROCTITLE_FALSE}"; then as_fn_error $? "conditional \"HAVE_SETPROCTITLE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_SIPHASH_TRUE}" && test -z "${HAVE_SIPHASH_FALSE}"; then as_fn_error $? "conditional \"HAVE_SIPHASH\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_CLOSEFROM_TRUE}" && test -z "${HAVE_CLOSEFROM_FALSE}"; then as_fn_error $? "conditional \"HAVE_CLOSEFROM\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_B64_TRUE}" && test -z "${HAVE_B64_FALSE}"; then as_fn_error $? "conditional \"HAVE_B64\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HOST_FREEBSD_TRUE}" && test -z "${HOST_FREEBSD_FALSE}"; then as_fn_error $? "conditional \"HOST_FREEBSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HOST_LINUX_TRUE}" && test -z "${HOST_LINUX_FALSE}"; then as_fn_error $? "conditional \"HOST_LINUX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HOST_DARWIN_TRUE}" && test -z "${HOST_DARWIN_FALSE}"; then as_fn_error $? "conditional \"HOST_DARWIN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HOST_NETBSD_TRUE}" && test -z "${HOST_NETBSD_FALSE}"; then as_fn_error $? "conditional \"HOST_NETBSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HOST_OPENBSD_TRUE}" && test -z "${HOST_OPENBSD_FALSE}"; then as_fn_error $? "conditional \"HOST_OPENBSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HOST_DRAGONFLYBSD_TRUE}" && test -z "${HOST_DRAGONFLYBSD_FALSE}"; then as_fn_error $? "conditional \"HOST_DRAGONFLYBSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_LINUX_LANDLOCK_TRUE}" && test -z "${HAVE_LINUX_LANDLOCK_FALSE}"; then as_fn_error $? "conditional \"HAVE_LINUX_LANDLOCK\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_IMSG_TRUE}" && test -z "${HAVE_IMSG_FALSE}"; then as_fn_error $? "conditional \"HAVE_IMSG\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${CVG_ENABLED_TRUE}" && test -z "${CVG_ENABLED_FALSE}"; then as_fn_error $? "conditional \"CVG_ENABLED\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by got-portable $as_me 0.101, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to ." _ACEOF ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ got-portable config.status 0.101 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX printf "%s\n" "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "include/got_compat.h") CONFIG_HEADERS="$CONFIG_HEADERS include/got_compat.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "compat/Makefile") CONFIG_FILES="$CONFIG_FILES compat/Makefile" ;; "gitwrapper/Makefile") CONFIG_FILES="$CONFIG_FILES gitwrapper/Makefile" ;; "got/Makefile") CONFIG_FILES="$CONFIG_FILES got/Makefile" ;; "gotadmin/Makefile") CONFIG_FILES="$CONFIG_FILES gotadmin/Makefile" ;; "gotctl/Makefile") CONFIG_FILES="$CONFIG_FILES gotctl/Makefile" ;; "gotd/Makefile") CONFIG_FILES="$CONFIG_FILES gotd/Makefile" ;; "gotd/libexec/Makefile") CONFIG_FILES="$CONFIG_FILES gotd/libexec/Makefile" ;; "gotd/libexec/got-notify-email/Makefile") CONFIG_FILES="$CONFIG_FILES gotd/libexec/got-notify-email/Makefile" ;; "gotd/libexec/got-notify-http/Makefile") CONFIG_FILES="$CONFIG_FILES gotd/libexec/got-notify-http/Makefile" ;; "gotsh/Makefile") CONFIG_FILES="$CONFIG_FILES gotsh/Makefile" ;; "gotwebd/Makefile") CONFIG_FILES="$CONFIG_FILES gotwebd/Makefile" ;; "libexec/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/Makefile" ;; "libexec/got-fetch-http/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-fetch-http/Makefile" ;; "libexec/got-fetch-pack/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-fetch-pack/Makefile" ;; "libexec/got-index-pack/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-index-pack/Makefile" ;; "libexec/got-read-blob/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-read-blob/Makefile" ;; "libexec/got-read-commit/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-read-commit/Makefile" ;; "libexec/got-read-gitconfig/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-read-gitconfig/Makefile" ;; "libexec/got-read-gotconfig/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-read-gotconfig/Makefile" ;; "libexec/got-read-object/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-read-object/Makefile" ;; "libexec/got-read-pack/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-read-pack/Makefile" ;; "libexec/got-read-patch/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-read-patch/Makefile" ;; "libexec/got-read-tag/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-read-tag/Makefile" ;; "libexec/got-read-tree/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-read-tree/Makefile" ;; "libexec/got-send-pack/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-send-pack/Makefile" ;; "tog/Makefile") CONFIG_FILES="$CONFIG_FILES tog/Makefile" ;; "Makefile.common") CONFIG_FILES="$CONFIG_FILES Makefile.common:Makefile.common.in" ;; "cvg/Makefile") CONFIG_FILES="$CONFIG_FILES cvg/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 printf "%s\n" "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. case $CONFIG_FILES in #( *\'*) : eval set x "$CONFIG_FILES" ;; #( *) : set x $CONFIG_FILES ;; #( *) : ;; esac shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`printf "%s\n" "$am_mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`$as_dirname -- "$am_mf" || $as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$am_mf" : 'X\(//\)[^/]' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$am_mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` am_filepart=`$as_basename -- "$am_mf" || $as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$am_mf" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` { echo "$as_me:$LINENO: cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles" >&5 (cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } || am_rc=$? done if test $am_rc -ne 0; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE=\"gmake\" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking). See \`config.log' for more details" "$LINENO" 5; } fi { am_dirpart=; unset am_dirpart;} { am_filepart=; unset am_filepart;} { am_mf=; unset am_mf;} { am_rc=; unset am_rc;} rm -f conftest-deps.mk } ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi # # CONFIG_SUBDIRS section. # if test "$no_recursion" != yes; then # Remove --cache-file, --srcdir, and --disable-option-checking arguments # so they do not pile up. ac_sub_configure_args= ac_prev= eval "set x $ac_configure_args" shift for ac_arg do if test -n "$ac_prev"; then ac_prev= continue fi case $ac_arg in -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \ | --c=*) ;; --config-cache | -C) ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) ;; --disable-option-checking) ;; *) case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_sub_configure_args " '$ac_arg'" ;; esac done # Always prepend --prefix to ensure using the same prefix # in subdir configurations. ac_arg="--prefix=$prefix" case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args" # Pass --silent if test "$silent" = yes; then ac_sub_configure_args="--silent $ac_sub_configure_args" fi # Always prepend --disable-option-checking to silence warnings, since # different subdirs can have different --enable and --with options. ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args" ac_popdir=`pwd` for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue # Do not complain, so a configure script can configure whichever # parts of a large source tree are present. test -d "$srcdir/$ac_dir" || continue ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)" printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5 printf "%s\n" "$ac_msg" >&6 as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" # Check for configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then ac_sub_configure=$ac_srcdir/configure.gnu elif test -f "$ac_srcdir/configure"; then ac_sub_configure=$ac_srcdir/configure else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5 printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2;} ac_sub_configure= fi # The recursion is here. if test -n "$ac_sub_configure"; then # Make the cache file name correct relative to the subdirectory. case $cache_file in [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;; *) # Relative name. ac_sub_cache_file=$ac_top_build_prefix$cache_file ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5 printf "%s\n" "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;} # The eval makes quoting arguments work. eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \ --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" || as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5 fi cd "$ac_popdir" done fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi executables="$(eval echo ${exec_prefix}/bin)" helpers="$(eval echo ${libexecdir})" manpages="$(eval echo ${mandir})" gotdep="$GOTD_EMPTY_PATHC" gotgwlep="$GITWRAPPER_LIBEXEC_PATHC" if test -z "$enable_cvg"; then enable_cvg="no" fi if test -z "$gotdep"; then gotdep="N/A" fi if test -z "$gotgwlep"; then gotgwlep="N/A" fi echo " Configured got-portable with: Version: $VERSION Prefix: ${prefix} Executables: ${executables} Bison: $YACC CFlags: $CFLAGS cvg: ${enable_cvg} Gotd: Empty Path: ${gotdep} Gitwrapper: ${gotgwlep} Helpers: ${helpers} Man pages: ${manpages} " got-portable-0.101/cvg/0000775000175100017510000000000014644145571010451 5got-portable-0.101/cvg/Makefile.am0000664000175100017510000000445414644144735012435 sbin_PROGRAMS = cvg include $(top_builddir)/Makefile.common cvg_SOURCES = cvg.c \ $(top_srcdir)/lib/blame.c \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/commit_graph.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/diff.c \ $(top_srcdir)/lib/diff3.c \ $(top_srcdir)/lib/diff_atomize_text.c \ $(top_srcdir)/lib/diff_main.c \ $(top_srcdir)/lib/diff_myers.c \ $(top_srcdir)/lib/diff_output.c \ $(top_srcdir)/lib/diff_output_edscript.c \ $(top_srcdir)/lib/diff_output_plain.c \ $(top_srcdir)/lib/diff_output_unidiff.c \ $(top_srcdir)/lib/diff_patience.c \ $(top_srcdir)/lib/diffreg.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fetch.c \ $(top_srcdir)/lib/fileindex.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/patch.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/rcsutil.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/send.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/lib/worktree.c \ $(top_srcdir)/lib/worktree_cvg.c \ $(top_srcdir)/lib/worktree_open.c cvg_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = cvg.1 man1_MANS = cvg.1 LDADD = -L$(top_builddir)/compat \ -lopenbsd-compat -lm LDADD += $(libbsd_LIBS) \ $(zlib_LIBS) \ $(libuuid_LIBS) \ $(libutil_LIBS) \ $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(libbsd_CFLAGS) $(zlib_CFLAGS) \ $(libuuid_CFLAGS) $(libmd_CFLAGS) got-portable-0.101/cvg/cvg.10000664000175100017510000017547214644143163011245 .\" .\" Copyright (c) 2017 Martin Pieuchot .\" Copyright (c) 2018, 2019, 2020 Stefan Sperling .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt CVG 1 .Os .Sh NAME .Nm cvg .Nd CVS-like Git client .Sh SYNOPSIS .Nm .Op Fl hV .Ar command .Op Ar arg ... .Sh DESCRIPTION .Nm is a Git-compatible version control system with a user interface similar to .Xr cvs 1 . .Pp .Nm supports local and remote Git repositories. The Git repository format is described in .Xr git-repository 5 . .Pp Files managed by .Nm must be checked out from the repository for modification. Checked out files are stored in a .Em work tree which can be placed at an arbitrary directory in the filesystem hierarchy. The on-disk format of this work tree is described in .Xr cvg-worktree 5 . .Pp .Nm provides global and command-specific options. Global options must precede the command name, and are as follows: .Bl -tag -width tenletters .It Fl h Display usage information and exit immediately. .It Fl V , -version Display program version and exit immediately. .El .Pp The commands for .Nm are as follows: .Bl -tag -width checkout .Tg im .It Xo .Cm import .Op Fl b Ar branch .Op Fl I Ar pattern .Op Fl m Ar message .Op Fl r Ar repository-path .Ar directory .Xc .Dl Pq alias: Cm im Create an initial commit in a repository from the file hierarchy within the specified .Ar directory . The created commit will not have any parent commits, i.e. it will be a root commit. Also create a new reference which provides a branch name for the newly created commit. Show the path of each imported file to indicate progress. .Pp The .Cm got import command requires the .Ev GOT_AUTHOR environment variable to be set, unless an author has been configured in .Xr got.conf 5 or Git's .Dv user.name and .Dv user.email configuration settings can be obtained from the repository's .Pa .git/config file or from Git's global .Pa ~/.gitconfig configuration file. .Pp The options for .Cm got import are as follows: .Bl -tag -width Ds .It Fl b Ar branch Create the specified .Ar branch . If this option is not specified, a branch corresponding to the repository's HEAD reference will be used. Use of this option is required if the branch resolved via the repository's HEAD reference already exists. .It Fl I Ar pattern Ignore files or directories with a name which matches the specified .Ar pattern . This option may be specified multiple times to build a list of ignore patterns. The .Ar pattern follows the globbing rules documented in .Xr glob 7 . Ignore patterns which end with a slash, .Dq / , will only match directories. .It Fl m Ar message Use the specified log message when creating the new commit. Without the .Fl m option, .Cm got import opens a temporary file in an editor where a log message can be written. Quitting the editor without saving the file will abort the import operation. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. .El .Tg cl .It Xo .Cm clone .Op Fl almqv .Op Fl b Ar branch .Op Fl R Ar reference .Ar repository-URL .Op Ar directory .Xc .Dl Pq alias: Cm cl Clone a Git repository at the specified .Ar repository-URL into the specified .Ar directory . If no .Ar directory is specified, the directory name will be derived from the name of the cloned repository. .Cm got clone will refuse to run if the .Ar directory already exists. .Pp The .Ar repository-URL specifies a protocol scheme, a server hostname, an optional port number separated from the hostname by a colon, and a path to the repository on the server: .Lk scheme://hostname:port/path/to/repository .Pp The following protocol schemes are supported: .Bl -tag -width git+ssh .It git The Git protocol as implemented by the .Xr git-daemon 1 server. Use of this protocol is discouraged since it supports neither authentication nor encryption. .It git+ssh The Git protocol wrapped in an authenticated and encrypted .Xr ssh 1 tunnel. With this protocol the hostname may contain an embedded username for .Xr ssh 1 to use: .Mt user@hostname .It ssh Short alias for git+ssh. .El .Pp Objects in the cloned repository are stored in a pack file which is downloaded from the server. This pack file will then be indexed to facilitate access to the objects stored within. If any objects in the pack file are stored in deltified form, all deltas will be fully resolved in order to compute the ID of such objects. This can take some time. More details about the pack file format are documented in .Xr git-repository 5 . .Pp .Cm got clone creates a remote repository entry in the .Xr got.conf 5 and .Pa config files of the cloned repository to store the .Ar repository-url and any .Ar branch or .Ar reference arguments for future use by .Cm got fetch or .Xr git-fetch 1 . .Pp The options for .Cm got clone are as follows: .Bl -tag -width Ds .It Fl a Fetch all branches from the remote repository's .Dq refs/heads/ reference namespace and set .Cm fetch_all_branches in the cloned repository's .Xr got.conf 5 file for future use by .Cm got fetch . If this option is not specified, a branch resolved via the remote repository's HEAD reference will be fetched. Cannot be used together with the .Fl b option. .It Fl b Ar branch Fetch the specified .Ar branch from the remote repository's .Dq refs/heads/ reference namespace. This option may be specified multiple times to build a list of branches to fetch. If the branch corresponding to the remote repository's HEAD reference is not in this list, the cloned repository's HEAD reference will be set to the first branch which was fetched. If this option is not specified, a branch resolved via the remote repository's HEAD reference will be fetched. Cannot be used together with the .Fl a option. .It Fl l List branches and tags available for fetching from the remote repository and exit immediately. Cannot be used together with any of the other options except .Fl q and .Fl v . .It Fl m Create the cloned repository as a mirror of the original repository. This is useful if the cloned repository will not be used to store locally created commits. .Pp The repository's .Xr got.conf 5 and .Pa config files will be set up with the .Dq mirror option enabled, such that .Cm got fetch or .Xr git-fetch 1 will write incoming changes directly to branches in the .Dq refs/heads/ reference namespace, rather than to branches in the .Dq refs/remotes/ namespace. This avoids the usual requirement of having to run .Cm got rebase or .Cm got merge after .Cm got fetch in order to make incoming changes appear on branches in the .Dq refs/heads/ namespace. But maintaining custom changes in the cloned repository becomes difficult since such changes will be at risk of being discarded whenever incoming changes are fetched. .It Fl q Suppress progress reporting output. The same option will be passed to .Xr ssh 1 if applicable. .It Fl R Ar reference In addition to the branches and tags that will be fetched, fetch an arbitrary .Ar reference from the remote repository's .Dq refs/ namespace. This option may be specified multiple times to build a list of additional references to fetch. The specified .Ar reference may either be a path to a specific reference, or a reference namespace which will cause all references in this namespace to be fetched. .Pp Each reference will be mapped into the cloned repository's .Dq refs/remotes/ namespace, unless the .Fl m option is used to mirror references directly into the cloned repository's .Dq refs/ namespace. .Pp .Cm got clone will refuse to fetch references from the remote repository's .Dq refs/remotes/ or .Dq refs/got/ namespace. .It Fl v Verbose mode. Causes .Cm got clone to print debugging messages to standard error output. This option will be passed to .Xr ssh 1 if applicable. Multiple -v options increase the verbosity. The maximum is 3. .El .Tg co .It Xo .Cm checkout .Op Fl Eq .Op Fl b Ar branch .Op Fl c Ar commit .Op Fl p Ar path-prefix .Ar repository-path .Op Ar work-tree-path .Xc .Dl Pq alias: Cm co Copy files from a repository into a new work tree. Show the status of each affected file, using the following status codes: .Bl -column YXZ description .It A Ta new file was added .It E Ta file already exists in work tree's meta-data .El .Pp If the .Ar work tree path is not specified, either use the last component of .Ar repository path , or if a .Ar path prefix was specified use the last component of .Ar path prefix . .Pp The options for .Cm got checkout are as follows: .Bl -tag -width Ds .It Fl b Ar branch Check out files from a commit on the specified .Ar branch . If this option is not specified, a branch resolved via the repository's HEAD reference will be used. .It Fl c Ar commit Check out files from the specified .Ar commit on the selected branch. The expected argument is a commit ID SHA1 hash or an existing reference or tag name which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full SHA1 hash automatically, provided the abbreviation is unique. If this option is not specified, the most recent commit on the selected branch will be used. .Pp If the specified .Ar commit is not contained in the selected branch, a different branch which contains this commit must be specified with the .Fl b option. If no such branch is known, a new branch must be created for this commit with .Cm got branch before .Cm got checkout can be used. Checking out work trees with an unknown branch is intentionally not supported. .It Fl E Proceed with the checkout operation even if the directory at .Ar work-tree-path is not empty. Existing files will be left intact. .It Fl p Ar path-prefix Restrict the work tree to a subset of the repository's tree hierarchy. Only files beneath the specified .Ar path-prefix will be checked out. .It Fl q Silence progress output. .El .Tg up .It Xo .Cm update .Op Fl q .Op Fl b Ar branch .Op Fl c Ar commit .Op Ar path ... .Xc .Dl Pq alias: Cm up Update an existing work tree to a different .Ar commit . Change existing files in the work tree as necessary to match file contents of this commit. Preserve any local changes in the work tree and merge them with the incoming changes. .Pp Files which already contain merge conflicts will not be updated to avoid further complications. Such files will be updated when .Cm got update is run again after merge conflicts have been resolved. If the conflicting changes are no longer needed, affected files can be reverted with .Cm got revert before running .Cm got update again. .Pp Show the status of each affected file, using the following status codes: .Bl -column YXZ description .It U Ta file was updated and contained no local changes .It G Ta file was updated and local changes were merged cleanly .It C Ta file was updated and conflicts occurred during merge .It D Ta file was deleted .It d Ta file's deletion was prevented by local modifications .It A Ta new file was added .It \(a~ Ta versioned file is obstructed by a non-regular file .It ! Ta a missing versioned file was restored .It # Ta file was not updated because it contains merge conflicts .It ? Ta changes destined for an unversioned file were not merged .El .Pp If no .Ar path is specified, update the entire work tree. Otherwise, restrict the update operation to files at or within the specified paths. Each path is required to exist in the update operation's target commit. Files in the work tree outside specified paths will remain unchanged and will retain their previously recorded base commit. Some .Nm commands may refuse to run while the work tree contains files from multiple base commits. The base commit of such a work tree can be made consistent by running .Cm got update across the entire work tree. Specifying a .Ar path is incompatible with the .Fl b option. .Pp .Cm got update cannot update paths with staged changes. If changes have been staged with .Cm got stage , these changes must first be committed with .Cm got commit or unstaged with .Cm got unstage . .Pp The options for .Cm got update are as follows: .Bl -tag -width Ds .It Fl b Ar branch Switch the work tree's branch reference to the specified .Ar branch before updating the work tree. This option requires that all paths in the work tree are updated. .Pp As usual, any local changes in the work tree will be preserved. This can be useful when switching to a newly created branch in order to commit existing local changes to this branch. .Pp Any local changes must be dealt with separately in order to obtain a work tree with pristine file contents corresponding exactly to the specified .Ar branch . Such changes could first be committed to a different branch with .Cm got commit , or could be discarded with .Cm got revert . .It Fl c Ar commit Update the work tree to the specified .Ar commit . The expected argument is a commit ID SHA1 hash or an existing reference or tag name which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full SHA1 hash automatically, provided the abbreviation is unique. If this option is not specified, the most recent commit on the work tree's branch will be used. .It Fl q Silence progress output. .El .Tg st .It Xo .Cm status .Op Fl I .Op Fl S Ar status-codes .Op Fl s Ar status-codes .Op Ar path ... .Xc .Dl Pq alias: Cm st Show the current modification status of files in a work tree, using the following status codes: .Bl -column YXZ description .It M Ta modified file .It A Ta file scheduled for addition in next commit .It D Ta file scheduled for deletion in next commit .It C Ta modified or added file which contains merge conflicts .It ! Ta versioned file was expected on disk but is missing .It \(a~ Ta versioned file is obstructed by a non-regular file .It ? Ta unversioned item not tracked by .Nm .It m Ta modified file modes (executable bit only) .It N Ta non-existent .Ar path specified on the command line .El .Pp If no .Ar path is specified, show modifications in the entire work tree. Otherwise, show modifications at or within the specified paths. .Pp If changes have been staged with .Cm got stage , staged changes are shown in the second output column, using the following status codes: .Bl -column YXZ description .It M Ta file modification is staged .It A Ta file addition is staged .It D Ta file deletion is staged .El .Pp Changes created on top of staged changes are indicated in the first column: .Bl -column YXZ description .It MM Ta file was modified after earlier changes have been staged .It MA Ta file was modified after having been staged for addition .El .Pp The options for .Cm got status are as follows: .Bl -tag -width Ds .It Fl I Show unversioned files even if they match an ignore pattern. .It Fl S Ar status-codes Suppress the output of files with a modification status matching any of the single-character status codes contained in the .Ar status-codes argument. Any combination of codes from the above list of possible status codes may be specified. For staged files, status codes displayed in either column will be matched. Cannot be used together with the .Fl s option. .It Fl s Ar status-codes Only show files with a modification status matching any of the single-character status codes contained in the .Ar status-codes argument. Any combination of codes from the above list of possible status codes may be specified. For staged files, status codes displayed in either column will be matched. Cannot be used together with the .Fl S option. .El .Pp For compatibility with .Xr cvs 1 and .Xr git 1 , .Cm got status reads .Xr glob 7 patterns from .Pa .cvsignore and .Pa .gitignore files in each traversed directory and will not display unversioned files which match these patterns. Ignore patterns which end with a slash, .Dq / , will only match directories. As an extension to .Xr glob 7 matching rules, .Cm got status supports consecutive asterisks, .Dq ** , which will match an arbitrary amount of directories. Unlike .Xr cvs 1 , .Cm got status only supports a single ignore pattern per line. Unlike .Xr git 1 , .Cm got status does not support negated ignore patterns prefixed with .Dq \&! , and gives no special significance to the location of path component separators, .Dq / , in a pattern. .It Xo .Cm log .Op Fl bdPpRs .Op Fl C Ar number .Op Fl c Ar commit .Op Fl l Ar N .Op Fl r Ar repository-path .Op Fl S Ar search-pattern .Op Fl x Ar commit .Op Ar path .Xc Display history of a repository. If a .Ar path is specified, show only commits which modified this path. If invoked in a work tree, the .Ar path is interpreted relative to the current working directory, and the work tree's path prefix is implicitly prepended. Otherwise, the path is interpreted relative to the repository root. .Pp The options for .Cm got log are as follows: .Bl -tag -width Ds .It Fl b Display individual commits which were merged into the current branch from other branches. By default, .Cm got log shows the linear history of the current branch only. .It Fl C Ar number Set the number of context lines shown in diffs with .Fl p . By default, 3 lines of context are shown. .It Fl c Ar commit Start traversing history at the specified .Ar commit . The expected argument is a commit ID SHA1 hash or an existing reference or tag name which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full SHA1 hash automatically, provided the abbreviation is unique. If this option is not specified, default to the work tree's current branch if invoked in a work tree, or to the repository's HEAD reference. .It Fl d Display diffstat of changes introduced in each commit. Cannot be used with the .Fl s option. .It Fl l Ar N Limit history traversal to a given number of commits. If this option is not specified, a default limit value of zero is used, which is treated as an unbounded limit. The .Ev GOT_LOG_DEFAULT_LIMIT environment variable may be set to change this default value. .It Fl P Display the list of file paths changed in each commit, using the following status codes: .Bl -column YXZ description .It M Ta modified file .It D Ta file was deleted .It A Ta new file was added .It m Ta modified file modes (executable bit only) .El .Pp Cannot be used with the .Fl s option. .It Fl p Display the patch of modifications made in each commit. If a .Ar path is specified, only show the patch of modifications at or within this path. Cannot be used with the .Fl s option. .It Fl R Determine a set of commits to display as usual, but display these commits in reverse order. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .It Fl S Ar search-pattern If specified, show only commits with a log message, author name, committer name, or ID SHA1 hash matched by the extended regular expression .Ar search-pattern . Lines in committed patches will be matched if .Fl p is specified. File paths changed by a commit will be matched if .Fl P is specified. Regular expression syntax is documented in .Xr re_format 7 . .It Fl s Display a short one-line summary of each commit, instead of the default history format. Cannot be used together with the .Fl p or .Fl P option. .It Fl x Ar commit Stop traversing commit history immediately after the specified .Ar commit has been traversed. This option has no effect if the specified .Ar commit is never traversed. .El .Tg di .It Xo .Cm diff .Op Fl adPsw .Op Fl C Ar number .Op Fl c Ar commit .Op Fl r Ar repository-path .Op Ar object1 Ar object2 | Ar path ... .Xc .Dl Pq alias: Cm di When invoked within a work tree without any arguments, display all local changes in the work tree. If one or more .Ar path arguments are specified, only show changes within the specified paths. .Pp If two arguments are provided, treat each argument as a reference, a tag name, or an object ID SHA1 hash, and display differences between the corresponding objects. Both objects must be of the same type (blobs, trees, or commits). An abbreviated hash argument will be expanded to a full SHA1 hash automatically, provided the abbreviation is unique. If none of these interpretations produce a valid result or if the .Fl P option is used, and if .Cm got diff is running in a work tree, attempt to interpret the two arguments as paths. .Pp The options for .Cm got diff are as follows: .Bl -tag -width Ds .It Fl a Treat file contents as ASCII text even if binary data is detected. .It Fl C Ar number Set the number of context lines shown in the diff. By default, 3 lines of context are shown. .It Fl c Ar commit Show differences between commits in the repository. This option may be used up to two times. When used only once, show differences between the specified .Ar commit and its first parent commit. When used twice, show differences between the two specified commits. .Pp The expected argument is a commit ID SHA1 hash or an existing reference or tag name which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full SHA1 hash automatically, provided the abbreviation is unique. .Pp If the .Fl c option is used, all non-option arguments will be interpreted as paths. If one or more such .Ar path arguments are provided, only show differences for the specified paths. .Pp Cannot be used together with the .Fl P option. .It Fl d Display diffstat of changes before the actual diff by annotating each file path or blob hash being diffed with the total number of lines added and removed. A summary line will display the total number of changes across all files. .It Fl P Interpret all arguments as paths only. This option can be used to resolve ambiguity in cases where paths look like tag names, reference names, or object IDs. This option is only valid when .Cm got diff is invoked in a work tree. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .It Fl s Show changes staged with .Cm got stage instead of showing local changes in the work tree. This option is only valid when .Cm got diff is invoked in a work tree. .It Fl w Ignore whitespace-only changes. .El .Tg bl .It Xo .Cm blame .Op Fl c Ar commit .Op Fl r Ar repository-path .Ar path .Xc .Dl Pq alias: Cm bl Display line-by-line history of a file at the specified path. .Pp The options for .Cm got blame are as follows: .Bl -tag -width Ds .It Fl c Ar commit Start traversing history at the specified .Ar commit . The expected argument is a commit ID SHA1 hash or an existing reference or tag name which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full SHA1 hash automatically, provided the abbreviation is unique. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .El .Tg tr .It Xo .Cm tree .Op Fl iR .Op Fl c Ar commit .Op Fl r Ar repository-path .Op Ar path .Xc .Dl Pq alias: Cm tr Display a listing of files and directories at the specified directory path in the repository. Entries shown in this listing may carry one of the following trailing annotations: .Bl -column YXZ description .It @ Ta entry is a symbolic link .It / Ta entry is a directory .It * Ta entry is an executable file .It $ Ta entry is a Git submodule .El .Pp Symbolic link entries are also annotated with the target path of the link. .Pp If no .Ar path is specified, list the repository path corresponding to the current directory of the work tree, or the root directory of the repository if there is no work tree. .Pp The options for .Cm got tree are as follows: .Bl -tag -width Ds .It Fl c Ar commit List files and directories as they appear in the specified .Ar commit . The expected argument is a commit ID SHA1 hash or an existing reference or tag name which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full SHA1 hash automatically, provided the abbreviation is unique. .It Fl i Show object IDs of files (blob objects) and directories (tree objects). .It Fl R Recurse into sub-directories in the repository. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .El .It Xo .Cm tag .Op Fl lVv .Op Fl c Ar commit .Op Fl m Ar message .Op Fl r Ar repository-path .Op Fl s Ar signer-id .Ar name .Xc Manage tags in a repository. .Pp Tags are managed via references which live in the .Dq refs/tags/ reference namespace. The .Cm got tag command operates on references in this namespace only. References in this namespace point at tag objects which contain a pointer to another object, a tag message, as well as author and timestamp information. .Pp Attempt to create a tag with the given .Ar name , and make this tag point at the given .Ar commit . If no commit is specified, default to the latest commit on the work tree's current branch if invoked in a work tree, and to a commit resolved via the repository's HEAD reference otherwise. .Pp The options for .Cm got tag are as follows: .Bl -tag -width Ds .It Fl c Ar commit Make the newly created tag reference point at the specified .Ar commit . The expected .Ar commit argument is a commit ID SHA1 hash or an existing reference or tag name which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full SHA1 hash automatically, provided the abbreviation is unique. .It Fl l List all existing tags in the repository instead of creating a new tag. If a .Ar name argument is passed, show only the tag with the given .Ar name . .It Fl m Ar message Use the specified tag message when creating the new tag. Without the .Fl m option, .Cm got tag opens a temporary file in an editor where a tag message can be written. Quitting the editor without saving the file will abort the tag operation. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .It Fl s Ar signer-id While creating a new tag, sign this tag with the identity given in .Ar signer-id . .Pp For SSH-based signatures, .Ar signer-id is the path to a file which may refer to either a private SSH key, or a public SSH key with the private half available via .Xr ssh-agent 1 . .Cm got tag will sign the tag object by invoking .Xr ssh-keygen 1 with the .Fl Y Cm sign command, using the signature namespace .Dq git for compatibility with .Xr git 1 . .It Fl V Verify tag object signatures. If a .Ar name is specified, show and verify the tag object with the provided name. Otherwise, list all tag objects and verify signatures where present. .Pp .Cm got tag verifies SSH-based signatures by invoking .Xr ssh-keygen 1 with the options .Fl Y Cm verify Fl f Ar allowed_signers . A path to the .Ar allowed_signers file must be set in .Xr got.conf 5 , otherwise verification is impossible. .It Fl v Verbose mode. During SSH signature creation and verification this option will be passed to .Xr ssh-keygen 1 . Multiple -v options increase the verbosity. The maximum is 3. .El .Pp By design, the .Cm got tag command will not delete tags or change existing tags. If a tag must be deleted, the .Cm got ref command may be used to delete a tag's reference. This should only be done if the tag has not already been copied to another repository. .It Xo .Cm add .Op Fl IR .Ar path ... .Xc Schedule unversioned files in a work tree for addition to the repository in the next commit. By default, files which match a .Cm got status ignore pattern will not be added. .Pp If a .Ar path mentioned in the command line is not an unversioned file then .Cm got add may raise an error. To avoid unnecessary errors from paths picked up by file globbing patterns in the shell, paths in the argument list will be silently ignored if they are not reported by .Cm got status at all, or if they are reported with one of the following status codes and do not have changes staged via .Cm got stage : .Bl -column YXZ description .It M Ta modified file .It A Ta file scheduled for addition in next commit .It C Ta modified or added file which contains merge conflicts .It m Ta modified file modes (executable bit only) .El .Pp The options for .Cm got add are as follows: .Bl -tag -width Ds .It Fl I Add files even if they match a .Cm got status ignore pattern. .It Fl R Permit recursion into directories. If this option is not specified, .Cm got add will refuse to run if a specified .Ar path is a directory. .El .Tg rm .It Xo .Cm remove .Op Fl fkR .Op Fl s Ar status-codes .Ar path ... .Xc .Dl Pq alias: Cm rm Remove versioned files from a work tree and schedule them for deletion from the repository in the next commit. .Pp The options for .Cm got remove are as follows: .Bl -tag -width Ds .It Fl f Perform the operation even if a file contains local modifications, and do not raise an error if a specified .Ar path does not exist on disk. .It Fl k Keep affected files on disk. .It Fl R Permit recursion into directories. If this option is not specified, .Cm got remove will refuse to run if a specified .Ar path is a directory. .It Fl s Ar status-codes Only delete files with a modification status matching one of the single-character status codes contained in the .Ar status-codes argument. The following status codes may be specified: .Bl -column YXZ description .It M Ta modified file (this implies the .Fl f option) .It ! Ta versioned file expected on disk but missing .El .El .Tg pa .It Xo .Cm patch .Op Fl nR .Op Fl c Ar commit .Op Fl p Ar strip-count .Op Ar patchfile .Xc .Dl Pq alias: Cm pa Apply changes from .Ar patchfile to files in a work tree. Files added or removed by a patch will be scheduled for addition or removal in the work tree. .Pp The patch must be in the unified diff format as produced by .Cm got diff , .Xr git-diff 1 , or by .Xr diff 1 and .Xr cvs 1 diff when invoked with their .Fl u options. If no .Ar patchfile argument is provided, read unified diff data from standard input instead. .Pp If the .Ar patchfile contains multiple patches, then attempt to apply each of them in sequence. .Pp Show the status of each affected file, using the following status codes: .Bl -column XYZ description .It M Ta file was modified .It G Ta file was merged using a merge-base found in the repository .It C Ta file was merged and conflicts occurred during merge .It D Ta file was deleted .It A Ta file was added .It # Ta failed to patch the file .El .Pp If a change does not match at its exact line number, attempt to apply it somewhere else in the file if a good spot can be found. Otherwise, the patch will fail to apply. .Pp .Nm .Cm patch will refuse to apply a patch if certain preconditions are not met. Files to be deleted must already be under version control, and must not have been scheduled for deletion already. Files to be added must not yet be under version control and must not already be present on disk. Files to be modified must already be under version control and may not contain conflict markers. .Pp If an error occurs, the .Cm patch operation will be aborted. Any changes made to the work tree up to this point will be left behind. Such changes can be viewed with .Cm got diff and can be reverted with .Cm got revert if needed. .Pp The options for .Cm got patch are as follows: .Bl -tag -width Ds .It Fl c Ar commit Attempt to locate files within the specified .Ar commit for use as a merge-base for 3-way merges. Ideally, the specified .Ar commit should contain versions of files which the changes contained in the .Ar patchfile were based on. Files will be located by path, relative to the repository root. If the .Fl p option is used then leading path components will be stripped before paths are looked up in the repository. .Pp If the .Fl c option is not used then .Cm got patch will attempt to locate merge-bases via object IDs found in .Ar patchfile meta-data, such as produced by .Cm got diff or .Xr git-diff 1 . Use of the .Fl c option is only recommended in the absence of such meta-data. .Pp In case no merge-base is available for a file, changes will be applied without doing a 3-way merge. Changes which do not apply cleanly may then be rejected entirely, rather than producing merge conflicts in the patched target file. .It Fl n Do not make any modifications to the work tree. This can be used to check whether a patch would apply without issues. If the .Ar patchfile contains diffs that affect the same file multiple times, the results displayed may be incorrect. .It Fl p Ar strip-count Specify the number of leading path components to strip from paths parsed from .Ar patchfile . If the .Fl p option is not used, .Sq a/ and .Sq b/ path prefixes generated by .Xr git-diff 1 will be recognized and stripped automatically. .It Fl R Reverse the patch before applying it. .El .Tg rv .It Xo .Cm revert .Op Fl pR .Op Fl F Ar response-script .Ar path ... .Xc .Dl Pq alias: Cm rv Revert any local changes in files at the specified paths in a work tree. File contents will be overwritten with those contained in the work tree's base commit. There is no way to bring discarded changes back after .Cm got revert ! .Pp If a file was added with .Cm got add , it will become an unversioned file again. If a file was deleted with .Cm got remove , it will be restored. .Pp The options for .Cm got revert are as follows: .Bl -tag -width Ds .It Fl F Ar response-script With the .Fl p option, read .Dq y , .Dq n , and .Dq q responses line-by-line from the specified .Ar response-script file instead of prompting interactively. .It Fl p Instead of reverting all changes in files, interactively select or reject changes to revert based on .Dq y (revert change), .Dq n (keep change), and .Dq q (quit reverting this file) responses. If a file is in modified status, individual patches derived from the modified file content can be reverted. Files in added or deleted status may only be reverted in their entirety. .It Fl R Permit recursion into directories. If this option is not specified, .Cm got revert will refuse to run if a specified .Ar path is a directory. .El .Tg ci .It Xo .Cm commit .Op Fl CNnS .Op Fl A Ar author .Op Fl F Ar path .Op Fl m Ar message .Op Ar path ... .Xc .Dl Pq alias: Cm ci Create a new commit in the repository from changes in a work tree and use this commit as the new base commit for the work tree. If no .Ar path is specified, commit all changes in the work tree. Otherwise, commit changes at or within the specified paths. .Pp If changes have been explicitly staged for commit with .Cm got stage , only commit staged changes and reject any specified paths which have not been staged. .Pp .Cm got commit opens a temporary file in an editor where a log message can be written unless the .Fl m option is used or the .Fl F and .Fl N options are used together. Quitting the editor without saving the file will abort the commit operation. .Pp Show the status of each affected file, using the following status codes: .Bl -column YXZ description .It M Ta modified file .It D Ta file was deleted .It A Ta new file was added .It m Ta modified file modes (executable bit only) .El .Pp Files which are not part of the new commit will retain their previously recorded base commit. Some .Nm commands may refuse to run while the work tree contains files from multiple base commits. The base commit of such a work tree can be made consistent by running .Cm got update across the entire work tree. .Pp The .Cm got commit command requires the .Ev GOT_AUTHOR environment variable to be set, unless an author has been configured in .Xr got.conf 5 or Git's .Dv user.name and .Dv user.email configuration settings can be obtained from the repository's .Pa .git/config file or from Git's global .Pa ~/.gitconfig configuration file. .Pp The options for .Cm got commit are as follows: .Bl -tag -width Ds .It Fl A Ar author Set author information in the newly created commit to .Ar author . This is useful when committing changes on behalf of someone else. The .Ar author argument must use the same format as the .Ev GOT_AUTHOR environment variable. .Pp In addition to storing author information, the newly created commit object will retain .Dq committer information which is obtained, as usual, from the .Ev GOT_AUTHOR environment variable, or .Xr got.conf 5 , or Git configuration settings. .It Fl C Allow committing files in conflicted status. .Pp Committing files with conflict markers should generally be avoided. Cases where conflict markers must be stored in the repository for some legitimate reason should be very rare. There are usually ways to avoid storing conflict markers verbatim by applying appropriate programming tricks. .It Fl F Ar path Use the prepared log message stored in the file found at .Ar path when creating the new commit. .Cm got commit opens a temporary file in an editor where the prepared log message can be reviewed and edited further if needed. Cannot be used together with the .Fl m option. .It Fl m Ar message Use the specified log message when creating the new commit. Cannot be used together with the .Fl F option. .It Fl N This option prevents .Cm got commit from opening the commit message in an editor. It has no effect unless it is used together with the .Fl F option and is intended for non-interactive use such as scripting. .It Fl n This option prevents .Cm got commit from generating a diff of the to-be-committed changes in a temporary file which can be viewed while editing a commit message. .It Fl S Allow the addition of symbolic links which point outside of the path space that is under version control. By default, .Cm got commit will reject such symbolic links due to safety concerns. As a precaution, .Nm may decide to represent such a symbolic link as a regular file which contains the link's target path, rather than creating an actual symbolic link which points outside of the work tree. Use of this option is discouraged because external mechanisms such as .Dq make obj are better suited for managing symbolic links to paths not under version control. .El .Pp .Cm got commit will refuse to run if certain preconditions are not met. If the work tree's current branch is not in the .Dq refs/heads/ reference namespace, new commits may not be created on this branch. Local changes may only be committed if they are based on file content found in the most recent commit on the work tree's branch. If a path is found to be out of date, .Cm got update must be used first in order to merge local changes with changes made in the repository. .Tg cy .It Xo .Cm cherrypick .Op Fl lX .Op Ar commit .Xc .Dl Pq alias: Cm cy Merge changes from a single .Ar commit into the work tree. The specified .Ar commit should be on a different branch than the work tree's base commit. The expected argument is a reference or a commit ID SHA1 hash. An abbreviated hash argument will be expanded to a full SHA1 hash automatically, provided the abbreviation is unique. .Pp Show the status of each affected file, using the following status codes: .Bl -column YXZ description .It G Ta file was merged .It C Ta file was merged and conflicts occurred during merge .It ! Ta changes destined for a missing file were not merged .It D Ta file was deleted .It d Ta file's deletion was prevented by local modifications .It A Ta new file was added .It \(a~ Ta changes destined for a non-regular file were not merged .It ? Ta changes destined for an unversioned file were not merged .El .Pp The merged changes will appear as local changes in the work tree, which may be viewed with .Cm got diff , amended manually or with further .Cm got cherrypick commands, committed with .Cm got commit . .Pp If invoked in a work tree where no .Cm rebase , .Cm histedit , or .Cm merge operation is taking place, .Cm got cherrypick creates a record of commits which have been merged into the work tree. When a file changed by .Cm got cherrypick is committed with .Cm got commit , the log messages of relevant merged commits will then appear in the editor, where the messages should be further adjusted to convey the reasons for cherrypicking the changes. Upon exiting the editor, if the time stamp of the log message file is unchanged or the log message is empty, .Cm got commit will fail with an unmodified or empty log message error. .Pp If all the changes in all files touched by a given commit are discarded, e.g. with .Cm got revert , this commit's log message record will also disappear. .Pp .Cm got cherrypick will refuse to run if certain preconditions are not met. If the work tree contains multiple base commits, it must first be updated to a single base commit with .Cm got update . If any relevant files already contain merge conflicts, these conflicts must be resolved first. .Pp The options for .Nm .Cm cherrypick are as follows: .Bl -tag -width Ds .It Fl l Display a list of commit log messages recorded by cherrypick operations, represented by references in the .Dq refs/got/worktree reference namespace. If a .Ar commit is specified, only show the log message of the specified commit. .Pp If invoked in a work tree, only log messages recorded by cherrypick operations in the current work tree will be displayed. Otherwise, all commit log messages will be displayed irrespective of the work tree in which they were created. This option cannot be used with .Fl X . .It Fl X Delete log messages created by previous cherrypick operations, represented by references in the .Dq refs/got/worktree reference namespace. If a .Ar commit is specified, only delete the log message of the specified commit. .Pp If invoked in a work tree, only log messages recorded by cherrypick operations in the current work tree will be deleted. Otherwise, all commit log messages will be deleted irrespective of the work tree in which they were created. This option cannot be used with .Fl l . .El .Pp .Tg bo .It Xo .Cm backout .Op Fl lX .Op Ar commit .Xc .Dl Pq alias: Cm bo Reverse-merge changes from a single .Ar commit into the work tree. The specified .Ar commit should be on the same branch as the work tree's base commit. The expected argument is a reference or a commit ID SHA1 hash. An abbreviated hash argument will be expanded to a full SHA1 hash automatically, provided the abbreviation is unique. .Pp Show the status of each affected file, using the following status codes: .Bl -column YXZ description .It G Ta file was merged .It C Ta file was merged and conflicts occurred during merge .It ! Ta changes destined for a missing file were not merged .It D Ta file was deleted .It d Ta file's deletion was prevented by local modifications .It A Ta new file was added .It \(a~ Ta changes destined for a non-regular file were not merged .It ? Ta changes destined for an unversioned file were not merged .El .Pp The reverse-merged changes will appear as local changes in the work tree, which may be viewed with .Cm got diff , amended manually or with further .Cm got backout commands, committed with .Cm got commit . .Pp If invoked in a work tree where no .Cm rebase , .Cm histedit , or .Cm merge operation is taking place, .Cm got backout creates a record of commits which have been reverse-merged into the work tree. When a file changed by .Cm got backout is committed with .Cm got commit , the log messages of relevant reverse-merged commits will then appear in the editor, where the messages should be further adjusted to convey the reasons for backing out the changes. Upon exiting the editor, if the time stamp of the log message file is unchanged or the log message is empty, .Cm got commit will fail with an unmodified or empty log message error. .Pp If all the changes in all files touched by a given commit are discarded, e.g. with .Cm got revert , this commit's log message record will also disappear. .Pp .Cm got backout will refuse to run if certain preconditions are not met. If the work tree contains multiple base commits, it must first be updated to a single base commit with .Cm got update . If any relevant files already contain merge conflicts, these conflicts must be resolved first. .Pp The options for .Nm .Cm backout are as follows: .Bl -tag -width Ds .It Fl l Display a list of commit log messages recorded by backout operations, represented by references in the .Dq refs/got/worktree reference namespace. If a .Ar commit is specified, only show the log message of the specified commit. .Pp If invoked in a work tree, only log messages recorded by backout operations in the current work tree will be displayed. Otherwise, all commit log messages will be displayed irrespective of the work tree in which they were created. This option cannot be used with .Fl X . .It Fl X Delete log messages created by previous backout operations, represented by references in the .Dq refs/got/worktree reference namespace. If a .Ar commit is specified, only delete the log message of the specified commit. .Pp If invoked in a work tree, only log messages recorded by backout operations in the current work tree will be deleted. Otherwise, all commit log messages will be deleted irrespective of the work tree in which they were created. This option cannot be used with .Fl l . .El .It Xo .Cm cat .Op Fl P .Op Fl c Ar commit .Op Fl r Ar repository-path .Ar arg ... .Xc Parse and print contents of objects to standard output in a line-based text format. Content of commit, tree, and tag objects is printed in a way similar to the actual content stored in such objects. Blob object contents are printed as they would appear in files on disk. .Pp Attempt to interpret each argument as a reference, a tag name, or an object ID SHA1 hash. References will be resolved to an object ID. Tag names will resolved to a tag object. An abbreviated hash argument will be expanded to a full SHA1 hash automatically, provided the abbreviation is unique. .Pp If none of the above interpretations produce a valid result, or if the .Fl P option is used, attempt to interpret the argument as a path which will be resolved to the ID of an object found at this path in the repository. .Pp The options for .Cm got cat are as follows: .Bl -tag -width Ds .It Fl c Ar commit Look up paths in the specified .Ar commit . If this option is not used, paths are looked up in the commit resolved via the repository's HEAD reference. The expected argument is a commit ID SHA1 hash or an existing reference or tag name which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full SHA1 hash automatically, provided the abbreviation is unique. .It Fl P Interpret all arguments as paths only. This option can be used to resolve ambiguity in cases where paths look like tag names, reference names, or object IDs. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .El .It Cm info Op Ar path ... Display meta-data stored in a work tree. See .Xr got-worktree 5 for details. .Pp The work tree to use is resolved implicitly by walking upwards from the current working directory. .Pp If one or more .Ar path arguments are specified, show additional per-file information for tracked files located at or within these paths. If a .Ar path argument corresponds to the work tree's root directory, display information for all tracked files. .El .Sh ENVIRONMENT .Bl -tag -width GOT_IGNORE_GITCONFIG .It Ev GOT_AUTHOR The author's name and email address, such as .Dq An Flan Hacker Aq Mt flan_hacker@openbsd.org . Used by the .Cm got commit , .Cm got import , .Cm got rebase , .Cm got merge , and .Cm got histedit commands. Because .Xr git 1 may fail to parse commits without an email address in author data, .Nm attempts to reject .Ev GOT_AUTHOR environment variables with a missing email address. .Pp .Ev GOT_AUTHOR will be overridden by configuration settings in .Xr got.conf 5 or by Git's .Dv user.name and .Dv user.email configuration settings in the repository's .Pa .git/config file. The .Dv user.name and .Dv user.email configuration settings contained in Git's global .Pa ~/.gitconfig configuration file will only be used if neither .Xr got.conf 5 nor the .Ev GOT_AUTHOR environment variable provide author information. .It Ev GOT_IGNORE_GITCONFIG If this variable is set then any remote repository definitions or author information found in Git configuration files will be ignored. .It Ev GOT_LOG_DEFAULT_LIMIT The default limit on the number of commits traversed by .Cm got log . If set to zero, the limit is unbounded. This variable will be silently ignored if it is set to a non-numeric value. .It Ev VISUAL , EDITOR The editor spawned by .Cm got commit , .Cm got histedit , .Cm got import , or .Cm got tag . If not set, the .Xr vi 1 text editor will be spawned. .El .Sh FILES .Bl -tag -width packed-refs -compact .It Pa got.conf Repository-wide configuration settings for .Nm . If present, a .Xr got.conf 5 configuration file located in the root directory of a Git repository supersedes any relevant settings in Git's .Pa config file. .Pp .It Pa .cvg/got.conf Worktree-specific configuration settings for .Nm . If present, a .Xr got.conf 5 configuration file in the .Pa .cvg meta-data directory of a work tree supersedes any relevant settings in the repository's .Xr got.conf 5 configuration file and Git's .Pa config file. .El .Sh EXIT STATUS .Ex -std got .Sh EXAMPLES Enable tab-completion of .Nm command names in .Xr ksh 1 : .Pp .Dl $ set -A complete_got_1 -- $(got -h 2>&1 | sed -n s/commands://p) .Pp Clone an existing Git repository for use with .Nm : .Pp .Dl $ cd /var/git/ .Dl $ got clone ssh://git@github.com/openbsd/src.git .Pp Unfortunately, many of the popular Git hosting sites do not offer anonymous access via SSH. Such sites will require an account to be created, and a public SSH key to be uploaded to this account, before repository access via ssh:// URLs will work. .Pp Use of HTTP URLs currently requires .Xr git 1 : .Pp .Dl $ cd /var/git/ .Dl $ git clone --bare https://github.com/openbsd/src.git .Pp Alternatively, for quick and dirty local testing of .Nm a new Git repository could be created and populated with files, e.g. from a temporary CVS checkout located at .Pa /tmp/src : .Pp .Dl $ gotadmin init /var/git/src.git .Dl $ got import -r /var/git/src.git -I CVS -I obj /tmp/src .Pp Check out a work tree from the Git repository to /usr/src: .Pp .Dl $ got checkout /var/git/src.git /usr/src .Pp View local changes in a work tree directory: .Pp .Dl $ got diff | less .Pp In a work tree, display files in a potentially problematic state: .Pp .Dl $ got status -s 'C!~?' .Pp Interactively revert selected local changes in a work tree directory: .Pp .Dl $ got revert -p -R\ . .Pp In a work tree or a git repository directory, list all branch references: .Pp .Dl $ got branch -l .Pp As above, but list the most recently modified branches only: .Pp .Dl $ got branch -lt | head .Pp In a work tree or a git repository directory, create a new branch called .Dq unified-buffer-cache which is forked off the .Dq master branch: .Pp .Dl $ got branch -c master unified-buffer-cache .Pp Switch an existing work tree to the branch .Dq unified-buffer-cache . Local changes in the work tree will be preserved and merged if necessary: .Pp .Dl $ got update -b unified-buffer-cache .Pp Create a new commit from local changes in a work tree directory. This new commit will become the head commit of the work tree's current branch: .Pp .Dl $ got commit .Pp In a work tree or a git repository directory, view changes committed in the 3 most recent commits to the work tree's branch, or the branch resolved via the repository's HEAD reference, respectively: .Pp .Dl $ got log -p -l 3 .Pp As above, but display changes in the order in which .Xr patch 1 could apply them in sequence: .Pp .Dl $ got log -p -l 3 -R .Pp In a work tree or a git repository directory, log the history of a subdirectory: .Pp .Dl $ got log sys/uvm .Pp While operating inside a work tree, paths are specified relative to the current working directory, so this command will log the subdirectory .Pa sys/uvm : .Pp .Dl $ cd sys/uvm && got log\ . .Pp And this command has the same effect: .Pp .Dl $ cd sys/dev/usb && got log ../../uvm .Pp And this command displays work tree meta-data about all tracked files: .Pp .Dl $ cd /usr/src .Dl $ got info\ . | less .Pp Add new files and remove obsolete files in a work tree directory: .Pp .Dl $ got add sys/uvm/uvm_ubc.c .Dl $ got remove sys/uvm/uvm_vnode.c .Pp Create a new commit from local changes in a work tree directory with a pre-defined log message. .Pp .Dl $ got commit -m 'unify the buffer cache' .Pp Alternatively, create a new commit from local changes in a work tree directory with a log message that has been prepared in the file .Pa /tmp/msg : .Pp .Dl $ got commit -F /tmp/msg .Pp Update any work tree checked out from the .Dq unified-buffer-cache branch to the latest commit on this branch: .Pp .Dl $ got update .Pp Roll file content on the unified-buffer-cache branch back by one commit, and then fetch the rolled-back change into the work tree as a local change to be amended and perhaps committed again: .Pp .Dl $ got backout unified-buffer-cache .Dl $ got commit -m 'roll back previous' .Dl $ # now back out the previous backout :-) .Dl $ got backout unified-buffer-cache .Pp Fetch new changes on the remote repository's .Dq master branch, making them visible on the local repository's .Dq origin/master branch: .Pp .Dl $ cd /usr/src .Dl $ got fetch .Pp In a repository created with a HTTP URL and .Cm git clone --bare the .Xr git-fetch 1 command must be used instead: .Pp .Dl $ cd /var/git/src.git .Dl $ git fetch origin master:refs/remotes/origin/master .Pp Rebase the local .Dq master branch to merge the new changes that are now visible on the .Dq origin/master branch: .Pp .Dl $ cd /usr/src .Dl $ got update -b origin/master .Dl $ got rebase master .Pp Rebase the .Dq unified-buffer-cache branch on top of the new head commit of the .Dq master branch. .Pp .Dl $ got update -b master .Dl $ got rebase unified-buffer-cache .Pp Create a patch from all changes on the unified-buffer-cache branch. The patch can be mailed out for review and applied to .Ox Ns 's CVS tree: .Pp .Dl $ got diff master unified-buffer-cache > /tmp/ubc.diff .Pp Edit the entire commit history of the .Dq unified-buffer-cache branch: .Pp .Dl $ got update -b unified-buffer-cache .Dl $ got update -c master .Dl $ got histedit .Pp Before working against existing branches in a repository cloned with .Cm git clone --bare instead of .Cm got clone , a Git .Dq refspec must be configured to map all references in the remote repository into the .Dq refs/remotes namespace of the local repository. This can be achieved by setting Git's .Pa remote.origin.fetch configuration variable to the value .Dq +refs/heads/*:refs/remotes/origin/* with the .Cm git config command: .Pp .Dl $ cd /var/git/repo .Dl $ git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*' .Pp Additionally, the .Dq mirror option must be disabled: .Pp .Dl $ cd /var/git/repo .Dl $ git config remote.origin.mirror false .Pp Alternatively, the following .Xr git-fetch 1 configuration item can be added manually to the Git repository's .Pa config file: .Pp .Dl [remote \&"origin\&"] .Dl url = ... .Dl fetch = +refs/heads/*:refs/remotes/origin/* .Dl mirror = false .Pp This configuration leaves the local repository's .Dq refs/heads namespace free for use by local branches checked out with .Cm got checkout and, if needed, created with .Cm got branch . Branches in the .Dq refs/remotes/origin namespace can now be updated with incoming changes from the remote repository with .Cm got fetch or .Xr git-fetch 1 without extra command line arguments. Newly fetched changes can be examined with .Cm got log . .Pp Display changes on the remote repository's version of the .Dq master branch, as of the last time .Cm got fetch was run: .Pp .Dl $ got log -c origin/master | less .Pp As shown here, most commands accept abbreviated reference names such as .Dq origin/master instead of .Dq refs/remotes/origin/master . The latter is only needed in case of ambiguity. .Pp .Cm got rebase can be used to merge changes which are visible on the .Dq origin/master branch into the .Dq master branch. This will also merge local changes, if any, with the incoming changes: .Pp .Dl $ got update -b origin/master .Dl $ got rebase master .Pp In order to make changes committed to the .Dq unified-buffer-cache visible on the .Dq master branch, the .Dq unified-buffer-cache branch can be rebased onto the .Dq master branch: .Pp .Dl $ got update -b master .Dl $ got rebase unified-buffer-cache .Pp Changes on the .Dq unified-buffer-cache branch can now be made visible on the .Dq master branch with .Cm got integrate . Because the rebase operation switched the work tree to the .Dq unified-buffer-cache branch, the work tree must be switched back to the .Dq master branch first: .Pp .Dl $ got update -b master .Dl $ got integrate unified-buffer-cache .Pp On the .Dq master branch, log messages for local changes can now be amended with .Dq OK by other developers and any other important new information: .Pp .Dl $ got update -c origin/master .Dl $ got histedit -m .Pp If the remote repository offers write access, local changes on the .Dq master branch can be sent to the remote repository with .Cm got send . Usually, .Cm got send can be run without further arguments. The arguments shown here match defaults, provided the work tree's current branch is the .Dq master branch: .Pp .Dl $ got send -b master origin .Pp If the remote repository requires the HTTPS protocol, the .Xr git-push 1 command must be used instead: .Pp .Dl $ cd /var/git/src.git .Dl $ git push origin master .Pp When making contributions to projects which use the .Dq pull request workflow, SSH protocol repository access needs to be set up first. Once an account has been created on a Git hosting site it should be possible to upload a public SSH key for repository access authentication. .Pp The .Dq pull request workflow will usually involve two remote repositories. In the real-life example below, the .Dq origin repository was forked from the .Dq upstream repository by using the Git hosting site's web interface. The .Xr got.conf 5 file in the local repository describes both remote repositories: .Bd -literal -offset indent # Jelmers's repository, which accepts pull requests remote "upstream" { server git@github.com protocol ssh repository "/jelmer/dulwich" branch { "master" } } # Stefan's fork, used as the default remote repository remote "origin" { server git@github.com protocol ssh repository "/stspdotname/dulwich" branch { "master" } } .Ed .Pp With this configuration, Stefan can create commits on .Dq refs/heads/master and send them to the .Dq origin repository by running: .Pp .Dl $ got send -b master origin .Pp The changes can now be proposed to Jelmer by opening a pull request via the Git hosting site's web interface. If Jelmer requests further changes to be made, additional commits can be created on the .Dq master branch and be added to the pull request by running .Cd got send again. .Pp If Jelmer prefers additional commits to be .Dq squashed then the following commands can be used to achieve this: .Pp .Dl $ got update -b master .Dl $ got update -c origin/master .Dl $ got histedit -f .Dl $ got send -f -b master origin .Pp In addition to reviewing the pull request in the web user interface, Jelmer can fetch the pull request's branch into his local repository and create a local branch which contains the proposed changes: .Pp .Dl $ got fetch -R refs/pull/1046/head origin .Dl $ got branch -c refs/remotes/origin/pull/1046/head pr1046 .Pp Once Jelmer has accepted the pull request, Stefan can fetch the merged changes, and possibly several other new changes, by running: .Pp .Dl $ got fetch upstream .Pp The merged changes will now be visible under the reference .Dq refs/remotes/upstream/master . The local .Dq master branch can now be rebased on top of the latest changes from upstream: .Pp .Dl $ got update -b upstream/master .Dl $ got rebase master .Pp As an alternative to .Cm got rebase , branches can be merged with .Cm got merge : .Pp .Dl $ got update -b master .Dl $ got merge upstream/master .Pp The question of whether to rebase or merge branches is philosophical. When in doubt, refer to the software project's policies set by project maintainers. .Pp As a final step, the forked repository's copy of the master branch needs to be kept in sync by sending the new changes there: .Pp .Dl $ got send -f -b master origin .Pp If multiple pull requests need to be managed in parallel, a separate branch must be created for each pull request with .Cm got branch . Each such branch can then be used as above, in place of .Dq refs/heads/master . Changes for any accepted pull requests will still appear under .Dq refs/remotes/upstream/master, regardless of which branch was used in the forked repository to create a pull request. .Sh SEE ALSO .Xr gotadmin 1 , .Xr tog 1 , .Xr git-repository 5 , .Xr got-worktree 5 , .Xr got.conf 5 , .Xr gotwebd 8 .Sh AUTHORS .An Anthony J. Bentley Aq Mt bentley@openbsd.org .An Christian Weisgerber Aq Mt naddy@openbsd.org .An Hiltjo Posthuma Aq Mt hiltjo@codemadness.org .An Josh Rickmar Aq Mt jrick@zettaport.com .An Joshua Stein Aq Mt jcs@openbsd.org .An Klemens Nanni Aq Mt kn@openbsd.org .An Martin Pieuchot Aq Mt mpi@openbsd.org .An Neels Hofmeyr Aq Mt neels@hofmeyr.de .An Omar Polo Aq Mt op@openbsd.org .An Ori Bernstein Aq Mt ori@openbsd.org .An Sebastien Marie Aq Mt semarie@openbsd.org .An Stefan Sperling Aq Mt stsp@openbsd.org .An Steven McDonald Aq Mt steven@steven-mcdonald.id.au .An Theo Buehler Aq Mt tb@openbsd.org .An Thomas Adam Aq Mt thomas@xteddy.org .An Tracey Emery Aq Mt tracey@traceyemery.net .An Yang Zhong Aq Mt yzhong@freebsdfoundation.org .Pp Parts of .Nm , .Xr tog 1 , and .Xr gotwebd 8 were derived from code under copyright by: .Pp .An Caldera International .An Daniel Hartmeier .An Esben Norby .An Henning Brauer .An Håkan Olsson .An Ingo Schwarze .An Jean-Francois Brousseau .An Joris Vink .An Jyri J. Virkki .An Larry Wall .An Markus Friedl .An Niall O'Higgins .An Niklas Hallqvist .An Ray Lai .An Ryan McBride .An Theo de Raadt .An Todd C. Miller .An Xavier Santolaria .Pp .Nm contains code contributed to the public domain by .An Austin Appleby . .Sh CAVEATS .Nm is a work-in-progress and some features remain to be implemented. .Pp At present, the user has to fall back on .Xr git 1 to perform some tasks. In particular: .Bl -bullet .It Reading from remote repositories over HTTP or HTTPS protocols requires .Xr git-clone 1 and .Xr git-fetch 1 . .It Writing to remote repositories over HTTP or HTTPS protocols requires .Xr git-push 1 . .It The creation of merge commits with more than two parent commits requires .Xr git-merge 1 . .It In situations where files or directories were moved around .Cm got will not automatically merge changes to new locations and .Xr git 1 will usually produce better results. .El got-portable-0.101/cvg/Makefile.in0000664000175100017510000014054114644145543012442 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ sbin_PROGRAMS = cvg$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = cvg ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man1dir)" PROGRAMS = $(sbin_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_cvg_OBJECTS = cvg.$(OBJEXT) $(top_builddir)/lib/blame.$(OBJEXT) \ $(top_builddir)/lib/bloom.$(OBJEXT) \ $(top_builddir)/lib/buf.$(OBJEXT) \ $(top_builddir)/lib/commit_graph.$(OBJEXT) \ $(top_builddir)/lib/date.$(OBJEXT) \ $(top_builddir)/lib/deflate.$(OBJEXT) \ $(top_builddir)/lib/delta.$(OBJEXT) \ $(top_builddir)/lib/delta_cache.$(OBJEXT) \ $(top_builddir)/lib/deltify.$(OBJEXT) \ $(top_builddir)/lib/dial.$(OBJEXT) \ $(top_builddir)/lib/diff.$(OBJEXT) \ $(top_builddir)/lib/diff3.$(OBJEXT) \ $(top_builddir)/lib/diff_atomize_text.$(OBJEXT) \ $(top_builddir)/lib/diff_main.$(OBJEXT) \ $(top_builddir)/lib/diff_myers.$(OBJEXT) \ $(top_builddir)/lib/diff_output.$(OBJEXT) \ $(top_builddir)/lib/diff_output_edscript.$(OBJEXT) \ $(top_builddir)/lib/diff_output_plain.$(OBJEXT) \ $(top_builddir)/lib/diff_output_unidiff.$(OBJEXT) \ $(top_builddir)/lib/diff_patience.$(OBJEXT) \ $(top_builddir)/lib/diffreg.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/fetch.$(OBJEXT) \ $(top_builddir)/lib/fileindex.$(OBJEXT) \ $(top_builddir)/lib/gotconfig.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/lockfile.$(OBJEXT) \ $(top_builddir)/lib/murmurhash2.$(OBJEXT) \ $(top_builddir)/lib/object.$(OBJEXT) \ $(top_builddir)/lib/object_cache.$(OBJEXT) \ $(top_builddir)/lib/object_create.$(OBJEXT) \ $(top_builddir)/lib/object_idset.$(OBJEXT) \ $(top_builddir)/lib/object_open_privsep.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/opentemp.$(OBJEXT) \ $(top_builddir)/lib/pack.$(OBJEXT) \ $(top_builddir)/lib/pack_create.$(OBJEXT) \ $(top_builddir)/lib/pack_create_privsep.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/patch.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) \ $(top_builddir)/lib/ratelimit.$(OBJEXT) \ $(top_builddir)/lib/rcsutil.$(OBJEXT) \ $(top_builddir)/lib/read_gitconfig_privsep.$(OBJEXT) \ $(top_builddir)/lib/read_gotconfig_privsep.$(OBJEXT) \ $(top_builddir)/lib/reference.$(OBJEXT) \ $(top_builddir)/lib/reference_parse.$(OBJEXT) \ $(top_builddir)/lib/repository.$(OBJEXT) \ $(top_builddir)/lib/send.$(OBJEXT) \ $(top_builddir)/lib/sigs.$(OBJEXT) \ $(top_builddir)/lib/worktree.$(OBJEXT) \ $(top_builddir)/lib/worktree_cvg.$(OBJEXT) \ $(top_builddir)/lib/worktree_open.$(OBJEXT) cvg_OBJECTS = $(am_cvg_OBJECTS) cvg_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/blame.Po \ $(top_builddir)/lib/$(DEPDIR)/bloom.Po \ $(top_builddir)/lib/$(DEPDIR)/buf.Po \ $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po \ $(top_builddir)/lib/$(DEPDIR)/date.Po \ $(top_builddir)/lib/$(DEPDIR)/deflate.Po \ $(top_builddir)/lib/$(DEPDIR)/delta.Po \ $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/deltify.Po \ $(top_builddir)/lib/$(DEPDIR)/dial.Po \ $(top_builddir)/lib/$(DEPDIR)/diff.Po \ $(top_builddir)/lib/$(DEPDIR)/diff3.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_main.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po \ $(top_builddir)/lib/$(DEPDIR)/diffreg.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/fetch.Po \ $(top_builddir)/lib/$(DEPDIR)/fileindex.Po \ $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/lockfile.Po \ $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po \ $(top_builddir)/lib/$(DEPDIR)/object.Po \ $(top_builddir)/lib/$(DEPDIR)/object_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/object_create.Po \ $(top_builddir)/lib/$(DEPDIR)/object_idset.Po \ $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/opentemp.Po \ $(top_builddir)/lib/$(DEPDIR)/pack.Po \ $(top_builddir)/lib/$(DEPDIR)/pack_create.Po \ $(top_builddir)/lib/$(DEPDIR)/pack_create_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/patch.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po \ $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po \ $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/reference.Po \ $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/repository.Po \ $(top_builddir)/lib/$(DEPDIR)/send.Po \ $(top_builddir)/lib/$(DEPDIR)/sigs.Po \ $(top_builddir)/lib/$(DEPDIR)/worktree.Po \ $(top_builddir)/lib/$(DEPDIR)/worktree_cvg.Po \ $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po \ ./$(DEPDIR)/cvg.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(cvg_SOURCES) DIST_SOURCES = $(cvg_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } man1dir = $(mandir)/man1 NROFF = nroff MANS = $(man1_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(libbsd_CFLAGS) $(zlib_CFLAGS) \ $(libuuid_CFLAGS) $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ cvg_SOURCES = cvg.c \ $(top_srcdir)/lib/blame.c \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/commit_graph.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/diff.c \ $(top_srcdir)/lib/diff3.c \ $(top_srcdir)/lib/diff_atomize_text.c \ $(top_srcdir)/lib/diff_main.c \ $(top_srcdir)/lib/diff_myers.c \ $(top_srcdir)/lib/diff_output.c \ $(top_srcdir)/lib/diff_output_edscript.c \ $(top_srcdir)/lib/diff_output_plain.c \ $(top_srcdir)/lib/diff_output_unidiff.c \ $(top_srcdir)/lib/diff_patience.c \ $(top_srcdir)/lib/diffreg.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fetch.c \ $(top_srcdir)/lib/fileindex.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/patch.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/rcsutil.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/send.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/lib/worktree.c \ $(top_srcdir)/lib/worktree_cvg.c \ $(top_srcdir)/lib/worktree_open.c cvg_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = cvg.1 man1_MANS = cvg.1 LDADD = -L$(top_builddir)/compat -lopenbsd-compat -lm $(libbsd_LIBS) \ $(zlib_LIBS) $(libuuid_LIBS) $(libutil_LIBS) $(libmd_LIBS) \ $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign cvg/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign cvg/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: > $(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: > $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/blame.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/bloom.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/buf.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/commit_graph.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/date.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/deflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/deltify.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/dial.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff3.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_atomize_text.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_main.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_myers.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_edscript.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_plain.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_unidiff.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_patience.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diffreg.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/fetch.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/fileindex.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gotconfig.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/lockfile.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/murmurhash2.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_create.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_idset.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_open_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/opentemp.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack_create.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack_create_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/patch.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/ratelimit.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/rcsutil.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/read_gitconfig_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/read_gotconfig_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/repository.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/send.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/sigs.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/worktree.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/worktree_cvg.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/worktree_open.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) cvg$(EXEEXT): $(cvg_OBJECTS) $(cvg_DEPENDENCIES) $(EXTRA_cvg_DEPENDENCIES) @rm -f cvg$(EXEEXT) $(AM_V_CCLD)$(LINK) $(cvg_OBJECTS) $(cvg_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/blame.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/bloom.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/buf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/commit_graph.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/date.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/deflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/deltify.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/dial.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff3.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_myers.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_patience.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diffreg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/fetch.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/fileindex.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gotconfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/lockfile.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_create.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_idset.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/opentemp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack_create.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack_create_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/patch.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/ratelimit.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/rcsutil.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/repository.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/send.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/sigs.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/worktree.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/worktree_cvg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/worktree_open.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cvg.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` install-man1: $(man1_MANS) @$(NORMAL_INSTALL) @list1='$(man1_MANS)'; \ list2=''; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list='$(man1_MANS)'; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(MANS) installdirs: for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man1dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/blame.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/bloom.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/buf.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/date.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deltify.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/dial.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff3.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_main.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diffreg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fetch.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fileindex.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/lockfile.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/patch.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/send.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/sigs.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree_cvg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po -rm -f ./$(DEPDIR)/cvg.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/blame.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/bloom.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/buf.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/date.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deltify.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/dial.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff3.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_main.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diffreg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fetch.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fileindex.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/lockfile.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/patch.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/send.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/sigs.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree_cvg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po -rm -f ./$(DEPDIR)/cvg.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-man uninstall-sbinPROGRAMS uninstall-man: uninstall-man1 .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-sbinPROGRAMS cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-man1 install-pdf install-pdf-am install-ps \ install-ps-am install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-man uninstall-man1 \ uninstall-sbinPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/cvg/cvg.c0000664000175100017510000066774314644144735011344 /* * Copyright (c) 2017 Martin Pieuchot * Copyright (c) 2018, 2019, 2020 Stefan Sperling * Copyright (c) 2020 Ori Bernstein * Copyright (C) 2023 Josh Rickmar * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_version.h" #include "got_error.h" #include "got_object.h" #include "got_reference.h" #include "got_repository.h" #include "got_path.h" #include "got_cancel.h" #include "got_worktree.h" #include "got_worktree_cvg.h" #include "got_diff.h" #include "got_commit_graph.h" #include "got_fetch.h" #include "got_send.h" #include "got_blame.h" #include "got_privsep.h" #include "got_opentemp.h" #include "got_gotconfig.h" #include "got_dial.h" #include "got_patch.h" #include "got_sigs.h" #include "got_date.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif #ifndef GOT_DEFAULT_EDITOR #define GOT_DEFAULT_EDITOR "/usr/bin/vi" #endif static volatile sig_atomic_t sigint_received; static volatile sig_atomic_t sigpipe_received; static void catch_sigint(int signo) { sigint_received = 1; } static void catch_sigpipe(int signo) { sigpipe_received = 1; } struct got_cmd { const char *cmd_name; const struct got_error *(*cmd_main)(int, char *[]); void (*cmd_usage)(void); const char *cmd_alias; }; __dead static void usage(int, int); __dead static void usage_import(void); __dead static void usage_clone(void); __dead static void usage_checkout(void); __dead static void usage_update(void); __dead static void usage_log(void); __dead static void usage_diff(void); __dead static void usage_blame(void); __dead static void usage_tree(void); __dead static void usage_status(void); __dead static void usage_tag(void); __dead static void usage_add(void); __dead static void usage_remove(void); __dead static void usage_patch(void); __dead static void usage_revert(void); __dead static void usage_commit(void); __dead static void usage_cherrypick(void); __dead static void usage_backout(void); __dead static void usage_cat(void); __dead static void usage_info(void); static const struct got_error* cmd_import(int, char *[]); static const struct got_error* cmd_clone(int, char *[]); static const struct got_error* cmd_checkout(int, char *[]); static const struct got_error* cmd_update(int, char *[]); static const struct got_error* cmd_log(int, char *[]); static const struct got_error* cmd_diff(int, char *[]); static const struct got_error* cmd_blame(int, char *[]); static const struct got_error* cmd_tree(int, char *[]); static const struct got_error* cmd_status(int, char *[]); static const struct got_error* cmd_tag(int, char *[]); static const struct got_error* cmd_add(int, char *[]); static const struct got_error* cmd_remove(int, char *[]); static const struct got_error* cmd_patch(int, char *[]); static const struct got_error* cmd_revert(int, char *[]); static const struct got_error* cmd_commit(int, char *[]); static const struct got_error* cmd_cherrypick(int, char *[]); static const struct got_error* cmd_backout(int, char *[]); static const struct got_error* cmd_cat(int, char *[]); static const struct got_error* cmd_info(int, char *[]); static const struct got_cmd got_commands[] = { { "import", cmd_import, usage_import, "im" }, { "clone", cmd_clone, usage_clone, "cl" }, { "checkout", cmd_checkout, usage_checkout, "co" }, { "update", cmd_update, usage_update, "up" }, { "log", cmd_log, usage_log, "" }, { "diff", cmd_diff, usage_diff, "di" }, { "blame", cmd_blame, usage_blame, "bl" }, { "tree", cmd_tree, usage_tree, "tr" }, { "status", cmd_status, usage_status, "st" }, { "tag", cmd_tag, usage_tag, "" }, { "add", cmd_add, usage_add, "" }, { "remove", cmd_remove, usage_remove, "rm" }, { "patch", cmd_patch, usage_patch, "pa" }, { "revert", cmd_revert, usage_revert, "rv" }, { "commit", cmd_commit, usage_commit, "ci" }, { "cherrypick", cmd_cherrypick, usage_cherrypick, "cy" }, { "backout", cmd_backout, usage_backout, "bo" }, { "cat", cmd_cat, usage_cat, "" }, { "info", cmd_info, usage_info, "" }, }; static void list_commands(FILE *fp) { size_t i; fprintf(fp, "commands:"); for (i = 0; i < nitems(got_commands); i++) { const struct got_cmd *cmd = &got_commands[i]; fprintf(fp, " %s", cmd->cmd_name); } fputc('\n', fp); } __dead static void option_conflict(char a, char b) { errx(1, "-%c and -%c options are mutually exclusive", a, b); } int main(int argc, char *argv[]) { const struct got_cmd *cmd; size_t i; int ch; int hflag = 0, Vflag = 0; static const struct option longopts[] = { { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; setlocale(LC_CTYPE, ""); while ((ch = getopt_long(argc, argv, "+hV", longopts, NULL)) != -1) { switch (ch) { case 'h': hflag = 1; break; case 'V': Vflag = 1; break; default: usage(hflag, 1); /* NOTREACHED */ } } argc -= optind; argv += optind; optind = 1; optreset = 1; if (Vflag) { got_version_print_str(); return 0; } if (argc <= 0) usage(hflag, hflag ? 0 : 1); signal(SIGINT, catch_sigint); signal(SIGPIPE, catch_sigpipe); for (i = 0; i < nitems(got_commands); i++) { const struct got_error *error; cmd = &got_commands[i]; if (strcmp(cmd->cmd_name, argv[0]) != 0 && strcmp(cmd->cmd_alias, argv[0]) != 0) continue; if (hflag) cmd->cmd_usage(); error = cmd->cmd_main(argc, argv); if (error && error->code != GOT_ERR_CANCELLED && error->code != GOT_ERR_PRIVSEP_EXIT && !(sigpipe_received && error->code == GOT_ERR_ERRNO && errno == EPIPE) && !(sigint_received && error->code == GOT_ERR_ERRNO && errno == EINTR)) { fflush(stdout); fprintf(stderr, "%s: %s\n", getprogname(), error->msg); return 1; } return 0; } fprintf(stderr, "%s: unknown command '%s'\n", getprogname(), argv[0]); list_commands(stderr); return 1; } __dead static void usage(int hflag, int status) { FILE *fp = (status == 0) ? stdout : stderr; fprintf(fp, "usage: %s [-hV] command [arg ...]\n", getprogname()); if (hflag) list_commands(fp); exit(status); } static const struct got_error * get_editor(char **abspath) { const struct got_error *err = NULL; const char *editor; *abspath = NULL; editor = getenv("VISUAL"); if (editor == NULL) editor = getenv("EDITOR"); if (editor) { err = got_path_find_prog(abspath, editor); if (err) return err; } if (*abspath == NULL) { *abspath = strdup(GOT_DEFAULT_EDITOR); if (*abspath == NULL) return got_error_from_errno("strdup"); } return NULL; } static const struct got_error * apply_unveil(const char *repo_path, int repo_read_only, const char *worktree_path) { const struct got_error *err; #ifdef PROFILE if (unveil("gmon.out", "rwc") != 0) return got_error_from_errno2("unveil", "gmon.out"); #endif if (repo_path && unveil(repo_path, repo_read_only ? "r" : "rwc") != 0) return got_error_from_errno2("unveil", repo_path); if (worktree_path && unveil(worktree_path, "rwc") != 0) return got_error_from_errno2("unveil", worktree_path); if (unveil(GOT_TMPDIR_STR, "rwc") != 0) return got_error_from_errno2("unveil", GOT_TMPDIR_STR); err = got_privsep_unveil_exec_helpers(); if (err != NULL) return err; if (unveil(NULL, NULL) != 0) return got_error_from_errno("unveil"); return NULL; } __dead static void usage_import(void) { fprintf(stderr, "usage: %s import [-b branch] [-I pattern] [-m message] " "[-r repository-path] directory\n", getprogname()); exit(1); } static int spawn_editor(const char *editor, const char *file) { pid_t pid; sig_t sighup, sigint, sigquit; int st = -1; sighup = signal(SIGHUP, SIG_IGN); sigint = signal(SIGINT, SIG_IGN); sigquit = signal(SIGQUIT, SIG_IGN); switch (pid = fork()) { case -1: goto doneediting; case 0: execl(editor, editor, file, (char *)NULL); _exit(127); } while (waitpid(pid, &st, 0) == -1) if (errno != EINTR) break; doneediting: (void)signal(SIGHUP, sighup); (void)signal(SIGINT, sigint); (void)signal(SIGQUIT, sigquit); if (!WIFEXITED(st)) { errno = EINTR; return -1; } return WEXITSTATUS(st); } static const struct got_error * read_logmsg(char **logmsg, size_t *len, FILE *fp, size_t filesize) { const struct got_error *err = NULL; char *line = NULL; size_t linesize = 0; *logmsg = NULL; *len = 0; if (fseeko(fp, 0L, SEEK_SET) == -1) return got_error_from_errno("fseeko"); *logmsg = malloc(filesize + 1); if (*logmsg == NULL) return got_error_from_errno("malloc"); (*logmsg)[0] = '\0'; while (getline(&line, &linesize, fp) != -1) { if (line[0] == '#' || (*len == 0 && line[0] == '\n')) continue; /* remove comments and leading empty lines */ *len = strlcat(*logmsg, line, filesize + 1); if (*len >= filesize + 1) { err = got_error(GOT_ERR_NO_SPACE); goto done; } } if (ferror(fp)) { err = got_ferror(fp, GOT_ERR_IO); goto done; } while (*len > 0 && (*logmsg)[*len - 1] == '\n') { (*logmsg)[*len - 1] = '\0'; (*len)--; } done: free(line); if (err) { free(*logmsg); *logmsg = NULL; *len = 0; } return err; } static const struct got_error * edit_logmsg(char **logmsg, const char *editor, const char *logmsg_path, const char *initial_content, size_t initial_content_len, int require_modification) { const struct got_error *err = NULL; struct stat st, st2; FILE *fp = NULL; size_t logmsg_len; *logmsg = NULL; if (stat(logmsg_path, &st) == -1) return got_error_from_errno2("stat", logmsg_path); if (spawn_editor(editor, logmsg_path) == -1) return got_error_from_errno("failed spawning editor"); if (require_modification) { struct timespec timeout; timeout.tv_sec = 0; timeout.tv_nsec = 1; nanosleep(&timeout, NULL); } if (stat(logmsg_path, &st2) == -1) return got_error_from_errno2("stat", logmsg_path); if (require_modification && st.st_size == st2.st_size && timespeccmp(&st.st_mtim, &st2.st_mtim, ==)) return got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY, "no changes made to commit message, aborting"); fp = fopen(logmsg_path, "re"); if (fp == NULL) { err = got_error_from_errno("fopen"); goto done; } /* strip comments and leading/trailing newlines */ err = read_logmsg(logmsg, &logmsg_len, fp, st2.st_size); if (err) goto done; if (logmsg_len == 0) { err = got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY, "commit message cannot be empty, aborting"); goto done; } done: if (fp && fclose(fp) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (err) { free(*logmsg); *logmsg = NULL; } return err; } static const struct got_error * collect_import_msg(char **logmsg, char **logmsg_path, const char *editor, const char *path_dir, const char *branch_name) { char *initial_content = NULL; const struct got_error *err = NULL; int initial_content_len; int fd = -1; initial_content_len = asprintf(&initial_content, "\n# %s to be imported to branch %s\n", path_dir, branch_name); if (initial_content_len == -1) return got_error_from_errno("asprintf"); err = got_opentemp_named_fd(logmsg_path, &fd, GOT_TMPDIR_STR "/got-importmsg", ""); if (err) goto done; if (write(fd, initial_content, initial_content_len) == -1) { err = got_error_from_errno2("write", *logmsg_path); goto done; } if (close(fd) == -1) { err = got_error_from_errno2("close", *logmsg_path); goto done; } fd = -1; err = edit_logmsg(logmsg, editor, *logmsg_path, initial_content, initial_content_len, 1); done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno2("close", *logmsg_path); free(initial_content); if (err) { free(*logmsg_path); *logmsg_path = NULL; } return err; } static const struct got_error * import_progress(void *arg, const char *path) { printf("A %s\n", path); return NULL; } static const struct got_error * valid_author(const char *author) { const char *email = author; /* * Git' expects the author (or committer) to be in the form * "name ", which are mostly free form (see the * "committer" description in git-fast-import(1)). We're only * doing this to avoid git's object parser breaking on commits * we create. */ while (*author && *author != '\n' && *author != '<' && *author != '>') author++; if (author != email && *author == '<' && *(author - 1) != ' ') return got_error_fmt(GOT_ERR_COMMIT_BAD_AUTHOR, "%s: space " "between author name and email required", email); if (*author++ != '<') return got_error_fmt(GOT_ERR_COMMIT_NO_EMAIL, "%s", email); while (*author && *author != '\n' && *author != '<' && *author != '>') author++; if (strcmp(author, ">") != 0) return got_error_fmt(GOT_ERR_COMMIT_NO_EMAIL, "%s", email); return NULL; } static const struct got_error * get_author(char **author, struct got_repository *repo, struct got_worktree *worktree) { const struct got_error *err = NULL; const char *got_author = NULL, *name, *email; const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL; *author = NULL; if (worktree) worktree_conf = got_worktree_get_gotconfig(worktree); repo_conf = got_repo_get_gotconfig(repo); /* * Priority of potential author information sources, from most * significant to least significant: * 1) work tree's .got/got.conf file * 2) repository's got.conf file * 3) repository's git config file * 4) environment variables * 5) global git config files (in user's home directory or /etc) */ if (worktree_conf) got_author = got_gotconfig_get_author(worktree_conf); if (got_author == NULL) got_author = got_gotconfig_get_author(repo_conf); if (got_author == NULL) { name = got_repo_get_gitconfig_author_name(repo); email = got_repo_get_gitconfig_author_email(repo); if (name && email) { if (asprintf(author, "%s <%s>", name, email) == -1) return got_error_from_errno("asprintf"); return NULL; } got_author = getenv("GOT_AUTHOR"); if (got_author == NULL) { name = got_repo_get_global_gitconfig_author_name(repo); email = got_repo_get_global_gitconfig_author_email( repo); if (name && email) { if (asprintf(author, "%s <%s>", name, email) == -1) return got_error_from_errno("asprintf"); return NULL; } /* TODO: Look up user in password database? */ return got_error(GOT_ERR_COMMIT_NO_AUTHOR); } } *author = strdup(got_author); if (*author == NULL) return got_error_from_errno("strdup"); err = valid_author(*author); if (err) { free(*author); *author = NULL; } return err; } static const struct got_error * get_allowed_signers(char **allowed_signers, struct got_repository *repo, struct got_worktree *worktree) { const char *got_allowed_signers = NULL; const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL; *allowed_signers = NULL; if (worktree) worktree_conf = got_worktree_get_gotconfig(worktree); repo_conf = got_repo_get_gotconfig(repo); /* * Priority of potential author information sources, from most * significant to least significant: * 1) work tree's .got/got.conf file * 2) repository's got.conf file */ if (worktree_conf) got_allowed_signers = got_gotconfig_get_allowed_signers_file( worktree_conf); if (got_allowed_signers == NULL) got_allowed_signers = got_gotconfig_get_allowed_signers_file( repo_conf); if (got_allowed_signers) { *allowed_signers = strdup(got_allowed_signers); if (*allowed_signers == NULL) return got_error_from_errno("strdup"); } return NULL; } static const struct got_error * get_revoked_signers(char **revoked_signers, struct got_repository *repo, struct got_worktree *worktree) { const char *got_revoked_signers = NULL; const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL; *revoked_signers = NULL; if (worktree) worktree_conf = got_worktree_get_gotconfig(worktree); repo_conf = got_repo_get_gotconfig(repo); /* * Priority of potential author information sources, from most * significant to least significant: * 1) work tree's .got/got.conf file * 2) repository's got.conf file */ if (worktree_conf) got_revoked_signers = got_gotconfig_get_revoked_signers_file( worktree_conf); if (got_revoked_signers == NULL) got_revoked_signers = got_gotconfig_get_revoked_signers_file( repo_conf); if (got_revoked_signers) { *revoked_signers = strdup(got_revoked_signers); if (*revoked_signers == NULL) return got_error_from_errno("strdup"); } return NULL; } static const char * get_signer_id(struct got_repository *repo, struct got_worktree *worktree) { const char *got_signer_id = NULL; const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL; if (worktree) worktree_conf = got_worktree_get_gotconfig(worktree); repo_conf = got_repo_get_gotconfig(repo); /* * Priority of potential author information sources, from most * significant to least significant: * 1) work tree's .got/got.conf file * 2) repository's got.conf file */ if (worktree_conf) got_signer_id = got_gotconfig_get_signer_id(worktree_conf); if (got_signer_id == NULL) got_signer_id = got_gotconfig_get_signer_id(repo_conf); return got_signer_id; } static const struct got_error * get_gitconfig_path(char **gitconfig_path) { const char *homedir = getenv("HOME"); *gitconfig_path = NULL; if (homedir) { if (asprintf(gitconfig_path, "%s/.gitconfig", homedir) == -1) return got_error_from_errno("asprintf"); } return NULL; } static const struct got_error * cmd_import(int argc, char *argv[]) { const struct got_error *error = NULL; char *path_dir = NULL, *repo_path = NULL, *logmsg = NULL; char *gitconfig_path = NULL, *editor = NULL, *author = NULL; const char *branch_name = NULL; char *id_str = NULL, *logmsg_path = NULL; char refname[PATH_MAX] = "refs/heads/"; struct got_repository *repo = NULL; struct got_reference *branch_ref = NULL, *head_ref = NULL; struct got_object_id *new_commit_id = NULL; int ch, n = 0; struct got_pathlist_head ignores; struct got_pathlist_entry *pe; int preserve_logmsg = 0; int *pack_fds = NULL; TAILQ_INIT(&ignores); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "b:I:m:r:")) != -1) { switch (ch) { case 'b': branch_name = optarg; break; case 'I': if (optarg[0] == '\0') break; error = got_pathlist_insert(&pe, &ignores, optarg, NULL); if (error) goto done; break; case 'm': logmsg = strdup(optarg); if (logmsg == NULL) { error = got_error_from_errno("strdup"); goto done; } break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) { error = got_error_from_errno2("realpath", optarg); goto done; } break; default: usage_import(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc != 1) usage_import(); if (repo_path == NULL) { repo_path = getcwd(NULL, 0); if (repo_path == NULL) return got_error_from_errno("getcwd"); } got_path_strip_trailing_slashes(repo_path); error = get_gitconfig_path(&gitconfig_path); if (error) goto done; error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_repo_open(&repo, repo_path, gitconfig_path, pack_fds); if (error) goto done; error = get_author(&author, repo, NULL); if (error) return error; /* * Don't let the user create a branch name with a leading '-'. * While technically a valid reference name, this case is usually * an unintended typo. */ if (branch_name && branch_name[0] == '-') return got_error_path(branch_name, GOT_ERR_REF_NAME_MINUS); error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0); if (error && error->code != GOT_ERR_NOT_REF) goto done; if (branch_name) n = strlcat(refname, branch_name, sizeof(refname)); else if (head_ref && got_ref_is_symbolic(head_ref)) n = strlcpy(refname, got_ref_get_symref_target(head_ref), sizeof(refname)); else n = strlcat(refname, "main", sizeof(refname)); if (n >= sizeof(refname)) { error = got_error(GOT_ERR_NO_SPACE); goto done; } error = got_ref_open(&branch_ref, repo, refname, 0); if (error) { if (error->code != GOT_ERR_NOT_REF) goto done; } else { error = got_error_msg(GOT_ERR_BRANCH_EXISTS, "import target branch already exists"); goto done; } path_dir = realpath(argv[0], NULL); if (path_dir == NULL) { error = got_error_from_errno2("realpath", argv[0]); goto done; } got_path_strip_trailing_slashes(path_dir); /* * unveil(2) traverses exec(2); if an editor is used we have * to apply unveil after the log message has been written. */ if (logmsg == NULL || *logmsg == '\0') { error = get_editor(&editor); if (error) goto done; free(logmsg); error = collect_import_msg(&logmsg, &logmsg_path, editor, path_dir, refname); if (error) { if (error->code != GOT_ERR_COMMIT_MSG_EMPTY && logmsg_path != NULL) preserve_logmsg = 1; goto done; } } if (unveil(path_dir, "r") != 0) { error = got_error_from_errno2("unveil", path_dir); if (logmsg_path) preserve_logmsg = 1; goto done; } error = apply_unveil(got_repo_get_path(repo), 0, NULL); if (error) { if (logmsg_path) preserve_logmsg = 1; goto done; } error = got_repo_import(&new_commit_id, path_dir, logmsg, author, &ignores, repo, import_progress, NULL); if (error) { if (logmsg_path) preserve_logmsg = 1; goto done; } error = got_ref_alloc(&branch_ref, refname, new_commit_id); if (error) { if (logmsg_path) preserve_logmsg = 1; goto done; } error = got_ref_write(branch_ref, repo); if (error) { if (logmsg_path) preserve_logmsg = 1; goto done; } error = got_object_id_str(&id_str, new_commit_id); if (error) { if (logmsg_path) preserve_logmsg = 1; goto done; } error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0); if (error) { if (error->code != GOT_ERR_NOT_REF) { if (logmsg_path) preserve_logmsg = 1; goto done; } error = got_ref_alloc_symref(&head_ref, GOT_REF_HEAD, branch_ref); if (error) { if (logmsg_path) preserve_logmsg = 1; goto done; } error = got_ref_write(head_ref, repo); if (error) { if (logmsg_path) preserve_logmsg = 1; goto done; } } printf("Created branch %s with commit %s\n", got_ref_get_name(branch_ref), id_str); done: if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (preserve_logmsg) { fprintf(stderr, "%s: log message preserved in %s\n", getprogname(), logmsg_path); } else if (logmsg_path && unlink(logmsg_path) == -1 && error == NULL) error = got_error_from_errno2("unlink", logmsg_path); free(logmsg); free(logmsg_path); free(repo_path); free(editor); free(new_commit_id); free(id_str); free(author); free(gitconfig_path); if (branch_ref) got_ref_close(branch_ref); if (head_ref) got_ref_close(head_ref); return error; } __dead static void usage_clone(void) { fprintf(stderr, "usage: %s clone [-almqv] [-b branch] [-R reference] " "repository-URL [directory]\n", getprogname()); exit(1); } struct got_fetch_progress_arg { char last_scaled_size[FMT_SCALED_STRSIZE]; int last_p_indexed; int last_p_resolved; int verbosity; struct got_repository *repo; int create_configs; int configs_created; struct { struct got_pathlist_head *symrefs; struct got_pathlist_head *wanted_branches; struct got_pathlist_head *wanted_refs; const char *proto; const char *host; const char *port; const char *remote_repo_path; const char *git_url; int fetch_all_branches; int mirror_references; } config_info; }; /* XXX forward declaration */ static const struct got_error * create_config_files(const char *proto, const char *host, const char *port, const char *remote_repo_path, const char *git_url, int fetch_all_branches, int mirror_references, struct got_pathlist_head *symrefs, struct got_pathlist_head *wanted_branches, struct got_pathlist_head *wanted_refs, struct got_repository *repo); static const struct got_error * fetch_progress(void *arg, const char *message, off_t packfile_size, int nobj_total, int nobj_indexed, int nobj_loose, int nobj_resolved) { const struct got_error *err = NULL; struct got_fetch_progress_arg *a = arg; char scaled_size[FMT_SCALED_STRSIZE]; int p_indexed, p_resolved; int print_size = 0, print_indexed = 0, print_resolved = 0; /* * In order to allow a failed clone to be resumed with 'got fetch' * we try to create configuration files as soon as possible. * Once the server has sent information about its default branch * we have all required information. */ if (a->create_configs && !a->configs_created && !TAILQ_EMPTY(a->config_info.symrefs)) { err = create_config_files(a->config_info.proto, a->config_info.host, a->config_info.port, a->config_info.remote_repo_path, a->config_info.git_url, a->config_info.fetch_all_branches, a->config_info.mirror_references, a->config_info.symrefs, a->config_info.wanted_branches, a->config_info.wanted_refs, a->repo); if (err) return err; a->configs_created = 1; } if (a->verbosity < 0) return NULL; if (message && message[0] != '\0') { printf("\rserver: %s", message); fflush(stdout); return NULL; } if (packfile_size > 0 || nobj_indexed > 0) { if (fmt_scaled(packfile_size, scaled_size) == 0 && (a->last_scaled_size[0] == '\0' || strcmp(scaled_size, a->last_scaled_size)) != 0) { print_size = 1; if (strlcpy(a->last_scaled_size, scaled_size, FMT_SCALED_STRSIZE) >= FMT_SCALED_STRSIZE) return got_error(GOT_ERR_NO_SPACE); } if (nobj_indexed > 0) { p_indexed = (nobj_indexed * 100) / nobj_total; if (p_indexed != a->last_p_indexed) { a->last_p_indexed = p_indexed; print_indexed = 1; print_size = 1; } } if (nobj_resolved > 0) { p_resolved = (nobj_resolved * 100) / (nobj_total - nobj_loose); if (p_resolved != a->last_p_resolved) { a->last_p_resolved = p_resolved; print_resolved = 1; print_indexed = 1; print_size = 1; } } } if (print_size || print_indexed || print_resolved) printf("\r"); if (print_size) printf("%*s fetched", FMT_SCALED_STRSIZE - 2, scaled_size); if (print_indexed) printf("; indexing %d%%", p_indexed); if (print_resolved) printf("; resolving deltas %d%%", p_resolved); if (print_size || print_indexed || print_resolved) fflush(stdout); return NULL; } static const struct got_error * create_symref(const char *refname, struct got_reference *target_ref, int verbosity, struct got_repository *repo) { const struct got_error *err; struct got_reference *head_symref; err = got_ref_alloc_symref(&head_symref, refname, target_ref); if (err) return err; err = got_ref_write(head_symref, repo); if (err == NULL && verbosity > 0) { printf("Created reference %s: %s\n", GOT_REF_HEAD, got_ref_get_name(target_ref)); } got_ref_close(head_symref); return err; } static const struct got_error * list_remote_refs(struct got_pathlist_head *symrefs, struct got_pathlist_head *refs) { const struct got_error *err; struct got_pathlist_entry *pe; TAILQ_FOREACH(pe, symrefs, entry) { const char *refname = pe->path; const char *targetref = pe->data; printf("%s: %s\n", refname, targetref); } TAILQ_FOREACH(pe, refs, entry) { const char *refname = pe->path; struct got_object_id *id = pe->data; char *id_str; err = got_object_id_str(&id_str, id); if (err) return err; printf("%s: %s\n", refname, id_str); free(id_str); } return NULL; } static const struct got_error * create_ref(const char *refname, struct got_object_id *id, int verbosity, struct got_repository *repo) { const struct got_error *err = NULL; struct got_reference *ref; char *id_str; err = got_object_id_str(&id_str, id); if (err) return err; err = got_ref_alloc(&ref, refname, id); if (err) goto done; err = got_ref_write(ref, repo); got_ref_close(ref); if (err == NULL && verbosity >= 0) printf("Created reference %s: %s\n", refname, id_str); done: free(id_str); return err; } static int match_wanted_ref(const char *refname, const char *wanted_ref) { if (strncmp(refname, "refs/", 5) != 0) return 0; refname += 5; /* * Prevent fetching of references that won't make any * sense outside of the remote repository's context. */ if (strncmp(refname, "got/", 4) == 0) return 0; if (strncmp(refname, "remotes/", 8) == 0) return 0; if (strncmp(wanted_ref, "refs/", 5) == 0) wanted_ref += 5; /* Allow prefix match. */ if (got_path_is_child(refname, wanted_ref, strlen(wanted_ref))) return 1; /* Allow exact match. */ return (strcmp(refname, wanted_ref) == 0); } static int is_wanted_ref(struct got_pathlist_head *wanted_refs, const char *refname) { struct got_pathlist_entry *pe; TAILQ_FOREACH(pe, wanted_refs, entry) { if (match_wanted_ref(refname, pe->path)) return 1; } return 0; } static const struct got_error * create_wanted_ref(const char *refname, struct got_object_id *id, const char *remote_repo_name, int verbosity, struct got_repository *repo) { const struct got_error *err; char *remote_refname; if (strncmp("refs/", refname, 5) == 0) refname += 5; if (asprintf(&remote_refname, "refs/remotes/%s/%s", remote_repo_name, refname) == -1) return got_error_from_errno("asprintf"); err = create_ref(remote_refname, id, verbosity, repo); free(remote_refname); return err; } static const struct got_error * create_gotconfig(const char *proto, const char *host, const char *port, const char *remote_repo_path, const char *default_branch, int fetch_all_branches, struct got_pathlist_head *wanted_branches, struct got_pathlist_head *wanted_refs, int mirror_references, struct got_repository *repo) { const struct got_error *err = NULL; char *gotconfig_path = NULL; char *gotconfig = NULL; FILE *gotconfig_file = NULL; const char *branchname = NULL; char *branches = NULL, *refs = NULL; ssize_t n; if (!fetch_all_branches && !TAILQ_EMPTY(wanted_branches)) { struct got_pathlist_entry *pe; TAILQ_FOREACH(pe, wanted_branches, entry) { char *s; branchname = pe->path; if (strncmp(branchname, "refs/heads/", 11) == 0) branchname += 11; if (asprintf(&s, "%s\"%s\" ", branches ? branches : "", branchname) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(branches); branches = s; } } else if (!fetch_all_branches && default_branch) { branchname = default_branch; if (strncmp(branchname, "refs/heads/", 11) == 0) branchname += 11; if (asprintf(&branches, "\"%s\" ", branchname) == -1) { err = got_error_from_errno("asprintf"); goto done; } } if (!TAILQ_EMPTY(wanted_refs)) { struct got_pathlist_entry *pe; TAILQ_FOREACH(pe, wanted_refs, entry) { char *s; const char *refname = pe->path; if (strncmp(refname, "refs/", 5) == 0) branchname += 5; if (asprintf(&s, "%s\"%s\" ", refs ? refs : "", refname) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(refs); refs = s; } } /* Create got.conf(5). */ gotconfig_path = got_repo_get_path_gotconfig(repo); if (gotconfig_path == NULL) { err = got_error_from_errno("got_repo_get_path_gotconfig"); goto done; } gotconfig_file = fopen(gotconfig_path, "ae"); if (gotconfig_file == NULL) { err = got_error_from_errno2("fopen", gotconfig_path); goto done; } if (asprintf(&gotconfig, "remote \"%s\" {\n" "\tserver %s\n" "\tprotocol %s\n" "%s%s%s" "\trepository \"%s\"\n" "%s%s%s" "%s%s%s" "%s" "%s" "}\n", GOT_FETCH_DEFAULT_REMOTE_NAME, host, proto, port ? "\tport " : "", port ? port : "", port ? "\n" : "", remote_repo_path, branches ? "\tbranch { " : "", branches ? branches : "", branches ? "}\n" : "", refs ? "\treference { " : "", refs ? refs : "", refs ? "}\n" : "", mirror_references ? "\tmirror_references yes\n" : "", fetch_all_branches ? "\tfetch_all_branches yes\n" : "") == -1) { err = got_error_from_errno("asprintf"); goto done; } n = fwrite(gotconfig, 1, strlen(gotconfig), gotconfig_file); if (n != strlen(gotconfig)) { err = got_ferror(gotconfig_file, GOT_ERR_IO); goto done; } done: if (gotconfig_file && fclose(gotconfig_file) == EOF && err == NULL) err = got_error_from_errno2("fclose", gotconfig_path); free(gotconfig_path); free(branches); return err; } static const struct got_error * create_gitconfig(const char *git_url, const char *default_branch, int fetch_all_branches, struct got_pathlist_head *wanted_branches, struct got_pathlist_head *wanted_refs, int mirror_references, struct got_repository *repo) { const struct got_error *err = NULL; char *gitconfig_path = NULL; char *gitconfig = NULL; FILE *gitconfig_file = NULL; char *branches = NULL, *refs = NULL; const char *branchname; ssize_t n; /* Create a config file Git can understand. */ gitconfig_path = got_repo_get_path_gitconfig(repo); if (gitconfig_path == NULL) { err = got_error_from_errno("got_repo_get_path_gitconfig"); goto done; } gitconfig_file = fopen(gitconfig_path, "ae"); if (gitconfig_file == NULL) { err = got_error_from_errno2("fopen", gitconfig_path); goto done; } if (fetch_all_branches) { if (mirror_references) { if (asprintf(&branches, "\tfetch = refs/heads/*:refs/heads/*\n") == -1) { err = got_error_from_errno("asprintf"); goto done; } } else if (asprintf(&branches, "\tfetch = refs/heads/*:refs/remotes/%s/*\n", GOT_FETCH_DEFAULT_REMOTE_NAME) == -1) { err = got_error_from_errno("asprintf"); goto done; } } else if (!TAILQ_EMPTY(wanted_branches)) { struct got_pathlist_entry *pe; TAILQ_FOREACH(pe, wanted_branches, entry) { char *s; branchname = pe->path; if (strncmp(branchname, "refs/heads/", 11) == 0) branchname += 11; if (mirror_references) { if (asprintf(&s, "%s\tfetch = refs/heads/%s:refs/heads/%s\n", branches ? branches : "", branchname, branchname) == -1) { err = got_error_from_errno("asprintf"); goto done; } } else if (asprintf(&s, "%s\tfetch = refs/heads/%s:refs/remotes/%s/%s\n", branches ? branches : "", branchname, GOT_FETCH_DEFAULT_REMOTE_NAME, branchname) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(branches); branches = s; } } else { /* * If the server specified a default branch, use just that one. * Otherwise fall back to fetching all branches on next fetch. */ if (default_branch) { branchname = default_branch; if (strncmp(branchname, "refs/heads/", 11) == 0) branchname += 11; } else branchname = "*"; /* fall back to all branches */ if (mirror_references) { if (asprintf(&branches, "\tfetch = refs/heads/%s:refs/heads/%s\n", branchname, branchname) == -1) { err = got_error_from_errno("asprintf"); goto done; } } else if (asprintf(&branches, "\tfetch = refs/heads/%s:refs/remotes/%s/%s\n", branchname, GOT_FETCH_DEFAULT_REMOTE_NAME, branchname) == -1) { err = got_error_from_errno("asprintf"); goto done; } } if (!TAILQ_EMPTY(wanted_refs)) { struct got_pathlist_entry *pe; TAILQ_FOREACH(pe, wanted_refs, entry) { char *s; const char *refname = pe->path; if (strncmp(refname, "refs/", 5) == 0) refname += 5; if (mirror_references) { if (asprintf(&s, "%s\tfetch = refs/%s:refs/%s\n", refs ? refs : "", refname, refname) == -1) { err = got_error_from_errno("asprintf"); goto done; } } else if (asprintf(&s, "%s\tfetch = refs/%s:refs/remotes/%s/%s\n", refs ? refs : "", refname, GOT_FETCH_DEFAULT_REMOTE_NAME, refname) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(refs); refs = s; } } if (asprintf(&gitconfig, "[remote \"%s\"]\n" "\turl = %s\n" "%s" "%s" "\tfetch = refs/tags/*:refs/tags/*\n", GOT_FETCH_DEFAULT_REMOTE_NAME, git_url, branches ? branches : "", refs ? refs : "") == -1) { err = got_error_from_errno("asprintf"); goto done; } n = fwrite(gitconfig, 1, strlen(gitconfig), gitconfig_file); if (n != strlen(gitconfig)) { err = got_ferror(gitconfig_file, GOT_ERR_IO); goto done; } done: if (gitconfig_file && fclose(gitconfig_file) == EOF && err == NULL) err = got_error_from_errno2("fclose", gitconfig_path); free(gitconfig_path); free(branches); return err; } static const struct got_error * create_config_files(const char *proto, const char *host, const char *port, const char *remote_repo_path, const char *git_url, int fetch_all_branches, int mirror_references, struct got_pathlist_head *symrefs, struct got_pathlist_head *wanted_branches, struct got_pathlist_head *wanted_refs, struct got_repository *repo) { const struct got_error *err = NULL; const char *default_branch = NULL; struct got_pathlist_entry *pe; /* * If we asked for a set of wanted branches then use the first * one of those. */ if (!TAILQ_EMPTY(wanted_branches)) { pe = TAILQ_FIRST(wanted_branches); default_branch = pe->path; } else { /* First HEAD ref listed by server is the default branch. */ TAILQ_FOREACH(pe, symrefs, entry) { const char *refname = pe->path; const char *target = pe->data; if (strcmp(refname, GOT_REF_HEAD) != 0) continue; default_branch = target; break; } } /* Create got.conf(5). */ err = create_gotconfig(proto, host, port, remote_repo_path, default_branch, fetch_all_branches, wanted_branches, wanted_refs, mirror_references, repo); if (err) return err; /* Create a config file Git can understand. */ return create_gitconfig(git_url, default_branch, fetch_all_branches, wanted_branches, wanted_refs, mirror_references, repo); } static const struct got_error * cmd_clone(int argc, char *argv[]) { const struct got_error *error = NULL; const char *uri, *dirname; char *proto, *host, *port, *repo_name, *server_path; char *default_destdir = NULL, *id_str = NULL; const char *repo_path; struct got_repository *repo = NULL; struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs; struct got_pathlist_entry *pe; struct got_object_id *pack_hash = NULL; int ch, fetchfd = -1, fetchstatus; pid_t fetchpid = -1; struct got_fetch_progress_arg fpa; char *git_url = NULL; int verbosity = 0, fetch_all_branches = 0, mirror_references = 0; int bflag = 0, list_refs_only = 0; int *pack_fds = NULL; TAILQ_INIT(&refs); TAILQ_INIT(&symrefs); TAILQ_INIT(&wanted_branches); TAILQ_INIT(&wanted_refs); while ((ch = getopt(argc, argv, "ab:lmqR:v")) != -1) { switch (ch) { case 'a': fetch_all_branches = 1; break; case 'b': error = got_pathlist_append(&wanted_branches, optarg, NULL); if (error) return error; bflag = 1; break; case 'l': list_refs_only = 1; break; case 'm': mirror_references = 1; break; case 'q': verbosity = -1; break; case 'R': error = got_pathlist_append(&wanted_refs, optarg, NULL); if (error) return error; break; case 'v': if (verbosity < 0) verbosity = 0; else if (verbosity < 3) verbosity++; break; default: usage_clone(); break; } } argc -= optind; argv += optind; if (fetch_all_branches && !TAILQ_EMPTY(&wanted_branches)) option_conflict('a', 'b'); if (list_refs_only) { if (!TAILQ_EMPTY(&wanted_branches)) option_conflict('l', 'b'); if (fetch_all_branches) option_conflict('l', 'a'); if (mirror_references) option_conflict('l', 'm'); if (!TAILQ_EMPTY(&wanted_refs)) option_conflict('l', 'R'); } uri = argv[0]; if (argc == 1) dirname = NULL; else if (argc == 2) dirname = argv[1]; else usage_clone(); error = got_dial_parse_uri(&proto, &host, &port, &server_path, &repo_name, uri); if (error) goto done; if (asprintf(&git_url, "%s://%s%s%s%s%s", proto, host, port ? ":" : "", port ? port : "", server_path[0] != '/' ? "/" : "", server_path) == -1) { error = got_error_from_errno("asprintf"); goto done; } if (strcmp(proto, "git") == 0) { #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd dns inet unveil", NULL) == -1) err(1, "pledge"); #endif } else if (strcmp(proto, "git+ssh") == 0 || strcmp(proto, "ssh") == 0) { #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd unveil", NULL) == -1) err(1, "pledge"); #endif } else if (strcmp(proto, "http") == 0 || strcmp(proto, "git+http") == 0) { error = got_error_path(proto, GOT_ERR_NOT_IMPL); goto done; } else { error = got_error_path(proto, GOT_ERR_BAD_PROTO); goto done; } if (dirname == NULL) { if (asprintf(&default_destdir, "%s.git", repo_name) == -1) { error = got_error_from_errno("asprintf"); goto done; } repo_path = default_destdir; } else repo_path = dirname; if (!list_refs_only) { error = got_path_mkdir(repo_path); if (error && (!(error->code == GOT_ERR_ERRNO && errno == EISDIR) && !(error->code == GOT_ERR_ERRNO && errno == EEXIST))) goto done; if (!got_path_dir_is_empty(repo_path)) { error = got_error_path(repo_path, GOT_ERR_DIR_NOT_EMPTY); goto done; } } error = got_dial_apply_unveil(proto); if (error) goto done; error = apply_unveil(repo_path, 0, NULL); if (error) goto done; if (verbosity >= 0) printf("Connecting to %s\n", git_url); error = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port, server_path, verbosity); if (error) goto done; if (!list_refs_only) { error = got_repo_init(repo_path, NULL); if (error) goto done; error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error) goto done; } fpa.last_scaled_size[0] = '\0'; fpa.last_p_indexed = -1; fpa.last_p_resolved = -1; fpa.verbosity = verbosity; fpa.create_configs = 1; fpa.configs_created = 0; fpa.repo = repo; fpa.config_info.symrefs = &symrefs; fpa.config_info.wanted_branches = &wanted_branches; fpa.config_info.wanted_refs = &wanted_refs; fpa.config_info.proto = proto; fpa.config_info.host = host; fpa.config_info.port = port; fpa.config_info.remote_repo_path = server_path; fpa.config_info.git_url = git_url; fpa.config_info.fetch_all_branches = fetch_all_branches; fpa.config_info.mirror_references = mirror_references; error = got_fetch_pack(&pack_hash, &refs, &symrefs, GOT_FETCH_DEFAULT_REMOTE_NAME, mirror_references, fetch_all_branches, &wanted_branches, &wanted_refs, list_refs_only, verbosity, fetchfd, repo, NULL, NULL, bflag, fetch_progress, &fpa); if (error) goto done; if (list_refs_only) { error = list_remote_refs(&symrefs, &refs); goto done; } if (pack_hash == NULL) { error = got_error_fmt(GOT_ERR_FETCH_FAILED, "%s", "server sent an empty pack file"); goto done; } error = got_object_id_str(&id_str, pack_hash); if (error) goto done; if (verbosity >= 0) printf("\nFetched %s.pack\n", id_str); free(id_str); /* Set up references provided with the pack file. */ TAILQ_FOREACH(pe, &refs, entry) { const char *refname = pe->path; struct got_object_id *id = pe->data; char *remote_refname; if (is_wanted_ref(&wanted_refs, refname) && !mirror_references) { error = create_wanted_ref(refname, id, GOT_FETCH_DEFAULT_REMOTE_NAME, verbosity - 1, repo); if (error) goto done; continue; } error = create_ref(refname, id, verbosity - 1, repo); if (error) goto done; if (mirror_references) continue; if (strncmp("refs/heads/", refname, 11) != 0) continue; if (asprintf(&remote_refname, "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME, refname + 11) == -1) { error = got_error_from_errno("asprintf"); goto done; } error = create_ref(remote_refname, id, verbosity - 1, repo); free(remote_refname); if (error) goto done; } /* Set the HEAD reference if the server provided one. */ TAILQ_FOREACH(pe, &symrefs, entry) { struct got_reference *target_ref; const char *refname = pe->path; const char *target = pe->data; char *remote_refname = NULL, *remote_target = NULL; if (strcmp(refname, GOT_REF_HEAD) != 0) continue; error = got_ref_open(&target_ref, repo, target, 0); if (error) { if (error->code == GOT_ERR_NOT_REF) { error = NULL; continue; } goto done; } error = create_symref(refname, target_ref, verbosity, repo); got_ref_close(target_ref); if (error) goto done; if (mirror_references) continue; if (strncmp("refs/heads/", target, 11) != 0) continue; if (asprintf(&remote_refname, "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME, refname) == -1) { error = got_error_from_errno("asprintf"); goto done; } if (asprintf(&remote_target, "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME, target + 11) == -1) { error = got_error_from_errno("asprintf"); free(remote_refname); goto done; } error = got_ref_open(&target_ref, repo, remote_target, 0); if (error) { free(remote_refname); free(remote_target); if (error->code == GOT_ERR_NOT_REF) { error = NULL; continue; } goto done; } error = create_symref(remote_refname, target_ref, verbosity - 1, repo); free(remote_refname); free(remote_target); got_ref_close(target_ref); if (error) goto done; } if (pe == NULL) { /* * We failed to set the HEAD reference. If we asked for * a set of wanted branches use the first of one of those * which could be fetched instead. */ TAILQ_FOREACH(pe, &wanted_branches, entry) { const char *target = pe->path; struct got_reference *target_ref; error = got_ref_open(&target_ref, repo, target, 0); if (error) { if (error->code == GOT_ERR_NOT_REF) { error = NULL; continue; } goto done; } error = create_symref(GOT_REF_HEAD, target_ref, verbosity, repo); got_ref_close(target_ref); if (error) goto done; break; } if (!fpa.configs_created && pe != NULL) { error = create_config_files(fpa.config_info.proto, fpa.config_info.host, fpa.config_info.port, fpa.config_info.remote_repo_path, fpa.config_info.git_url, fpa.config_info.fetch_all_branches, fpa.config_info.mirror_references, fpa.config_info.symrefs, fpa.config_info.wanted_branches, fpa.config_info.wanted_refs, fpa.repo); if (error) goto done; } } if (verbosity >= 0) printf("Created %s repository '%s'\n", mirror_references ? "mirrored" : "cloned", repo_path); done: if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } if (fetchpid > 0) { if (kill(fetchpid, SIGTERM) == -1) error = got_error_from_errno("kill"); if (waitpid(fetchpid, &fetchstatus, 0) == -1 && error == NULL) error = got_error_from_errno("waitpid"); } if (fetchfd != -1 && close(fetchfd) == -1 && error == NULL) error = got_error_from_errno("close"); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } got_pathlist_free(&refs, GOT_PATHLIST_FREE_ALL); got_pathlist_free(&symrefs, GOT_PATHLIST_FREE_ALL); got_pathlist_free(&wanted_branches, GOT_PATHLIST_FREE_NONE); got_pathlist_free(&wanted_refs, GOT_PATHLIST_FREE_NONE); free(pack_hash); free(proto); free(host); free(port); free(server_path); free(repo_name); free(default_destdir); free(git_url); return error; } static const struct got_error * update_ref(struct got_reference *ref, struct got_object_id *new_id, int replace_tags, int verbosity, struct got_repository *repo) { const struct got_error *err = NULL; char *new_id_str = NULL; struct got_object_id *old_id = NULL; err = got_object_id_str(&new_id_str, new_id); if (err) goto done; if (!replace_tags && strncmp(got_ref_get_name(ref), "refs/tags/", 10) == 0) { err = got_ref_resolve(&old_id, repo, ref); if (err) goto done; if (got_object_id_cmp(old_id, new_id) == 0) goto done; if (verbosity >= 0) { printf("Rejecting update of existing tag %s: %s\n", got_ref_get_name(ref), new_id_str); } goto done; } if (got_ref_is_symbolic(ref)) { if (verbosity >= 0) { printf("Replacing reference %s: %s\n", got_ref_get_name(ref), got_ref_get_symref_target(ref)); } err = got_ref_change_symref_to_ref(ref, new_id); if (err) goto done; err = got_ref_write(ref, repo); if (err) goto done; } else { err = got_ref_resolve(&old_id, repo, ref); if (err) goto done; if (got_object_id_cmp(old_id, new_id) == 0) goto done; err = got_ref_change_ref(ref, new_id); if (err) goto done; err = got_ref_write(ref, repo); if (err) goto done; } if (verbosity >= 0) printf("Updated %s: %s\n", got_ref_get_name(ref), new_id_str); done: free(old_id); free(new_id_str); return err; } static const struct got_error * update_wanted_ref(const char *refname, struct got_object_id *id, const char *remote_repo_name, int verbosity, struct got_repository *repo) { const struct got_error *err, *unlock_err; char *remote_refname; struct got_reference *ref; if (strncmp("refs/", refname, 5) == 0) refname += 5; if (asprintf(&remote_refname, "refs/remotes/%s/%s", remote_repo_name, refname) == -1) return got_error_from_errno("asprintf"); err = got_ref_open(&ref, repo, remote_refname, 1); if (err) { if (err->code != GOT_ERR_NOT_REF) goto done; err = create_ref(remote_refname, id, verbosity, repo); } else { err = update_ref(ref, id, 0, verbosity, repo); unlock_err = got_ref_unlock(ref); if (unlock_err && err == NULL) err = unlock_err; got_ref_close(ref); } done: free(remote_refname); return err; } __dead static void usage_checkout(void) { fprintf(stderr, "usage: %s checkout [-Eq] [-b branch] [-c commit] " "[-p path-prefix] repository-path [work-tree-path]\n", getprogname()); exit(1); } static void show_worktree_base_ref_warning(void) { fprintf(stderr, "%s: warning: could not create a reference " "to the work tree's base commit; the commit could be " "garbage-collected by Git or 'gotadmin cleanup'; making the " "repository writable and running 'got update' will prevent this\n", getprogname()); } struct got_checkout_progress_arg { const char *worktree_path; int had_base_commit_ref_error; int verbosity; }; static const struct got_error * checkout_progress(void *arg, unsigned char status, const char *path) { struct got_checkout_progress_arg *a = arg; /* Base commit bump happens silently. */ if (status == GOT_STATUS_BUMP_BASE) return NULL; if (status == GOT_STATUS_BASE_REF_ERR) { a->had_base_commit_ref_error = 1; return NULL; } while (path[0] == '/') path++; if (a->verbosity >= 0) printf("%c %s/%s\n", status, a->worktree_path, path); return NULL; } static const struct got_error * check_cancelled(void *arg) { if (sigint_received || sigpipe_received) return got_error(GOT_ERR_CANCELLED); return NULL; } static const struct got_error * check_linear_ancestry(struct got_object_id *commit_id, struct got_object_id *base_commit_id, int allow_forwards_in_time_only, struct got_repository *repo) { const struct got_error *err = NULL; struct got_object_id *yca_id; err = got_commit_graph_find_youngest_common_ancestor(&yca_id, commit_id, base_commit_id, 1, 0, repo, check_cancelled, NULL); if (err) return err; if (yca_id == NULL) return got_error(GOT_ERR_ANCESTRY); /* * Require a straight line of history between the target commit * and the work tree's base commit. * * Non-linear situations such as this require a rebase: * * (commit) D F (base_commit) * \ / * C E * \ / * B (yca) * | * A * * 'got update' only handles linear cases: * Update forwards in time: A (base/yca) - B - C - D (commit) * Update backwards in time: D (base) - C - B - A (commit/yca) */ if (allow_forwards_in_time_only) { if (got_object_id_cmp(base_commit_id, yca_id) != 0) return got_error(GOT_ERR_ANCESTRY); } else if (got_object_id_cmp(commit_id, yca_id) != 0 && got_object_id_cmp(base_commit_id, yca_id) != 0) return got_error(GOT_ERR_ANCESTRY); free(yca_id); return NULL; } static const struct got_error * check_same_branch(struct got_object_id *commit_id, struct got_reference *head_ref, struct got_repository *repo) { const struct got_error *err = NULL; struct got_commit_graph *graph = NULL; struct got_object_id *head_commit_id = NULL; err = got_ref_resolve(&head_commit_id, repo, head_ref); if (err) goto done; if (got_object_id_cmp(head_commit_id, commit_id) == 0) goto done; err = got_commit_graph_open(&graph, "/", 1); if (err) goto done; err = got_commit_graph_bfsort(graph, head_commit_id, repo, check_cancelled, NULL); if (err) goto done; for (;;) { struct got_object_id id; err = got_commit_graph_iter_next(&id, graph, repo, check_cancelled, NULL); if (err) { if (err->code == GOT_ERR_ITER_COMPLETED) err = got_error(GOT_ERR_ANCESTRY); break; } if (got_object_id_cmp(&id, commit_id) == 0) break; } done: if (graph) got_commit_graph_close(graph); free(head_commit_id); return err; } static const struct got_error * checkout_ancestry_error(struct got_reference *ref, const char *commit_id_str) { static char msg[512]; const char *branch_name; if (got_ref_is_symbolic(ref)) branch_name = got_ref_get_symref_target(ref); else branch_name = got_ref_get_name(ref); if (strncmp("refs/heads/", branch_name, 11) == 0) branch_name += 11; snprintf(msg, sizeof(msg), "target commit is not contained in branch '%s'; " "the branch to use must be specified with -b; " "if necessary a new branch can be created for " "this commit with 'got branch -c %s BRANCH_NAME'", branch_name, commit_id_str); return got_error_msg(GOT_ERR_ANCESTRY, msg); } static const struct got_error * cmd_checkout(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_repository *repo = NULL; struct got_reference *head_ref = NULL, *ref = NULL; struct got_worktree *worktree = NULL; char *repo_path = NULL; char *worktree_path = NULL; const char *path_prefix = ""; const char *branch_name = GOT_REF_HEAD, *refname = NULL; char *commit_id_str = NULL; struct got_object_id *commit_id = NULL; char *cwd = NULL; int ch, same_path_prefix, allow_nonempty = 0, verbosity = 0; struct got_pathlist_head paths; struct got_checkout_progress_arg cpa; int *pack_fds = NULL; TAILQ_INIT(&paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "b:c:Ep:q")) != -1) { switch (ch) { case 'b': branch_name = optarg; break; case 'c': commit_id_str = strdup(optarg); if (commit_id_str == NULL) return got_error_from_errno("strdup"); break; case 'E': allow_nonempty = 1; break; case 'p': path_prefix = optarg; break; case 'q': verbosity = -1; break; default: usage_checkout(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc == 1) { char *base, *dotgit; const char *path; repo_path = realpath(argv[0], NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", argv[0]); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } if (path_prefix[0]) path = path_prefix; else path = repo_path; error = got_path_basename(&base, path); if (error) goto done; dotgit = strstr(base, ".git"); if (dotgit) *dotgit = '\0'; if (asprintf(&worktree_path, "%s/%s", cwd, base) == -1) { error = got_error_from_errno("asprintf"); free(base); goto done; } free(base); } else if (argc == 2) { repo_path = realpath(argv[0], NULL); if (repo_path == NULL) { error = got_error_from_errno2("realpath", argv[0]); goto done; } worktree_path = realpath(argv[1], NULL); if (worktree_path == NULL) { if (errno != ENOENT) { error = got_error_from_errno2("realpath", argv[1]); goto done; } worktree_path = strdup(argv[1]); if (worktree_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } else usage_checkout(); got_path_strip_trailing_slashes(repo_path); got_path_strip_trailing_slashes(worktree_path); error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; /* Pre-create work tree path for unveil(2) */ error = got_path_mkdir(worktree_path); if (error) { if (!(error->code == GOT_ERR_ERRNO && errno == EISDIR) && !(error->code == GOT_ERR_ERRNO && errno == EEXIST)) goto done; if (!allow_nonempty && !got_path_dir_is_empty(worktree_path)) { error = got_error_path(worktree_path, GOT_ERR_DIR_NOT_EMPTY); goto done; } } error = apply_unveil(got_repo_get_path(repo), 0, worktree_path); if (error) goto done; error = got_ref_open(&head_ref, repo, branch_name, 0); if (error != NULL) goto done; error = got_worktree_init(worktree_path, head_ref, path_prefix, GOT_WORKTREE_CVG_DIR, repo); if (error != NULL && !(error->code == GOT_ERR_ERRNO && errno == EEXIST)) goto done; error = got_worktree_open(&worktree, worktree_path, GOT_WORKTREE_CVG_DIR); if (error != NULL) goto done; error = got_worktree_match_path_prefix(&same_path_prefix, worktree, path_prefix); if (error != NULL) goto done; if (!same_path_prefix) { error = got_error(GOT_ERR_PATH_PREFIX); goto done; } if (commit_id_str) { struct got_reflist_head refs; TAILQ_INIT(&refs); error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; error = got_repo_match_object_id(&commit_id, NULL, commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo); got_ref_list_free(&refs); if (error) goto done; error = check_linear_ancestry(commit_id, got_worktree_get_base_commit_id(worktree), 0, repo); if (error != NULL) { if (error->code == GOT_ERR_ANCESTRY) { error = checkout_ancestry_error( head_ref, commit_id_str); } goto done; } error = check_same_branch(commit_id, head_ref, repo); if (error) { if (error->code == GOT_ERR_ANCESTRY) { error = checkout_ancestry_error( head_ref, commit_id_str); } goto done; } error = got_worktree_set_base_commit_id(worktree, repo, commit_id); if (error) goto done; /* Expand potentially abbreviated commit ID string. */ free(commit_id_str); error = got_object_id_str(&commit_id_str, commit_id); if (error) goto done; } else { commit_id = got_object_id_dup( got_worktree_get_base_commit_id(worktree)); if (commit_id == NULL) { error = got_error_from_errno("got_object_id_dup"); goto done; } error = got_object_id_str(&commit_id_str, commit_id); if (error) goto done; } error = got_pathlist_append(&paths, "", NULL); if (error) goto done; cpa.worktree_path = worktree_path; cpa.had_base_commit_ref_error = 0; cpa.verbosity = verbosity; error = got_worktree_checkout_files(worktree, &paths, repo, checkout_progress, &cpa, check_cancelled, NULL); if (error != NULL) goto done; if (got_ref_is_symbolic(head_ref)) { error = got_ref_resolve_symbolic(&ref, repo, head_ref); if (error) goto done; refname = got_ref_get_name(ref); } else refname = got_ref_get_name(head_ref); printf("Checked out %s: %s\n", refname, commit_id_str); printf("Now shut up and hack\n"); if (cpa.had_base_commit_ref_error) show_worktree_base_ref_warning(); done: if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } if (head_ref) got_ref_close(head_ref); if (ref) got_ref_close(ref); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE); free(commit_id_str); free(commit_id); free(repo_path); free(worktree_path); free(cwd); return error; } struct got_update_progress_arg { int did_something; int conflicts; int obstructed; int not_updated; int missing; int not_deleted; int unversioned; int verbosity; }; static void print_update_progress_stats(struct got_update_progress_arg *upa) { if (!upa->did_something) return; if (upa->conflicts > 0) printf("Files with new merge conflicts: %d\n", upa->conflicts); if (upa->obstructed > 0) printf("File paths obstructed by a non-regular file: %d\n", upa->obstructed); if (upa->not_updated > 0) printf("Files not updated because of existing merge " "conflicts: %d\n", upa->not_updated); } /* * The meaning of some status codes differs between merge-style operations and * update operations. For example, the ! status code means "file was missing" * if changes were merged into the work tree, and "missing file was restored" * if the work tree was updated. This function should be used by any operation * which merges changes into the work tree without updating the work tree. */ static void print_merge_progress_stats(struct got_update_progress_arg *upa) { if (!upa->did_something) return; if (upa->conflicts > 0) printf("Files with new merge conflicts: %d\n", upa->conflicts); if (upa->obstructed > 0) printf("File paths obstructed by a non-regular file: %d\n", upa->obstructed); if (upa->missing > 0) printf("Files which had incoming changes but could not be " "found in the work tree: %d\n", upa->missing); if (upa->not_deleted > 0) printf("Files not deleted due to differences in deleted " "content: %d\n", upa->not_deleted); if (upa->unversioned > 0) printf("Files not merged because an unversioned file was " "found in the work tree: %d\n", upa->unversioned); } __dead static void usage_update(void) { fprintf(stderr, "usage: %s update [-qtvX] [-c commit] [-r remote] " "[path ...]\n", getprogname()); exit(1); } static const struct got_error * update_progress(void *arg, unsigned char status, const char *path) { struct got_update_progress_arg *upa = arg; if (status == GOT_STATUS_EXISTS || status == GOT_STATUS_BASE_REF_ERR) return NULL; upa->did_something = 1; /* Base commit bump happens silently. */ if (status == GOT_STATUS_BUMP_BASE) return NULL; if (status == GOT_STATUS_CONFLICT) upa->conflicts++; if (status == GOT_STATUS_OBSTRUCTED) upa->obstructed++; if (status == GOT_STATUS_CANNOT_UPDATE) upa->not_updated++; if (status == GOT_STATUS_MISSING) upa->missing++; if (status == GOT_STATUS_CANNOT_DELETE) upa->not_deleted++; if (status == GOT_STATUS_UNVERSIONED) upa->unversioned++; while (path[0] == '/') path++; if (upa->verbosity >= 0) printf("%c %s\n", status, path); return NULL; } static const struct got_error * check_rebase_or_histedit_in_progress(struct got_worktree *worktree) { const struct got_error *err; int in_progress; err = got_worktree_rebase_in_progress(&in_progress, worktree); if (err) return err; if (in_progress) return got_error(GOT_ERR_REBASING); err = got_worktree_histedit_in_progress(&in_progress, worktree); if (err) return err; if (in_progress) return got_error(GOT_ERR_HISTEDIT_BUSY); return NULL; } static const struct got_error * check_merge_in_progress(struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; int in_progress; err = got_worktree_merge_in_progress(&in_progress, worktree, repo); if (err) return err; if (in_progress) return got_error(GOT_ERR_MERGE_BUSY); return NULL; } static const struct got_error * get_worktree_paths_from_argv(struct got_pathlist_head *paths, int argc, char *argv[], struct got_worktree *worktree) { const struct got_error *err = NULL; char *path; struct got_pathlist_entry *new; int i; if (argc == 0) { path = strdup(""); if (path == NULL) return got_error_from_errno("strdup"); return got_pathlist_append(paths, path, NULL); } for (i = 0; i < argc; i++) { err = got_worktree_resolve_path(&path, worktree, argv[i]); if (err) break; err = got_pathlist_insert(&new, paths, path, NULL); if (err || new == NULL /* duplicate */) { free(path); if (err) break; } } return err; } static const struct got_error * wrap_not_worktree_error(const struct got_error *orig_err, const char *cmdname, const char *path) { const struct got_error *err; struct got_repository *repo; static char msg[512]; int *pack_fds = NULL; err = got_repo_pack_fds_open(&pack_fds); if (err) return err; err = got_repo_open(&repo, path, NULL, pack_fds); if (err) return orig_err; snprintf(msg, sizeof(msg), "'got %s' needs a work tree in addition to a git repository\n" "Work trees can be checked out from this Git repository with " "'got checkout'.\n" "The got(1) manual page contains more information.", cmdname); err = got_error_msg(GOT_ERR_NOT_WORKTREE, msg); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (err == NULL) err = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (err == NULL) err = pack_err; } return err; } static const struct got_error * cmd_update(int argc, char *argv[]) { const struct got_error *error = NULL, *unlock_err; char *worktree_path = NULL; const char *repo_path = NULL; const char *remote_name = NULL; char *proto = NULL, *host = NULL, *port = NULL; char *repo_name = NULL, *server_path = NULL; const struct got_remote_repo *remotes, *remote = NULL; int nremotes; char *id_str = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; const struct got_gotconfig *repo_conf = NULL, *worktree_conf = NULL; struct got_pathlist_head paths, refs, symrefs; struct got_pathlist_head wanted_branches, wanted_refs; struct got_pathlist_entry *pe; struct got_reflist_head remote_refs; struct got_reflist_entry *re; struct got_object_id *pack_hash = NULL; int i, ch, fetchfd = -1, fetchstatus; pid_t fetchpid = -1; struct got_fetch_progress_arg fpa; struct got_update_progress_arg upa; int verbosity = 0; int delete_remote = 0; int replace_tags = 0; int *pack_fds = NULL; const char *remote_head = NULL, *worktree_branch = NULL; struct got_object_id *commit_id = NULL; char *commit_id_str = NULL; const char *refname; struct got_reference *head_ref = NULL; TAILQ_INIT(&paths); TAILQ_INIT(&refs); TAILQ_INIT(&symrefs); TAILQ_INIT(&remote_refs); TAILQ_INIT(&wanted_branches); TAILQ_INIT(&wanted_refs); while ((ch = getopt(argc, argv, "c:qr:vX")) != -1) { switch (ch) { case 'c': commit_id_str = strdup(optarg); if (commit_id_str == NULL) return got_error_from_errno("strdup"); break; case 't': replace_tags = 1; break; case 'q': verbosity = -1; break; case 'r': remote_name = optarg; break; case 'v': if (verbosity < 0) verbosity = 0; else if (verbosity < 3) verbosity++; break; case 'X': delete_remote = 1; break; default: usage_update(); break; } } argc -= optind; argv += optind; if (delete_remote) { if (replace_tags) option_conflict('X', 't'); if (remote_name == NULL) errx(1, "-X option requires a remote name"); } if (remote_name == NULL) remote_name = GOT_FETCH_DEFAULT_REMOTE_NAME; worktree_path = getcwd(NULL, 0); if (worktree_path == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_worktree_open(&worktree, worktree_path, GOT_WORKTREE_CVG_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "update", worktree_path); goto done; } repo_path = got_worktree_get_repo_path(worktree); error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error) goto done; error = check_rebase_or_histedit_in_progress(worktree); if (error) goto done; error = check_merge_in_progress(worktree, repo); if (error) goto done; error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; worktree_conf = got_worktree_get_gotconfig(worktree); if (worktree_conf) { got_gotconfig_get_remotes(&nremotes, &remotes, worktree_conf); for (i = 0; i < nremotes; i++) { if (strcmp(remotes[i].name, remote_name) == 0) { remote = &remotes[i]; break; } } } if (remote == NULL) { repo_conf = got_repo_get_gotconfig(repo); if (repo_conf) { got_gotconfig_get_remotes(&nremotes, &remotes, repo_conf); for (i = 0; i < nremotes; i++) { if (strcmp(remotes[i].name, remote_name) == 0) { remote = &remotes[i]; break; } } } } if (remote == NULL) { got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo); for (i = 0; i < nremotes; i++) { if (strcmp(remotes[i].name, remote_name) == 0) { remote = &remotes[i]; break; } } } if (remote == NULL) { error = got_error_path(remote_name, GOT_ERR_NO_REMOTE); goto done; } error = got_dial_parse_uri(&proto, &host, &port, &server_path, &repo_name, remote->fetch_url); if (error) goto done; if (strcmp(proto, "git") == 0) { #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd dns inet unveil", NULL) == -1) err(1, "pledge"); #endif } else if (strcmp(proto, "git+ssh") == 0 || strcmp(proto, "ssh") == 0) { #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd unveil", NULL) == -1) err(1, "pledge"); #endif } else if (strcmp(proto, "http") == 0 || strcmp(proto, "git+http") == 0) { error = got_error_path(proto, GOT_ERR_NOT_IMPL); goto done; } else { error = got_error_path(proto, GOT_ERR_BAD_PROTO); goto done; } error = got_dial_apply_unveil(proto); if (error) goto done; error = apply_unveil(got_repo_get_path(repo), 0, got_worktree_get_root_path(worktree)); if (error) goto done; if (verbosity >= 0) { printf("Connecting to \"%s\" %s://%s%s%s%s%s\n", remote->name, proto, host, port ? ":" : "", port ? port : "", *server_path == '/' ? "" : "/", server_path); } error = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port, server_path, verbosity); if (error) goto done; /* * If set, get this remote's HEAD ref target so * if it has changed on the server we can fetch it. */ error = got_ref_list(&remote_refs, repo, "refs/remotes", got_ref_cmp_by_name, repo); if (error) goto done; TAILQ_FOREACH(re, &remote_refs, entry) { const char *remote_refname, *remote_target; size_t remote_name_len; if (!got_ref_is_symbolic(re->ref)) continue; remote_name_len = strlen(remote->name); remote_refname = got_ref_get_name(re->ref); /* we only want refs/remotes/$remote->name/HEAD */ if (strncmp(remote_refname + 13, remote->name, remote_name_len) != 0) continue; if (strcmp(remote_refname + remote_name_len + 14, GOT_REF_HEAD) != 0) continue; /* * Take the name itself because we already * only match with refs/heads/ in fetch_pack(). */ remote_target = got_ref_get_symref_target(re->ref); remote_head = remote_target + remote_name_len + 14; break; } refname = got_worktree_get_head_ref_name(worktree); if (strncmp(refname, "refs/heads/", 11) == 0) worktree_branch = refname; fpa.last_scaled_size[0] = '\0'; fpa.last_p_indexed = -1; fpa.last_p_resolved = -1; fpa.verbosity = verbosity; fpa.repo = repo; fpa.create_configs = 0; fpa.configs_created = 0; memset(&fpa.config_info, 0, sizeof(fpa.config_info)); error = got_fetch_pack(&pack_hash, &refs, &symrefs, remote->name, remote->mirror_references, 0, &wanted_branches, &wanted_refs, 0, verbosity, fetchfd, repo, worktree_branch, remote_head, 0, fetch_progress, &fpa); if (error) goto done; if (pack_hash != NULL && verbosity >= 0) { error = got_object_id_str(&id_str, pack_hash); if (error) goto done; printf("\nFetched %s.pack\n", id_str); free(id_str); id_str = NULL; } /* Update references provided with the pack file. */ TAILQ_FOREACH(pe, &refs, entry) { const char *refname = pe->path; struct got_object_id *id = pe->data; struct got_reference *ref; if (is_wanted_ref(&wanted_refs, refname)) { error = update_wanted_ref(refname, id, remote->name, verbosity, repo); if (error) goto done; continue; } error = got_ref_open(&ref, repo, refname, 1); if (error) { if (error->code != GOT_ERR_NOT_REF) goto done; error = create_ref(refname, id, verbosity, repo); if (error) goto done; } else { error = update_ref(ref, id, replace_tags, verbosity-1, repo); unlock_err = got_ref_unlock(ref); if (unlock_err && error == NULL) error = unlock_err; got_ref_close(ref); if (error) goto done; } } /* Update worktree */ error = got_ref_open(&head_ref, repo, got_worktree_get_head_ref_name(worktree), 0); if (error != NULL) goto done; if (commit_id_str == NULL) { error = got_ref_resolve(&commit_id, repo, head_ref); if (error != NULL) goto done; error = got_object_id_str(&commit_id_str, commit_id); if (error != NULL) goto done; } else { struct got_reflist_head refs; TAILQ_INIT(&refs); error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; error = got_repo_match_object_id(&commit_id, NULL, commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo); got_ref_list_free(&refs); free(commit_id_str); commit_id_str = NULL; if (error) goto done; error = got_object_id_str(&commit_id_str, commit_id); if (error) goto done; } error = check_linear_ancestry(commit_id, got_worktree_get_base_commit_id(worktree), 0, repo); if (error != NULL) { if (error->code == GOT_ERR_ANCESTRY) error = got_error(GOT_ERR_BRANCH_MOVED); goto done; } error = check_same_branch(commit_id, head_ref, repo); if (error) goto done; if (got_object_id_cmp(got_worktree_get_base_commit_id(worktree), commit_id) != 0) { error = got_worktree_set_base_commit_id(worktree, repo, commit_id); if (error) goto done; } memset(&upa, 0, sizeof(upa)); upa.verbosity = verbosity; error = got_worktree_checkout_files(worktree, &paths, repo, update_progress, &upa, check_cancelled, NULL); if (error != NULL) goto done; if (upa.did_something) { printf("Updated to %s: %s\n", got_worktree_get_head_ref_name(worktree), commit_id_str); } else printf("Already up-to-date\n"); print_update_progress_stats(&upa); done: if (fetchpid > 0) { if (kill(fetchpid, SIGTERM) == -1) error = got_error_from_errno("kill"); if (waitpid(fetchpid, &fetchstatus, 0) == -1 && error == NULL) error = got_error_from_errno("waitpid"); } if (fetchfd != -1 && close(fetchfd) == -1 && error == NULL) error = got_error_from_errno("close"); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); got_pathlist_free(&refs, GOT_PATHLIST_FREE_ALL); got_pathlist_free(&symrefs, GOT_PATHLIST_FREE_ALL); got_pathlist_free(&wanted_branches, GOT_PATHLIST_FREE_NONE); got_pathlist_free(&wanted_refs, GOT_PATHLIST_FREE_NONE); got_ref_list_free(&remote_refs); free(id_str); free(worktree_path); free(pack_hash); free(proto); free(host); free(port); free(server_path); free(repo_name); free(commit_id); free(commit_id_str); return error; } static const struct got_error * diff_blobs(struct got_object_id *blob_id1, struct got_object_id *blob_id2, const char *path, int diff_context, int ignore_whitespace, int force_text_diff, struct got_diffstat_cb_arg *dsa, struct got_repository *repo, FILE *outfile) { const struct got_error *err = NULL; struct got_blob_object *blob1 = NULL, *blob2 = NULL; FILE *f1 = NULL, *f2 = NULL; int fd1 = -1, fd2 = -1; fd1 = got_opentempfd(); if (fd1 == -1) return got_error_from_errno("got_opentempfd"); fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } if (blob_id1) { err = got_object_open_as_blob(&blob1, repo, blob_id1, 8192, fd1); if (err) goto done; } err = got_object_open_as_blob(&blob2, repo, blob_id2, 8192, fd2); if (err) goto done; f1 = got_opentemp(); if (f1 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } f2 = got_opentemp(); if (f2 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } while (path[0] == '/') path++; err = got_diff_blob(NULL, NULL, blob1, blob2, f1, f2, path, path, GOT_DIFF_ALGORITHM_PATIENCE, diff_context, ignore_whitespace, force_text_diff, dsa, outfile); done: if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob1) got_object_blob_close(blob1); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob2) got_object_blob_close(blob2); if (f1 && fclose(f1) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (f2 && fclose(f2) == EOF && err == NULL) err = got_error_from_errno("fclose"); return err; } static const struct got_error * diff_trees(struct got_object_id *tree_id1, struct got_object_id *tree_id2, const char *path, int diff_context, int ignore_whitespace, int force_text_diff, struct got_diffstat_cb_arg *dsa, struct got_repository *repo, FILE *outfile) { const struct got_error *err = NULL; struct got_tree_object *tree1 = NULL, *tree2 = NULL; struct got_diff_blob_output_unidiff_arg arg; FILE *f1 = NULL, *f2 = NULL; int fd1 = -1, fd2 = -1; if (tree_id1) { err = got_object_open_as_tree(&tree1, repo, tree_id1); if (err) goto done; fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } } err = got_object_open_as_tree(&tree2, repo, tree_id2); if (err) goto done; f1 = got_opentemp(); if (f1 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } f2 = got_opentemp(); if (f2 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } arg.diff_context = diff_context; arg.ignore_whitespace = ignore_whitespace; arg.force_text_diff = force_text_diff; arg.diffstat = dsa; arg.diff_algo = GOT_DIFF_ALGORITHM_PATIENCE; arg.outfile = outfile; arg.lines = NULL; arg.nlines = 0; while (path[0] == '/') path++; err = got_diff_tree(tree1, tree2, f1, f2, fd1, fd2, path, path, repo, got_diff_blob_output_unidiff, &arg, 1); done: if (tree1) got_object_tree_close(tree1); if (tree2) got_object_tree_close(tree2); if (f1 && fclose(f1) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (f2 && fclose(f2) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno("close"); return err; } static const struct got_error * get_changed_paths(struct got_pathlist_head *paths, struct got_commit_object *commit, struct got_repository *repo, struct got_diffstat_cb_arg *dsa) { const struct got_error *err = NULL; struct got_object_id *tree_id1 = NULL, *tree_id2 = NULL; struct got_tree_object *tree1 = NULL, *tree2 = NULL; struct got_object_qid *qid; got_diff_blob_cb cb = got_diff_tree_collect_changed_paths; FILE *f1 = NULL, *f2 = NULL; int fd1 = -1, fd2 = -1; if (dsa) { cb = got_diff_tree_compute_diffstat; f1 = got_opentemp(); if (f1 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } f2 = got_opentemp(); if (f2 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } } qid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); if (qid != NULL) { struct got_commit_object *pcommit; err = got_object_open_as_commit(&pcommit, repo, &qid->id); if (err) return err; tree_id1 = got_object_id_dup( got_object_commit_get_tree_id(pcommit)); if (tree_id1 == NULL) { got_object_commit_close(pcommit); return got_error_from_errno("got_object_id_dup"); } got_object_commit_close(pcommit); } if (tree_id1) { err = got_object_open_as_tree(&tree1, repo, tree_id1); if (err) goto done; } tree_id2 = got_object_commit_get_tree_id(commit); err = got_object_open_as_tree(&tree2, repo, tree_id2); if (err) goto done; err = got_diff_tree(tree1, tree2, f1, f2, fd1, fd2, "", "", repo, cb, dsa ? (void *)dsa : paths, dsa ? 1 : 0); done: if (tree1) got_object_tree_close(tree1); if (tree2) got_object_tree_close(tree2); if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno("close"); if (f1 && fclose(f1) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (f2 && fclose(f2) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(tree_id1); return err; } static const struct got_error * print_patch(struct got_commit_object *commit, struct got_object_id *id, const char *path, int diff_context, struct got_diffstat_cb_arg *dsa, struct got_repository *repo, FILE *outfile) { const struct got_error *err = NULL; struct got_commit_object *pcommit = NULL; char *id_str1 = NULL, *id_str2 = NULL; struct got_object_id *obj_id1 = NULL, *obj_id2 = NULL; struct got_object_qid *qid; qid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); if (qid != NULL) { err = got_object_open_as_commit(&pcommit, repo, &qid->id); if (err) return err; err = got_object_id_str(&id_str1, &qid->id); if (err) goto done; } err = got_object_id_str(&id_str2, id); if (err) goto done; if (path && path[0] != '\0') { int obj_type; err = got_object_id_by_path(&obj_id2, repo, commit, path); if (err) goto done; if (pcommit) { err = got_object_id_by_path(&obj_id1, repo, pcommit, path); if (err) { if (err->code != GOT_ERR_NO_TREE_ENTRY) { free(obj_id2); goto done; } } } err = got_object_get_type(&obj_type, repo, obj_id2); if (err) { free(obj_id2); goto done; } fprintf(outfile, "diff %s %s\n", id_str1 ? id_str1 : "/dev/null", id_str2); fprintf(outfile, "commit - %s\n", id_str1 ? id_str1 : "/dev/null"); fprintf(outfile, "commit + %s\n", id_str2); switch (obj_type) { case GOT_OBJ_TYPE_BLOB: err = diff_blobs(obj_id1, obj_id2, path, diff_context, 0, 0, dsa, repo, outfile); break; case GOT_OBJ_TYPE_TREE: err = diff_trees(obj_id1, obj_id2, path, diff_context, 0, 0, dsa, repo, outfile); break; default: err = got_error(GOT_ERR_OBJ_TYPE); break; } free(obj_id1); free(obj_id2); } else { obj_id2 = got_object_commit_get_tree_id(commit); if (pcommit) obj_id1 = got_object_commit_get_tree_id(pcommit); fprintf(outfile, "diff %s %s\n", id_str1 ? id_str1 : "/dev/null", id_str2); fprintf(outfile, "commit - %s\n", id_str1 ? id_str1 : "/dev/null"); fprintf(outfile, "commit + %s\n", id_str2); err = diff_trees(obj_id1, obj_id2, "", diff_context, 0, 0, dsa, repo, outfile); } done: free(id_str1); free(id_str2); if (pcommit) got_object_commit_close(pcommit); return err; } static char * get_datestr(time_t *time, char *datebuf) { struct tm mytm, *tm; char *p, *s; tm = gmtime_r(time, &mytm); if (tm == NULL) return NULL; s = asctime_r(tm, datebuf); if (s == NULL) return NULL; p = strchr(s, '\n'); if (p) *p = '\0'; return s; } static const struct got_error * match_commit(int *have_match, struct got_object_id *id, struct got_commit_object *commit, regex_t *regex) { const struct got_error *err = NULL; regmatch_t regmatch; char *id_str = NULL, *logmsg = NULL; *have_match = 0; err = got_object_id_str(&id_str, id); if (err) return err; err = got_object_commit_get_logmsg(&logmsg, commit); if (err) goto done; if (regexec(regex, got_object_commit_get_author(commit), 1, ®match, 0) == 0 || regexec(regex, got_object_commit_get_committer(commit), 1, ®match, 0) == 0 || regexec(regex, id_str, 1, ®match, 0) == 0 || regexec(regex, logmsg, 1, ®match, 0) == 0) *have_match = 1; done: free(id_str); free(logmsg); return err; } static void match_changed_paths(int *have_match, struct got_pathlist_head *changed_paths, regex_t *regex) { regmatch_t regmatch; struct got_pathlist_entry *pe; *have_match = 0; TAILQ_FOREACH(pe, changed_paths, entry) { if (regexec(regex, pe->path, 1, ®match, 0) == 0) { *have_match = 1; break; } } } static const struct got_error * match_patch(int *have_match, struct got_commit_object *commit, struct got_object_id *id, const char *path, int diff_context, struct got_repository *repo, regex_t *regex, FILE *f) { const struct got_error *err = NULL; char *line = NULL; size_t linesize = 0; regmatch_t regmatch; *have_match = 0; err = got_opentemp_truncate(f); if (err) return err; err = print_patch(commit, id, path, diff_context, NULL, repo, f); if (err) goto done; if (fseeko(f, 0L, SEEK_SET) == -1) { err = got_error_from_errno("fseeko"); goto done; } while (getline(&line, &linesize, f) != -1) { if (regexec(regex, line, 1, ®match, 0) == 0) { *have_match = 1; break; } } done: free(line); return err; } #define GOT_COMMIT_SEP_STR "-----------------------------------------------\n" static const struct got_error* build_refs_str(char **refs_str, struct got_reflist_head *refs, struct got_object_id *id, struct got_repository *repo, int local_only) { static const struct got_error *err = NULL; struct got_reflist_entry *re; char *s; const char *name; *refs_str = NULL; TAILQ_FOREACH(re, refs, entry) { struct got_tag_object *tag = NULL; struct got_object_id *ref_id; int cmp; name = got_ref_get_name(re->ref); if (strcmp(name, GOT_REF_HEAD) == 0) continue; if (strncmp(name, "refs/", 5) == 0) name += 5; if (strncmp(name, "got/", 4) == 0) continue; if (strncmp(name, "heads/", 6) == 0) name += 6; if (strncmp(name, "remotes/", 8) == 0) { if (local_only) continue; name += 8; s = strstr(name, "/" GOT_REF_HEAD); if (s != NULL && strcmp(s, "/" GOT_REF_HEAD) == 0) continue; } err = got_ref_resolve(&ref_id, repo, re->ref); if (err) break; if (strncmp(name, "tags/", 5) == 0) { err = got_object_open_as_tag(&tag, repo, ref_id); if (err) { if (err->code != GOT_ERR_OBJ_TYPE) { free(ref_id); break; } /* Ref points at something other than a tag. */ err = NULL; tag = NULL; } } cmp = got_object_id_cmp(tag ? got_object_tag_get_object_id(tag) : ref_id, id); free(ref_id); if (tag) got_object_tag_close(tag); if (cmp != 0) continue; s = *refs_str; if (asprintf(refs_str, "%s%s%s", s ? s : "", s ? ", " : "", name) == -1) { err = got_error_from_errno("asprintf"); free(s); *refs_str = NULL; break; } free(s); } return err; } static const struct got_error * print_commit_oneline(struct got_commit_object *commit, struct got_object_id *id, struct got_repository *repo, struct got_reflist_object_id_map *refs_idmap) { const struct got_error *err = NULL; char *ref_str = NULL, *id_str = NULL, *logmsg0 = NULL; char *comma, *s, *nl; struct got_reflist_head *refs; char datebuf[12]; /* YYYY-MM-DD + SPACE + NUL */ struct tm tm; time_t committer_time; refs = got_reflist_object_id_map_lookup(refs_idmap, id); if (refs) { err = build_refs_str(&ref_str, refs, id, repo, 1); if (err) return err; /* Display the first matching ref only. */ if (ref_str && (comma = strchr(ref_str, ',')) != NULL) *comma = '\0'; } if (ref_str == NULL) { err = got_object_id_str(&id_str, id); if (err) return err; } committer_time = got_object_commit_get_committer_time(commit); if (gmtime_r(&committer_time, &tm) == NULL) { err = got_error_from_errno("gmtime_r"); goto done; } if (strftime(datebuf, sizeof(datebuf), "%F ", &tm) == 0) { err = got_error(GOT_ERR_NO_SPACE); goto done; } err = got_object_commit_get_logmsg(&logmsg0, commit); if (err) goto done; s = logmsg0; while (isspace((unsigned char)s[0])) s++; nl = strchr(s, '\n'); if (nl) { *nl = '\0'; } if (ref_str) printf("%s%-7s %s\n", datebuf, ref_str, s); else printf("%s%.7s %s\n", datebuf, id_str, s); if (fflush(stdout) != 0 && err == NULL) err = got_error_from_errno("fflush"); done: free(id_str); free(ref_str); free(logmsg0); return err; } static const struct got_error * print_diffstat(struct got_diffstat_cb_arg *dsa, const char *header) { struct got_pathlist_entry *pe; if (header != NULL) printf("%s\n", header); TAILQ_FOREACH(pe, dsa->paths, entry) { struct got_diff_changed_path *cp = pe->data; int pad = dsa->max_path_len - pe->path_len + 1; printf(" %c %s%*c | %*d+ %*d-\n", cp->status, pe->path, pad, ' ', dsa->add_cols + 1, cp->add, dsa->rm_cols + 1, cp->rm); } printf("\n%d file%s changed, %d insertion%s(+), %d deletion%s(-)\n\n", dsa->nfiles, dsa->nfiles > 1 ? "s" : "", dsa->ins, dsa->ins != 1 ? "s" : "", dsa->del, dsa->del != 1 ? "s" : ""); if (fflush(stdout) != 0) return got_error_from_errno("fflush"); return NULL; } static const struct got_error * printfile(FILE *f) { char buf[8192]; size_t r; if (fseeko(f, 0L, SEEK_SET) == -1) return got_error_from_errno("fseek"); for (;;) { r = fread(buf, 1, sizeof(buf), f); if (r == 0) { if (ferror(f)) return got_error_from_errno("fread"); if (feof(f)) break; } if (fwrite(buf, 1, r, stdout) != r) return got_ferror(stdout, GOT_ERR_IO); } return NULL; } static const struct got_error * print_commit(struct got_commit_object *commit, struct got_object_id *id, struct got_repository *repo, const char *path, struct got_pathlist_head *changed_paths, struct got_diffstat_cb_arg *diffstat, int show_patch, int diff_context, struct got_reflist_object_id_map *refs_idmap, const char *custom_refs_str, const char *prefix) { const struct got_error *err = NULL; FILE *f = NULL; char *id_str, *datestr, *logmsg0, *logmsg, *line; char datebuf[26]; time_t committer_time; const char *author, *committer; char *refs_str = NULL; err = got_object_id_str(&id_str, id); if (err) return err; if (custom_refs_str == NULL) { struct got_reflist_head *refs; refs = got_reflist_object_id_map_lookup(refs_idmap, id); if (refs) { err = build_refs_str(&refs_str, refs, id, repo, 0); if (err) goto done; } } printf(GOT_COMMIT_SEP_STR); if (custom_refs_str) printf("%s %s (%s)\n", prefix ? prefix : "commit", id_str, custom_refs_str); else printf("%s %s%s%s%s\n", prefix ? prefix : "commit", id_str, refs_str ? " (" : "", refs_str ? refs_str : "", refs_str ? ")" : ""); free(id_str); id_str = NULL; free(refs_str); refs_str = NULL; printf("from: %s\n", got_object_commit_get_author(commit)); author = got_object_commit_get_author(commit); committer = got_object_commit_get_committer(commit); if (strcmp(author, committer) != 0) printf("via: %s\n", committer); committer_time = got_object_commit_get_committer_time(commit); datestr = get_datestr(&committer_time, datebuf); if (datestr) printf("date: %s UTC\n", datestr); if (got_object_commit_get_nparents(commit) > 1) { const struct got_object_id_queue *parent_ids; struct got_object_qid *qid; int n = 1; parent_ids = got_object_commit_get_parent_ids(commit); STAILQ_FOREACH(qid, parent_ids, entry) { err = got_object_id_str(&id_str, &qid->id); if (err) goto done; printf("parent %d: %s\n", n++, id_str); free(id_str); id_str = NULL; } } err = got_object_commit_get_logmsg(&logmsg0, commit); if (err) goto done; logmsg = logmsg0; do { line = strsep(&logmsg, "\n"); if (line) printf(" %s\n", line); } while (line); free(logmsg0); if (changed_paths && diffstat == NULL) { struct got_pathlist_entry *pe; TAILQ_FOREACH(pe, changed_paths, entry) { struct got_diff_changed_path *cp = pe->data; printf(" %c %s\n", cp->status, pe->path); } printf("\n"); } if (show_patch) { if (diffstat) { f = got_opentemp(); if (f == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } } err = print_patch(commit, id, path, diff_context, diffstat, repo, diffstat == NULL ? stdout : f); if (err) goto done; } if (diffstat) { err = print_diffstat(diffstat, NULL); if (err) goto done; if (show_patch) { err = printfile(f); if (err) goto done; } } if (show_patch) printf("\n"); if (fflush(stdout) != 0 && err == NULL) err = got_error_from_errno("fflush"); done: if (f && fclose(f) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(id_str); free(refs_str); return err; } static const struct got_error * print_commits(struct got_object_id *root_id, struct got_object_id *end_id, struct got_repository *repo, const char *path, int show_changed_paths, int show_diffstat, int show_patch, const char *search_pattern, int diff_context, int limit, int log_branches, int reverse_display_order, struct got_reflist_object_id_map *refs_idmap, int one_line, FILE *tmpfile) { const struct got_error *err; struct got_commit_graph *graph; regex_t regex; int have_match; struct got_object_id_queue reversed_commits; struct got_object_qid *qid; struct got_commit_object *commit; struct got_pathlist_head changed_paths; STAILQ_INIT(&reversed_commits); TAILQ_INIT(&changed_paths); if (search_pattern && regcomp(®ex, search_pattern, REG_EXTENDED | REG_NOSUB | REG_NEWLINE)) return got_error_msg(GOT_ERR_REGEX, search_pattern); err = got_commit_graph_open(&graph, path, !log_branches); if (err) return err; err = got_commit_graph_bfsort(graph, root_id, repo, check_cancelled, NULL); if (err) goto done; for (;;) { struct got_object_id id; struct got_diffstat_cb_arg dsa = { 0, 0, 0, 0, 0, 0, &changed_paths, 0, 0, GOT_DIFF_ALGORITHM_PATIENCE }; if (sigint_received || sigpipe_received) break; err = got_commit_graph_iter_next(&id, graph, repo, check_cancelled, NULL); if (err) { if (err->code == GOT_ERR_ITER_COMPLETED) err = NULL; break; } err = got_object_open_as_commit(&commit, repo, &id); if (err) break; if ((show_changed_paths || (show_diffstat && !show_patch)) && !reverse_display_order) { err = get_changed_paths(&changed_paths, commit, repo, show_diffstat ? &dsa : NULL); if (err) break; } if (search_pattern) { err = match_commit(&have_match, &id, commit, ®ex); if (err) { got_object_commit_close(commit); break; } if (have_match == 0 && show_changed_paths) match_changed_paths(&have_match, &changed_paths, ®ex); if (have_match == 0 && show_patch) { err = match_patch(&have_match, commit, &id, path, diff_context, repo, ®ex, tmpfile); if (err) break; } if (have_match == 0) { got_object_commit_close(commit); got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL); continue; } } if (reverse_display_order) { err = got_object_qid_alloc(&qid, &id); if (err) break; STAILQ_INSERT_HEAD(&reversed_commits, qid, entry); got_object_commit_close(commit); } else { if (one_line) err = print_commit_oneline(commit, &id, repo, refs_idmap); else err = print_commit(commit, &id, repo, path, (show_changed_paths || show_diffstat) ? &changed_paths : NULL, show_diffstat ? &dsa : NULL, show_patch, diff_context, refs_idmap, NULL, NULL); got_object_commit_close(commit); if (err) break; } if ((limit && --limit == 0) || (end_id && got_object_id_cmp(&id, end_id) == 0)) break; got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL); } if (reverse_display_order) { STAILQ_FOREACH(qid, &reversed_commits, entry) { struct got_diffstat_cb_arg dsa = { 0, 0, 0, 0, 0, 0, &changed_paths, 0, 0, GOT_DIFF_ALGORITHM_PATIENCE }; err = got_object_open_as_commit(&commit, repo, &qid->id); if (err) break; if (show_changed_paths || (show_diffstat && !show_patch)) { err = get_changed_paths(&changed_paths, commit, repo, show_diffstat ? &dsa : NULL); if (err) break; } if (one_line) err = print_commit_oneline(commit, &qid->id, repo, refs_idmap); else err = print_commit(commit, &qid->id, repo, path, (show_changed_paths || show_diffstat) ? &changed_paths : NULL, show_diffstat ? &dsa : NULL, show_patch, diff_context, refs_idmap, NULL, NULL); got_object_commit_close(commit); if (err) break; got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL); } } done: while (!STAILQ_EMPTY(&reversed_commits)) { qid = STAILQ_FIRST(&reversed_commits); STAILQ_REMOVE_HEAD(&reversed_commits, entry); got_object_qid_free(qid); } got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL); if (search_pattern) regfree(®ex); got_commit_graph_close(graph); return err; } __dead static void usage_log(void) { fprintf(stderr, "usage: %s log [-bdPpRs] [-C number] [-c commit] " "[-l N] [-r repository-path] [-S search-pattern] [-x commit] " "[path]\n", getprogname()); exit(1); } static int get_default_log_limit(void) { const char *got_default_log_limit; long long n; const char *errstr; got_default_log_limit = getenv("GOT_LOG_DEFAULT_LIMIT"); if (got_default_log_limit == NULL) return 0; n = strtonum(got_default_log_limit, 0, INT_MAX, &errstr); if (errstr != NULL) return 0; return n; } static const struct got_error * cmd_log(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; struct got_object_id *start_id = NULL, *end_id = NULL; char *repo_path = NULL, *path = NULL, *cwd = NULL, *in_repo_path = NULL; const char *start_commit = NULL, *end_commit = NULL; const char *search_pattern = NULL; int diff_context = -1, ch; int show_changed_paths = 0, show_patch = 0, limit = 0, log_branches = 0; int show_diffstat = 0, reverse_display_order = 0, one_line = 0; const char *errstr; struct got_reflist_head refs; struct got_reflist_object_id_map *refs_idmap = NULL; FILE *tmpfile = NULL; int *pack_fds = NULL; TAILQ_INIT(&refs); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif limit = get_default_log_limit(); while ((ch = getopt(argc, argv, "bC:c:dl:PpRr:S:sx:")) != -1) { switch (ch) { case 'b': log_branches = 1; break; case 'C': diff_context = strtonum(optarg, 0, GOT_DIFF_MAX_CONTEXT, &errstr); if (errstr != NULL) errx(1, "number of context lines is %s: %s", errstr, optarg); break; case 'c': start_commit = optarg; break; case 'd': show_diffstat = 1; break; case 'l': limit = strtonum(optarg, 0, INT_MAX, &errstr); if (errstr != NULL) errx(1, "number of commits is %s: %s", errstr, optarg); break; case 'P': show_changed_paths = 1; break; case 'p': show_patch = 1; break; case 'R': reverse_display_order = 1; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; case 'S': search_pattern = optarg; break; case 's': one_line = 1; break; case 'x': end_commit = optarg; break; default: usage_log(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (diff_context == -1) diff_context = 3; else if (!show_patch) errx(1, "-C requires -p"); if (one_line && (show_patch || show_changed_paths || show_diffstat)) errx(1, "cannot use -s with -d, -p or -P"); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; error = NULL; } if (argc == 1) { if (worktree) { error = got_worktree_resolve_path(&path, worktree, argv[0]); if (error) goto done; } else { path = strdup(argv[0]); if (path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } else if (argc != 0) usage_log(); if (repo_path == NULL) { repo_path = worktree ? strdup(got_worktree_get_repo_path(worktree)) : strdup(cwd); } if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 1, worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; error = got_reflist_object_id_map_create(&refs_idmap, &refs, repo); if (error) goto done; if (start_commit == NULL) { struct got_reference *head_ref; struct got_commit_object *commit = NULL; error = got_ref_open(&head_ref, repo, worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, 0); if (error != NULL) goto done; error = got_ref_resolve(&start_id, repo, head_ref); got_ref_close(head_ref); if (error != NULL) goto done; error = got_object_open_as_commit(&commit, repo, start_id); if (error != NULL) goto done; got_object_commit_close(commit); } else { error = got_repo_match_object_id(&start_id, NULL, start_commit, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (error != NULL) goto done; } if (end_commit != NULL) { error = got_repo_match_object_id(&end_id, NULL, end_commit, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (error != NULL) goto done; } if (worktree) { /* * If a path was specified on the command line it was resolved * to a path in the work tree above. Prepend the work tree's * path prefix to obtain the corresponding in-repository path. */ if (path) { const char *prefix; prefix = got_worktree_get_path_prefix(worktree); if (asprintf(&in_repo_path, "%s%s%s", prefix, (path[0] != '\0') ? "/" : "", path) == -1) { error = got_error_from_errno("asprintf"); goto done; } } } else error = got_repo_map_path(&in_repo_path, repo, path ? path : ""); if (error != NULL) goto done; if (in_repo_path) { free(path); path = in_repo_path; } if (worktree) { /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } if (search_pattern && show_patch) { tmpfile = got_opentemp(); if (tmpfile == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } } error = print_commits(start_id, end_id, repo, path ? path : "", show_changed_paths, show_diffstat, show_patch, search_pattern, diff_context, limit, log_branches, reverse_display_order, refs_idmap, one_line, tmpfile); done: free(path); free(repo_path); free(cwd); free(start_id); free(end_id); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } if (refs_idmap) got_reflist_object_id_map_free(refs_idmap); if (tmpfile && fclose(tmpfile) == EOF && error == NULL) error = got_error_from_errno("fclose"); got_ref_list_free(&refs); return error; } __dead static void usage_diff(void) { fprintf(stderr, "usage: %s diff [-adPsw] [-C number] [-c commit] " "[-r repository-path] [object1 object2 | path ...]\n", getprogname()); exit(1); } struct print_diff_arg { struct got_repository *repo; struct got_worktree *worktree; struct got_diffstat_cb_arg *diffstat; int diff_context; const char *id_str; int header_shown; int diff_staged; enum got_diff_algorithm diff_algo; int ignore_whitespace; int force_text_diff; FILE *f1; FILE *f2; FILE *outfile; }; /* * Create a file which contains the target path of a symlink so we can feed * it as content to the diff engine. */ static const struct got_error * get_symlink_target_file(int *fd, int dirfd, const char *de_name, const char *abspath) { const struct got_error *err = NULL; char target_path[PATH_MAX]; ssize_t target_len, outlen; *fd = -1; if (dirfd != -1) { target_len = readlinkat(dirfd, de_name, target_path, PATH_MAX); if (target_len == -1) return got_error_from_errno2("readlinkat", abspath); } else { target_len = readlink(abspath, target_path, PATH_MAX); if (target_len == -1) return got_error_from_errno2("readlink", abspath); } *fd = got_opentempfd(); if (*fd == -1) return got_error_from_errno("got_opentempfd"); outlen = write(*fd, target_path, target_len); if (outlen == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } if (lseek(*fd, 0, SEEK_SET) == -1) { err = got_error_from_errno2("lseek", abspath); goto done; } done: if (err) { close(*fd); *fd = -1; } return err; } static const struct got_error * print_diff(void *arg, unsigned char status, unsigned char staged_status, const char *path, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { struct print_diff_arg *a = arg; const struct got_error *err = NULL; struct got_blob_object *blob1 = NULL; int fd = -1, fd1 = -1, fd2 = -1; FILE *f2 = NULL; char *abspath = NULL, *label1 = NULL; struct stat sb; off_t size1 = 0; int f2_exists = 0; memset(&sb, 0, sizeof(sb)); if (a->diff_staged) { if (staged_status != GOT_STATUS_MODIFY && staged_status != GOT_STATUS_ADD && staged_status != GOT_STATUS_DELETE) return NULL; } else { if (staged_status == GOT_STATUS_DELETE) return NULL; if (status == GOT_STATUS_NONEXISTENT) return got_error_set_errno(ENOENT, path); if (status != GOT_STATUS_MODIFY && status != GOT_STATUS_ADD && status != GOT_STATUS_DELETE && status != GOT_STATUS_CONFLICT) return NULL; } err = got_opentemp_truncate(a->f1); if (err) return got_error_from_errno("got_opentemp_truncate"); err = got_opentemp_truncate(a->f2); if (err) return got_error_from_errno("got_opentemp_truncate"); if (!a->header_shown) { if (fprintf(a->outfile, "diff %s%s\n", a->diff_staged ? "-s " : "", got_worktree_get_root_path(a->worktree)) < 0) { err = got_error_from_errno("fprintf"); goto done; } if (fprintf(a->outfile, "commit - %s\n", a->id_str) < 0) { err = got_error_from_errno("fprintf"); goto done; } if (fprintf(a->outfile, "path + %s%s\n", got_worktree_get_root_path(a->worktree), a->diff_staged ? " (staged changes)" : "") < 0) { err = got_error_from_errno("fprintf"); goto done; } a->header_shown = 1; } if (a->diff_staged) { const char *label1 = NULL, *label2 = NULL; switch (staged_status) { case GOT_STATUS_MODIFY: label1 = path; label2 = path; break; case GOT_STATUS_ADD: label2 = path; break; case GOT_STATUS_DELETE: label1 = path; break; default: return got_error(GOT_ERR_FILE_STATUS); } fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } err = got_diff_objects_as_blobs(NULL, NULL, a->f1, a->f2, fd1, fd2, blob_id, staged_blob_id, label1, label2, a->diff_algo, a->diff_context, a->ignore_whitespace, a->force_text_diff, a->diffstat, a->repo, a->outfile); goto done; } fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } if (staged_status == GOT_STATUS_ADD || staged_status == GOT_STATUS_MODIFY) { char *id_str; err = got_object_open_as_blob(&blob1, a->repo, staged_blob_id, 8192, fd1); if (err) goto done; err = got_object_id_str(&id_str, staged_blob_id); if (err) goto done; if (asprintf(&label1, "%s (staged)", id_str) == -1) { err = got_error_from_errno("asprintf"); free(id_str); goto done; } free(id_str); } else if (status != GOT_STATUS_ADD) { err = got_object_open_as_blob(&blob1, a->repo, blob_id, 8192, fd1); if (err) goto done; } if (status != GOT_STATUS_DELETE) { if (asprintf(&abspath, "%s/%s", got_worktree_get_root_path(a->worktree), path) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (dirfd != -1) { fd = openat(dirfd, de_name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { if (!got_err_open_nofollow_on_symlink()) { err = got_error_from_errno2("openat", abspath); goto done; } err = get_symlink_target_file(&fd, dirfd, de_name, abspath); if (err) goto done; } } else { fd = open(abspath, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { if (!got_err_open_nofollow_on_symlink()) { err = got_error_from_errno2("open", abspath); goto done; } err = get_symlink_target_file(&fd, dirfd, de_name, abspath); if (err) goto done; } } if (fstatat(fd, abspath, &sb, AT_SYMLINK_NOFOLLOW) == -1) { err = got_error_from_errno2("fstatat", abspath); goto done; } f2 = fdopen(fd, "r"); if (f2 == NULL) { err = got_error_from_errno2("fdopen", abspath); goto done; } fd = -1; f2_exists = 1; } if (blob1) { err = got_object_blob_dump_to_file(&size1, NULL, NULL, a->f1, blob1); if (err) goto done; } err = got_diff_blob_file(blob1, a->f1, size1, label1, f2 ? f2 : a->f2, f2_exists, &sb, path, GOT_DIFF_ALGORITHM_PATIENCE, a->diff_context, a->ignore_whitespace, a->force_text_diff, a->diffstat, a->outfile); done: if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob1) got_object_blob_close(blob1); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (f2 && fclose(f2) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(abspath); return err; } static const struct got_error * cmd_diff(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL; const char *commit_args[2] = { NULL, NULL }; int ncommit_args = 0; struct got_object_id *ids[2] = { NULL, NULL }; char *labels[2] = { NULL, NULL }; int type1 = GOT_OBJ_TYPE_ANY, type2 = GOT_OBJ_TYPE_ANY; int diff_context = 3, diff_staged = 0, ignore_whitespace = 0, ch, i; int force_text_diff = 0, force_path = 0, rflag = 0, show_diffstat = 0; const char *errstr; struct got_reflist_head refs; struct got_pathlist_head diffstat_paths, paths; FILE *f1 = NULL, *f2 = NULL, *outfile = NULL; int fd1 = -1, fd2 = -1; int *pack_fds = NULL; struct got_diffstat_cb_arg dsa; memset(&dsa, 0, sizeof(dsa)); TAILQ_INIT(&refs); TAILQ_INIT(&paths); TAILQ_INIT(&diffstat_paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "aC:c:dPr:sw")) != -1) { switch (ch) { case 'a': force_text_diff = 1; break; case 'C': diff_context = strtonum(optarg, 0, GOT_DIFF_MAX_CONTEXT, &errstr); if (errstr != NULL) errx(1, "number of context lines is %s: %s", errstr, optarg); break; case 'c': if (ncommit_args >= 2) errx(1, "too many -c options used"); commit_args[ncommit_args++] = optarg; break; case 'd': show_diffstat = 1; break; case 'P': force_path = 1; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); rflag = 1; break; case 's': diff_staged = 1; break; case 'w': ignore_whitespace = 1; break; default: usage_diff(); /* NOTREACHED */ } } argc -= optind; argv += optind; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else error = NULL; if (worktree) { repo_path = strdup(got_worktree_get_repo_path(worktree)); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } else { repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); free(repo_path); if (error != NULL) goto done; if (show_diffstat) { dsa.paths = &diffstat_paths; dsa.force_text = force_text_diff; dsa.ignore_ws = ignore_whitespace; dsa.diff_algo = GOT_DIFF_ALGORITHM_PATIENCE; } if (rflag || worktree == NULL || ncommit_args > 0) { if (force_path) { error = got_error_msg(GOT_ERR_NOT_IMPL, "-P option can only be used when diffing " "a work tree"); goto done; } if (diff_staged) { error = got_error_msg(GOT_ERR_NOT_IMPL, "-s option can only be used when diffing " "a work tree"); goto done; } } error = apply_unveil(got_repo_get_path(repo), 1, worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; if ((!force_path && argc == 2) || ncommit_args > 0) { int obj_type = (ncommit_args > 0 ? GOT_OBJ_TYPE_COMMIT : GOT_OBJ_TYPE_ANY); error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; for (i = 0; i < (ncommit_args > 0 ? ncommit_args : argc); i++) { const char *arg; if (ncommit_args > 0) arg = commit_args[i]; else arg = argv[i]; error = got_repo_match_object_id(&ids[i], &labels[i], arg, obj_type, &refs, repo); if (error) { if (error->code != GOT_ERR_NOT_REF && error->code != GOT_ERR_NO_OBJ) goto done; if (ncommit_args > 0) goto done; error = NULL; break; } } } f1 = got_opentemp(); if (f1 == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } f2 = got_opentemp(); if (f2 == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } outfile = got_opentemp(); if (outfile == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } if (ncommit_args == 0 && (ids[0] == NULL || ids[1] == NULL)) { struct print_diff_arg arg; char *id_str; if (worktree == NULL) { if (argc == 2 && ids[0] == NULL) { error = got_error_path(argv[0], GOT_ERR_NO_OBJ); goto done; } else if (argc == 2 && ids[1] == NULL) { error = got_error_path(argv[1], GOT_ERR_NO_OBJ); goto done; } else if (argc > 0) { error = got_error_fmt(GOT_ERR_NOT_WORKTREE, "%s", "specified paths cannot be resolved"); goto done; } else { error = got_error(GOT_ERR_NOT_WORKTREE); goto done; } } error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; error = got_object_id_str(&id_str, got_worktree_get_base_commit_id(worktree)); if (error) goto done; arg.repo = repo; arg.worktree = worktree; arg.diff_algo = GOT_DIFF_ALGORITHM_PATIENCE; arg.diff_context = diff_context; arg.id_str = id_str; arg.header_shown = 0; arg.diff_staged = diff_staged; arg.ignore_whitespace = ignore_whitespace; arg.force_text_diff = force_text_diff; arg.diffstat = show_diffstat ? &dsa : NULL; arg.f1 = f1; arg.f2 = f2; arg.outfile = outfile; error = got_worktree_status(worktree, &paths, repo, 0, print_diff, &arg, check_cancelled, NULL); free(id_str); if (error) goto done; if (show_diffstat && dsa.nfiles > 0) { char *header; if (asprintf(&header, "diffstat %s%s", diff_staged ? "-s " : "", got_worktree_get_root_path(worktree)) == -1) { error = got_error_from_errno("asprintf"); goto done; } error = print_diffstat(&dsa, header); free(header); if (error) goto done; } error = printfile(outfile); goto done; } if (ncommit_args == 1) { struct got_commit_object *commit; error = got_object_open_as_commit(&commit, repo, ids[0]); if (error) goto done; labels[1] = labels[0]; ids[1] = ids[0]; if (got_object_commit_get_nparents(commit) > 0) { const struct got_object_id_queue *pids; struct got_object_qid *pid; pids = got_object_commit_get_parent_ids(commit); pid = STAILQ_FIRST(pids); ids[0] = got_object_id_dup(&pid->id); if (ids[0] == NULL) { error = got_error_from_errno( "got_object_id_dup"); got_object_commit_close(commit); goto done; } error = got_object_id_str(&labels[0], ids[0]); if (error) { got_object_commit_close(commit); goto done; } } else { ids[0] = NULL; labels[0] = strdup("/dev/null"); if (labels[0] == NULL) { error = got_error_from_errno("strdup"); got_object_commit_close(commit); goto done; } } got_object_commit_close(commit); } if (ncommit_args == 0 && argc > 2) { error = got_error_msg(GOT_ERR_BAD_PATH, "path arguments cannot be used when diffing two objects"); goto done; } if (ids[0]) { error = got_object_get_type(&type1, repo, ids[0]); if (error) goto done; } error = got_object_get_type(&type2, repo, ids[1]); if (error) goto done; if (type1 != GOT_OBJ_TYPE_ANY && type1 != type2) { error = got_error(GOT_ERR_OBJ_TYPE); goto done; } if (type1 == GOT_OBJ_TYPE_BLOB && argc > 2) { error = got_error_msg(GOT_ERR_OBJ_TYPE, "path arguments cannot be used when diffing blobs"); goto done; } for (i = 0; ncommit_args > 0 && i < argc; i++) { char *in_repo_path; struct got_pathlist_entry *new; if (worktree) { const char *prefix; char *p; error = got_worktree_resolve_path(&p, worktree, argv[i]); if (error) goto done; prefix = got_worktree_get_path_prefix(worktree); while (prefix[0] == '/') prefix++; if (asprintf(&in_repo_path, "%s%s%s", prefix, (p[0] != '\0' && prefix[0] != '\0') ? "/" : "", p) == -1) { error = got_error_from_errno("asprintf"); free(p); goto done; } free(p); } else { char *mapped_path, *s; error = got_repo_map_path(&mapped_path, repo, argv[i]); if (error) goto done; s = mapped_path; while (s[0] == '/') s++; in_repo_path = strdup(s); if (in_repo_path == NULL) { error = got_error_from_errno("asprintf"); free(mapped_path); goto done; } free(mapped_path); } error = got_pathlist_insert(&new, &paths, in_repo_path, NULL); if (error || new == NULL /* duplicate */) free(in_repo_path); if (error) goto done; } if (worktree) { /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } fd1 = got_opentempfd(); if (fd1 == -1) { error = got_error_from_errno("got_opentempfd"); goto done; } fd2 = got_opentempfd(); if (fd2 == -1) { error = got_error_from_errno("got_opentempfd"); goto done; } switch (type1 == GOT_OBJ_TYPE_ANY ? type2 : type1) { case GOT_OBJ_TYPE_BLOB: error = got_diff_objects_as_blobs(NULL, NULL, f1, f2, fd1, fd2, ids[0], ids[1], NULL, NULL, GOT_DIFF_ALGORITHM_PATIENCE, diff_context, ignore_whitespace, force_text_diff, show_diffstat ? &dsa : NULL, repo, outfile); break; case GOT_OBJ_TYPE_TREE: error = got_diff_objects_as_trees(NULL, NULL, f1, f2, fd1, fd2, ids[0], ids[1], &paths, "", "", GOT_DIFF_ALGORITHM_PATIENCE, diff_context, ignore_whitespace, force_text_diff, show_diffstat ? &dsa : NULL, repo, outfile); break; case GOT_OBJ_TYPE_COMMIT: fprintf(outfile, "diff %s %s\n", labels[0], labels[1]); error = got_diff_objects_as_commits(NULL, NULL, f1, f2, fd1, fd2, ids[0], ids[1], &paths, GOT_DIFF_ALGORITHM_PATIENCE, diff_context, ignore_whitespace, force_text_diff, show_diffstat ? &dsa : NULL, repo, outfile); break; default: error = got_error(GOT_ERR_OBJ_TYPE); } if (error) goto done; if (show_diffstat && dsa.nfiles > 0) { char *header = NULL; if (asprintf(&header, "diffstat %s %s", labels[0], labels[1]) == -1) { error = got_error_from_errno("asprintf"); goto done; } error = print_diffstat(&dsa, header); free(header); if (error) goto done; } error = printfile(outfile); done: free(labels[0]); free(labels[1]); free(ids[0]); free(ids[1]); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); got_pathlist_free(&diffstat_paths, GOT_PATHLIST_FREE_ALL); got_ref_list_free(&refs); if (outfile && fclose(outfile) == EOF && error == NULL) error = got_error_from_errno("fclose"); if (f1 && fclose(f1) == EOF && error == NULL) error = got_error_from_errno("fclose"); if (f2 && fclose(f2) == EOF && error == NULL) error = got_error_from_errno("fclose"); if (fd1 != -1 && close(fd1) == -1 && error == NULL) error = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && error == NULL) error = got_error_from_errno("close"); return error; } __dead static void usage_blame(void) { fprintf(stderr, "usage: %s blame [-c commit] [-r repository-path] path\n", getprogname()); exit(1); } struct blame_line { int annotated; char *id_str; char *committer; char datebuf[11]; /* YYYY-MM-DD + NUL */ }; struct blame_cb_args { struct blame_line *lines; int nlines; int nlines_prec; int lineno_cur; off_t *line_offsets; FILE *f; struct got_repository *repo; }; static const struct got_error * blame_cb(void *arg, int nlines, int lineno, struct got_commit_object *commit, struct got_object_id *id) { const struct got_error *err = NULL; struct blame_cb_args *a = arg; struct blame_line *bline; char *line = NULL; size_t linesize = 0; off_t offset; struct tm tm; time_t committer_time; if (nlines != a->nlines || (lineno != -1 && lineno < 1) || lineno > a->nlines) return got_error(GOT_ERR_RANGE); if (sigint_received) return got_error(GOT_ERR_ITER_COMPLETED); if (lineno == -1) return NULL; /* no change in this commit */ /* Annotate this line. */ bline = &a->lines[lineno - 1]; if (bline->annotated) return NULL; err = got_object_id_str(&bline->id_str, id); if (err) return err; bline->committer = strdup(got_object_commit_get_committer(commit)); if (bline->committer == NULL) { err = got_error_from_errno("strdup"); goto done; } committer_time = got_object_commit_get_committer_time(commit); if (gmtime_r(&committer_time, &tm) == NULL) return got_error_from_errno("gmtime_r"); if (strftime(bline->datebuf, sizeof(bline->datebuf), "%F", &tm) == 0) { err = got_error(GOT_ERR_NO_SPACE); goto done; } bline->annotated = 1; /* Print lines annotated so far. */ bline = &a->lines[a->lineno_cur - 1]; if (!bline->annotated) goto done; offset = a->line_offsets[a->lineno_cur - 1]; if (fseeko(a->f, offset, SEEK_SET) == -1) { err = got_error_from_errno("fseeko"); goto done; } while (a->lineno_cur <= a->nlines && bline->annotated) { char *smallerthan, *at, *nl, *committer; size_t len; if (getline(&line, &linesize, a->f) == -1) { if (ferror(a->f)) err = got_error_from_errno("getline"); break; } committer = bline->committer; smallerthan = strchr(committer, '<'); if (smallerthan && smallerthan[1] != '\0') committer = smallerthan + 1; at = strchr(committer, '@'); if (at) *at = '\0'; len = strlen(committer); if (len >= 9) committer[8] = '\0'; nl = strchr(line, '\n'); if (nl) *nl = '\0'; printf("%.*d) %.8s %s %-8s %s\n", a->nlines_prec, a->lineno_cur, bline->id_str, bline->datebuf, committer, line); a->lineno_cur++; bline = &a->lines[a->lineno_cur - 1]; } done: free(line); return err; } static const struct got_error * cmd_blame(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *path, *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL; char *link_target = NULL; struct got_object_id *obj_id = NULL; struct got_object_id *commit_id = NULL; struct got_commit_object *commit = NULL; struct got_blob_object *blob = NULL; char *commit_id_str = NULL; struct blame_cb_args bca; int ch, obj_type, i, fd1 = -1, fd2 = -1, fd3 = -1; off_t filesize; int *pack_fds = NULL; FILE *f1 = NULL, *f2 = NULL; fd1 = got_opentempfd(); if (fd1 == -1) return got_error_from_errno("got_opentempfd"); memset(&bca, 0, sizeof(bca)); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "c:r:")) != -1) { switch (ch) { case 'c': commit_id_str = optarg; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; default: usage_blame(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc == 1) path = argv[0]; else usage_blame(); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else error = NULL; if (worktree) { repo_path = strdup(got_worktree_get_repo_path(worktree)); if (repo_path == NULL) { error = got_error_from_errno("strdup"); if (error) goto done; } } else { repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; if (worktree) { const char *prefix = got_worktree_get_path_prefix(worktree); char *p; error = got_worktree_resolve_path(&p, worktree, path); if (error) goto done; if (asprintf(&in_repo_path, "%s%s%s", prefix, (p[0] != '\0' && !got_path_is_root_dir(prefix)) ? "/" : "", p) == -1) { error = got_error_from_errno("asprintf"); free(p); goto done; } free(p); error = apply_unveil(got_repo_get_path(repo), 1, NULL); } else { error = apply_unveil(got_repo_get_path(repo), 1, NULL); if (error) goto done; error = got_repo_map_path(&in_repo_path, repo, path); } if (error) goto done; if (commit_id_str == NULL) { struct got_reference *head_ref; error = got_ref_open(&head_ref, repo, worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, 0); if (error != NULL) goto done; error = got_ref_resolve(&commit_id, repo, head_ref); got_ref_close(head_ref); if (error != NULL) goto done; } else { struct got_reflist_head refs; TAILQ_INIT(&refs); error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; error = got_repo_match_object_id(&commit_id, NULL, commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo); got_ref_list_free(&refs); if (error) goto done; } if (worktree) { /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; error = got_object_resolve_symlinks(&link_target, in_repo_path, commit, repo); if (error) goto done; error = got_object_id_by_path(&obj_id, repo, commit, link_target ? link_target : in_repo_path); if (error) goto done; error = got_object_get_type(&obj_type, repo, obj_id); if (error) goto done; if (obj_type != GOT_OBJ_TYPE_BLOB) { error = got_error_path(link_target ? link_target : in_repo_path, GOT_ERR_OBJ_TYPE); goto done; } error = got_object_open_as_blob(&blob, repo, obj_id, 8192, fd1); if (error) goto done; bca.f = got_opentemp(); if (bca.f == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } error = got_object_blob_dump_to_file(&filesize, &bca.nlines, &bca.line_offsets, bca.f, blob); if (error || bca.nlines == 0) goto done; /* Don't include \n at EOF in the blame line count. */ if (bca.line_offsets[bca.nlines - 1] == filesize) bca.nlines--; bca.lines = calloc(bca.nlines, sizeof(*bca.lines)); if (bca.lines == NULL) { error = got_error_from_errno("calloc"); goto done; } bca.lineno_cur = 1; bca.nlines_prec = 0; i = bca.nlines; while (i > 0) { i /= 10; bca.nlines_prec++; } bca.repo = repo; fd2 = got_opentempfd(); if (fd2 == -1) { error = got_error_from_errno("got_opentempfd"); goto done; } fd3 = got_opentempfd(); if (fd3 == -1) { error = got_error_from_errno("got_opentempfd"); goto done; } f1 = got_opentemp(); if (f1 == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } f2 = got_opentemp(); if (f2 == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } error = got_blame(link_target ? link_target : in_repo_path, commit_id, repo, GOT_DIFF_ALGORITHM_PATIENCE, blame_cb, &bca, check_cancelled, NULL, fd2, fd3, f1, f2); done: free(in_repo_path); free(link_target); free(repo_path); free(cwd); free(commit_id); free(obj_id); if (commit) got_object_commit_close(commit); if (fd1 != -1 && close(fd1) == -1 && error == NULL) error = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && error == NULL) error = got_error_from_errno("close"); if (fd3 != -1 && close(fd3) == -1 && error == NULL) error = got_error_from_errno("close"); if (f1 && fclose(f1) == EOF && error == NULL) error = got_error_from_errno("fclose"); if (f2 && fclose(f2) == EOF && error == NULL) error = got_error_from_errno("fclose"); if (blob) got_object_blob_close(blob); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } if (bca.lines) { for (i = 0; i < bca.nlines; i++) { struct blame_line *bline = &bca.lines[i]; free(bline->id_str); free(bline->committer); } free(bca.lines); } free(bca.line_offsets); if (bca.f && fclose(bca.f) == EOF && error == NULL) error = got_error_from_errno("fclose"); return error; } __dead static void usage_tree(void) { fprintf(stderr, "usage: %s tree [-iR] [-c commit] [-r repository-path] " "[path]\n", getprogname()); exit(1); } static const struct got_error * print_entry(struct got_tree_entry *te, const char *id, const char *path, const char *root_path, struct got_repository *repo) { const struct got_error *err = NULL; int is_root_path = (strcmp(path, root_path) == 0); const char *modestr = ""; mode_t mode = got_tree_entry_get_mode(te); char *link_target = NULL; path += strlen(root_path); while (path[0] == '/') path++; if (got_object_tree_entry_is_submodule(te)) modestr = "$"; else if (S_ISLNK(mode)) { int i; err = got_tree_entry_get_symlink_target(&link_target, te, repo); if (err) return err; for (i = 0; link_target[i] != '\0'; i++) { if (!isprint((unsigned char)link_target[i])) link_target[i] = '?'; } modestr = "@"; } else if (S_ISDIR(mode)) modestr = "/"; else if (mode & S_IXUSR) modestr = "*"; printf("%s%s%s%s%s%s%s\n", id ? id : "", path, is_root_path ? "" : "/", got_tree_entry_get_name(te), modestr, link_target ? " -> ": "", link_target ? link_target : ""); free(link_target); return NULL; } static const struct got_error * print_tree(const char *path, struct got_commit_object *commit, int show_ids, int recurse, const char *root_path, struct got_repository *repo) { const struct got_error *err = NULL; struct got_object_id *tree_id = NULL; struct got_tree_object *tree = NULL; int nentries, i; err = got_object_id_by_path(&tree_id, repo, commit, path); if (err) goto done; err = got_object_open_as_tree(&tree, repo, tree_id); if (err) goto done; nentries = got_object_tree_get_nentries(tree); for (i = 0; i < nentries; i++) { struct got_tree_entry *te; char *id = NULL; if (sigint_received || sigpipe_received) break; te = got_object_tree_get_entry(tree, i); if (show_ids) { char *id_str; err = got_object_id_str(&id_str, got_tree_entry_get_id(te)); if (err) goto done; if (asprintf(&id, "%s ", id_str) == -1) { err = got_error_from_errno("asprintf"); free(id_str); goto done; } free(id_str); } err = print_entry(te, id, path, root_path, repo); free(id); if (err) goto done; if (recurse && S_ISDIR(got_tree_entry_get_mode(te))) { char *child_path; if (asprintf(&child_path, "%s%s%s", path, path[0] == '/' && path[1] == '\0' ? "" : "/", got_tree_entry_get_name(te)) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = print_tree(child_path, commit, show_ids, 1, root_path, repo); free(child_path); if (err) goto done; } } done: if (tree) got_object_tree_close(tree); free(tree_id); return err; } static const struct got_error * cmd_tree(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; const char *path, *refname = NULL; char *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL; struct got_object_id *commit_id = NULL; struct got_commit_object *commit = NULL; char *commit_id_str = NULL; int show_ids = 0, recurse = 0; int ch; int *pack_fds = NULL; #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "c:iRr:")) != -1) { switch (ch) { case 'c': commit_id_str = optarg; break; case 'i': show_ids = 1; break; case 'R': recurse = 1; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; default: usage_tree(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc == 1) path = argv[0]; else if (argc > 1) usage_tree(); else path = NULL; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else error = NULL; if (worktree) { repo_path = strdup(got_worktree_get_repo_path(worktree)); if (repo_path == NULL) error = got_error_from_errno("strdup"); if (error) goto done; } else { repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; if (worktree) { const char *prefix = got_worktree_get_path_prefix(worktree); char *p; if (path == NULL || got_path_is_root_dir(path)) path = ""; error = got_worktree_resolve_path(&p, worktree, path); if (error) goto done; if (asprintf(&in_repo_path, "%s%s%s", prefix, (p[0] != '\0' && !got_path_is_root_dir(prefix)) ? "/" : "", p) == -1) { error = got_error_from_errno("asprintf"); free(p); goto done; } free(p); error = apply_unveil(got_repo_get_path(repo), 1, NULL); if (error) goto done; } else { error = apply_unveil(got_repo_get_path(repo), 1, NULL); if (error) goto done; if (path == NULL) path = "/"; error = got_repo_map_path(&in_repo_path, repo, path); if (error != NULL) goto done; } if (commit_id_str == NULL) { struct got_reference *head_ref; if (worktree) refname = got_worktree_get_head_ref_name(worktree); else refname = GOT_REF_HEAD; error = got_ref_open(&head_ref, repo, refname, 0); if (error != NULL) goto done; error = got_ref_resolve(&commit_id, repo, head_ref); got_ref_close(head_ref); if (error != NULL) goto done; } else { struct got_reflist_head refs; TAILQ_INIT(&refs); error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; error = got_repo_match_object_id(&commit_id, NULL, commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo); got_ref_list_free(&refs); if (error) goto done; } if (worktree) { /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; error = print_tree(in_repo_path, commit, show_ids, recurse, in_repo_path, repo); done: free(in_repo_path); free(repo_path); free(cwd); free(commit_id); if (commit) got_object_commit_close(commit); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } return error; } __dead static void usage_status(void) { fprintf(stderr, "usage: %s status [-I] [-S status-codes] " "[-s status-codes] [path ...]\n", getprogname()); exit(1); } struct got_status_arg { char *status_codes; int suppress; }; static const struct got_error * print_status(void *arg, unsigned char status, unsigned char staged_status, const char *path, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { struct got_status_arg *st = arg; if (status == staged_status && (status == GOT_STATUS_DELETE)) status = GOT_STATUS_NO_CHANGE; if (st != NULL && st->status_codes) { size_t ncodes = strlen(st->status_codes); int i, j = 0; for (i = 0; i < ncodes ; i++) { if (st->suppress) { if (status == st->status_codes[i] || staged_status == st->status_codes[i]) { j++; continue; } } else { if (status == st->status_codes[i] || staged_status == st->status_codes[i]) break; } } if (st->suppress && j == 0) goto print; if (i == ncodes) return NULL; } print: printf("%c%c %s\n", status, staged_status, path); return NULL; } static const struct got_error * cmd_status(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; struct got_status_arg st; char *cwd = NULL; struct got_pathlist_head paths; int ch, i, no_ignores = 0; int *pack_fds = NULL; TAILQ_INIT(&paths); memset(&st, 0, sizeof(st)); st.status_codes = NULL; st.suppress = 0; #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "IS:s:")) != -1) { switch (ch) { case 'I': no_ignores = 1; break; case 'S': if (st.status_codes != NULL && st.suppress == 0) option_conflict('S', 's'); st.suppress = 1; /* fallthrough */ case 's': for (i = 0; optarg[i] != '\0'; i++) { switch (optarg[i]) { case GOT_STATUS_MODIFY: case GOT_STATUS_ADD: case GOT_STATUS_DELETE: case GOT_STATUS_CONFLICT: case GOT_STATUS_MISSING: case GOT_STATUS_OBSTRUCTED: case GOT_STATUS_UNVERSIONED: case GOT_STATUS_MODE_CHANGE: case GOT_STATUS_NONEXISTENT: break; default: errx(1, "invalid status code '%c'", optarg[i]); } } if (ch == 's' && st.suppress) option_conflict('s', 'S'); st.status_codes = optarg; break; default: usage_status(); /* NOTREACHED */ } } argc -= optind; argv += optind; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "status", cwd); goto done; } error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 1, got_worktree_get_root_path(worktree)); if (error) goto done; error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; error = got_worktree_status(worktree, &paths, repo, no_ignores, print_status, &st, check_cancelled, NULL); done: if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(cwd); return error; } __dead static void usage_tag(void) { fprintf(stderr, "usage: %s tag [-lVv] [-c commit] [-m message] " "[-r repository-path] [-s signer-id] name\n", getprogname()); exit(1); } #if 0 static const struct got_error * sort_tags(struct got_reflist_head *sorted, struct got_reflist_head *tags) { const struct got_error *err = NULL; struct got_reflist_entry *re, *se, *new; struct got_object_id *re_id, *se_id; struct got_tag_object *re_tag, *se_tag; time_t re_time, se_time; STAILQ_FOREACH(re, tags, entry) { se = STAILQ_FIRST(sorted); if (se == NULL) { err = got_reflist_entry_dup(&new, re); if (err) return err; STAILQ_INSERT_HEAD(sorted, new, entry); continue; } else { err = got_ref_resolve(&re_id, repo, re->ref); if (err) break; err = got_object_open_as_tag(&re_tag, repo, re_id); free(re_id); if (err) break; re_time = got_object_tag_get_tagger_time(re_tag); got_object_tag_close(re_tag); } while (se) { err = got_ref_resolve(&se_id, repo, re->ref); if (err) break; err = got_object_open_as_tag(&se_tag, repo, se_id); free(se_id); if (err) break; se_time = got_object_tag_get_tagger_time(se_tag); got_object_tag_close(se_tag); if (se_time > re_time) { err = got_reflist_entry_dup(&new, re); if (err) return err; STAILQ_INSERT_AFTER(sorted, se, new, entry); break; } se = STAILQ_NEXT(se, entry); continue; } } done: return err; } #endif static const struct got_error * get_tag_refname(char **refname, const char *tag_name) { const struct got_error *err; if (strncmp("refs/tags/", tag_name, 10) == 0) { *refname = strdup(tag_name); if (*refname == NULL) return got_error_from_errno("strdup"); } else if (asprintf(refname, "refs/tags/%s", tag_name) == -1) { err = got_error_from_errno("asprintf"); *refname = NULL; return err; } return NULL; } static const struct got_error * list_tags(struct got_repository *repo, const char *tag_name, int verify_tags, const char *allowed_signers, const char *revoked_signers, int verbosity) { static const struct got_error *err = NULL; struct got_reflist_head refs; struct got_reflist_entry *re; char *wanted_refname = NULL; int bad_sigs = 0; TAILQ_INIT(&refs); err = got_ref_list(&refs, repo, "refs/tags", got_ref_cmp_tags, repo); if (err) return err; if (tag_name) { struct got_reference *ref; err = get_tag_refname(&wanted_refname, tag_name); if (err) goto done; /* Wanted tag reference should exist. */ err = got_ref_open(&ref, repo, wanted_refname, 0); if (err) goto done; got_ref_close(ref); } TAILQ_FOREACH(re, &refs, entry) { const char *refname; char *refstr, *tagmsg0, *tagmsg, *line, *id_str, *datestr; char datebuf[26]; const char *tagger, *ssh_sig = NULL; char *sig_msg = NULL; time_t tagger_time; struct got_object_id *id; struct got_tag_object *tag; struct got_commit_object *commit = NULL; refname = got_ref_get_name(re->ref); if (strncmp(refname, "refs/tags/", 10) != 0 || (wanted_refname && strcmp(refname, wanted_refname) != 0)) continue; refname += 10; refstr = got_ref_to_str(re->ref); if (refstr == NULL) { err = got_error_from_errno("got_ref_to_str"); break; } err = got_ref_resolve(&id, repo, re->ref); if (err) break; err = got_object_open_as_tag(&tag, repo, id); if (err) { if (err->code != GOT_ERR_OBJ_TYPE) { free(id); break; } /* "lightweight" tag */ err = got_object_open_as_commit(&commit, repo, id); if (err) { free(id); break; } tagger = got_object_commit_get_committer(commit); tagger_time = got_object_commit_get_committer_time(commit); err = got_object_id_str(&id_str, id); free(id); if (err) break; } else { free(id); tagger = got_object_tag_get_tagger(tag); tagger_time = got_object_tag_get_tagger_time(tag); err = got_object_id_str(&id_str, got_object_tag_get_object_id(tag)); if (err) break; } if (tag && verify_tags) { ssh_sig = got_sigs_get_tagmsg_ssh_signature( got_object_tag_get_message(tag)); if (ssh_sig && allowed_signers == NULL) { err = got_error_msg( GOT_ERR_VERIFY_TAG_SIGNATURE, "SSH signature verification requires " "setting allowed_signers in " "got.conf(5)"); break; } } printf("%stag %s %s\n", GOT_COMMIT_SEP_STR, refname, refstr); free(refstr); printf("from: %s\n", tagger); datestr = get_datestr(&tagger_time, datebuf); if (datestr) printf("date: %s UTC\n", datestr); if (commit) printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT, id_str); else { switch (got_object_tag_get_object_type(tag)) { case GOT_OBJ_TYPE_BLOB: printf("object: %s %s\n", GOT_OBJ_LABEL_BLOB, id_str); break; case GOT_OBJ_TYPE_TREE: printf("object: %s %s\n", GOT_OBJ_LABEL_TREE, id_str); break; case GOT_OBJ_TYPE_COMMIT: printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT, id_str); break; case GOT_OBJ_TYPE_TAG: printf("object: %s %s\n", GOT_OBJ_LABEL_TAG, id_str); break; default: break; } } free(id_str); if (ssh_sig) { err = got_sigs_verify_tag_ssh(&sig_msg, tag, ssh_sig, allowed_signers, revoked_signers, verbosity); if (err && err->code == GOT_ERR_BAD_TAG_SIGNATURE) bad_sigs = 1; else if (err) break; printf("signature: %s", sig_msg); free(sig_msg); sig_msg = NULL; } if (commit) { err = got_object_commit_get_logmsg(&tagmsg0, commit); if (err) break; got_object_commit_close(commit); } else { tagmsg0 = strdup(got_object_tag_get_message(tag)); got_object_tag_close(tag); if (tagmsg0 == NULL) { err = got_error_from_errno("strdup"); break; } } tagmsg = tagmsg0; do { line = strsep(&tagmsg, "\n"); if (line) printf(" %s\n", line); } while (line); free(tagmsg0); } done: got_ref_list_free(&refs); free(wanted_refname); if (err == NULL && bad_sigs) err = got_error(GOT_ERR_BAD_TAG_SIGNATURE); return err; } static const struct got_error * get_tag_message(char **tagmsg, char **tagmsg_path, const char *commit_id_str, const char *tag_name, const char *repo_path) { const struct got_error *err = NULL; char *template = NULL, *initial_content = NULL; char *editor = NULL; int initial_content_len; int fd = -1; if (asprintf(&template, GOT_TMPDIR_STR "/got-tagmsg") == -1) { err = got_error_from_errno("asprintf"); goto done; } initial_content_len = asprintf(&initial_content, "\n# tagging commit %s as %s\n", commit_id_str, tag_name); if (initial_content_len == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_opentemp_named_fd(tagmsg_path, &fd, template, ""); if (err) goto done; if (write(fd, initial_content, initial_content_len) == -1) { err = got_error_from_errno2("write", *tagmsg_path); goto done; } if (close(fd) == -1) { err = got_error_from_errno2("close", *tagmsg_path); goto done; } fd = -1; err = get_editor(&editor); if (err) goto done; err = edit_logmsg(tagmsg, editor, *tagmsg_path, initial_content, initial_content_len, 1); done: free(initial_content); free(template); free(editor); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno2("close", *tagmsg_path); if (err) { free(*tagmsg); *tagmsg = NULL; } return err; } static const struct got_error * add_tag(struct got_repository *repo, const char *tagger, const char *tag_name, const char *commit_arg, const char *tagmsg_arg, const char *signer_id, int verbosity) { const struct got_error *err = NULL; struct got_object_id *commit_id = NULL, *tag_id = NULL; char *label = NULL, *commit_id_str = NULL; struct got_reference *ref = NULL; char *refname = NULL, *tagmsg = NULL; char *tagmsg_path = NULL, *tag_id_str = NULL; int preserve_tagmsg = 0; struct got_reflist_head refs; TAILQ_INIT(&refs); /* * Don't let the user create a tag name with a leading '-'. * While technically a valid reference name, this case is usually * an unintended typo. */ if (tag_name[0] == '-') return got_error_path(tag_name, GOT_ERR_REF_NAME_MINUS); err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (err) goto done; err = got_repo_match_object_id(&commit_id, &label, commit_arg, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (err) goto done; err = got_object_id_str(&commit_id_str, commit_id); if (err) goto done; err = get_tag_refname(&refname, tag_name); if (err) goto done; if (strncmp("refs/tags/", tag_name, 10) == 0) tag_name += 10; err = got_ref_open(&ref, repo, refname, 0); if (err == NULL) { err = got_error(GOT_ERR_TAG_EXISTS); goto done; } else if (err->code != GOT_ERR_NOT_REF) goto done; if (tagmsg_arg == NULL) { err = get_tag_message(&tagmsg, &tagmsg_path, commit_id_str, tag_name, got_repo_get_path(repo)); if (err) { if (err->code != GOT_ERR_COMMIT_MSG_EMPTY && tagmsg_path != NULL) preserve_tagmsg = 1; goto done; } /* Editor is done; we can now apply unveil(2) */ err = got_sigs_apply_unveil(); if (err) goto done; err = apply_unveil(got_repo_get_path(repo), 0, NULL); if (err) goto done; } err = got_object_tag_create(&tag_id, tag_name, commit_id, tagger, time(NULL), tagmsg ? tagmsg : tagmsg_arg, signer_id, repo, verbosity); if (err) { if (tagmsg_path) preserve_tagmsg = 1; goto done; } err = got_ref_alloc(&ref, refname, tag_id); if (err) { if (tagmsg_path) preserve_tagmsg = 1; goto done; } err = got_ref_write(ref, repo); if (err) { if (tagmsg_path) preserve_tagmsg = 1; goto done; } err = got_object_id_str(&tag_id_str, tag_id); if (err) { if (tagmsg_path) preserve_tagmsg = 1; goto done; } printf("Created tag %s\n", tag_id_str); done: if (preserve_tagmsg) { fprintf(stderr, "%s: tag message preserved in %s\n", getprogname(), tagmsg_path); } else if (tagmsg_path && unlink(tagmsg_path) == -1 && err == NULL) err = got_error_from_errno2("unlink", tagmsg_path); free(tag_id_str); if (ref) got_ref_close(ref); free(commit_id); free(commit_id_str); free(refname); free(tagmsg); free(tagmsg_path); got_ref_list_free(&refs); return err; } static const struct got_error * cmd_tag(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL, *commit_id_str = NULL; char *gitconfig_path = NULL, *tagger = NULL; char *allowed_signers = NULL, *revoked_signers = NULL; const char *signer_id = NULL; const char *tag_name = NULL, *commit_id_arg = NULL, *tagmsg = NULL; int ch, do_list = 0, verify_tags = 0, verbosity = 0; int *pack_fds = NULL; #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "c:lm:r:s:Vv")) != -1) { switch (ch) { case 'c': commit_id_arg = optarg; break; case 'l': do_list = 1; break; case 'm': tagmsg = optarg; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) { error = got_error_from_errno2("realpath", optarg); goto done; } got_path_strip_trailing_slashes(repo_path); break; case 's': signer_id = optarg; break; case 'V': verify_tags = 1; break; case 'v': if (verbosity < 0) verbosity = 0; else if (verbosity < 3) verbosity++; break; default: usage_tag(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (do_list || verify_tags) { if (commit_id_arg != NULL) errx(1, "-c option can only be used when creating a tag"); if (tagmsg) { if (do_list) option_conflict('l', 'm'); else option_conflict('V', 'm'); } if (signer_id) { if (do_list) option_conflict('l', 's'); else option_conflict('V', 's'); } if (argc > 1) usage_tag(); } else if (argc != 1) usage_tag(); if (argc == 1) tag_name = argv[0]; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else error = NULL; if (worktree) { repo_path = strdup(got_worktree_get_repo_path(worktree)); if (repo_path == NULL) error = got_error_from_errno("strdup"); if (error) goto done; } else { repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } if (do_list || verify_tags) { error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; error = get_allowed_signers(&allowed_signers, repo, worktree); if (error) goto done; error = get_revoked_signers(&revoked_signers, repo, worktree); if (error) goto done; if (worktree) { /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } /* * Remove "cpath" promise unless needed for signature tmpfile * creation. */ if (verify_tags) got_sigs_apply_unveil(); else { #ifndef PROFILE if (pledge("stdio rpath wpath flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif } error = apply_unveil(got_repo_get_path(repo), 1, NULL); if (error) goto done; error = list_tags(repo, tag_name, verify_tags, allowed_signers, revoked_signers, verbosity); } else { error = get_gitconfig_path(&gitconfig_path); if (error) goto done; error = got_repo_open(&repo, repo_path, gitconfig_path, pack_fds); if (error != NULL) goto done; error = get_author(&tagger, repo, worktree); if (error) goto done; if (signer_id == NULL) signer_id = get_signer_id(repo, worktree); if (tagmsg) { if (signer_id) { error = got_sigs_apply_unveil(); if (error) goto done; } error = apply_unveil(got_repo_get_path(repo), 0, NULL); if (error) goto done; } if (commit_id_arg == NULL) { struct got_reference *head_ref; struct got_object_id *commit_id; error = got_ref_open(&head_ref, repo, worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, 0); if (error) goto done; error = got_ref_resolve(&commit_id, repo, head_ref); got_ref_close(head_ref); if (error) goto done; error = got_object_id_str(&commit_id_str, commit_id); free(commit_id); if (error) goto done; } if (worktree) { /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } error = add_tag(repo, tagger, tag_name, commit_id_str ? commit_id_str : commit_id_arg, tagmsg, signer_id, verbosity); } done: if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } free(cwd); free(repo_path); free(gitconfig_path); free(commit_id_str); free(tagger); free(allowed_signers); free(revoked_signers); return error; } __dead static void usage_add(void) { fprintf(stderr, "usage: %s add [-IR] path ...\n", getprogname()); exit(1); } static const struct got_error * add_progress(void *arg, unsigned char status, const char *path) { while (path[0] == '/') path++; printf("%c %s\n", status, path); return NULL; } static const struct got_error * cmd_add(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL; struct got_pathlist_head paths; struct got_pathlist_entry *pe; int ch, can_recurse = 0, no_ignores = 0; int *pack_fds = NULL; TAILQ_INIT(&paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "IR")) != -1) { switch (ch) { case 'I': no_ignores = 1; break; case 'R': can_recurse = 1; break; default: usage_add(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc < 1) usage_add(); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "add", cwd); goto done; } error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 1, got_worktree_get_root_path(worktree)); if (error) goto done; error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; if (!can_recurse) { char *ondisk_path; struct stat sb; TAILQ_FOREACH(pe, &paths, entry) { if (asprintf(&ondisk_path, "%s/%s", got_worktree_get_root_path(worktree), pe->path) == -1) { error = got_error_from_errno("asprintf"); goto done; } if (lstat(ondisk_path, &sb) == -1) { if (errno == ENOENT) { free(ondisk_path); continue; } error = got_error_from_errno2("lstat", ondisk_path); free(ondisk_path); goto done; } free(ondisk_path); if (S_ISDIR(sb.st_mode)) { error = got_error_msg(GOT_ERR_BAD_PATH, "adding directories requires -R option"); goto done; } } } error = got_worktree_schedule_add(worktree, &paths, add_progress, NULL, repo, no_ignores); done: if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(cwd); return error; } __dead static void usage_remove(void) { fprintf(stderr, "usage: %s remove [-fkR] [-s status-codes] path ...\n", getprogname()); exit(1); } static const struct got_error * print_remove_status(void *arg, unsigned char status, unsigned char staged_status, const char *path) { while (path[0] == '/') path++; if (status == GOT_STATUS_NONEXISTENT) return NULL; if (status == staged_status && (status == GOT_STATUS_DELETE)) status = GOT_STATUS_NO_CHANGE; printf("%c%c %s\n", status, staged_status, path); return NULL; } static const struct got_error * cmd_remove(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; const char *status_codes = NULL; char *cwd = NULL; struct got_pathlist_head paths; struct got_pathlist_entry *pe; int ch, delete_local_mods = 0, can_recurse = 0, keep_on_disk = 0, i; int ignore_missing_paths = 0; int *pack_fds = NULL; TAILQ_INIT(&paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "fkRs:")) != -1) { switch (ch) { case 'f': delete_local_mods = 1; ignore_missing_paths = 1; break; case 'k': keep_on_disk = 1; break; case 'R': can_recurse = 1; break; case 's': for (i = 0; optarg[i] != '\0'; i++) { switch (optarg[i]) { case GOT_STATUS_MODIFY: delete_local_mods = 1; break; case GOT_STATUS_MISSING: ignore_missing_paths = 1; break; default: errx(1, "invalid status code '%c'", optarg[i]); } } status_codes = optarg; break; default: usage_remove(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc < 1) usage_remove(); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "remove", cwd); goto done; } error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), NULL, pack_fds); if (error) goto done; error = apply_unveil(got_repo_get_path(repo), 1, got_worktree_get_root_path(worktree)); if (error) goto done; error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; if (!can_recurse) { char *ondisk_path; struct stat sb; TAILQ_FOREACH(pe, &paths, entry) { if (asprintf(&ondisk_path, "%s/%s", got_worktree_get_root_path(worktree), pe->path) == -1) { error = got_error_from_errno("asprintf"); goto done; } if (lstat(ondisk_path, &sb) == -1) { if (errno == ENOENT) { free(ondisk_path); continue; } error = got_error_from_errno2("lstat", ondisk_path); free(ondisk_path); goto done; } free(ondisk_path); if (S_ISDIR(sb.st_mode)) { error = got_error_msg(GOT_ERR_BAD_PATH, "removing directories requires -R option"); goto done; } } } error = got_worktree_schedule_delete(worktree, &paths, delete_local_mods, status_codes, print_remove_status, NULL, repo, keep_on_disk, ignore_missing_paths); done: if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(cwd); return error; } __dead static void usage_patch(void) { fprintf(stderr, "usage: %s patch [-nR] [-c commit] [-p strip-count] " "[patchfile]\n", getprogname()); exit(1); } static const struct got_error * patch_from_stdin(int *patchfd) { const struct got_error *err = NULL; ssize_t r; char buf[BUFSIZ]; sig_t sighup, sigint, sigquit; *patchfd = got_opentempfd(); if (*patchfd == -1) return got_error_from_errno("got_opentempfd"); sighup = signal(SIGHUP, SIG_DFL); sigint = signal(SIGINT, SIG_DFL); sigquit = signal(SIGQUIT, SIG_DFL); for (;;) { r = read(0, buf, sizeof(buf)); if (r == -1) { err = got_error_from_errno("read"); break; } if (r == 0) break; if (write(*patchfd, buf, r) == -1) { err = got_error_from_errno("write"); break; } } signal(SIGHUP, sighup); signal(SIGINT, sigint); signal(SIGQUIT, sigquit); if (err == NULL && lseek(*patchfd, 0, SEEK_SET) == -1) err = got_error_from_errno("lseek"); if (err != NULL) { close(*patchfd); *patchfd = -1; } return err; } struct got_patch_progress_arg { int did_something; int conflicts; int rejects; }; static const struct got_error * patch_progress(void *arg, const char *old, const char *new, unsigned char status, const struct got_error *error, int old_from, int old_lines, int new_from, int new_lines, int offset, int ws_mangled, const struct got_error *hunk_err) { const char *path = new == NULL ? old : new; struct got_patch_progress_arg *a = arg; while (*path == '/') path++; if (status != GOT_STATUS_NO_CHANGE && status != 0 /* per-hunk progress */) { printf("%c %s\n", status, path); a->did_something = 1; } if (hunk_err == NULL) { if (status == GOT_STATUS_CANNOT_UPDATE) a->rejects++; else if (status == GOT_STATUS_CONFLICT) a->conflicts++; } if (error != NULL) fprintf(stderr, "%s: %s\n", getprogname(), error->msg); if (offset != 0 || hunk_err != NULL || ws_mangled) { printf("@@ -%d,%d +%d,%d @@ ", old_from, old_lines, new_from, new_lines); if (hunk_err != NULL) printf("%s\n", hunk_err->msg); else if (offset != 0) printf("applied with offset %d\n", offset); else printf("hunk contains mangled whitespace\n"); } return NULL; } static void print_patch_progress_stats(struct got_patch_progress_arg *ppa) { if (!ppa->did_something) return; if (ppa->conflicts > 0) printf("Files with merge conflicts: %d\n", ppa->conflicts); if (ppa->rejects > 0) { printf("Files where patch failed to apply: %d\n", ppa->rejects); } } static const struct got_error * cmd_patch(int argc, char *argv[]) { const struct got_error *error = NULL, *close_error = NULL; struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; struct got_reflist_head refs; struct got_object_id *commit_id = NULL; const char *commit_id_str = NULL; struct stat sb; const char *errstr; char *cwd = NULL; int ch, nop = 0, strip = -1, reverse = 0; int patchfd; int *pack_fds = NULL; struct got_patch_progress_arg ppa; TAILQ_INIT(&refs); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr proc exec sendfd flock " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "c:np:R")) != -1) { switch (ch) { case 'c': commit_id_str = optarg; break; case 'n': nop = 1; break; case 'p': strip = strtonum(optarg, 0, INT_MAX, &errstr); if (errstr != NULL) errx(1, "pathname strip count is %s: %s", errstr, optarg); break; case 'R': reverse = 1; break; default: usage_patch(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc == 0) { error = patch_from_stdin(&patchfd); if (error) return error; } else if (argc == 1) { patchfd = open(argv[0], O_RDONLY); if (patchfd == -1) { error = got_error_from_errno2("open", argv[0]); return error; } if (fstat(patchfd, &sb) == -1) { error = got_error_from_errno2("fstat", argv[0]); goto done; } if (!S_ISREG(sb.st_mode)) { error = got_error_path(argv[0], GOT_ERR_BAD_FILETYPE); goto done; } } else usage_patch(); if ((cwd = getcwd(NULL, 0)) == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error != NULL) goto done; const char *repo_path = got_worktree_get_repo_path(worktree); error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 0, got_worktree_get_root_path(worktree)); if (error != NULL) goto done; error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; if (commit_id_str != NULL) { error = got_repo_match_object_id(&commit_id, NULL, commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (error) goto done; } memset(&ppa, 0, sizeof(ppa)); error = got_patch(patchfd, worktree, repo, nop, strip, reverse, commit_id, patch_progress, &ppa, check_cancelled, NULL); print_patch_progress_stats(&ppa); done: got_ref_list_free(&refs); free(commit_id); if (repo) { close_error = got_repo_close(repo); if (error == NULL) error = close_error; } if (worktree != NULL) { close_error = got_worktree_close(worktree); if (error == NULL) error = close_error; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } free(cwd); return error; } __dead static void usage_revert(void) { fprintf(stderr, "usage: %s revert [-pR] [-F response-script] path ...\n", getprogname()); exit(1); } static const struct got_error * revert_progress(void *arg, unsigned char status, const char *path) { if (status == GOT_STATUS_UNVERSIONED) return NULL; while (path[0] == '/') path++; printf("%c %s\n", status, path); return NULL; } struct choose_patch_arg { FILE *patch_script_file; const char *action; }; static const struct got_error * show_change(unsigned char status, const char *path, FILE *patch_file, int n, int nchanges, const char *action) { const struct got_error *err; char *line = NULL; size_t linesize = 0; ssize_t linelen; switch (status) { case GOT_STATUS_ADD: printf("A %s\n%s this addition? [y/n] ", path, action); break; case GOT_STATUS_DELETE: printf("D %s\n%s this deletion? [y/n] ", path, action); break; case GOT_STATUS_MODIFY: if (fseek(patch_file, 0L, SEEK_SET) == -1) return got_error_from_errno("fseek"); printf(GOT_COMMIT_SEP_STR); while ((linelen = getline(&line, &linesize, patch_file)) != -1) printf("%s", line); if (linelen == -1 && ferror(patch_file)) { err = got_error_from_errno("getline"); free(line); return err; } free(line); printf(GOT_COMMIT_SEP_STR); printf("M %s (change %d of %d)\n%s this change? [y/n/q] ", path, n, nchanges, action); break; default: return got_error_path(path, GOT_ERR_FILE_STATUS); } fflush(stdout); return NULL; } static const struct got_error * choose_patch(int *choice, void *arg, unsigned char status, const char *path, FILE *patch_file, int n, int nchanges) { const struct got_error *err = NULL; char *line = NULL; size_t linesize = 0; ssize_t linelen; int resp = ' '; struct choose_patch_arg *a = arg; *choice = GOT_PATCH_CHOICE_NONE; if (a->patch_script_file) { char *nl; err = show_change(status, path, patch_file, n, nchanges, a->action); if (err) return err; linelen = getline(&line, &linesize, a->patch_script_file); if (linelen == -1) { if (ferror(a->patch_script_file)) return got_error_from_errno("getline"); return NULL; } nl = strchr(line, '\n'); if (nl) *nl = '\0'; if (strcmp(line, "y") == 0) { *choice = GOT_PATCH_CHOICE_YES; printf("y\n"); } else if (strcmp(line, "n") == 0) { *choice = GOT_PATCH_CHOICE_NO; printf("n\n"); } else if (strcmp(line, "q") == 0 && status == GOT_STATUS_MODIFY) { *choice = GOT_PATCH_CHOICE_QUIT; printf("q\n"); } else printf("invalid response '%s'\n", line); free(line); return NULL; } while (resp != 'y' && resp != 'n' && resp != 'q') { err = show_change(status, path, patch_file, n, nchanges, a->action); if (err) return err; resp = getchar(); if (resp == '\n') resp = getchar(); if (status == GOT_STATUS_MODIFY) { if (resp != 'y' && resp != 'n' && resp != 'q') { printf("invalid response '%c'\n", resp); resp = ' '; } } else if (resp != 'y' && resp != 'n') { printf("invalid response '%c'\n", resp); resp = ' '; } } if (resp == 'y') *choice = GOT_PATCH_CHOICE_YES; else if (resp == 'n') *choice = GOT_PATCH_CHOICE_NO; else if (resp == 'q' && status == GOT_STATUS_MODIFY) *choice = GOT_PATCH_CHOICE_QUIT; return NULL; } struct wt_commitable_path_arg { struct got_pathlist_head *commit_paths; int *has_changes; }; /* * Shortcut work tree status callback to determine if the set of paths scanned * has at least one versioned path that is being modified and, if not NULL, is * in the arg->commit_paths list. Set arg and return GOT_ERR_FILE_MODIFIED as * soon as a path is passed with a status that satisfies this criteria. */ static const struct got_error * worktree_has_commitable_path(void *arg, unsigned char status, unsigned char staged_status, const char *path, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { struct wt_commitable_path_arg *a = arg; if (status == staged_status && (status == GOT_STATUS_DELETE)) status = GOT_STATUS_NO_CHANGE; if (!(status == GOT_STATUS_NO_CHANGE || status == GOT_STATUS_UNVERSIONED) || staged_status != GOT_STATUS_NO_CHANGE) { if (a->commit_paths != NULL) { struct got_pathlist_entry *pe; TAILQ_FOREACH(pe, a->commit_paths, entry) { if (strncmp(path, pe->path, pe->path_len) == 0) { *a->has_changes = 1; break; } } } else *a->has_changes = 1; if (*a->has_changes) return got_error(GOT_ERR_FILE_MODIFIED); } return NULL; } /* * Check that the changeset of the commit identified by id is * comprised of at least one modified path that is being committed. */ static const struct got_error * commit_path_changed_in_worktree(struct wt_commitable_path_arg *wcpa, struct got_object_id *id, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; struct got_pathlist_head paths; struct got_commit_object *commit = NULL, *pcommit = NULL; struct got_tree_object *tree = NULL, *ptree = NULL; struct got_object_qid *pid; TAILQ_INIT(&paths); err = got_object_open_as_commit(&commit, repo, id); if (err) goto done; err = got_object_open_as_tree(&tree, repo, got_object_commit_get_tree_id(commit)); if (err) goto done; pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); if (pid != NULL) { err = got_object_open_as_commit(&pcommit, repo, &pid->id); if (err) goto done; err = got_object_open_as_tree(&ptree, repo, got_object_commit_get_tree_id(pcommit)); if (err) goto done; } err = got_diff_tree(ptree, tree, NULL, NULL, -1, -1, "", "", repo, got_diff_tree_collect_changed_paths, &paths, 0); if (err) goto done; err = got_worktree_status(worktree, &paths, repo, 0, worktree_has_commitable_path, wcpa, check_cancelled, NULL); if (err && err->code == GOT_ERR_FILE_MODIFIED) { /* * At least one changed path in the referenced commit is * modified in the work tree, that's all we need to know! */ err = NULL; } done: got_pathlist_free(&paths, GOT_PATHLIST_FREE_ALL); if (commit) got_object_commit_close(commit); if (pcommit) got_object_commit_close(pcommit); if (tree) got_object_tree_close(tree); if (ptree) got_object_tree_close(ptree); return err; } /* * Remove any "logmsg" reference comprised entirely of paths that have * been reverted in this work tree. If any path in the logmsg ref changeset * remains in a changed state in the worktree, do not remove the reference. */ static const struct got_error * rm_logmsg_ref(struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; struct got_reflist_head refs; struct got_reflist_entry *re; struct got_commit_object *commit = NULL; struct got_object_id *commit_id = NULL; struct wt_commitable_path_arg wcpa; char *uuidstr = NULL; TAILQ_INIT(&refs); err = got_worktree_get_uuid(&uuidstr, worktree); if (err) goto done; err = got_ref_list(&refs, repo, "refs/got/worktree", got_ref_cmp_by_name, repo); if (err) goto done; TAILQ_FOREACH(re, &refs, entry) { const char *refname; int has_changes = 0; refname = got_ref_get_name(re->ref); if (!strncmp(refname, GOT_WORKTREE_CHERRYPICK_REF_PREFIX, GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN)) refname += GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN + 1; else if (!strncmp(refname, GOT_WORKTREE_BACKOUT_REF_PREFIX, GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN)) refname += GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN + 1; else continue; if (strncmp(refname, uuidstr, GOT_WORKTREE_UUID_STRLEN) == 0) refname += GOT_WORKTREE_UUID_STRLEN + 1; /* skip '-' */ else continue; err = got_repo_match_object_id(&commit_id, NULL, refname, GOT_OBJ_TYPE_COMMIT, NULL, repo); if (err) goto done; err = got_object_open_as_commit(&commit, repo, commit_id); if (err) goto done; wcpa.commit_paths = NULL; wcpa.has_changes = &has_changes; err = commit_path_changed_in_worktree(&wcpa, commit_id, worktree, repo); if (err) goto done; if (!has_changes) { err = got_ref_delete(re->ref, repo); if (err) goto done; } got_object_commit_close(commit); commit = NULL; free(commit_id); commit_id = NULL; } done: free(uuidstr); free(commit_id); got_ref_list_free(&refs); if (commit) got_object_commit_close(commit); return err; } static const struct got_error * cmd_revert(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; char *cwd = NULL, *path = NULL; struct got_pathlist_head paths; struct got_pathlist_entry *pe; int ch, can_recurse = 0, pflag = 0; FILE *patch_script_file = NULL; const char *patch_script_path = NULL; struct choose_patch_arg cpa; int *pack_fds = NULL; TAILQ_INIT(&paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "F:pR")) != -1) { switch (ch) { case 'F': patch_script_path = optarg; break; case 'p': pflag = 1; break; case 'R': can_recurse = 1; break; default: usage_revert(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc < 1) usage_revert(); if (patch_script_path && !pflag) errx(1, "-F option can only be used together with -p option"); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "revert", cwd); goto done; } error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), NULL, pack_fds); if (error != NULL) goto done; if (patch_script_path) { patch_script_file = fopen(patch_script_path, "re"); if (patch_script_file == NULL) { error = got_error_from_errno2("fopen", patch_script_path); goto done; } } /* * XXX "c" perm needed on repo dir to delete merge references. */ error = apply_unveil(got_repo_get_path(repo), 0, got_worktree_get_root_path(worktree)); if (error) goto done; error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; if (!can_recurse) { char *ondisk_path; struct stat sb; TAILQ_FOREACH(pe, &paths, entry) { if (asprintf(&ondisk_path, "%s/%s", got_worktree_get_root_path(worktree), pe->path) == -1) { error = got_error_from_errno("asprintf"); goto done; } if (lstat(ondisk_path, &sb) == -1) { if (errno == ENOENT) { free(ondisk_path); continue; } error = got_error_from_errno2("lstat", ondisk_path); free(ondisk_path); goto done; } free(ondisk_path); if (S_ISDIR(sb.st_mode)) { error = got_error_msg(GOT_ERR_BAD_PATH, "reverting directories requires -R option"); goto done; } } } cpa.patch_script_file = patch_script_file; cpa.action = "revert"; error = got_worktree_revert(worktree, &paths, revert_progress, NULL, pflag ? choose_patch : NULL, &cpa, repo); error = rm_logmsg_ref(worktree, repo); done: if (patch_script_file && fclose(patch_script_file) == EOF && error == NULL) error = got_error_from_errno2("fclose", patch_script_path); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(path); free(cwd); return error; } __dead static void usage_commit(void) { fprintf(stderr, "usage: %s commit [-CNnS] [-A author] [-F path] " "[-m message] [path ...]\n", getprogname()); exit(1); } struct collect_commit_logmsg_arg { const char *cmdline_log; const char *prepared_log; const char *merged_log; int non_interactive; const char *editor; const char *worktree_path; const char *repo_path; const char *dial_proto; char *logmsg_path; }; static const struct got_error * read_prepared_logmsg(char **logmsg, const char *path) { const struct got_error *err = NULL; FILE *f = NULL; struct stat sb; size_t r; *logmsg = NULL; memset(&sb, 0, sizeof(sb)); f = fopen(path, "re"); if (f == NULL) return got_error_from_errno2("fopen", path); if (fstat(fileno(f), &sb) == -1) { err = got_error_from_errno2("fstat", path); goto done; } if (sb.st_size == 0) { err = got_error(GOT_ERR_COMMIT_MSG_EMPTY); goto done; } *logmsg = malloc(sb.st_size + 1); if (*logmsg == NULL) { err = got_error_from_errno("malloc"); goto done; } r = fread(*logmsg, 1, sb.st_size, f); if (r != sb.st_size) { if (ferror(f)) err = got_error_from_errno2("fread", path); else err = got_error(GOT_ERR_IO); goto done; } (*logmsg)[sb.st_size] = '\0'; done: if (fclose(f) == EOF && err == NULL) err = got_error_from_errno2("fclose", path); if (err) { free(*logmsg); *logmsg = NULL; } return err; } static const struct got_error * collect_commit_logmsg(struct got_pathlist_head *commitable_paths, const char *diff_path, char **logmsg, void *arg) { char *initial_content = NULL; struct got_pathlist_entry *pe; const struct got_error *err = NULL; char *template = NULL; char *prepared_msg = NULL, *merged_msg = NULL; struct collect_commit_logmsg_arg *a = arg; int initial_content_len; int fd = -1; size_t len; /* if a message was specified on the command line, just use it */ if (a->cmdline_log != NULL && *a->cmdline_log != '\0') { len = strlen(a->cmdline_log) + 1; *logmsg = malloc(len + 1); if (*logmsg == NULL) return got_error_from_errno("malloc"); strlcpy(*logmsg, a->cmdline_log, len); return NULL; } else if (a->prepared_log != NULL && a->non_interactive) return read_prepared_logmsg(logmsg, a->prepared_log); if (asprintf(&template, "%s/logmsg", a->worktree_path) == -1) return got_error_from_errno("asprintf"); err = got_opentemp_named_fd(&a->logmsg_path, &fd, template, ""); if (err) goto done; if (a->prepared_log) { err = read_prepared_logmsg(&prepared_msg, a->prepared_log); if (err) goto done; } else if (a->merged_log) { err = read_prepared_logmsg(&merged_msg, a->merged_log); if (err) goto done; } initial_content_len = asprintf(&initial_content, "%s%s\n# changes to be committed:\n", prepared_msg ? prepared_msg : "", merged_msg ? merged_msg : ""); if (initial_content_len == -1) { err = got_error_from_errno("asprintf"); goto done; } if (write(fd, initial_content, initial_content_len) == -1) { err = got_error_from_errno2("write", a->logmsg_path); goto done; } TAILQ_FOREACH(pe, commitable_paths, entry) { struct got_commitable *ct = pe->data; dprintf(fd, "# %c %s\n", got_commitable_get_status(ct), got_commitable_get_path(ct)); } if (diff_path) { dprintf(fd, "# detailed changes can be viewed in %s\n", diff_path); } if (close(fd) == -1) { err = got_error_from_errno2("close", a->logmsg_path); goto done; } fd = -1; err = edit_logmsg(logmsg, a->editor, a->logmsg_path, initial_content, initial_content_len, a->prepared_log ? 0 : 1); done: free(initial_content); free(template); free(prepared_msg); free(merged_msg); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno2("close", a->logmsg_path); /* Editor is done; we can now apply unveil(2) */ if (err == NULL) err = got_dial_apply_unveil(a->dial_proto); if (err == NULL) err = apply_unveil(a->repo_path, 0, a->worktree_path); if (err) { free(*logmsg); *logmsg = NULL; } return err; } static const struct got_error * cat_logmsg(FILE *f, struct got_commit_object *commit, const char *idstr, const char *type, int has_content) { const struct got_error *err = NULL; char *logmsg = NULL; err = got_object_commit_get_logmsg(&logmsg, commit); if (err) return err; if (fprintf(f, "%s# log message of %s commit %s:%s", has_content ? "\n" : "", type, idstr, logmsg) < 0) err = got_ferror(f, GOT_ERR_IO); free(logmsg); return err; } /* * Lookup "logmsg" references of backed-out and cherrypicked commits * belonging to the current work tree. If found, and the worktree has * at least one modified file that was changed in the referenced commit, * add its log message to a new temporary file at *logmsg_path. * Add all refs found to matched_refs to be scheduled for removal on * successful commit. */ static const struct got_error * lookup_logmsg_ref(char **logmsg_path, struct got_pathlist_head *paths, struct got_reflist_head *matched_refs, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; struct got_commit_object *commit = NULL; struct got_object_id *id = NULL; struct got_reflist_head refs; struct got_reflist_entry *re, *re_match; FILE *f = NULL; char *uuidstr = NULL; int added_logmsg = 0; TAILQ_INIT(&refs); *logmsg_path = NULL; err = got_worktree_get_uuid(&uuidstr, worktree); if (err) goto done; err = got_ref_list(&refs, repo, "refs/got/worktree", got_ref_cmp_by_name, repo); if (err) goto done; TAILQ_FOREACH(re, &refs, entry) { const char *refname, *type; struct wt_commitable_path_arg wcpa; int add_logmsg = 0; refname = got_ref_get_name(re->ref); if (strncmp(refname, GOT_WORKTREE_CHERRYPICK_REF_PREFIX, GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN) == 0) { refname += GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN + 1; type = "cherrypicked"; } else if (strncmp(refname, GOT_WORKTREE_BACKOUT_REF_PREFIX, GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN) == 0) { refname += GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN + 1; type = "backed-out"; } else continue; if (strncmp(refname, uuidstr, GOT_WORKTREE_UUID_STRLEN) == 0) refname += GOT_WORKTREE_UUID_STRLEN + 1; /* skip '-' */ else continue; err = got_repo_match_object_id(&id, NULL, refname, GOT_OBJ_TYPE_COMMIT, NULL, repo); if (err) goto done; err = got_object_open_as_commit(&commit, repo, id); if (err) goto done; wcpa.commit_paths = paths; wcpa.has_changes = &add_logmsg; err = commit_path_changed_in_worktree(&wcpa, id, worktree, repo); if (err) goto done; if (add_logmsg) { if (f == NULL) { err = got_opentemp_named(logmsg_path, &f, "got-commit-logmsg", ""); if (err) goto done; } err = cat_logmsg(f, commit, refname, type, added_logmsg); if (err) goto done; if (!added_logmsg) ++added_logmsg; err = got_reflist_entry_dup(&re_match, re); if (err) goto done; TAILQ_INSERT_HEAD(matched_refs, re_match, entry); } got_object_commit_close(commit); commit = NULL; free(id); id = NULL; } done: free(id); free(uuidstr); got_ref_list_free(&refs); if (commit) got_object_commit_close(commit); if (f && fclose(f) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (!added_logmsg) { if (*logmsg_path && unlink(*logmsg_path) != 0 && err == NULL) err = got_error_from_errno2("unlink", *logmsg_path); *logmsg_path = NULL; } return err; } static const struct got_error * cmd_commit(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; char *cwd = NULL, *id_str = NULL; struct got_object_id *id = NULL; const char *logmsg = NULL; char *prepared_logmsg = NULL, *merged_logmsg = NULL; struct collect_commit_logmsg_arg cl_arg; const char *author = NULL; char *gitconfig_path = NULL, *editor = NULL, *committer = NULL; int ch, rebase_in_progress, histedit_in_progress, preserve_logmsg = 0; int allow_bad_symlinks = 0, non_interactive = 0, merge_in_progress = 0; int show_diff = 1, commit_conflicts = 0; struct got_pathlist_head paths; struct got_reflist_head refs; struct got_reflist_entry *re; int *pack_fds = NULL; const struct got_gotconfig *repo_conf = NULL, *worktree_conf = NULL; const struct got_remote_repo *remotes, *remote = NULL; int nremotes; char *proto = NULL, *host = NULL, *port = NULL; char *repo_name = NULL, *server_path = NULL; const char *remote_name; int verbosity = 0; int i; TAILQ_INIT(&refs); TAILQ_INIT(&paths); cl_arg.logmsg_path = NULL; #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "A:CF:m:NnS")) != -1) { switch (ch) { case 'A': author = optarg; error = valid_author(author); if (error) return error; break; case 'C': commit_conflicts = 1; break; case 'F': if (logmsg != NULL) option_conflict('F', 'm'); prepared_logmsg = realpath(optarg, NULL); if (prepared_logmsg == NULL) return got_error_from_errno2("realpath", optarg); break; case 'm': if (prepared_logmsg) option_conflict('m', 'F'); logmsg = optarg; break; case 'N': non_interactive = 1; break; case 'n': show_diff = 0; break; case 'S': allow_bad_symlinks = 1; break; default: usage_commit(); /* NOTREACHED */ } } argc -= optind; argv += optind; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "commit", cwd); goto done; } error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree); if (error) goto done; if (rebase_in_progress) { error = got_error(GOT_ERR_REBASING); goto done; } error = got_worktree_histedit_in_progress(&histedit_in_progress, worktree); if (error) goto done; error = get_gitconfig_path(&gitconfig_path); if (error) goto done; error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), gitconfig_path, pack_fds); if (error != NULL) goto done; error = got_worktree_merge_in_progress(&merge_in_progress, worktree, repo); if (error) goto done; if (merge_in_progress) { error = got_error(GOT_ERR_MERGE_BUSY); goto done; } error = get_author(&committer, repo, worktree); if (error) goto done; if (author == NULL) author = committer; remote_name = GOT_SEND_DEFAULT_REMOTE_NAME; worktree_conf = got_worktree_get_gotconfig(worktree); if (worktree_conf) { got_gotconfig_get_remotes(&nremotes, &remotes, worktree_conf); for (i = 0; i < nremotes; i++) { if (strcmp(remotes[i].name, remote_name) == 0) { remote = &remotes[i]; break; } } } if (remote == NULL) { repo_conf = got_repo_get_gotconfig(repo); if (repo_conf) { got_gotconfig_get_remotes(&nremotes, &remotes, repo_conf); for (i = 0; i < nremotes; i++) { if (strcmp(remotes[i].name, remote_name) == 0) { remote = &remotes[i]; break; } } } } if (remote == NULL) { got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo); for (i = 0; i < nremotes; i++) { if (strcmp(remotes[i].name, remote_name) == 0) { remote = &remotes[i]; break; } } } if (remote == NULL) { error = got_error_path(remote_name, GOT_ERR_NO_REMOTE); goto done; } error = got_dial_parse_uri(&proto, &host, &port, &server_path, &repo_name, remote->fetch_url); if (error) goto done; if (strcmp(proto, "git") == 0) { #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd dns inet unveil", NULL) == -1) err(1, "pledge"); #endif } else if (strcmp(proto, "git+ssh") == 0 || strcmp(proto, "ssh") == 0) { #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd unveil", NULL) == -1) err(1, "pledge"); #endif } else if (strcmp(proto, "http") == 0 || strcmp(proto, "git+http") == 0) { error = got_error_path(proto, GOT_ERR_NOT_IMPL); goto done; } else { error = got_error_path(proto, GOT_ERR_BAD_PROTO); goto done; } /*if (verbosity >= 0) { printf("Connecting to \"%s\" %s://%s%s%s%s%s\n", remote->name, proto, host, port ? ":" : "", port ? port : "", *server_path == '/' ? "" : "/", server_path); }*/ /* * unveil(2) traverses exec(2); if an editor is used we have * to apply unveil after the log message has been written during * the callback. */ if (logmsg == NULL || strlen(logmsg) == 0) error = get_editor(&editor); else { error = got_dial_apply_unveil(proto); if (error) goto done; error = apply_unveil(got_repo_get_path(repo), 0, got_worktree_get_root_path(worktree)); } if (error) goto done; if (prepared_logmsg == NULL) { error = lookup_logmsg_ref(&merged_logmsg, argc > 0 ? &paths : NULL, &refs, worktree, repo); if (error) goto done; } error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; cl_arg.editor = editor; cl_arg.cmdline_log = logmsg; cl_arg.prepared_log = prepared_logmsg; cl_arg.merged_log = merged_logmsg; cl_arg.non_interactive = non_interactive; cl_arg.worktree_path = got_worktree_get_root_path(worktree); cl_arg.repo_path = got_repo_get_path(repo); cl_arg.dial_proto = proto; error = got_worktree_cvg_commit(&id, worktree, &paths, author, committer, allow_bad_symlinks, show_diff, commit_conflicts, collect_commit_logmsg, &cl_arg, print_status, NULL, proto, host, port, server_path, verbosity, remote, check_cancelled, repo); if (error) { if (error->code != GOT_ERR_COMMIT_MSG_EMPTY && cl_arg.logmsg_path != NULL) preserve_logmsg = 1; goto done; } error = got_object_id_str(&id_str, id); if (error) goto done; printf("Created commit %s\n", id_str); TAILQ_FOREACH(re, &refs, entry) { error = got_ref_delete(re->ref, repo); if (error) goto done; } done: if (preserve_logmsg) { fprintf(stderr, "%s: log message preserved in %s\n", getprogname(), cl_arg.logmsg_path); } else if (cl_arg.logmsg_path && unlink(cl_arg.logmsg_path) == -1 && error == NULL) error = got_error_from_errno2("unlink", cl_arg.logmsg_path); free(cl_arg.logmsg_path); if (merged_logmsg && unlink(merged_logmsg) == -1 && error == NULL) error = got_error_from_errno2("unlink", merged_logmsg); free(merged_logmsg); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_ref_list_free(&refs); got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(cwd); free(id_str); free(gitconfig_path); free(editor); free(committer); free(prepared_logmsg); return error; } /* * Print and if delete is set delete all ref_prefix references. * If wanted_ref is not NULL, only print or delete this reference. */ static const struct got_error * process_logmsg_refs(const char *ref_prefix, size_t prefix_len, const char *wanted_ref, int delete, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; struct got_pathlist_head paths; struct got_reflist_head refs; struct got_reflist_entry *re; struct got_reflist_object_id_map *refs_idmap = NULL; struct got_commit_object *commit = NULL; struct got_object_id *id = NULL; const char *header_prefix; char *uuidstr = NULL; int found = 0; TAILQ_INIT(&refs); TAILQ_INIT(&paths); err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, repo); if (err) goto done; err = got_reflist_object_id_map_create(&refs_idmap, &refs, repo); if (err) goto done; if (worktree != NULL) { err = got_worktree_get_uuid(&uuidstr, worktree); if (err) goto done; } if (wanted_ref) { if (strncmp(wanted_ref, "refs/heads/", 11) == 0) wanted_ref += 11; } if (strcmp(ref_prefix, GOT_WORKTREE_BACKOUT_REF_PREFIX) == 0) header_prefix = "backout"; else header_prefix = "cherrypick"; TAILQ_FOREACH(re, &refs, entry) { const char *refname, *wt; refname = got_ref_get_name(re->ref); err = check_cancelled(NULL); if (err) goto done; if (strncmp(refname, ref_prefix, prefix_len) == 0) refname += prefix_len + 1; /* skip '-' delimiter */ else continue; wt = refname; if (worktree == NULL || strncmp(refname, uuidstr, GOT_WORKTREE_UUID_STRLEN) == 0) refname += GOT_WORKTREE_UUID_STRLEN + 1; /* skip '-' */ else continue; err = got_repo_match_object_id(&id, NULL, refname, GOT_OBJ_TYPE_COMMIT, NULL, repo); if (err) goto done; err = got_object_open_as_commit(&commit, repo, id); if (err) goto done; if (wanted_ref) found = strncmp(wanted_ref, refname, strlen(wanted_ref)) == 0; if (wanted_ref && !found) { struct got_reflist_head *ci_refs; ci_refs = got_reflist_object_id_map_lookup(refs_idmap, id); if (ci_refs) { char *refs_str = NULL; char const *r = NULL; err = build_refs_str(&refs_str, ci_refs, id, repo, 1); if (err) goto done; r = refs_str; while (r) { if (strncmp(r, wanted_ref, strlen(wanted_ref)) == 0) { found = 1; break; } r = strchr(r, ' '); if (r) ++r; } free(refs_str); } } if (wanted_ref == NULL || found) { if (delete) { err = got_ref_delete(re->ref, repo); if (err) goto done; printf("Deleted: "); err = print_commit_oneline(commit, id, repo, refs_idmap); } else { /* * Print paths modified by commit to help * associate commits with worktree changes. */ err = get_changed_paths(&paths, commit, repo, NULL); if (err) goto done; err = print_commit(commit, id, repo, NULL, &paths, NULL, 0, 0, refs_idmap, NULL, header_prefix); got_pathlist_free(&paths, GOT_PATHLIST_FREE_ALL); if (worktree == NULL) printf("work tree: %.*s\n\n", GOT_WORKTREE_UUID_STRLEN, wt); } if (err || found) goto done; } got_object_commit_close(commit); commit = NULL; free(id); id = NULL; } if (wanted_ref != NULL && !found) err = got_error_fmt(GOT_ERR_NOT_REF, "%s", wanted_ref); done: free(id); free(uuidstr); got_ref_list_free(&refs); got_pathlist_free(&paths, GOT_PATHLIST_FREE_ALL); if (refs_idmap) got_reflist_object_id_map_free(refs_idmap); if (commit) got_object_commit_close(commit); return err; } /* * Create new temp "logmsg" ref of the backed-out or cherrypicked commit * identified by id for log messages to prepopulate the editor on commit. */ static const struct got_error * logmsg_ref(struct got_object_id *id, const char *prefix, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err = NULL; char *idstr, *ref = NULL, *refname = NULL; int histedit_in_progress; int rebase_in_progress, merge_in_progress; /* * Silenty refuse to create merge reference if any histedit, merge, * or rebase operation is in progress. */ err = got_worktree_histedit_in_progress(&histedit_in_progress, worktree); if (err) return err; if (histedit_in_progress) return NULL; err = got_worktree_rebase_in_progress(&rebase_in_progress, worktree); if (err) return err; if (rebase_in_progress) return NULL; err = got_worktree_merge_in_progress(&merge_in_progress, worktree, repo); if (err) return err; if (merge_in_progress) return NULL; err = got_object_id_str(&idstr, id); if (err) return err; err = got_worktree_get_logmsg_ref_name(&refname, worktree, prefix); if (err) goto done; if (asprintf(&ref, "%s-%s", refname, idstr) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = create_ref(ref, got_worktree_get_base_commit_id(worktree), -1, repo); done: free(ref); free(idstr); free(refname); return err; } __dead static void usage_cherrypick(void) { fprintf(stderr, "usage: %s cherrypick [-lX] [commit-id]\n", getprogname()); exit(1); } static const struct got_error * cmd_cherrypick(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; char *cwd = NULL, *commit_id_str = NULL; struct got_object_id *commit_id = NULL; struct got_commit_object *commit = NULL; struct got_object_qid *pid; int ch, list_refs = 0, remove_refs = 0; struct got_update_progress_arg upa; int *pack_fds = NULL; #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "lX")) != -1) { switch (ch) { case 'l': list_refs = 1; break; case 'X': remove_refs = 1; break; default: usage_cherrypick(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (list_refs || remove_refs) { if (argc != 0 && argc != 1) usage_cherrypick(); } else if (argc != 1) usage_cherrypick(); if (list_refs && remove_refs) option_conflict('l', 'X'); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error) { if (list_refs || remove_refs) { if (error->code != GOT_ERR_NOT_WORKTREE) goto done; } else { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "cherrypick", cwd); goto done; } } error = got_repo_open(&repo, worktree ? got_worktree_get_repo_path(worktree) : cwd, NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 0, worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; if (list_refs || remove_refs) { error = process_logmsg_refs(GOT_WORKTREE_CHERRYPICK_REF_PREFIX, GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN, argc == 1 ? argv[0] : NULL, remove_refs, worktree, repo); goto done; } error = got_repo_match_object_id(&commit_id, NULL, argv[0], GOT_OBJ_TYPE_COMMIT, NULL, repo); if (error) goto done; error = got_object_id_str(&commit_id_str, commit_id); if (error) goto done; error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); memset(&upa, 0, sizeof(upa)); error = got_worktree_merge_files(worktree, pid ? &pid->id : NULL, commit_id, repo, update_progress, &upa, check_cancelled, NULL); if (error != NULL) goto done; if (upa.did_something) { error = logmsg_ref(commit_id, GOT_WORKTREE_CHERRYPICK_REF_PREFIX, worktree, repo); if (error) goto done; printf("Merged commit %s\n", commit_id_str); } print_merge_progress_stats(&upa); done: free(cwd); if (commit) got_object_commit_close(commit); free(commit_id_str); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } return error; } __dead static void usage_backout(void) { fprintf(stderr, "usage: %s backout [-lX] [commit-id]\n", getprogname()); exit(1); } static const struct got_error * cmd_backout(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; char *cwd = NULL, *commit_id_str = NULL; struct got_object_id *commit_id = NULL; struct got_commit_object *commit = NULL; struct got_object_qid *pid; int ch, list_refs = 0, remove_refs = 0; struct got_update_progress_arg upa; int *pack_fds = NULL; #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "lX")) != -1) { switch (ch) { case 'l': list_refs = 1; break; case 'X': remove_refs = 1; break; default: usage_backout(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (list_refs || remove_refs) { if (argc != 0 && argc != 1) usage_backout(); } else if (argc != 1) usage_backout(); if (list_refs && remove_refs) option_conflict('l', 'X'); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error) { if (list_refs || remove_refs) { if (error->code != GOT_ERR_NOT_WORKTREE) goto done; } else { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "backout", cwd); goto done; } } error = got_repo_open(&repo, worktree ? got_worktree_get_repo_path(worktree) : cwd, NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 0, worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; if (list_refs || remove_refs) { error = process_logmsg_refs(GOT_WORKTREE_BACKOUT_REF_PREFIX, GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN, argc == 1 ? argv[0] : NULL, remove_refs, worktree, repo); goto done; } error = got_repo_match_object_id(&commit_id, NULL, argv[0], GOT_OBJ_TYPE_COMMIT, NULL, repo); if (error) goto done; error = got_object_id_str(&commit_id_str, commit_id); if (error) goto done; error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); if (pid == NULL) { error = got_error(GOT_ERR_ROOT_COMMIT); goto done; } memset(&upa, 0, sizeof(upa)); error = got_worktree_merge_files(worktree, commit_id, &pid->id, repo, update_progress, &upa, check_cancelled, NULL); if (error != NULL) goto done; if (upa.did_something) { error = logmsg_ref(commit_id, GOT_WORKTREE_BACKOUT_REF_PREFIX, worktree, repo); if (error) goto done; printf("Backed out commit %s\n", commit_id_str); } print_merge_progress_stats(&upa); done: free(cwd); if (commit) got_object_commit_close(commit); free(commit_id_str); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } return error; } __dead static void usage_cat(void) { fprintf(stderr, "usage: %s cat [-P] [-c commit] [-r repository-path] " "arg ...\n", getprogname()); exit(1); } static const struct got_error * cat_blob(struct got_object_id *id, struct got_repository *repo, FILE *outfile) { const struct got_error *err; struct got_blob_object *blob; int fd = -1; fd = got_opentempfd(); if (fd == -1) return got_error_from_errno("got_opentempfd"); err = got_object_open_as_blob(&blob, repo, id, 8192, fd); if (err) goto done; err = got_object_blob_dump_to_file(NULL, NULL, NULL, outfile, blob); done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob) got_object_blob_close(blob); return err; } static const struct got_error * cat_tree(struct got_object_id *id, struct got_repository *repo, FILE *outfile) { const struct got_error *err; struct got_tree_object *tree; int nentries, i; err = got_object_open_as_tree(&tree, repo, id); if (err) return err; nentries = got_object_tree_get_nentries(tree); for (i = 0; i < nentries; i++) { struct got_tree_entry *te; char *id_str; if (sigint_received || sigpipe_received) break; te = got_object_tree_get_entry(tree, i); err = got_object_id_str(&id_str, got_tree_entry_get_id(te)); if (err) break; fprintf(outfile, "%s %.7o %s\n", id_str, got_tree_entry_get_mode(te), got_tree_entry_get_name(te)); free(id_str); } got_object_tree_close(tree); return err; } static const struct got_error * cat_commit(struct got_object_id *id, struct got_repository *repo, FILE *outfile) { const struct got_error *err; struct got_commit_object *commit; const struct got_object_id_queue *parent_ids; struct got_object_qid *pid; char *id_str = NULL; const char *logmsg = NULL; char gmtoff[6]; err = got_object_open_as_commit(&commit, repo, id); if (err) return err; err = got_object_id_str(&id_str, got_object_commit_get_tree_id(commit)); if (err) goto done; fprintf(outfile, "%s%s\n", GOT_COMMIT_LABEL_TREE, id_str); parent_ids = got_object_commit_get_parent_ids(commit); fprintf(outfile, "numparents %d\n", got_object_commit_get_nparents(commit)); STAILQ_FOREACH(pid, parent_ids, entry) { char *pid_str; err = got_object_id_str(&pid_str, &pid->id); if (err) goto done; fprintf(outfile, "%s%s\n", GOT_COMMIT_LABEL_PARENT, pid_str); free(pid_str); } got_date_format_gmtoff(gmtoff, sizeof(gmtoff), got_object_commit_get_author_gmtoff(commit)); fprintf(outfile, "%s%s %lld %s\n", GOT_COMMIT_LABEL_AUTHOR, got_object_commit_get_author(commit), (long long)got_object_commit_get_author_time(commit), gmtoff); got_date_format_gmtoff(gmtoff, sizeof(gmtoff), got_object_commit_get_committer_gmtoff(commit)); fprintf(outfile, "%s%s %lld %s\n", GOT_COMMIT_LABEL_COMMITTER, got_object_commit_get_committer(commit), (long long)got_object_commit_get_committer_time(commit), gmtoff); logmsg = got_object_commit_get_logmsg_raw(commit); fprintf(outfile, "messagelen %zd\n", strlen(logmsg)); fprintf(outfile, "%s", logmsg); done: free(id_str); got_object_commit_close(commit); return err; } static const struct got_error * cat_tag(struct got_object_id *id, struct got_repository *repo, FILE *outfile) { const struct got_error *err; struct got_tag_object *tag; char *id_str = NULL; const char *tagmsg = NULL; char gmtoff[6]; err = got_object_open_as_tag(&tag, repo, id); if (err) return err; err = got_object_id_str(&id_str, got_object_tag_get_object_id(tag)); if (err) goto done; fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_OBJECT, id_str); switch (got_object_tag_get_object_type(tag)) { case GOT_OBJ_TYPE_BLOB: fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE, GOT_OBJ_LABEL_BLOB); break; case GOT_OBJ_TYPE_TREE: fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE, GOT_OBJ_LABEL_TREE); break; case GOT_OBJ_TYPE_COMMIT: fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE, GOT_OBJ_LABEL_COMMIT); break; case GOT_OBJ_TYPE_TAG: fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE, GOT_OBJ_LABEL_TAG); break; default: break; } fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TAG, got_object_tag_get_name(tag)); got_date_format_gmtoff(gmtoff, sizeof(gmtoff), got_object_tag_get_tagger_gmtoff(tag)); fprintf(outfile, "%s%s %lld %s\n", GOT_TAG_LABEL_TAGGER, got_object_tag_get_tagger(tag), (long long)got_object_tag_get_tagger_time(tag), gmtoff); tagmsg = got_object_tag_get_message(tag); fprintf(outfile, "messagelen %zd\n", strlen(tagmsg)); fprintf(outfile, "%s", tagmsg); done: free(id_str); got_object_tag_close(tag); return err; } static const struct got_error * cmd_cat(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL, *label = NULL; const char *commit_id_str = NULL; struct got_object_id *id = NULL, *commit_id = NULL; struct got_commit_object *commit = NULL; int ch, obj_type, i, force_path = 0; struct got_reflist_head refs; int *pack_fds = NULL; TAILQ_INIT(&refs); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "c:Pr:")) != -1) { switch (ch) { case 'c': commit_id_str = optarg; break; case 'P': force_path = 1; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; default: usage_cat(); /* NOTREACHED */ } } argc -= optind; argv += optind; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; if (worktree) { repo_path = strdup( got_worktree_get_repo_path(worktree)); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } } if (repo_path == NULL) { repo_path = strdup(cwd); if (repo_path == NULL) return got_error_from_errno("strdup"); } error = got_repo_open(&repo, repo_path, NULL, pack_fds); free(repo_path); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 1, NULL); if (error) goto done; error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; if (commit_id_str == NULL) commit_id_str = GOT_REF_HEAD; error = got_repo_match_object_id(&commit_id, NULL, commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (error) goto done; error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; for (i = 0; i < argc; i++) { if (force_path) { error = got_object_id_by_path(&id, repo, commit, argv[i]); if (error) break; } else { error = got_repo_match_object_id(&id, &label, argv[i], GOT_OBJ_TYPE_ANY, NULL /* do not resolve tags */, repo); if (error) { if (error->code != GOT_ERR_BAD_OBJ_ID_STR && error->code != GOT_ERR_NOT_REF) break; error = got_object_id_by_path(&id, repo, commit, argv[i]); if (error) break; } } error = got_object_get_type(&obj_type, repo, id); if (error) break; switch (obj_type) { case GOT_OBJ_TYPE_BLOB: error = cat_blob(id, repo, stdout); break; case GOT_OBJ_TYPE_TREE: error = cat_tree(id, repo, stdout); break; case GOT_OBJ_TYPE_COMMIT: error = cat_commit(id, repo, stdout); break; case GOT_OBJ_TYPE_TAG: error = cat_tag(id, repo, stdout); break; default: error = got_error(GOT_ERR_OBJ_TYPE); break; } if (error) break; free(label); label = NULL; free(id); id = NULL; } done: free(label); free(id); free(commit_id); if (commit) got_object_commit_close(commit); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_ref_list_free(&refs); return error; } __dead static void usage_info(void) { fprintf(stderr, "usage: %s info [path ...]\n", getprogname()); exit(1); } static const struct got_error * print_path_info(void *arg, const char *path, mode_t mode, time_t mtime, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id) { const struct got_error *err = NULL; char *id_str = NULL; char datebuf[128]; struct tm mytm, *tm; struct got_pathlist_head *paths = arg; struct got_pathlist_entry *pe; /* * Clear error indication from any of the path arguments which * would cause this file index entry to be displayed. */ TAILQ_FOREACH(pe, paths, entry) { if (got_path_cmp(path, pe->path, strlen(path), pe->path_len) == 0 || got_path_is_child(path, pe->path, pe->path_len)) pe->data = NULL; /* no error */ } printf(GOT_COMMIT_SEP_STR); if (S_ISLNK(mode)) printf("symlink: %s\n", path); else if (S_ISREG(mode)) { printf("file: %s\n", path); printf("mode: %o\n", mode & (S_IRWXU | S_IRWXG | S_IRWXO)); } else if (S_ISDIR(mode)) printf("directory: %s\n", path); else printf("something: %s\n", path); tm = localtime_r(&mtime, &mytm); if (tm == NULL) return NULL; if (strftime(datebuf, sizeof(datebuf), "%c %Z", tm) == 0) return got_error(GOT_ERR_NO_SPACE); printf("timestamp: %s\n", datebuf); if (blob_id) { err = got_object_id_str(&id_str, blob_id); if (err) return err; printf("based on blob: %s\n", id_str); free(id_str); } if (staged_blob_id) { err = got_object_id_str(&id_str, staged_blob_id); if (err) return err; printf("based on staged blob: %s\n", id_str); free(id_str); } if (commit_id) { err = got_object_id_str(&id_str, commit_id); if (err) return err; printf("based on commit: %s\n", id_str); free(id_str); } return NULL; } static const struct got_error * cmd_info(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *id_str = NULL; struct got_pathlist_head paths; char *uuidstr = NULL; int ch, show_files = 0; TAILQ_INIT(&paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "")) != -1) { switch (ch) { default: usage_info(); /* NOTREACHED */ } } argc -= optind; argv += optind; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "info", cwd); goto done; } #ifndef PROFILE /* Remove "wpath cpath proc exec sendfd" promises. */ if (pledge("stdio rpath flock unveil", NULL) == -1) err(1, "pledge"); #endif error = apply_unveil(NULL, 0, got_worktree_get_root_path(worktree)); if (error) goto done; if (argc >= 1) { error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; show_files = 1; } error = got_object_id_str(&id_str, got_worktree_get_base_commit_id(worktree)); if (error) goto done; error = got_worktree_get_uuid(&uuidstr, worktree); if (error) goto done; printf("work tree: %s\n", got_worktree_get_root_path(worktree)); printf("work tree base commit: %s\n", id_str); printf("work tree path prefix: %s\n", got_worktree_get_path_prefix(worktree)); printf("work tree branch reference: %s\n", got_worktree_get_head_ref_name(worktree)); printf("work tree UUID: %s\n", uuidstr); printf("repository: %s\n", got_worktree_get_repo_path(worktree)); if (show_files) { struct got_pathlist_entry *pe; TAILQ_FOREACH(pe, &paths, entry) { if (pe->path_len == 0) continue; /* * Assume this path will fail. This will be corrected * in print_path_info() in case the path does suceeed. */ pe->data = (void *)got_error(GOT_ERR_BAD_PATH); } error = got_worktree_path_info(worktree, &paths, print_path_info, &paths, check_cancelled, NULL); if (error) goto done; TAILQ_FOREACH(pe, &paths, entry) { if (pe->data != NULL) { const struct got_error *perr; perr = pe->data; error = got_error_fmt(perr->code, "%s", pe->path); break; } } } done: if (worktree) got_worktree_close(worktree); got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(cwd); free(id_str); free(uuidstr); return error; } got-portable-0.101/include/0000775000175100017510000000000014644145570011314 5got-portable-0.101/include/got_privsep.h0000644000175100017510000000153714644143163013746 /* * Copyright (c) 2018, 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ const struct got_error *got_privsep_unveil_exec_helpers(void); got-portable-0.101/include/got_repository_admin.h0000644000175100017510000001146014644143163015641 /* * Copyright (c) 2021 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* A callback function which gets invoked with progress information to print. */ typedef const struct got_error *(*got_pack_progress_cb)(void *arg, int ncolored, int nfound, int ntrees, off_t packfile_size, int ncommits, int nobj_total, int obj_deltify, int nobj_written); /* * Attempt to pack objects reachable via 'include_refs' into a new packfile. * If 'excluded_refs' is not an empty list, do not pack any objects * reachable from the listed references. * If loose_obj_only is zero, pack reachable objects even if they are * already packed in another packfile. Otherwise, add only loose * objects to the new pack file. * Return an open file handle for the generated pack file. * Return the SHA1 digest of the resulting pack file in pack_hash which * must freed by the caller when done. */ const struct got_error * got_repo_pack_objects(FILE **packfile, struct got_object_id **pack_hash, struct got_reflist_head *include_refs, struct got_reflist_head *exclude_refs, struct got_repository *repo, int loose_obj_only, int force_refdelta, got_pack_progress_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg); /* * Attempt to open a pack file at the specified path. Return an open * file handle and the expected hash of pack file contents. */ const struct got_error * got_repo_find_pack(FILE **packfile, struct got_object_id **pack_hash, struct got_repository *repo, const char *packfile_path); /* A callback function which gets invoked with progress information to print. */ typedef const struct got_error *(*got_pack_index_progress_cb)(void *arg, off_t packfile_size, int nobj_total, int nobj_indexed, int nobj_loose, int nobj_resolved); /* (Re-)Index the pack file identified by the given hash. */ const struct got_error * got_repo_index_pack(FILE *packfile, struct got_object_id *pack_hash, struct got_repository *repo, got_pack_index_progress_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg); typedef const struct got_error *(*got_pack_list_cb)(void *arg, struct got_object_id *id, int type, off_t offset, off_t size, off_t base_offset, struct got_object_id *base_id); /* List the pack file identified by the given hash. */ const struct got_error * got_repo_list_pack(FILE *packfile, struct got_object_id *pack_hash, struct got_repository *repo, got_pack_list_cb list_cb, void *list_arg, got_cancel_cb cancel_cb, void *cancel_arg); /* A callback function which gets invoked with cleanup information to print. */ typedef const struct got_error *(*got_cleanup_progress_cb)(void *arg, int ncommits, int nloose, int npurged, int nredundant); /* * Walk objects reachable via references to determine whether any loose * objects can be removed from disk. Do remove such objects from disk * unless the dry_run parameter is set. * Do not remove objects with a modification timestamp above an * implementation-defined timestamp threshold, unless ignore_mtime is set. * Remove packfiles which objects are either unreachable or provided * by biggest pack files. * Return the disk space size occupied by loose objects and pack files * before and after the operation. * Return the number of loose objects which are also stored in a pack file. */ const struct got_error * got_repo_cleanup(struct got_repository *repo, off_t *loose_before, off_t *loose_after, off_t *pack_before, off_t *pack_after, int *ncommits, int *nloose, int *npacked, int dry_run, int ignore_mtime, got_cleanup_progress_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg); /* A callback function which gets invoked with cleanup information to print. */ typedef const struct got_error *(*got_lonely_packidx_progress_cb)(void *arg, const char *path); /* Remove pack index files which do not have a corresponding pack file. */ const struct got_error * got_repo_remove_lonely_packidx(struct got_repository *repo, int dry_run, got_lonely_packidx_progress_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg); got-portable-0.101/include/got_repository.h0000644000175100017510000001712714644143163014477 /* * Copyright (c) 2018, 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct got_repository; struct got_pathlist_head; struct got_tag_object; /* Open and close repositories. */ const struct got_error *got_repo_open(struct got_repository**, const char *, const char *, int *); const struct got_error *got_repo_close(struct got_repository*); /* Obtain the on-disk path to the repository. */ const char *got_repo_get_path(struct got_repository *); /* * Obtain the path to a non-bare repository's .git directory. * For bare repositories, this returns the same result as got_repo_get_path(). */ const char *got_repo_get_path_git_dir(struct got_repository *); /* Obtain the file descriptor of the repository's .git directory. */ int got_repo_get_fd(struct got_repository *); /* Obtain the object format */ enum got_hash_algorithm got_repo_get_object_format(struct got_repository *); /* Obtain the commit author name if parsed from gitconfig, else NULL. */ const char *got_repo_get_gitconfig_author_name(struct got_repository *); /* Obtain the commit author email if parsed from gitconfig, else NULL. */ const char *got_repo_get_gitconfig_author_email(struct got_repository *); /* Obtain global commit author name parsed ~/.gitconfig, else NULL. */ const char *got_repo_get_global_gitconfig_author_name(struct got_repository *); /* Obtain global commit author email parsed ~/.gitconfig, else NULL. */ const char *got_repo_get_global_gitconfig_author_email(struct got_repository *); /* Obtain repository owner name if parsed from gitconfig, else NULL. */ const char *got_repo_get_gitconfig_owner(struct got_repository *); /* Query if a given Git extension is enabled in gitconfig. */ int got_repo_has_extension(struct got_repository *, const char *); /* Information about one remote repository. */ struct got_remote_repo { char *name; char *fetch_url; char *send_url; /* * If set, fetched references are mirrored 1:1 into our repository. * If not set, references are mapped into "refs/remotes/$name/". */ int mirror_references; /* * If set, fetch all branches by default and ignore the list of * branches below. */ int fetch_all_branches; /* Branches to fetch by default. */ int nfetch_branches; char **fetch_branches; /* Branches to send by default. */ int nsend_branches; char **send_branches; /* Other arbitrary references to fetch by default. */ int nfetch_refs; char **fetch_refs; }; /* * Return a deep copy of a given remote_repo. The result should be * freed with got_repo_free_remote_repo_data() and then free(3). * Return NULL on failure. */ const struct got_error *got_repo_remote_repo_dup(struct got_remote_repo **, const struct got_remote_repo *); /* * Free data allocated for the specified remote repository. * Do not free the remote_repo pointer itself. */ void got_repo_free_remote_repo_data(struct got_remote_repo *); /* Obtain the list of remote repositories parsed from gitconfig. */ void got_repo_get_gitconfig_remotes(int *, const struct got_remote_repo **, struct got_repository *); /* * Obtain a parsed representation of this repository's got.conf file. * Return NULL if this configuration file could not be read. */ const struct got_gotconfig *got_repo_get_gotconfig(struct got_repository *); /* * Obtain paths to various directories within a repository. * The caller must dispose of a path with free(3). */ char *got_repo_get_path_objects(struct got_repository *); char *got_repo_get_path_objects_pack(struct got_repository *); char *got_repo_get_path_refs(struct got_repository *); char *got_repo_get_path_packed_refs(struct got_repository *); char *got_repo_get_path_gitconfig(struct got_repository *); char *got_repo_get_path_gotconfig(struct got_repository *); struct got_reference; struct got_reflist_head; /* * Obtain a reference, by name, from a repository. * The caller must dispose of it with got_ref_close(). */ const struct got_error *got_repo_get_reference(struct got_reference **, struct got_repository *, const char *); /* Indicate whether this is a bare repositiry (contains no git working tree). */ int got_repo_is_bare(struct got_repository *); /* Attempt to map an arbitrary path to a path within the repository. */ const struct got_error *got_repo_map_path(char **, struct got_repository *, const char *); /* * Create a new repository with optional specified * HEAD ref in an empty directory at a specified path. */ const struct got_error *got_repo_init(const char *, const char *); /* Attempt to find a unique object ID for a given ID string prefix. */ const struct got_error *got_repo_match_object_id_prefix(struct got_object_id **, const char *, int, struct got_repository *); /* * Given an object ID string or reference name, attempt to find a corresponding * object. * The object type may be restricted to commit, tree, blob, or tag. * Tags will only be matched if a list of references is provided. * GOT_OBJ_TYPE_ANY will match any type of object. * A human-readable label can optionally be returned, which the caller should * dispose of with free(3). * Return GOT_ERR_NO_OBJ if no matching commit can be found. */ const struct got_error *got_repo_match_object_id(struct got_object_id **, char **, const char *, int, struct got_reflist_head *, struct got_repository *); /* * Search the provided list of references for a tag with a given name * and target object type. * Return GOT_ERR_NO_OBJ if no matching tag can be found. */ const struct got_error *got_repo_object_match_tag(struct got_tag_object **, const char *, int, struct got_reflist_head *, struct got_repository *); /* A callback function which is invoked when a path is imported. */ typedef const struct got_error *(*got_repo_import_cb)(void *, const char *); /* * Import an unversioned directory tree into the repository. * Creates a root commit, i.e. a commit with zero parents. */ const struct got_error *got_repo_import(struct got_object_id **, const char *, const char *, const char *, struct got_pathlist_head *, struct got_repository *, got_repo_import_cb, void *); /* Obtain the number and size of loose objects in the repository. */ const struct got_error *got_repo_get_loose_object_info(int *nobjects, off_t *ondisk_size, struct got_repository *); /* Obtain the number and size of packed objects in the repository. */ const struct got_error *got_repo_get_packfile_info(int *npackfiles, int *nobjects, off_t *total_packsize, struct got_repository *); /* Create an array of file descriptors to hand over to got_repo_open for pack */ const struct got_error *got_repo_pack_fds_open(int **); /* Close the array of file descriptors handed over to got_repo_open for pack */ const struct got_error *got_repo_pack_fds_close(int *); /* Open/set/close temporary files for internal use. Needed by gotd(8). */ const struct got_error *got_repo_temp_fds_open(int **); void got_repo_temp_fds_set(struct got_repository *, int *); const struct got_error *got_repo_temp_fds_close(int *); got-portable-0.101/include/got_repository_dump.h0000644000175100017510000000210614644143163015513 /* * Copyright (c) 2023 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Output a bundle to the given file. */ const struct got_error * got_repo_dump(FILE *out, struct got_reflist_head *include_refs, struct got_reflist_head *exclude_refs, struct got_repository *repo, got_pack_progress_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg); got-portable-0.101/include/got_serve.h0000644000175100017510000000164014644143163013375 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ const struct got_error *got_serve(int infd, int outfd, const char *command, const char *repo_path, int gotd_sock, int chattygot); got-portable-0.101/include/got_version.h0000644000175100017510000000213214644143163013733 /* * Copyright (c) 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef GOT_VERSION #error "GOT_VERSION is undefined" #endif #define GOT_STRINGIFY_VERSION(x) #x #define GOT_STRINGVAL_VERSION(x) GOT_STRINGIFY_VERSION(x) #define GOT_VERSION_STR GOT_STRINGVAL_VERSION(GOT_VERSION) static inline void got_version_print_str(void) { printf("%s %s\n", getprogname(), GOT_VERSION_STR); } got-portable-0.101/include/got_reference.h0000644000175100017510000001725714644143163014222 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* A reference which points to an arbitrary object. */ struct got_reference; /* Well-known reference names. */ #define GOT_REF_HEAD "HEAD" #define GOT_REF_ORIG_HEAD "ORIG_HEAD" #define GOT_REF_MERGE_HEAD "MERGE_HEAD" #define GOT_REF_FETCH_HEAD "FETCH_HEAD" struct got_repository; struct got_object_id; /* Determine whether a given reference name is valid. */ int got_ref_name_is_valid(const char *); /* * Attempt to open the reference with the provided name in a repository. * The caller must dispose of the reference with got_ref_close(). * Optionally, the underlying reference file can be locked before it is opened * to prevent concurrent modification of the reference, in which case the file * must be unlocked with got_ref_unlock() before got_ref_close() is called. */ const struct got_error *got_ref_open(struct got_reference **, struct got_repository *, const char *, int); /* * Allocate a new reference for a given object ID. * The caller must dispose of it with got_ref_close(). */ const struct got_error *got_ref_alloc(struct got_reference **, const char *, struct got_object_id *); /* * Allocate a new symbolic reference which points at a given reference. * The caller must dispose of it with got_ref_close(). */ const struct got_error *got_ref_alloc_symref(struct got_reference **, const char *, struct got_reference *); /* Dispose of a reference. */ void got_ref_close(struct got_reference *); /* Get the name of the reference. */ const char *got_ref_get_name(struct got_reference *); /* Get the name of the reference which a symoblic reference points at. */ const char *got_ref_get_symref_target(struct got_reference *); /* Get the last modification timestamp of the reference. */ time_t got_ref_get_mtime(struct got_reference *); /* * Create a duplicate copy of a reference. * The caller must dispose of this copy with got_ref_close(). */ struct got_reference *got_ref_dup(struct got_reference *); /* Attempt to resolve a symbolic reference to a non-symbolic one. */ const struct got_error *got_ref_resolve_symbolic(struct got_reference **, struct got_repository *, struct got_reference *); /* Attempt to resolve a reference (symbolic or not) to an object ID. */ const struct got_error *got_ref_resolve(struct got_object_id **, struct got_repository *, struct got_reference *); /* * Return a string representation of a reference. * The caller must dispose of it with free(3). */ char *got_ref_to_str(struct got_reference *); /* List of references. */ struct got_reflist_entry { TAILQ_ENTRY(got_reflist_entry) entry; struct got_reference *ref; }; TAILQ_HEAD(got_reflist_head, got_reflist_entry); /* Duplicate a reference list entry. Caller must dispose of it with free(3). */ const struct got_error *got_reflist_entry_dup(struct got_reflist_entry **, struct got_reflist_entry *); /* A function which compares two references. Used with got_ref_list(). */ typedef const struct got_error *(*got_ref_cmp_cb)(void *, int *, struct got_reference *, struct got_reference *); /* An implementation of got_ref_cmp_cb which compares two references by name. */ const struct got_error *got_ref_cmp_by_name(void *, int *, struct got_reference *, struct got_reference *); /* An implementation of got_ref_cmp_cb which compares two tags. */ const struct got_error *got_ref_cmp_tags(void *, int *, struct got_reference *, struct got_reference *); /* * An implementation of got_ref_cmp_cb which compares commit timestamps. * Requires a struct got_repository * as the void * argument. */ const struct got_error *got_ref_cmp_by_commit_timestamp_descending(void *, int *, struct got_reference *, struct got_reference *); /* * Append all known references to a caller-provided ref list head. * Optionally limit references returned to those within a given * reference namespace. Sort the list with the provided reference comparison * function, usually got_ref_cmp_by_name(). */ const struct got_error *got_ref_list(struct got_reflist_head *, struct got_repository *, const char *, got_ref_cmp_cb, void *); /* Free all references on a ref list. */ void got_ref_list_free(struct got_reflist_head *); /* * Insert a reference into a reference list. * Return a pointer to the newly allocated list entry in *newp. * If *newp is NULL and no error occured then the specified reference was * already an element of the list. If *newp is not NULL then the reference * was shallow-copied onto the list and should no longer be closed with * got_ref_close(). Instead it will be closed along with other list * elements by got_ref_list_free(). */ const struct got_error * got_reflist_insert(struct got_reflist_entry **newp, struct got_reflist_head *refs, struct got_reference *ref, got_ref_cmp_cb cmp_cb, void *cmp_arg); /* Sort a list of references with the provided comparison callback. */ const struct got_error * got_reflist_sort(struct got_reflist_head *refs, got_ref_cmp_cb cmp_cb, void *cmp_arg); /* Indicate whether the provided reference is symbolic (points at another * refernce) or not (points at an object ID). */ int got_ref_is_symbolic(struct got_reference *); /* Change the object ID a reference points to. */ const struct got_error * got_ref_change_ref(struct got_reference *, struct got_object_id *); /* Change the reference name a symbolic reference points to. */ const struct got_error *got_ref_change_symref(struct got_reference *, const char *); /* * Change a symbolic reference into a regular reference which points to * the provided object ID. */ const struct got_error *got_ref_change_symref_to_ref(struct got_reference *, struct got_object_id *); /* Write a reference to its on-disk path in the repository. */ const struct got_error *got_ref_write(struct got_reference *, struct got_repository *); /* Delete a reference from its on-disk path in the repository. */ const struct got_error *got_ref_delete(struct got_reference *, struct got_repository *); /* Unlock a reference which was opened in locked state. */ const struct got_error *got_ref_unlock(struct got_reference *); /* Map object IDs to references. */ struct got_reflist_object_id_map; /* * Create and populate an object ID map for a given list of references. * Map entries will contain deep-copies of elements of the reflist. * The caller must dispose of the map with got_reflist_object_id_map_free(). */ const struct got_error *got_reflist_object_id_map_create( struct got_reflist_object_id_map **, struct got_reflist_head *, struct got_repository *); /* * Return a list of references which correspond to a given object ID. * The returned list must be considered read-only. * The caller must _not_ call free(3) on the returned pointer! * If no references are associated with the ID, return NULL. */ struct got_reflist_head * got_reflist_object_id_map_lookup(struct got_reflist_object_id_map *, struct got_object_id *); /* Free the specified object ID map. */ void got_reflist_object_id_map_free(struct got_reflist_object_id_map *); got-portable-0.101/include/got_send.h0000644000175100017510000000575214644143163013212 /* * Copyright (c) 2018, 2019 Ori Bernstein * Copyright (c) 2021 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #define GOT_SEND_DEFAULT_REMOTE_NAME "origin" /* * Attempt to open a connection to a server using the provided protocol * scheme, hostname port number (as a string) and server-side path. * A verbosity level can be specified; it currently controls the amount * of -v options passed to ssh(1). If the level is -1 ssh(1) will be run * with the -q option. * * If successful return an open file descriptor for the connection which can * be passed to other functions below, and must be disposed of with close(2). * * If an ssh(1) process was started return its PID as well, in which case * the caller should eventually send SIGTERM to the procress and wait for * the process to exit with waitpid(2). Otherwise, return PID -1. */ const struct got_error *got_send_connect(pid_t *, int *, const char *, const char *, const char *, const char *, int); /* A callback function which gets invoked with progress information to print. */ typedef const struct got_error *(*got_send_progress_cb)(void *, int ncolored, int nfound, int ntrees, off_t packfile_size, int ncommits, int nobj_total, int nobj_deltify, int nobj_written, off_t bytes_sent, const char *refname, const char *, int success); /* * Attempt to generate a pack file and sent it to a server. * This pack file will contain objects which are reachable in the local * repository via the specified branches and tags. Any objects which are * already present in the remote repository will be omitted from the * pack file. * * If the server supports deletion of references, attempt to delete * branches on the specified delete_branches list from the server. * Such branches are not required to exist in the local repository. * Requesting deletion of branches results in an error if the server * does not support this feature. */ const struct got_error *got_send_pack(const char *remote_name, struct got_pathlist_head *branch_names, struct got_pathlist_head *tag_names, struct got_pathlist_head *delete_branches, int verbosity, int overwrite_refs, int sendfd, struct got_repository *repo, got_send_progress_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg); got-portable-0.101/include/got_object.h0000644000175100017510000003253214644143163013523 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #define GOT_OBJECT_ID_HEX_MAXLEN SHA1_DIGEST_STRING_LENGTH enum got_hash_algorithm { GOT_HASH_SHA1, GOT_HASH_SHA256, }; struct got_object_id { u_int8_t sha1[SHA1_DIGEST_LENGTH]; }; struct got_blob_object; struct got_tree_object; struct got_tree_entry; struct got_tag_object; struct got_commit_object; struct got_object_qid { STAILQ_ENTRY(got_object_qid) entry; struct got_object_id id; void *data; /* managed by API user */ }; STAILQ_HEAD(got_object_id_queue, got_object_qid); const struct got_error *got_object_qid_alloc(struct got_object_qid **, struct got_object_id *); void got_object_qid_free(struct got_object_qid *); void got_object_id_queue_free(struct got_object_id_queue *); /* * Deep-copy elements from ID queue src to ID queue dest. Do not copy any * qid->data pointers! This is the caller's responsibility if needed. */ const struct got_error *got_object_id_queue_copy( const struct got_object_id_queue *src, struct got_object_id_queue *dest); /* Object types. */ #define GOT_OBJ_TYPE_ANY 0 /* wildcard value at run-time */ #define GOT_OBJ_TYPE_COMMIT 1 #define GOT_OBJ_TYPE_TREE 2 #define GOT_OBJ_TYPE_BLOB 3 #define GOT_OBJ_TYPE_TAG 4 /* 5 is reserved */ #define GOT_OBJ_TYPE_OFFSET_DELTA 6 #define GOT_OBJ_TYPE_REF_DELTA 7 /* * Labels used in object data. */ #define GOT_OBJ_LABEL_COMMIT "commit" #define GOT_OBJ_LABEL_TREE "tree" #define GOT_OBJ_LABEL_BLOB "blob" #define GOT_OBJ_LABEL_TAG "tag" #define GOT_COMMIT_LABEL_TREE "tree " #define GOT_COMMIT_LABEL_PARENT "parent " #define GOT_COMMIT_LABEL_AUTHOR "author " #define GOT_COMMIT_LABEL_COMMITTER "committer " #define GOT_TAG_LABEL_OBJECT "object " #define GOT_TAG_LABEL_TYPE "type " #define GOT_TAG_LABEL_TAG "tag " #define GOT_TAG_LABEL_TAGGER "tagger " struct got_repository; /* * Obtain a string representation of an object ID. The output depends on * the hash function used by the repository format (currently SHA1). */ const struct got_error *got_object_id_str(char **, struct got_object_id *); /* * Compare two object IDs. Return value behaves like memcmp(3). */ int got_object_id_cmp(const struct got_object_id *, const struct got_object_id *); /* * Created a newly allocated copy of an object ID. * The caller should dispose of it with free(3). */ struct got_object_id *got_object_id_dup(struct got_object_id *); /* * Get a newly allocated ID of the object which resides at the specified * path in the specified tree. * The caller should dispose of it with free(3). */ const struct got_error *got_object_tree_find_path(struct got_object_id **id, mode_t *mode, struct got_repository *repo, struct got_tree_object *tree, const char *path); /* * Get a newly allocated ID of the object which resides at the specified * path in the tree of the specified commit. * The caller should dispose of it with free(3). */ const struct got_error *got_object_id_by_path(struct got_object_id **, struct got_repository *, struct got_commit_object *, const char *); /* * Obtain the type of an object. * Returns one of the GOT_OBJ_TYPE_x values (see above). */ const struct got_error *got_object_get_type(int *, struct got_repository *, struct got_object_id *); /* * Attempt to resolve the textual representation of an object ID * to the ID of an existing object in the repository. * The caller should dispose of the ID with free(3). */ const struct got_error *got_object_resolve_id_str(struct got_object_id **, struct got_repository *, const char *); /* * Attempt to open a commit object in a repository. * The caller must dispose of the commit with got_object_commit_close(). */ const struct got_error *got_object_open_as_commit(struct got_commit_object **, struct got_repository *, struct got_object_id *); /* Dispose of a commit object. */ void got_object_commit_close(struct got_commit_object *); /* Obtain the ID of the tree created in a commit. */ struct got_object_id *got_object_commit_get_tree_id(struct got_commit_object *); /* Obtain the number of parent commits of a commit. */ int got_object_commit_get_nparents(struct got_commit_object *); /* Obtain the list of parent commits of a commit. */ const struct got_object_id_queue *got_object_commit_get_parent_ids( struct got_commit_object *); /* Get the author's name and email address. */ const char *got_object_commit_get_author(struct got_commit_object *); /* Get an author's commit timestamp in UTC. */ time_t got_object_commit_get_author_time(struct got_commit_object *); /* Get an author's timezone offset. */ time_t got_object_commit_get_author_gmtoff(struct got_commit_object *); /* Get the committer's name and email address. */ const char *got_object_commit_get_committer(struct got_commit_object *); /* Get a committer's commit timestamp in UTC. */ time_t got_object_commit_get_committer_time(struct got_commit_object *); /* Get a committer's timezone offset. */ time_t got_object_commit_get_committer_gmtoff(struct got_commit_object *); /* * Get the commit log message. * PGP-signatures contained in the log message will be stripped. * The caller must dispose of it with free(3). */ const struct got_error *got_object_commit_get_logmsg(char **, struct got_commit_object *); /* Get the raw commit log message.*/ const char *got_object_commit_get_logmsg_raw(struct got_commit_object *); /* * Attempt to open a tree object in a repository. * The caller must dispose of the tree with got_object_tree_close(). */ const struct got_error *got_object_open_as_tree(struct got_tree_object **, struct got_repository *, struct got_object_id *); /* Dispose of a tree object. */ void got_object_tree_close(struct got_tree_object *); /* Get the number of entries in this tree object. */ int got_object_tree_get_nentries(struct got_tree_object *); /* Get the first tree entry from a tree, or NULL if there is none. */ struct got_tree_entry *got_object_tree_get_first_entry( struct got_tree_object *); /* Get the last tree entry from a tree, or NULL if there is none. */ struct got_tree_entry *got_object_tree_get_last_entry(struct got_tree_object *); /* Get the entry with the specified index from a tree object. */ struct got_tree_entry *got_object_tree_get_entry( struct got_tree_object *, int); /* Find a particular entry in a tree by name. */ struct got_tree_entry *got_object_tree_find_entry( struct got_tree_object *, const char *); /* Get the file permission mode of a tree entry. */ mode_t got_tree_entry_get_mode(struct got_tree_entry *); /* Get the name of a tree entry. */ const char *got_tree_entry_get_name(struct got_tree_entry *); /* Get the object ID of a tree entry. */ struct got_object_id *got_tree_entry_get_id(struct got_tree_entry *); /* * Get a string containing the target path of a given a symlink tree entry. * The caller should dispose of it with free(3). */ const struct got_error *got_tree_entry_get_symlink_target(char **, struct got_tree_entry *, struct got_repository *); /* Get the index of a tree entry. */ int got_tree_entry_get_index(struct got_tree_entry *); /* Get the next tree entry from a tree, or NULL if there is none. */ struct got_tree_entry *got_tree_entry_get_next(struct got_tree_object *, struct got_tree_entry *); /* Get the previous tree entry from a tree, or NULL if there is none. */ struct got_tree_entry *got_tree_entry_get_prev(struct got_tree_object *, struct got_tree_entry *); /* Return non-zero if the specified tree entry is a Git submodule. */ int got_object_tree_entry_is_submodule(struct got_tree_entry *); /* Return non-zero if the specified tree entry is a symbolic link. */ int got_object_tree_entry_is_symlink(struct got_tree_entry *); /* * Resolve an in-repository symlink at the specified path in the tree * corresponding to the specified commit. If the specified path is not * a symlink then set *link_target to NULL. * Otherwise, resolve symlinks recursively and return the final link * target path. The caller must dispose of it with free(3). */ const struct got_error *got_object_resolve_symlinks(char **, const char *, struct got_commit_object *, struct got_repository *); /* * Compare two trees and indicate whether the entry at the specified path * differs between them. The path must not be the root path "/"; the function * got_object_id_cmp() should be used instead to compare the tree roots. */ const struct got_error *got_object_tree_path_changed(int *, struct got_tree_object *, struct got_tree_object *, const char *, struct got_repository *); /* * Attempt to open a blob object in a repository. * The size_t argument specifies the block size of an associated read buffer. * The caller must dispose of the blob with got_object_blob_close(). */ const struct got_error *got_object_open_as_blob(struct got_blob_object **, struct got_repository *, struct got_object_id *, size_t, int); /* Dispose of a blob object. */ const struct got_error *got_object_blob_close(struct got_blob_object *); /* * Get the length of header data at the beginning of the blob's read buffer. * Note that header data is only present upon the first invocation of * got_object_blob_read_block() after the blob is opened. */ size_t got_object_blob_get_hdrlen(struct got_blob_object *); /* * Get a pointer to the blob's read buffer. * The read buffer is filled by got_object_blob_read_block(). */ const uint8_t *got_object_blob_get_read_buf(struct got_blob_object *); /* * Read the next chunk of data from a blob, up to the blob's read buffer * block size. The size_t output argument indicates how many bytes have * been read into the blob's read buffer. Zero bytes will be reported if * all data in the blob has been read. */ const struct got_error *got_object_blob_read_block(size_t *, struct got_blob_object *); /* Rewind an open blob's data stream back to the beginning. */ void got_object_blob_rewind(struct got_blob_object *); /* * Heuristic to check whether the blob contains binary data. Rewinds * the blob's data stream back after the header. */ const struct got_error *got_object_blob_is_binary(int *, struct got_blob_object *); /* * getline(3) for blobs. */ const struct got_error *got_object_blob_getline(char **, ssize_t *, size_t *, struct got_blob_object *); /* * Read the entire content of a blob and write it to the specified file. * Flush and rewind the file as well. Indicate the amount of bytes * written in the size_t output argument, and the number of lines in the * file in the int argument, and line offsets in the off_t argument * (NULL can be passed for any output argument). */ const struct got_error *got_object_blob_dump_to_file(off_t *, int *, off_t **, FILE *, struct got_blob_object *); /* * Read the entire content of a blob into a newly allocated string buffer * and terminate it with '\0'. This is intended for blobs which contain a * symlink target path. It should not be used to process arbitrary blobs. * Use got_object_blob_dump_to_file() or got_tree_entry_get_symlink_target() * instead if possible. The caller must dispose of the string with free(3). */ const struct got_error *got_object_blob_read_to_str(char **, struct got_blob_object *); /* * Attempt to open a tag object in a repository. * The caller must dispose of the tree with got_tag_object_close(). */ const struct got_error *got_object_open_as_tag(struct got_tag_object **, struct got_repository *, struct got_object_id *); /* Dispose of a tag object. */ void got_object_tag_close(struct got_tag_object *); /* Get the name of a tag. */ const char *got_object_tag_get_name(struct got_tag_object *); /* Get type of the object a tag points to. */ int got_object_tag_get_object_type(struct got_tag_object *); /* * Get ID of the object a tag points to. * This must not be freed by the caller. Use got_object_id_dup() if needed. */ struct got_object_id *got_object_tag_get_object_id(struct got_tag_object *); /* Get the timestamp of the tag. */ time_t got_object_tag_get_tagger_time(struct got_tag_object *); /* Get the tag's timestamp's GMT offset. */ time_t got_object_tag_get_tagger_gmtoff(struct got_tag_object *); /* Get the author of the tag. */ const char *got_object_tag_get_tagger(struct got_tag_object *); /* Get the tag message associated with the tag. */ const char *got_object_tag_get_message(struct got_tag_object *); const struct got_error *got_object_commit_add_parent(struct got_commit_object *, const char *); /* Create a new tag object in the repository. */ const struct got_error *got_object_tag_create(struct got_object_id **, const char *, struct got_object_id *, const char *, time_t, const char *, const char *, struct got_repository *, int verbosity); /* Increment commit object reference counter. */ void got_object_commit_retain(struct got_commit_object *); got-portable-0.101/include/got_dial.h0000644000175100017510000000310314644143163013156 /* * Copyright (c) 2021 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Apply any unveil(2) operations required to support the given protocol, * as obtained from the 'proto' output parameter of got_dial_parse_uri(). * This function must be called during initialization of the main program * if got_fetch.h or got_send.h funcionality will be used. */ const struct got_error *got_dial_apply_unveil(const char *proto); /* * Attempt to parse a URI into the following parts: * A protocol scheme, hostname, port number (as a string), path on server, * and a repository name. If the URI lacks some of this information return * default values where applicable. * The caller should dispose of the returned values with free(3). */ const struct got_error *got_dial_parse_uri(char **proto, char **host, char **port, char **server_path, char **repo_name, const char *uri); got-portable-0.101/include/got_gotconfig.h0000644000175100017510000000367214644143163014237 /* * Copyright (c) 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct got_gotconfig; /* * Obtain the commit author parsed from got.conf. * Return NULL if no configuration file or author could be found. */ const char *got_gotconfig_get_author(const struct got_gotconfig *); /* * Obtain the list of remote repositories parsed from got.conf. * Return 0 and NULL if no configuration file or remote repository * could be found. */ void got_gotconfig_get_remotes(int *, const struct got_remote_repo **, const struct got_gotconfig *); /* * Obtain the filename of the allowed signers file. * Returns NULL if no configuration file is found or no allowed signers file * is configured. */ const char * got_gotconfig_get_allowed_signers_file(const struct got_gotconfig *); /* * Obtain the filename of the revoked signers file. * Returns NULL if no configuration file is found or no revoked signers file * is configured. */ const char * got_gotconfig_get_revoked_signers_file(const struct got_gotconfig *); /* * Obtain the signer identity used to sign tag objects * Returns NULL if no configuration file is found or no revoked signers file * is configured. */ const char * got_gotconfig_get_signer_id(const struct got_gotconfig *); got-portable-0.101/include/got_repository_load.h0000644000175100017510000000221614644143163015467 /* * Copyright (c) 2023 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* A callback function which gets invoked with progress information. */ typedef const struct got_error *(*got_load_progress_cb)(void *, off_t, int, int, int, int); /* * Load a bundle in the repository. */ const struct got_error * got_repo_load(FILE *, struct got_pathlist_head *, struct got_repository *, int, int, got_load_progress_cb, void *, got_cancel_cb, void *); got-portable-0.101/include/got_commit_graph.h0000664000175100017510000000353514644143163014731 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct got_commit_graph; const struct got_error *got_commit_graph_open(struct got_commit_graph **, const char *, int); void got_commit_graph_close(struct got_commit_graph *); const struct got_error *got_commit_graph_bfsort( struct got_commit_graph *, struct got_object_id *, struct got_repository *, got_cancel_cb, void *); const struct got_error *got_commit_graph_toposort(struct got_commit_graph *, struct got_object_id *, struct got_repository *, got_cancel_cb, void *); const struct got_error *got_commit_graph_iter_next(struct got_object_id *, struct got_commit_graph *, struct got_repository *, got_cancel_cb, void *); const struct got_error *got_commit_graph_intersect(struct got_object_id **, struct got_commit_graph *, struct got_commit_graph *, struct got_repository *); /* Find the youngest common ancestor of two commits. */ const struct got_error *got_commit_graph_find_youngest_common_ancestor( struct got_object_id **, struct got_object_id *, struct got_object_id *, int, int, struct got_repository *, got_cancel_cb, void *); got-portable-0.101/include/got_date.h0000644000175100017510000000151714644143163013171 /* * Copyright (c) 2022 Josh Rickmar * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void got_date_format_gmtoff(char *, size_t, time_t); got-portable-0.101/include/got_blame.h0000644000175100017510000000352414644143163013334 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ typedef const struct got_error *(*got_blame_cb)(void *, int, int, struct got_commit_object *, struct got_object_id *); /* * Blame the blob at the specified path in the specified commit and invoke * a callback whenever an annotation has been computed for a line. * * The callback receives the provided void * argument, the total number * of lines of the annotated file, a line number, and the ID of the commit * which last changed this line. * * The callback is invoked for each commit as history is traversed. * If no changes to the file were made in a commit, line number -1 will * be reported. * * If the callback returns GOT_ERR_ITER_COMPLETED, the blame operation * will be aborted and this function returns NULL. * If the callback returns any other error, the blame operation will be * aborted and the callback's error is returned from this function. */ const struct got_error *got_blame(const char *, struct got_object_id *, struct got_repository *, enum got_diff_algorithm, got_blame_cb, void *, got_cancel_cb, void *, int, int, FILE *, FILE *); got-portable-0.101/include/got_opentemp.h0000664000175100017510000000351614644143163014106 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Utilities for opening temporary files. */ #ifndef GOT_TMPDIR #define GOT_TMPDIR /tmp #endif #define GOT_STRINGIFY_TMP(x) #x #define GOT_STRINGVAL_TMP(x) GOT_STRINGIFY_TMP(x) #define GOT_TMPDIR_STR GOT_STRINGVAL_TMP(GOT_TMPDIR) /* Open a file descriptor to a new temporary file for writing. * The file is not visible in the filesystem. */ int got_opentempfd(void); /* Open a new temporary file for writing. * The file is not visible in the filesystem. */ FILE *got_opentemp(void); /* Open a new temporary file for writing. * The file is visible in the filesystem. */ const struct got_error *got_opentemp_named(char **, FILE **, const char *, const char *); /* Like got_opentemp_named() but returns a file descriptor instead of a FILE. */ const struct got_error *got_opentemp_named_fd(char **, int *, const char *, const char *); /* Truncate a file. This is useful for re-using open temporary files. */ const struct got_error *got_opentemp_truncate(FILE *); /* Truncate a file via a file descriptor. */ const struct got_error *got_opentemp_truncatefd(int); got-portable-0.101/include/got_fetch.h0000644000175100017510000000462414644143163013347 /* * Copyright (c) 2018, 2019 Ori Bernstein * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #define GOT_FETCH_DEFAULT_REMOTE_NAME "origin" /* * Attempt to open a connection to a server using the provided protocol * scheme, hostname port number (as a string) and server-side path. * A verbosity level can be specified; it currently controls the amount * of -v options passed to ssh(1). If the level is -1 ssh(1) will be run * with the -q option. * * If successful return an open file descriptor for the connection which can * be passed to other functions below, and must be disposed of with close(2). * * If an ssh(1) process was started return its PID as well, in which case * the caller should eventually send SIGTERM to the procress and wait for * the process to exit with waitpid(2). Otherwise, return PID -1. */ const struct got_error *got_fetch_connect(pid_t *, int *, const char *, const char *, const char *, const char *, int); /* A callback function which gets invoked with progress information to print. */ typedef const struct got_error *(*got_fetch_progress_cb)(void *, const char *, off_t, int, int, int, int); /* * Attempt to fetch a packfile from a server. This pack file will contain * objects which that are not yet contained in the provided repository. * Return the hash of the packfile (in form of an object ID) and lists of * references and symbolic references learned from the server. */ const struct got_error *got_fetch_pack(struct got_object_id **, struct got_pathlist_head *, struct got_pathlist_head *, const char *, int, int, struct got_pathlist_head *, struct got_pathlist_head *, int, int, int, struct got_repository *, const char *, const char *, int, got_fetch_progress_cb, void *); got-portable-0.101/include/got_utf8.h0000644000175100017510000000200114644143163013127 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Return a sanitized UTF-8 string which is safe to write to a terminal. */ const struct got_error *got_mbsavis(char**, int *, const char *); /* Indicate whether the current locale supports UTF-8. */ int got_locale_is_utf8(void); got-portable-0.101/include/got_worktree_cvg.h0000644000175100017510000000374614644143163014763 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * Copyright (c) 2023 Josh Rickmar * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Create a new commit from changes in the work tree. * Return the ID of the newly created commit. * The worktree's base commit will be set to this new commit. * Files unaffected by this commit operation will retain their * current base commit. * An author and a non-empty log message must be specified. * The name of the committer is optional (may be NULL). * If a path to be committed contains a symlink which points outside * of the path space under version control, raise an error unless * committing of such paths is being forced by the caller. */ const struct got_error *got_worktree_cvg_commit(struct got_object_id **, struct got_worktree *, struct got_pathlist_head *, const char *, const char *, int, int, int, got_worktree_commit_msg_cb, void *, got_worktree_status_cb, void *, const char *, const char *, const char *, const char *, int, const struct got_remote_repo *, got_cancel_cb, struct got_repository *); /* * Get the reference name for a temporary commit to be trivially rebased * over a remote branch. */ const struct got_error *got_worktree_cvg_get_commit_ref_name(char **, struct got_worktree *); got-portable-0.101/include/got_compat2.h0000664000175100017510000002171414644144735013632 /* * Copyright (c) 2023 Thomas Adam * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _GOT_COMPAT_H_2 #define _GOT_COMPAT_H_2 #ifdef HAVE_STDINT_H #include #else #include #endif #include #include #if defined(__FreeBSD__) #include #include #elif defined(__APPLE__) #include #include #include "compat/bsd-poll.h" #define FMT_SCALED_STRSIZE 7 /* minus sign, 4 digits, suffix, null byte */ #define htobe16(x) OSSwapHostToBigInt16(x) #define htole16(x) OSSwapHostToLittleInt16(x) #define be16toh(x) OSSwapBigToHostInt16(x) #define le16toh(x) OSSwapLittleToHostInt16(x) #define htobe32(x) OSSwapHostToBigInt32(x) #define htole32(x) OSSwapHostToLittleInt32(x) #define be32toh(x) OSSwapBigToHostInt32(x) #define le32toh(x) OSSwapLittleToHostInt32(x) #define htobe64(x) OSSwapHostToBigInt64(x) #define htole64(x) OSSwapHostToLittleInt64(x) #define be64toh(x) OSSwapBigToHostInt64(x) #define le64toh(x) OSSwapLittleToHostInt64(x) #define st_atim st_atimespec #define st_ctim st_ctimespec #define st_mtim st_mtimespec #else /* Linux, etc... */ #include #include #include #endif #ifndef __GNUC__ #define __attribute__(a) #endif #ifndef UID_MAX # define UID_MAX UINT_MAX /* max value for a uid_t */ #endif #ifndef GID_MAX # define GID_MAX UINT_MAX /* max value for a gid_t */ #endif /* For flock. */ #ifndef O_EXLOCK #define O_EXLOCK 0 #endif #ifndef HAVE_FLOCK #define LOCK_SH 0 #define LOCK_EX 0 #define LOCK_NB 0 #define flock(fd, op) (0) #else #include #endif /* POSIX doesn't define WAIT_ANY, so provide it if it's not found. */ #ifndef WAIT_ANY #define WAIT_ANY (-1) #endif /* On FreeBSD (and possibly others), EAI_NODATA was removed, in favour of * using EAI_NONAME. */ #ifndef EAI_NODATA #define EAI_NODATA EAI_NONAME #endif #ifndef __dead #define __dead __attribute__ ((__noreturn__)) #endif #ifndef __unused #define __unused __attribute__ ((__unused__)) #endif #if !defined(__bounded__) && !defined(__OpenBSD__) #define __bounded__(a, b, c) #endif #ifndef __OpenBSD__ #define pledge(s, p) (0) #define unveil(s, p) (0) #endif #ifndef __FreeBSD__ #define cap_enter() (0) #endif #ifndef HAVE_B64_NTOP #undef b64_ntop #undef b64_pton int b64_ntop(u_char const *, size_t, char *, size_t); int b64_pton(char const *, u_char *, size_t); #endif #ifndef HAVE_SETRESGID #define setresgid(a, b, c) (0) #endif #ifndef HAVE_SETRESUID #define setresuid(a, b, c) (0) #endif #ifndef HAVE_LINUX_LANDLOCK_H #define landlock_no_fs() (0) #else int landlock_no_fs(void); #endif #ifndef INFTIM #define INFTIM -1 #endif #ifndef HAVE_BSD_UUID #include #define uuid_s_ok 0 #define uuid_s_bad_version 1 #define uuid_s_invalid_string_uuid 2 #define uuid_s_no_memory 3 /* Length of a node address (an IEEE 802 address). */ #define _UUID_NODE_LEN 6 struct uuid { uint32_t time_low; uint16_t time_mid; uint16_t time_hi_and_version; uint8_t clock_seq_hi_and_reserved; uint8_t clock_seq_low; uint8_t node[_UUID_NODE_LEN]; }; int32_t uuid_equal(struct uuid *, struct uuid *, uint32_t *); int32_t uuid_is_nil(struct uuid *, uint32_t *); void uuid_create(uuid_t *, uint32_t *); void uuid_create_nil(struct uuid *, uint32_t *); void uuid_from_string(const char *, uuid_t *, uint32_t *); void uuid_to_string(uuid_t *, char **, uint32_t *); #else #include #endif #ifdef HAVE_QUEUE_H #include #endif #ifndef HAVE_TREE_H #include "compat/tree.h" #else #include #endif #ifdef HAVE_UTIL_H #include #endif #ifdef HAVE_LIBUTIL_H #include #endif #ifndef IOV_MAX # define IOV_MAX 1024 #endif #ifndef HAVE_IMSG #include "compat/imsg.h" #else #include #endif #ifndef HAVE_SIPHASH #include "compat/siphash.h" #else #include #endif /* Include Apple-specific headers. Mostly for crypto.*/ #if defined(__APPLE__) #define COMMON_DIGEST_FOR_OPENSSL #include #endif #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) #define SHA256Init SHA256_Init #define SHA256Update SHA256_Update #define SHA256Final SHA256_Final #define SHA2_CTX SHA256_CTX #endif #ifndef __APPLE__ #ifdef HAVE_SHA_H # include #endif #ifdef HAVE_SHA1_H # include #endif #ifdef HAVE_SHA2_H # include #endif #ifdef HAVE_SHA256_H # include #endif #endif /* Catch-all for systems where the header files don't exist and/or the below * still are not defined. */ #ifndef SHA256_DIGEST_LENGTH #define SHA256_DIGEST_LENGTH 32 #endif #ifndef SHA256_DIGEST_STRING_LENGTH #define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) #endif #if defined(__DragonFly__) #include #endif #ifndef SHA1_DIGEST_LENGTH #define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH #define SHA1_DIGEST_STRING_LENGTH (SHA1_DIGEST_LENGTH * 2 + 1) #define SHA1_CTX SHA_CTX #define SHA1Init SHA1_Init #define SHA1Update SHA1_Update #define SHA1Final SHA1_Final #endif /* SOCK_NONBLOCK isn't available across BSDs... */ #if !defined(SOCK_NONBLOCK) && !defined(__linux__) #define SOCK_NONBLOCK 00004000 #endif #ifndef HAVE_ASPRINTF /* asprintf.c */ int asprintf(char **, const char *, ...); int vasprintf(char **, const char *, va_list); #endif #ifndef HAVE_EXPLICIT_BZERO /* explicit_bzero.c */ void explicit_bzero(void *, size_t); #endif #ifndef HAVE_GETDTABLECOUNT /* getdtablecount.c */ int getdtablecount(void); #endif #ifndef HAVE_CLOSEFROM /* closefrom.c */ void closefrom(int); #endif #ifndef HAVE_STRSEP /* strsep.c */ char *strsep(char **, const char *); #endif #ifndef HAVE_STRTONUM /* strtonum.c */ long long strtonum(const char *, long long, long long, const char **); #endif #ifndef HAVE_STRLCPY /* strlcpy.c */ size_t strlcpy(char *, const char *, size_t); #endif #ifndef HAVE_STRLCAT /* strlcat.c */ size_t strlcat(char *, const char *, size_t); #endif #ifndef HAVE_STRNLEN /* strnlen.c */ size_t strnlen(const char *, size_t); #endif #ifndef HAVE_STRNDUP /* strndup.c */ char *strndup(const char *, size_t); #endif #ifndef HAVE_GETPROGNAME /* getprogname.c */ const char *getprogname(void); #endif #ifndef HAVE_GETLINE /* getline.c */ ssize_t getline(char **, size_t *, FILE *); #endif #ifndef HAVE_FREEZERO /* freezero.c */ void freezero(void *, size_t); #endif #ifndef HAVE_GETDTABLECOUNT /* getdtablecount.c */ int getdtablecount(void); #endif #ifndef HAVE_REALLOCARRAY /* reallocarray.c */ void *reallocarray(void *, size_t, size_t); #endif #ifndef HAVE_RECALLOCARRAY /* recallocarray.c */ void *recallocarray(void *, size_t, size_t, size_t); #endif #ifndef HAVE_SETPROCTITLE /* setproctitle.c */ void setproctitle(const char *, ...); #endif #ifndef HAVE_FMT_SCALED /* fmt_scaled.c */ int fmt_scaled(long long, char *); int scan_scaled(char *, long long *); #define FMT_SCALED_STRSIZE 7 /* minus sign, 4 digits, suffix, null byte */ #endif #if !defined(HAVE_LIBBSD) && !defined(HAVE_GETOPT_OPTRESET) /* getopt.c */ extern int BSDopterr; extern int BSDoptind; extern int BSDoptopt; extern int BSDoptreset; extern char *BSDoptarg; int BSDgetopt(int, char *const *, const char *); #define getopt(ac, av, o) BSDgetopt(ac, av, o) #define opterr BSDopterr #define optind BSDoptind #define optopt BSDoptopt #define optreset BSDoptreset #define optarg BSDoptarg #endif /* Check for some of the non-portable timespec*() functions. * This should largely come from libbsd for systems which * aren't BSD, but this will depend on how old the library * is. */ #ifndef timespecisset #define timespecisset(tsp) \ ((tsp)->tv_sec || (tsp)->tv_nsec) #endif #ifndef timespecsub #define timespecsub(tsp, usp, vsp) \ do { \ (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \ (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \ if ((vsp)->tv_nsec < 0) { \ (vsp)->tv_sec--; \ (vsp)->tv_nsec += 1000000000L; \ } \ } while (0) #endif #ifndef timespeccmp #define timespeccmp(tvp, uvp, cmp) \ (((tvp)->tv_sec == (uvp)->tv_sec) ? \ ((tvp)->tv_nsec cmp (uvp)->tv_nsec) : \ ((tvp)->tv_sec cmp (uvp)->tv_sec)) #endif #ifndef HAVE_MERGESORT /* mergesort.c */ int mergesort(void *, size_t, size_t, int (*)(const void *, const void *)); #endif #endif got-portable-0.101/include/got_worktree.h0000664000175100017510000006461614644143163014131 /* * Copyright (c) 2018, 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct got_worktree; struct got_commitable; struct got_commit_object; struct got_fileindex; /* status codes */ #define GOT_STATUS_NO_CHANGE ' ' #define GOT_STATUS_ADD 'A' #define GOT_STATUS_EXISTS 'E' #define GOT_STATUS_UPDATE 'U' #define GOT_STATUS_DELETE 'D' #define GOT_STATUS_MODIFY 'M' #define GOT_STATUS_MODE_CHANGE 'm' #define GOT_STATUS_CONFLICT 'C' #define GOT_STATUS_MERGE 'G' #define GOT_STATUS_MISSING '!' #define GOT_STATUS_UNVERSIONED '?' #define GOT_STATUS_OBSTRUCTED '~' #define GOT_STATUS_NONEXISTENT 'N' #define GOT_STATUS_REVERT 'R' #define GOT_STATUS_CANNOT_DELETE 'd' #define GOT_STATUS_BUMP_BASE 'b' #define GOT_STATUS_BASE_REF_ERR 'B' #define GOT_STATUS_CANNOT_UPDATE '#' /* Also defined in got_lib_worktree.h in case got_worktree.h is not included. */ #define GOT_WORKTREE_GOT_DIR ".got" #define GOT_WORKTREE_CVG_DIR ".cvg" /* * Attempt to initialize a new work tree on disk. * The first argument is the path to a directory where the work tree * will be created. The path itself must not yet exist, but the dirname(3) * of the path must already exist. * The reference provided will be used to determine the new worktree's * base commit. The third argument speficies the work tree's path prefix. * The fourth argument specifies the meta data directory to use, which * should be either GOT_WORKTREE_GOT_DIR or GOT_WORKTREE_CVG_DIR. */ const struct got_error *got_worktree_init(const char *, struct got_reference *, const char *, const char *, struct got_repository *); /* * Attempt to open a worktree at or above the specified path, using * the specified meta data directory which should be either be NULL * in which case a meta directory is auto-discovered, or be one of * GOT_WORKTREE_GOT_DIR and GOT_WORKTREE_CVG_DIR. * The caller must dispose of it with got_worktree_close(). */ const struct got_error *got_worktree_open(struct got_worktree **, const char *path, const char *meta_dir); /* Dispose of an open work tree. */ const struct got_error *got_worktree_close(struct got_worktree *); /* * Get the path to the root directory of a worktree. */ const char *got_worktree_get_root_path(struct got_worktree *); /* * Get the path to the repository associated with a worktree. */ const char *got_worktree_get_repo_path(struct got_worktree *); /* * Get the path prefix associated with a worktree. */ const char *got_worktree_get_path_prefix(struct got_worktree *); /* * Get the UUID of a work tree as a string. * The caller must dispose of the returned UUID string with free(3). */ const struct got_error *got_worktree_get_uuid(char **, struct got_worktree *); /* * Check if a user-provided path prefix matches that of the worktree. */ const struct got_error *got_worktree_match_path_prefix(int *, struct got_worktree *, const char *); /* * Prefix for references pointing at base commit of backout/cherrypick commits. * Reference path takes the form: PREFIX-WORKTREE_UUID-COMMIT_ID */ #define GOT_WORKTREE_CHERRYPICK_REF_PREFIX "refs/got/worktree/cherrypick" #define GOT_WORKTREE_BACKOUT_REF_PREFIX "refs/got/worktree/backout" #define GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN \ sizeof(GOT_WORKTREE_CHERRYPICK_REF_PREFIX) - 1 #define GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN \ sizeof(GOT_WORKTREE_BACKOUT_REF_PREFIX) - 1 #define GOT_WORKTREE_UUID_STRLEN 36 const struct got_error *got_worktree_get_logmsg_ref_name(char **, struct got_worktree *, const char *); /* * Get the name of a work tree's HEAD reference. */ const char *got_worktree_get_head_ref_name(struct got_worktree *); /* * Set the branch head reference of the work tree. */ const struct got_error *got_worktree_set_head_ref(struct got_worktree *, struct got_reference *); /* * Get the current base commit ID of a worktree. */ struct got_object_id *got_worktree_get_base_commit_id(struct got_worktree *); /* * Set the base commit Id of a worktree. */ const struct got_error *got_worktree_set_base_commit_id(struct got_worktree *, struct got_repository *, struct got_object_id *); /* * Get the state of the work tree. If the work tree's global base commit is * the tip of the work tree's current branch, and each file in the index is * based on this same commit, the char out parameter will be * GOT_WORKTREE_STATE_UPTODATE, else it will be GOT_WORKTREE_STATE_OUTOFDATE. */ const struct got_error *got_worktree_get_state(char *, struct got_repository *, struct got_worktree *, got_cancel_cb, void *); #define GOT_WORKTREE_STATE_UNKNOWN ' ' #define GOT_WORKTREE_STATE_UPTODATE '*' #define GOT_WORKTREE_STATE_OUTOFDATE '~' /* * Obtain a parsed representation of this worktree's got.conf file. * Return NULL if this configuration file could not be read. */ const struct got_gotconfig *got_worktree_get_gotconfig(struct got_worktree *); /* A callback function which is invoked when a path is checked out. */ typedef const struct got_error *(*got_worktree_checkout_cb)(void *, unsigned char, const char *); /* A callback function which is invoked when a path is removed. */ typedef const struct got_error *(*got_worktree_delete_cb)(void *, unsigned char, unsigned char, const char *); /* * Attempt to check out files into a work tree from its associated repository * and path prefix, and update the work tree's file index accordingly. * File content is obtained from blobs within the work tree's path prefix * inside the tree corresponding to the work tree's base commit. * The checkout progress callback will be invoked with the provided * void * argument, and the path of each checked out file. * * It is possible to restrict the checkout operation to specific paths in * the work tree, in which case all files outside those paths will remain at * their currently recorded base commit. Inconsistent base commits can be * repaired later by running another update operation across the entire work * tree. Inconsistent base-commits may also occur if this function runs into * an error or if the checkout operation is cancelled by the cancel callback. * Allspecified paths are relative to the work tree's root. Pass a pathlist * with a single empty path "" to check out files across the entire work tree. * * Some operations may refuse to run while the work tree contains files from * multiple base commits. */ const struct got_error *got_worktree_checkout_files(struct got_worktree *, struct got_pathlist_head *, struct got_repository *, got_worktree_checkout_cb, void *, got_cancel_cb, void *); /* Merge the differences between two commits into a work tree. */ const struct got_error * got_worktree_merge_files(struct got_worktree *, struct got_object_id *, struct got_object_id *, struct got_repository *, got_worktree_checkout_cb, void *, got_cancel_cb, void *); /* * A callback function which is invoked to report a file's status. * * If a valid directory file descriptor and a directory entry name are passed, * these should be used to open the file instead of opening the file by path. * This prevents race conditions if the filesystem is modified concurrently. * If the directory descriptor is not available then its value will be -1. */ typedef const struct got_error *(*got_worktree_status_cb)(void *, unsigned char, unsigned char, const char *, struct got_object_id *, struct got_object_id *, struct got_object_id *, int, const char *); /* * Report the status of paths in the work tree. * The status callback will be invoked with the provided void * argument, * a path, and a corresponding status code. */ const struct got_error *got_worktree_status(struct got_worktree *, struct got_pathlist_head *, struct got_repository *, int no_ignores, got_worktree_status_cb, void *, got_cancel_cb cancel_cb, void *); /* * Try to resolve a user-provided path to an on-disk path in the work tree. * The caller must dispose of the resolved path with free(3). */ const struct got_error *got_worktree_resolve_path(char **, struct got_worktree *, const char *); /* Schedule files at on-disk paths for addition in the next commit. */ const struct got_error *got_worktree_schedule_add(struct got_worktree *, struct got_pathlist_head *, got_worktree_checkout_cb, void *, struct got_repository *, int); /* * Remove files from disk and schedule them to be deleted in the next commit. * Don't allow deleting files with uncommitted modifications, unless the * parameter 'delete_local_mods' is set. */ const struct got_error * got_worktree_schedule_delete(struct got_worktree *, struct got_pathlist_head *, int, const char *, got_worktree_delete_cb, void *, struct got_repository *, int, int); /* A callback function which is used to select or reject a patch. */ typedef const struct got_error *(*got_worktree_patch_cb)(int *, void *, unsigned char, const char *, FILE *, int, int); /* Values for result output parameter of got_wortree_patch_cb. */ #define GOT_PATCH_CHOICE_NONE 0 #define GOT_PATCH_CHOICE_YES 1 #define GOT_PATCH_CHOICE_NO 2 #define GOT_PATCH_CHOICE_QUIT 3 /* * Revert a file at the specified path such that it matches its * original state in the worktree's base commit. * If the patch callback is not NULL, call it to select patch hunks to * revert. Otherwise, revert the whole file found at each path. */ const struct got_error *got_worktree_revert(struct got_worktree *, struct got_pathlist_head *, got_worktree_checkout_cb, void *, got_worktree_patch_cb patch_cb, void *patch_arg, struct got_repository *); /* * A callback function which is invoked when a commit message is requested. * Passes a pathlist with a struct got_commitable * in the data pointer of * each element, the path to a file which contains a diff of changes to be * committed (may be NULL), and a pointer to the log message that must be * set by the callback and will be freed after committing, and an argument * passed through to the callback. */ typedef const struct got_error *(*got_worktree_commit_msg_cb)( struct got_pathlist_head *, const char *, char **, void *); /* * Create a new commit from changes in the work tree. * Return the ID of the newly created commit. * The worktree's base commit will be set to this new commit. * Files unaffected by this commit operation will retain their * current base commit. * An author and a non-empty log message must be specified. * The name of the committer is optional (may be NULL). * If a path to be committed contains a symlink which points outside * of the path space under version control, raise an error unless * committing of such paths is being forced by the caller. */ const struct got_error *got_worktree_commit(struct got_object_id **, struct got_worktree *, struct got_pathlist_head *, const char *, const char *, int, int, int, got_worktree_commit_msg_cb, void *, got_worktree_status_cb, void *, struct got_repository *); /* Get the path of a commitable worktree item. */ const char *got_commitable_get_path(struct got_commitable *); /* Get the status of a commitable worktree item. */ unsigned int got_commitable_get_status(struct got_commitable *); /* * Prepare for rebasing a branch onto the work tree's current branch. * This function creates references to a temporary branch, the branch * being rebased, and the work tree's current branch, under the * "got/worktree/rebase/" namespace. These references are used to * keep track of rebase operation state and are used as input and/or * output arguments with other rebase-related functions. * The function also returns a pointer to a fileindex which must be * passed back to other rebase-related functions. */ const struct got_error *got_worktree_rebase_prepare(struct got_reference **, struct got_reference **, struct got_fileindex **, struct got_worktree *, struct got_reference *, struct got_repository *); /* * Continue an interrupted rebase operation. * This function returns existing references created when rebase was prepared, * and the ID of the commit currently being rebased. This should be called * before either resuming or aborting a rebase operation. * The function also returns a pointer to a fileindex which must be * passed back to other rebase-related functions. */ const struct got_error *got_worktree_rebase_continue(struct got_object_id **, struct got_reference **, struct got_reference **, struct got_reference **, struct got_fileindex **, struct got_worktree *, struct got_repository *); /* Check whether a, potentially interrupted, rebase operation is in progress. */ const struct got_error *got_worktree_rebase_in_progress(int *, struct got_worktree *); /* Return information about an in-progress rebase operation. */ const struct got_error *got_worktree_rebase_info(char **new_base_branch_name, char **branch_name, struct got_worktree *, struct got_repository *); /* * Merge changes from the commit currently being rebased into the work tree. * Report affected files, including merge conflicts, via the specified * progress callback. Also populate a list of affected paths which should * be passed to got_worktree_rebase_commit() after a conflict-free merge. * This list must be initialized with TAILQ_INIT() and disposed of with * got_pathlist_free(list, GOT_PATHLIST_FREE_PATH). */ const struct got_error *got_worktree_rebase_merge_files( struct got_pathlist_head *, struct got_worktree *, struct got_fileindex *, struct got_object_id *, struct got_object_id *, struct got_repository *, got_worktree_checkout_cb, void *, got_cancel_cb, void *); /* * Commit changes merged by got_worktree_rebase_merge_files() to a temporary * branch and return the ID of the newly created commit. An optional list of * merged paths can be provided; otherwise this function will perform a status * crawl across the entire work tree to find paths to commit. */ const struct got_error *got_worktree_rebase_commit(struct got_object_id **, struct got_pathlist_head *, struct got_worktree *, struct got_fileindex *, struct got_reference *, const char *, struct got_commit_object *, struct got_object_id *, int, struct got_repository *); /* Postpone the rebase operation. Should be called after a merge conflict. */ const struct got_error *got_worktree_rebase_postpone(struct got_worktree *, struct got_fileindex *); /* * Complete the current rebase operation. This should be called once all * commits have been rebased successfully. * The create_backup parameter controls whether the rebased branch will * be backed up via a reference in refs/got/backup/rebase/. */ const struct got_error *got_worktree_rebase_complete(struct got_worktree *, struct got_fileindex *, struct got_reference *, struct got_reference *, struct got_repository *, int create_backup); /* * Abort the current rebase operation. * Report reverted files via the specified progress callback. */ const struct got_error *got_worktree_rebase_abort(struct got_worktree *, struct got_fileindex *, struct got_repository *, struct got_reference *, got_worktree_checkout_cb, void *); /* * Prepare for editing the history of the work tree's current branch. * This function creates references to a temporary branch, and the * work tree's current branch, under the "got/worktree/histedit/" namespace. * These references are used to keep track of histedit operation state and * are used as input and/or output arguments with other histedit-related * functions. */ const struct got_error *got_worktree_histedit_prepare(struct got_reference **, struct got_reference **, struct got_object_id **, struct got_fileindex **, struct got_worktree *, struct got_repository *); /* * Continue an interrupted histedit operation. * This function returns existing references created when histedit was * prepared and the ID of the commit currently being edited. * It should be called before resuming or aborting a histedit operation. */ const struct got_error *got_worktree_histedit_continue(struct got_object_id **, struct got_reference **, struct got_reference **, struct got_object_id **, struct got_fileindex **, struct got_worktree *, struct got_repository *); /* Check whether a histedit operation is in progress. */ const struct got_error *got_worktree_histedit_in_progress(int *, struct got_worktree *); /* Return information about an in-progress histedit operation. */ const struct got_error *got_worktree_histedit_info( char **branch_nane, struct got_worktree *, struct got_repository *); /* * Merge changes from the commit currently being edited into the work tree. * Report affected files, including merge conflicts, via the specified * progress callback. Also populate a list of affected paths which should * be passed to got_worktree_histedit_commit() after a conflict-free merge. * This list must be initialized with TAILQ_INIT() and disposed of with * got_pathlist_free(list, GOT_PATHLIST_FREE_PATH). */ const struct got_error *got_worktree_histedit_merge_files( struct got_pathlist_head *, struct got_worktree *, struct got_fileindex *, struct got_object_id *, struct got_object_id *, struct got_repository *, got_worktree_checkout_cb, void *, got_cancel_cb, void *); /* * Commit changes merged by got_worktree_histedit_merge_files() to a temporary * branch and return the ID of the newly created commit. An optional list of * merged paths can be provided; otherwise this function will perform a status * crawl across the entire work tree to find paths to commit. * An optional log message can be provided which will be used instead of the * commit's original message. */ const struct got_error *got_worktree_histedit_commit(struct got_object_id **, struct got_pathlist_head *, struct got_worktree *, struct got_fileindex *, struct got_reference *, const char *, struct got_commit_object *, struct got_object_id *, const char *, int, struct got_repository *); /* * Record the specified commit as skipped during histedit. * This should be called for commits which get dropped or get folded into * a subsequent commit. */ const struct got_error *got_worktree_histedit_skip_commit(struct got_worktree *, struct got_object_id *, struct got_repository *); /* Postpone the histedit operation. */ const struct got_error *got_worktree_histedit_postpone(struct got_worktree *, struct got_fileindex *); /* * Complete the current histedit operation. This should be called once all * commits have been edited successfully. */ const struct got_error *got_worktree_histedit_complete(struct got_worktree *, struct got_fileindex *, struct got_reference *, struct got_reference *, struct got_repository *); /* * Abort the current histedit operation. * Report reverted files via the specified progress callback. */ const struct got_error *got_worktree_histedit_abort(struct got_worktree *, struct got_fileindex *, struct got_repository *, struct got_reference *, struct got_object_id *, got_worktree_checkout_cb, void *); /* Get the path to this work tree's histedit script file. */ const struct got_error *got_worktree_get_histedit_script_path(char **, struct got_worktree *); /* * Prepare a work tree for integrating a branch. * Return pointers to a fileindex and locked references which must be * passed back to other integrate-related functions. */ const struct got_error * got_worktree_integrate_prepare(struct got_fileindex **, struct got_reference **, struct got_reference **, struct got_worktree *, const char *, struct got_repository *); /* * Carry out a prepared branch integration operation. * Report affected files via the specified progress callback. */ const struct got_error *got_worktree_integrate_continue( struct got_worktree *, struct got_fileindex *, struct got_repository *, struct got_reference *, struct got_reference *, got_worktree_checkout_cb, void *, got_cancel_cb, void *); /* Abort a prepared branch integration operation. */ const struct got_error *got_worktree_integrate_abort(struct got_worktree *, struct got_fileindex *, struct got_repository *, struct got_reference *, struct got_reference *); /* Postpone the merge operation. Should be called after a merge conflict. */ const struct got_error *got_worktree_merge_postpone(struct got_worktree *, struct got_fileindex *); /* Merge changes from the merge source branch into the worktree. */ const struct got_error * got_worktree_merge_branch(struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_object_id *yca_commit_id, struct got_object_id *branch_tip, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg); /* Attempt to commit merged changes. */ const struct got_error * got_worktree_merge_commit(struct got_object_id **new_commit_id, struct got_worktree *worktree, struct got_fileindex *fileindex, const char *author, const char *committer, int allow_bad_symlinks, struct got_object_id *branch_tip, const char *branch_name, int allow_conflict, struct got_repository *repo, got_worktree_status_cb status_cb, void *status_arg); /* * Complete the merge operation. * This should be called once changes have been successfully committed. */ const struct got_error *got_worktree_merge_complete( struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_repository *repo); /* Check whether a merge operation is in progress. */ const struct got_error *got_worktree_merge_in_progress(int *, struct got_worktree *, struct got_repository *); /* Return information about an in-progress merge operation. */ const struct got_error * got_worktree_merge_info(char **branch_name, struct got_worktree *, struct got_repository *); /* * Prepare for merging a branch into the work tree's current branch: lock the * worktree and check that preconditions are satisfied. The function also * returns a pointer to a fileindex which must be passed back to other * merge-related functions. */ const struct got_error *got_worktree_merge_prepare(struct got_fileindex **, struct got_worktree *, struct got_repository *); /* * This function creates a reference to the branch being merged, and to * this branch's current tip commit, in the "got/worktree/merge/" namespace. * These references are used to keep track of merge operation state and are * used as input and/or output arguments with other merge-related functions. */ const struct got_error *got_worktree_merge_write_refs(struct got_worktree *, struct got_reference *, struct got_repository *); /* * Continue an interrupted merge operation. * This function returns name of the branch being merged, and the ID of the * tip commit being merged. * This function should be called before either resuming or aborting a * merge operation. * The function also returns a pointer to a fileindex which must be * passed back to other merge-related functions. */ const struct got_error *got_worktree_merge_continue(char **, struct got_object_id **, struct got_fileindex **, struct got_worktree *, struct got_repository *); /* * Abort the current rebase operation. * Report reverted files via the specified progress callback. */ const struct got_error *got_worktree_merge_abort(struct got_worktree *, struct got_fileindex *, struct got_repository *, got_worktree_checkout_cb, void *); /* * Stage the specified paths for commit. * If the patch callback is not NULL, call it to select patch hunks for * staging. Otherwise, stage the full file content found at each path. * If a path being staged contains a symlink which points outside * of the path space under version control, raise an error unless * staging of such paths is being forced by the caller. */ const struct got_error *got_worktree_stage(struct got_worktree *, struct got_pathlist_head *, got_worktree_status_cb, void *, got_worktree_patch_cb, void *, int, struct got_repository *); /* * Merge staged changes for the specified paths back into the work tree * and mark the paths as non-staged again. */ const struct got_error *got_worktree_unstage(struct got_worktree *, struct got_pathlist_head *, got_worktree_checkout_cb, void *, got_worktree_patch_cb, void *, struct got_repository *); /* A callback function which is invoked with per-path info. */ typedef const struct got_error *(*got_worktree_path_info_cb)(void *, const char *path, mode_t mode, time_t mtime, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id); /* * Report work-tree meta data for paths in the work tree. * The info callback will be invoked with the provided void * argument, * a path, and meta-data arguments (see got_worktree_path_info_cb). */ const struct got_error * got_worktree_path_info(struct got_worktree *, struct got_pathlist_head *, got_worktree_path_info_cb, void *, got_cancel_cb , void *); /* References pointing at pre-rebase commit backups. */ #define GOT_WORKTREE_REBASE_BACKUP_REF_PREFIX "refs/got/backup/rebase" /* References pointing at pre-histedit commit backups. */ #define GOT_WORKTREE_HISTEDIT_BACKUP_REF_PREFIX "refs/got/backup/histedit" /* * Prepare for applying a patch. */ const struct got_error * got_worktree_patch_prepare(struct got_fileindex **, char **, struct got_worktree *); /* * Lookup paths for the "old" and "new" file before patching and check their * status. */ const struct got_error * got_worktree_patch_check_path(const char *, const char *, char **, char **, struct got_worktree *, struct got_repository *, struct got_fileindex *); const struct got_error * got_worktree_patch_schedule_add(const char *, struct got_repository *, struct got_worktree *, struct got_fileindex *, got_worktree_checkout_cb, void *); const struct got_error * got_worktree_patch_schedule_rm(const char *, struct got_repository *, struct got_worktree *, struct got_fileindex *, got_worktree_delete_cb, void *); /* Complete the patch operation. */ const struct got_error * got_worktree_patch_complete(struct got_fileindex *, const char *); got-portable-0.101/include/got_diff.h0000644000175100017510000002752214644143163013170 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ enum got_diff_algorithm { GOT_DIFF_ALGORITHM_MYERS, GOT_DIFF_ALGORITHM_PATIENCE, }; /* * List of all line types in a diff (including '{got,tog} log' lines). * XXX GOT_DIFF_LINE_HUNK to GOT_DIFF_LINE_NONE inclusive must map to the * DIFF_LINE_* macro counterparts defined in lib/diff_output.h (i.e., 60-64). */ enum got_diff_line_type { GOT_DIFF_LINE_LOGMSG, GOT_DIFF_LINE_AUTHOR, GOT_DIFF_LINE_DATE, GOT_DIFF_LINE_CHANGES, GOT_DIFF_LINE_META, GOT_DIFF_LINE_BLOB_MIN, GOT_DIFF_LINE_BLOB_PLUS, GOT_DIFF_LINE_HUNK = 60, GOT_DIFF_LINE_MINUS, GOT_DIFF_LINE_PLUS, GOT_DIFF_LINE_CONTEXT, GOT_DIFF_LINE_NONE }; struct got_diff_line { off_t offset; uint8_t type; }; struct got_diffstat_cb_arg; /* * Compute the differences between two blobs and write unified diff text * to the provided output file. Two open temporary files must be provided * for internal use; these files can be obtained from got_opentemp() and * must be closed by the caller. * If one of the blobs being diffed does not exist, all corresponding * blob object arguments should be set to NULL. * Two const char * diff header labels may be provided which will be used * to identify each blob in the diff output. * If a label is NULL, use the blob's SHA1 checksum instead. * The number of context lines to show in the diff must be specified as well. * Whitespace differences may optionally be ignored. * If not NULL, the two initial output arguments will be populated with an * array of line offsets for, and the number of lines in, the unidiff text. */ const struct got_error *got_diff_blob(struct got_diff_line **, size_t *, struct got_blob_object *, struct got_blob_object *, FILE *, FILE *, const char *, const char *, enum got_diff_algorithm, int, int, int, struct got_diffstat_cb_arg *, FILE *); /* * Compute the differences between a blob and a file and write unified diff * text to the provided output file. The blob object, its content, and its * size must be provided. The file's size must be provided, as well as a * const char * diff header label which identifies the file. * An optional const char * diff header label for the blob may be provided, too. * The number of context lines to show in the diff must be specified as well. * Whitespace differences may optionally be ignored. */ const struct got_error *got_diff_blob_file(struct got_blob_object *, FILE *, off_t, const char *, FILE *, int, struct stat *, const char *, enum got_diff_algorithm, int, int, int, struct got_diffstat_cb_arg *, FILE *); /* * A callback function invoked to handle the differences between two blobs * when diffing trees with got_diff_tree(). This callback receives two blobs, * their respective IDs, and two corresponding paths within the diffed trees. * The first blob contains content from the old side of the diff, and * the second blob contains content on the new side of the diff. * Two open temporary files must be provided for internal use; these files * can be obtained from got_opentemp() and must be closed by the caller. * The blob object argument for either blob may be NULL to indicate * that no content is present on its respective side of the diff. * File modes from relevant tree objects which contain the blobs may * also be passed. These will be zero if not available. */ typedef const struct got_error *(*got_diff_blob_cb)(void *, struct got_blob_object *, struct got_blob_object *, FILE *, FILE *, struct got_object_id *, struct got_object_id *, const char *, const char *, mode_t, mode_t, struct got_repository *); /* * A pre-defined implementation of got_diff_blob_cb() which appends unidiff * output to a file. The caller must allocate and fill in the argument * structure. */ struct got_diff_blob_output_unidiff_arg { FILE *outfile; /* Unidiff text will be written here. */ int diff_context; /* Sets the number of context lines. */ int ignore_whitespace; /* Ignore whitespace differences. */ int force_text_diff; /* Assume text even if binary data detected. */ struct got_diffstat_cb_arg *diffstat; /* Compute diffstat of changes */ enum got_diff_algorithm diff_algo; /* Diffing algorithm to use. */ /* * The number of lines contained in produced unidiff text output, * and an array of got_diff_lines with byte offset and line type to * each line. May be initialized to zero and NULL to ignore line * metadata. If not NULL, then the array of line offsets and types will * be populated. Optionally, the array can be pre-populated with line * offsets and types, with nlines > 0 indicating the length of the * pre-populated array. This is useful if the output file already * contains some lines of text. The array will be grown as needed to * accomodate additional offsets and types, and the last offset found * in a pre-populated array will be added to all subsequent offsets. */ size_t nlines; struct got_diff_line *lines; /* Dispose of with free(3) when done. */ }; const struct got_error *got_diff_blob_output_unidiff(void *, struct got_blob_object *, struct got_blob_object *, FILE *, FILE *, struct got_object_id *, struct got_object_id *, const char *, const char *, mode_t, mode_t, struct got_repository *); /* * Compute the differences between two trees and invoke the provided * got_diff_blob_cb() callback when content differs. * Diffing of blob content can be suppressed by passing zero for the * 'diff_content' parameter. The callback will then only receive blob * object IDs and diff labels, but NULL pointers instead of blob objects. * If 'diff_content' is set, two open temporary FILEs and two open * temporary file descriptors must be provided for internal use; these * files can be obtained from got_opentemp() and got_opentempfd(), * and must be closed by the caller. Otherwise the files can be NULL. * The set of arguments relating to either tree may be NULL to indicate * that no content is present on its respective side of the diff. */ const struct got_error *got_diff_tree(struct got_tree_object *, struct got_tree_object *, FILE *, FILE *, int, int, const char *, const char *, struct got_repository *, got_diff_blob_cb cb, void *cb_arg, int); /* * Pre-defined implementations of got_diff_blob_cb(): the first of which * collects a list of file paths that differ between two trees; the second * also computes a diffstat of added/removed lines for each collected path * and requires passing an initialized got_diffstat_cb_arg argument. * The caller must allocate and initialize a got_pathlist_head * argument. * Data pointers of entries added to the path list will point to a struct * got_diff_changed_path object. * The caller is expected to free both the path and data pointers of all * entries on the path list. */ struct got_diff_changed_path { uint32_t add; /* number of lines added */ uint32_t rm; /* number of lines removed */ /* * The modification status of this path. It can be GOT_STATUS_ADD, * GOT_STATUS_DELETE, GOT_STATUS_MODIFY, or GOT_STATUS_MODE_CHANGE. */ int status; }; const struct got_error *got_diff_tree_collect_changed_paths(void *, struct got_blob_object *, struct got_blob_object *, FILE *, FILE *, struct got_object_id *, struct got_object_id *, const char *, const char *, mode_t, mode_t, struct got_repository *); struct got_diffstat_cb_arg { size_t max_path_len; uint32_t ins; uint32_t del; int add_cols; int rm_cols; int nfiles; struct got_pathlist_head *paths; int ignore_ws; int force_text; enum got_diff_algorithm diff_algo; }; const struct got_error *got_diff_tree_compute_diffstat(void *, struct got_blob_object *, struct got_blob_object *, FILE *, FILE *, struct got_object_id *, struct got_object_id *, const char *, const char *, mode_t, mode_t, struct got_repository *); /* * Diff two objects, assuming both objects are blobs. Two const char * diff * header labels may be provided which will be used to identify each blob in * the diff output. If a label is NULL, use the blob's SHA1 checksum instead. * Two open temporary files and two temporary file descriptors must be * provided for internal use; these files can be obtained from * got_opentemp() and got_opentempfd(), and must be closed by the caller. * The set of arguments relating to either blob may be NULL/-1 to indicate * that no content is present on its respective side of the diff. * The number of context lines to show in the diff must be specified as well. * Write unified diff text to the provided output FILE. * If not NULL, the two initial output arguments will be populated with an * array of line offsets for, and the number of lines in, the unidiff text. */ const struct got_error *got_diff_objects_as_blobs(struct got_diff_line **, size_t *, FILE *, FILE *, int, int, struct got_object_id *, struct got_object_id *, const char *, const char *, enum got_diff_algorithm, int, int, int, struct got_diffstat_cb_arg *, struct got_repository *, FILE *); struct got_pathlist_head; /* * Diff two objects, assuming both objects are trees. Two const char * diff * header labels may be provided which will be used to identify each blob in * the trees. If a label is NULL, use the blob's SHA1 checksum instead. * The number of context lines to show in diffs must be specified. * Two open temporary files and two temporary file descriptors must be * provided for internal use; these files can be obtained from * got_opentemp() and got_opentempfd(), and must be closed by the caller. * If 'diff_content' is not set, the files may be NULL / -1. * The set of arguments relating to either tree may be NULL to indicate * that no content is present on its respective side of the diff. * Write unified diff text to the provided output FILE. * If not NULL, the two initial output arguments will be populated with an * array of line offsets for, and the number of lines in, the unidiff text. */ const struct got_error *got_diff_objects_as_trees(struct got_diff_line **, size_t *, FILE *, FILE *, int, int, struct got_object_id *, struct got_object_id *, struct got_pathlist_head *, const char *, const char *, enum got_diff_algorithm, int, int, int, struct got_diffstat_cb_arg *, struct got_repository *, FILE *); /* * Diff two objects, assuming both objects are commits. * The number of context lines to show in diffs must be specified. * Two open temporary files and two temporary file descriptors must be * provided for internal use; these files can be obtained from * got_opentemp() and got_opentempfd(), and must be closed by the caller. * The set of arguments relating to either commit may be NULL to indicate * that no content is present on its respective side of the diff. * Write unified diff text to the provided output FILE. * If not NULL, the two initial output arguments will be populated with an * array of line offsets for, and the number of lines in, the unidiff text. */ const struct got_error *got_diff_objects_as_commits(struct got_diff_line **, size_t *, FILE *, FILE *, int, int, struct got_object_id *, struct got_object_id *, struct got_pathlist_head *, enum got_diff_algorithm, int, int, int, struct got_diffstat_cb_arg *, struct got_repository *, FILE *); #define GOT_DIFF_MAX_CONTEXT 64 got-portable-0.101/include/got_sigs.h0000644000175100017510000000216214644143163013216 /* * Copyright (c) 2022 Josh Rickmar * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ const struct got_error * got_sigs_apply_unveil(void); const struct got_error * got_sigs_sign_tag_ssh(pid_t *, int *, int *, const char *, int); const char * got_sigs_get_tagmsg_ssh_signature(const char *); const struct got_error * got_sigs_verify_tag_ssh(char **, struct got_tag_object *, const char *, const char *, const char *, int); got-portable-0.101/include/got_error.h0000664000175100017510000002411614644143163013407 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * Copyright (c) 2020 Ori Bernstein * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Error codes */ #define GOT_ERR_OK 0 #define GOT_ERR_ERRNO 1 #define GOT_ERR_NOT_GIT_REPO 2 #define GOT_ERR_BAD_FILETYPE 3 #define GOT_ERR_BAD_PATH 4 #define GOT_ERR_NOT_REF 5 #define GOT_ERR_IO 6 #define GOT_ERR_EOF 7 #define GOT_ERR_DECOMPRESSION 8 #define GOT_ERR_NO_SPACE 9 #define GOT_ERR_BAD_OBJ_HDR 10 #define GOT_ERR_OBJ_TYPE 11 #define GOT_ERR_BAD_OBJ_DATA 12 #define GOT_ERR_AMBIGUOUS_ID 13 #define GOT_ERR_BAD_PACKIDX 14 #define GOT_ERR_PACKIDX_CSUM 15 #define GOT_ERR_BAD_PACKFILE 16 #define GOT_ERR_NO_OBJ 17 #define GOT_ERR_NOT_IMPL 18 #define GOT_ERR_OBJ_NOT_PACKED 19 #define GOT_ERR_BAD_DELTA_CHAIN 20 #define GOT_ERR_BAD_DELTA 21 #define GOT_ERR_COMPRESSION 22 #define GOT_ERR_BAD_OBJ_ID_STR 23 #define GOT_ERR_WORKTREE_EXISTS 26 #define GOT_ERR_WORKTREE_META 27 #define GOT_ERR_WORKTREE_VERS 28 #define GOT_ERR_WORKTREE_BUSY 29 #define GOT_ERR_DIR_OBSTRUCTED 30 #define GOT_ERR_FILE_OBSTRUCTED 31 #define GOT_ERR_RECURSION 32 #define GOT_ERR_TIMEOUT 33 #define GOT_ERR_INTERRUPT 34 #define GOT_ERR_PRIVSEP_READ 35 #define GOT_ERR_PRIVSEP_LEN 36 #define GOT_ERR_PRIVSEP_PIPE 37 #define GOT_ERR_PRIVSEP_NO_FD 38 #define GOT_ERR_PRIVSEP_MSG 39 #define GOT_ERR_PRIVSEP_DIED 40 #define GOT_ERR_PRIVSEP_EXIT 41 #define GOT_ERR_PACK_OFFSET 42 #define GOT_ERR_OBJ_EXISTS 43 #define GOT_ERR_BAD_OBJ_ID 44 /* 45 is currently unused */ #define GOT_ERR_ITER_COMPLETED 46 #define GOT_ERR_RANGE 47 #define GOT_ERR_EXPECTED 48 /* for use in regress tests only */ #define GOT_ERR_CANCELLED 49 #define GOT_ERR_NO_TREE_ENTRY 50 #define GOT_ERR_FILEIDX_SIG 51 #define GOT_ERR_FILEIDX_VER 52 #define GOT_ERR_FILEIDX_CSUM 53 #define GOT_ERR_PATH_PREFIX 54 #define GOT_ERR_ANCESTRY 55 #define GOT_ERR_FILEIDX_BAD 56 #define GOT_ERR_BAD_REF_DATA 57 #define GOT_ERR_TREE_DUP_ENTRY 58 #define GOT_ERR_DIR_DUP_ENTRY 59 #define GOT_ERR_NOT_WORKTREE 60 #define GOT_ERR_UUID_VERSION 61 #define GOT_ERR_UUID_INVALID 62 #define GOT_ERR_UUID 63 #define GOT_ERR_LOCKFILE_TIMEOUT 64 #define GOT_ERR_BAD_REF_NAME 65 #define GOT_ERR_WORKTREE_REPO 66 #define GOT_ERR_FILE_MODIFIED 67 #define GOT_ERR_FILE_STATUS 68 #define GOT_ERR_COMMIT_CONFLICT 69 #define GOT_ERR_BAD_REF_TYPE 70 #define GOT_ERR_COMMIT_NO_AUTHOR 71 #define GOT_ERR_COMMIT_HEAD_CHANGED 72 #define GOT_ERR_COMMIT_OUT_OF_DATE 73 #define GOT_ERR_COMMIT_MSG_EMPTY 74 #define GOT_ERR_DIR_NOT_EMPTY 75 #define GOT_ERR_COMMIT_NO_CHANGES 76 #define GOT_ERR_BRANCH_MOVED 77 #define GOT_ERR_OBJ_TOO_LARGE 78 #define GOT_ERR_SAME_BRANCH 79 #define GOT_ERR_ROOT_COMMIT 80 #define GOT_ERR_MIXED_COMMITS 81 #define GOT_ERR_CONFLICTS 82 #define GOT_ERR_BRANCH_EXISTS 83 #define GOT_ERR_MODIFIED 84 #define GOT_ERR_NOT_REBASING 85 #define GOT_ERR_WRONG_BRANCH 86 #define GOT_ERR_REBASE_COMMITID 87 #define GOT_ERR_REBASING 88 #define GOT_ERR_REBASE_PATH 89 #define GOT_ERR_NOT_HISTEDIT 90 #define GOT_ERR_EMPTY_HISTEDIT 91 #define GOT_ERR_NO_HISTEDIT_CMD 92 #define GOT_ERR_HISTEDIT_SYNTAX 93 #define GOT_ERR_HISTEDIT_CANCEL 94 /* 95 is currently unused */ #define GOT_ERR_HISTEDIT_BUSY 96 #define GOT_ERR_HISTEDIT_CMD 97 #define GOT_ERR_HISTEDIT_PATH 98 #define GOT_ERR_PACKFILE_CSUM 99 #define GOT_ERR_COMMIT_BRANCH 100 #define GOT_ERR_FILE_STAGED 101 #define GOT_ERR_STAGE_NO_CHANGE 102 #define GOT_ERR_STAGE_CONFLICT 103 #define GOT_ERR_STAGE_OUT_OF_DATE 104 #define GOT_ERR_FILE_NOT_STAGED 105 #define GOT_ERR_STAGED_PATHS 106 #define GOT_ERR_PATCH_CHOICE 107 #define GOT_ERR_COMMIT_NO_EMAIL 108 #define GOT_ERR_TAG_EXISTS 109 #define GOT_ERR_GIT_REPO_FORMAT 110 #define GOT_ERR_REBASE_REQUIRED 111 #define GOT_ERR_REGEX 112 #define GOT_ERR_REF_NAME_MINUS 113 #define GOT_ERR_GITCONFIG_SYNTAX 114 #define GOT_ERR_REBASE_OUT_OF_DATE 115 #define GOT_ERR_CACHE_DUP_ENTRY 116 /* 117 is currently unused */ #define GOT_ERR_FETCH_FAILED 118 #define GOT_ERR_PARSE_URI 119 #define GOT_ERR_BAD_PROTO 120 #define GOT_ERR_ADDRINFO 121 #define GOT_ERR_BAD_PACKET 122 #define GOT_ERR_NO_REMOTE 123 #define GOT_ERR_FETCH_NO_BRANCH 124 #define GOT_ERR_FETCH_BAD_REF 125 #define GOT_ERR_TREE_ENTRY_TYPE 126 #define GOT_ERR_PARSE_CONFIG 127 #define GOT_ERR_NO_CONFIG_FILE 128 #define GOT_ERR_BAD_SYMLINK 129 #define GOT_ERR_GIT_REPO_EXT 130 #define GOT_ERR_CANNOT_PACK 131 #define GOT_ERR_LONELY_PACKIDX 132 #define GOT_ERR_OBJ_CSUM 133 #define GOT_ERR_SEND_BAD_REF 134 #define GOT_ERR_SEND_FAILED 135 #define GOT_ERR_SEND_EMPTY 136 #define GOT_ERR_SEND_ANCESTRY 137 #define GOT_ERR_CAPA_DELETE_REFS 138 #define GOT_ERR_SEND_DELETE_REF 139 #define GOT_ERR_SEND_TAG_EXISTS 140 #define GOT_ERR_NOT_MERGING 141 #define GOT_ERR_MERGE_OUT_OF_DATE 142 #define GOT_ERR_MERGE_STAGED_PATHS 143 #define GOT_ERR_MERGE_BUSY 144 #define GOT_ERR_MERGE_PATH 145 #define GOT_ERR_FILE_BINARY 146 #define GOT_ERR_PATCH_MALFORMED 147 #define GOT_ERR_PATCH_TRUNCATED 148 #define GOT_ERR_NO_PATCH 149 #define GOT_ERR_HUNK_FAILED 150 #define GOT_ERR_PATCH_FAILED 151 #define GOT_ERR_FILEIDX_DUP_ENTRY 152 #define GOT_ERR_PIN_PACK 153 #define GOT_ERR_BAD_TAG_SIGNATURE 154 #define GOT_ERR_VERIFY_TAG_SIGNATURE 155 #define GOT_ERR_SIGNING_TAG 156 #define GOT_ERR_BAD_OPTION 157 #define GOT_ERR_BAD_QUERYSTRING 158 #define GOT_ERR_INTEGRATE_BRANCH 159 #define GOT_ERR_BAD_REQUEST 160 #define GOT_ERR_CLIENT_ID 161 #define GOT_ERR_REPO_TEMPFILE 162 #define GOT_ERR_REFS_PROTECTED 163 #define GOT_ERR_REF_PROTECTED 164 #define GOT_ERR_REF_BUSY 165 #define GOT_ERR_COMMIT_BAD_AUTHOR 166 #define GOT_ERR_UID 167 #define GOT_ERR_GID 168 #define GOT_ERR_NO_PROG 169 #define GOT_ERR_MERGE_COMMIT_OUT_OF_DATE 170 #define GOT_ERR_BUNDLE_FORMAT 171 #define GOT_ERR_BAD_KEYWORD 172 struct got_error { int code; const char *msg; }; #define GOT_ERR_MAX_MSG_SIZE 4080 /* includes '\0' */ /* * Get an error object from the above list, for a given error code. * The error message is fixed. */ const struct got_error *got_error(int); /* * Get an error object from the above list, for a given error code. * Use the specified error message instead of the default one. * Caution: If the message buffer lives in dynamically allocated memory, * then this memory likely won't be freed. */ const struct got_error *got_error_msg(int, const char *); /* * Get a statically allocated error object with code GOT_ERR_ERRNO * and an error message obtained from strerror(3), prefixed with a * string. */ const struct got_error *got_error_from_errno(const char *); /* * Get a statically allocated error object with code GOT_ERR_ERRNO * and an error message obtained from strerror(3), prefixed with two * strings. */ const struct got_error *got_error_from_errno2(const char *, const char *); /* * Get a statically allocated error object with code GOT_ERR_ERRNO * and an error message obtained from strerror(3), prefixed with three * strings. */ const struct got_error *got_error_from_errno3(const char *, const char *, const char *); /* * Get a statically allocated error object with code GOT_ERR_ERRNO * and an error message obtained from strerror(3), prefixed with a * string built with vsnprintf(3) from the provided format string * and the variable-length list of additional arguments. */ const struct got_error *got_error_from_errno_fmt(const char *, ...); /* * Set errno to the specified error code and return a statically * allocated error object with code GOT_ERR_ERRNO and an error * message obtained from strerror(3), optionally prefixed with a * string. */ const struct got_error *got_error_set_errno(int, const char *); /* * If ferror(3) indicates an error status for the FILE, obtain an error * from got_error_from_errno(). Else, obtain the error via got_error() * with the error code provided in the second argument. */ const struct got_error *got_ferror(FILE *, int); /* * Obtain an error with code GOT_ERR_NO_OBJ and an error message which * contains the specified object ID. The message buffer is statically * allocated; future invocations of this function will overwrite the * message set during earlier invocations. */ struct got_object_id; /* forward declaration */ const struct got_error *got_error_no_obj(struct got_object_id *); /* * Obtain an error with code GOT_ERR_OBJ_CSUM and an error message which * contains the specified object ID. The message buffer is statically * allocated; future invocations of this function will overwrite the * message set during earlier invocations. */ const struct got_error *got_error_checksum(struct got_object_id *); /* * Obtain an error with code GOT_ERR_NOT_REF and an error message which * contains the specified reference name. The message buffer is statically * allocated; future invocations of this function will overwrite the * message set during earlier invocations. */ const struct got_error *got_error_not_ref(const char *); /* Return an error based on a uuid(3) status code. */ const struct got_error *got_error_uuid(uint32_t, const char *); /* Return an error with a path prefixed to the error message. */ const struct got_error *got_error_path(const char *, int); /* * Return an error with an error message prefix built by vsnprintf(3) * from the provided format string and the variable-length list of * additional arguments. */ const struct got_error *got_error_fmt(int, const char *, ...) __attribute__((__format__ (printf, 2, 3))); /* * Check whether open(2) with O_NOFOLLOW failed on a symlink. * This must be called directly after open(2) because it uses errno! */ int got_err_open_nofollow_on_symlink(void); got-portable-0.101/include/got_path.h0000644000175100017510000001360614644143163013212 /* * Copyright (c) 2018, 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Utilities for dealing with filesystem paths. */ #define GOT_DEFAULT_PACK_MODE (S_IFREG | \ S_IRUSR | S_IRGRP | S_IROTH) #define GOT_DEFAULT_FILE_MODE (S_IFREG | \ S_IRUSR|S_IWUSR | S_IRGRP | S_IROTH) #define GOT_DEFAULT_DIR_MODE (S_IFDIR | \ S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH) struct dirent; /* Determine whether a path is an absolute path. */ int got_path_is_absolute(const char *); /* * Canonicalize absolute paths by removing redundant path separators * and resolving references to parent directories ("/../"). * Relative paths are copied from input to buf as-is. */ const struct got_error *got_canonpath(const char *, char *, size_t); /* * Get child part of two absolute paths. The second path must equal the first * path up to some path component, and must be longer than the first path. * The result is allocated with malloc(3). */ const struct got_error *got_path_skip_common_ancestor(char **, const char *, const char *); /* * Remove leading components from path. It's an error to strip more * component than present. The result is allocated dynamically. */ const struct got_error *got_path_strip(char **, const char *, int); /* Determine whether a path points to the root directory "/" . */ int got_path_is_root_dir(const char *); /* Determine whether a path is a path-wise child of another path. */ int got_path_is_child(const char *, const char *, size_t); /* * Like strcmp() but orders children in subdirectories directly after * their parents. String lengths must also be passed in. */ int got_path_cmp(const char *, const char *, size_t, size_t); /* * Path lists allow for predictable concurrent iteration over multiple lists * of paths obtained from disparate sources which don't all provide the same * ordering guarantees (e.g. git trees, file index, and on-disk directories). */ struct got_pathlist_entry { TAILQ_ENTRY(got_pathlist_entry) entry; const char *path; size_t path_len; void *data; /* data pointer provided to got_pathlist_insert() */ }; TAILQ_HEAD(got_pathlist_head, got_pathlist_entry); /* * Insert a path into the list of paths in a predictable order. * The caller should already have initialized the list head. This list stores * the pointer to the path as-is, i.e. the path is not copied internally and * must remain available until the list is freed with got_pathlist_free(). * If the first argument is not NULL, set it to a pointer to the newly inserted * element, or to a NULL pointer in case the path was already on the list. */ const struct got_error *got_pathlist_insert(struct got_pathlist_entry **, struct got_pathlist_head *, const char *, void *); /* * Append a path to the list of paths. * The caller should already have initialized the list head. This list stores * the pointer to the path as-is, i.e. the path is not copied internally and * must remain available until the list is freed with got_pathlist_free(). */ const struct got_error *got_pathlist_append(struct got_pathlist_head *, const char *, void *); /* Flags passed to got_pathlist_free() to control which pointers are freed. */ #define GOT_PATHLIST_FREE_NONE 0 /* pathlist entry only */ #define GOT_PATHLIST_FREE_PATH (1 << 0) /* entry and path pointer */ #define GOT_PATHLIST_FREE_DATA (1 << 1) /* entry and data pointer */ #define GOT_PATHLIST_FREE_ALL (GOT_PATHLIST_FREE_PATH|GOT_PATHLIST_FREE_DATA) /* Free resources allocated for a path list. */ void got_pathlist_free(struct got_pathlist_head *, int); /* Attempt to create a directory at a given path. */ const struct got_error *got_path_mkdir(const char *); /* Determine whether a directory has no files or directories in it. */ int got_path_dir_is_empty(const char *); /* * dirname(3) with error handling, dynamically allocated result, and * unmodified input. */ const struct got_error *got_path_dirname(char **, const char *); /* * Obtain the file type of a given directory entry. * * If the entry has some type other than DT_UNKNOWN, resolve to this type. * * Otherwise, attempt to resolve the type of a DT_UNKNOWN directory * entry with lstat(2), though the result may still be DT_UNKNOWN. * This is a fallback to accommodate filesystems which do not provide * directory entry type information. * DT_UNKNOWN directory entries occur on NFS mounts without "readdir plus" RPC. */ const struct got_error *got_path_dirent_type(int *, const char *, struct dirent *); /* basename(3) with dynamically allocated result and unmodified input. */ const struct got_error *got_path_basename(char **, const char *); /* Strip trailing slashes from a path; path will be modified in-place. */ void got_path_strip_trailing_slashes(char *); /* Look up the absolute path of a program in $PATH */ const struct got_error *got_path_find_prog(char **, const char *); /* Create a new file at a specified path, with optional content. */ const struct got_error *got_path_create_file(const char *, const char *); /* * Attempt to move an existing file to a new path, creating missing parent * directories at the destination path if necessary. * (Cross-mount-point moves are not yet implemented.) */ const struct got_error *got_path_move_file(const char *, const char *); got-portable-0.101/include/got_cancel.h0000644000175100017510000000173214644143163013500 /* * Copyright (c) 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * A callback function which is invoked at cancellation points. * May return GOT_ERR_CANCELLED to abort the runing operation. */ typedef const struct got_error *(*got_cancel_cb)(void *); got-portable-0.101/include/got_compat.h0000664000175100017510000004106014644145550013540 /* include/got_compat.h. Generated from got_compat.h.in by configure. */ /* include/got_compat.h.in. Generated from configure.ac by autoheader. */ /* GoT version string */ #define GOT_VERSION VERSION /* Got version number */ #define GOT_VERSION_NUMBER VERSION /* Define to 1 if you have the `asprintf' function. */ #define HAVE_ASPRINTF 1 /* define if b64_ntop is present */ #define HAVE_B64_NTOP 1 /* BSD UUID */ /* #undef HAVE_BSD_UUID */ /* Define to 1 if you have the `closefrom' function. */ #define HAVE_CLOSEFROM 1 /* Curses_h */ /* #undef HAVE_CURSES_H */ /* Define to 1 if you have the declaration of `strerror_r', and to 0 if you don't. */ #define HAVE_DECL_STRERROR_R 1 /* Define to 1 if you have the header file, and it defines `DIR'. */ #define HAVE_DIRENT_H 1 /* Define to 1 if you have the `dup2' function. */ #define HAVE_DUP2 1 /* libevent2 has event.h */ /* #undef HAVE_EVENT2_EVENT_H */ /* libevent */ /* #undef HAVE_EVENT_H */ /* Define to 1 if you have the `explicit_bzero' function. */ #define HAVE_EXPLICIT_BZERO 1 /* Use F_CLOSEM fcntl for closefrom */ /* #undef HAVE_FCNTL_CLOSEM */ /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the `flock' function. */ #define HAVE_FLOCK 1 /* Define to 1 if you have the `fmt_scaled' function. */ /* #undef HAVE_FMT_SCALED */ /* Define to 1 if you have the `fork' function. */ #define HAVE_FORK 1 /* Define to 1 if you have the `freezero' function. */ /* #undef HAVE_FREEZERO */ /* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ #define HAVE_FSEEKO 1 /* Define to 1 if you have the `getcwd' function. */ #define HAVE_GETCWD 1 /* Define to 1 if you have the `getdtablecount' function. */ /* #undef HAVE_GETDTABLECOUNT */ /* Define to 1 if you have the `getline' function. */ #define HAVE_GETLINE 1 /* Define to 1 if you have the header file. */ #define HAVE_GETOPT_H 1 /* Define if your getopt(3) defines and uses optreset */ /* #undef HAVE_GETOPT_OPTRESET */ /* Define to 1 if you have the `getpagesize' function. */ #define HAVE_GETPAGESIZE 1 /* Define to 1 if you have the `getprogname' function. */ /* #undef HAVE_GETPROGNAME */ /* Define to 1 if imsg is declared in libutil */ /* #undef HAVE_IMSG */ /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_LANGINFO_H 1 /* BSD UUID */ #define HAVE_LIBBSD 1 /* Define to 1 if you have the `panelw' library (-lpanelw). */ /* #undef HAVE_LIBPANELW */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LIBUTIL_H */ /* Define to 1 if you have the header file. */ #define HAVE_LIMITS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_LINUX_LANDLOCK_H 1 /* Define to 1 if you have the header file. */ #define HAVE_LOCALE_H 1 /* Define to 1 if you have the `localtime_r' function. */ #define HAVE_LOCALTIME_R 1 /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #define HAVE_MALLOC 1 /* Define to 1 if you have the `memchr' function. */ #define HAVE_MEMCHR 1 /* Define to 1 if you have the `memmove' function. */ #define HAVE_MEMMOVE 1 /* Define to 1 if you have the `memset' function. */ #define HAVE_MEMSET 1 /* Define to 1 if you have the `mergesort' function. */ /* #undef HAVE_MERGESORT */ /* Define to 1 if you have the header file. */ /* #undef HAVE_MINIX_CONFIG_H */ /* Define to 1 if you have the `mkdir' function. */ #define HAVE_MKDIR 1 /* Define to 1 if you have a working `mmap' system call. */ #define HAVE_MMAP 1 /* Define to 1 if you have the `munmap' function. */ #define HAVE_MUNMAP 1 /* NCurses */ #define HAVE_NCURSES_H 1 /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_NDIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_NETDB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NETINET_IN_H 1 /* Define to 1 if you have the `nl_langinfo' function. */ #define HAVE_NL_LANGINFO 1 /* Define to 1 if you have the header file. */ #define HAVE_PATHS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_POLL_H 1 /* Define if you have /proc/$pid/fd */ #define HAVE_PROC_PID 1 /* Define if program_invocation_short_name is defined */ #define HAVE_PROGRAM_INVOCATION_SHORT_NAME 1 /* Define if PR_SET_NAME is defined */ #define HAVE_PR_SET_NAME 1 /* sys/queue.h */ #define HAVE_QUEUE_H 1 /* Define to 1 if your system has a GNU libc compatible `realloc' function, and to 0 otherwise. */ #define HAVE_REALLOC 1 /* Define to 1 if you have the `reallocarray' function. */ #define HAVE_REALLOCARRAY 1 /* Define to 1 if you have the `realpath' function. */ #define HAVE_REALPATH 1 /* Define to 1 if you have the `recallocarray' function. */ /* #undef HAVE_RECALLOCARRAY */ /* Define to 1 if you have the `regcomp' function. */ #define HAVE_REGCOMP 1 /* Define to 1 if you have the `rmdir' function. */ #define HAVE_RMDIR 1 /* Define to 1 if you have the `setlocale' function. */ #define HAVE_SETLOCALE 1 /* Define to 1 if you have the `setproctitle' function. */ /* #undef HAVE_SETPROCTITLE */ /* Define to 1 if you have the `setresgid' function. */ #define HAVE_SETRESGID 1 /* Define to 1 if you have the `setresuid' function. */ #define HAVE_SETRESUID 1 /* Define to 1 if you have the header file. */ #define HAVE_SHA1_H 1 /* Define to 1 if you have the `SHA256Update' function. */ /* #undef HAVE_SHA256UPDATE */ /* Define to 1 if you have the header file. */ #define HAVE_SHA256_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SHA2_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SHA_H 1 /* Define to 1 if you have the `SipHash' function. */ /* #undef HAVE_SIPHASH */ /* Define to 1 if you have the `socket' function. */ #define HAVE_SOCKET 1 /* Define to 1 if you have the header file. */ #define HAVE_STDDEF_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the `strcasecmp' function. */ #define HAVE_STRCASECMP 1 /* Define to 1 if you have the `strchr' function. */ #define HAVE_STRCHR 1 /* Define to 1 if you have the `strcspn' function. */ #define HAVE_STRCSPN 1 /* Define to 1 if you have the `strdup' function. */ #define HAVE_STRDUP 1 /* Define to 1 if you have the `strerror' function. */ #define HAVE_STRERROR 1 /* Define if you have `strerror_r'. */ #define HAVE_STRERROR_R 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strlcat' function. */ #define HAVE_STRLCAT 1 /* Define to 1 if you have the `strlcpy' function. */ #define HAVE_STRLCPY 1 /* Define to 1 if you have the `strncasecmp' function. */ #define HAVE_STRNCASECMP 1 /* Define to 1 if you have the `strndup' function. */ #define HAVE_STRNDUP 1 /* Define to 1 if you have the `strnlen' function. */ #define HAVE_STRNLEN 1 /* Define to 1 if you have the `strrchr' function. */ #define HAVE_STRRCHR 1 /* Define to 1 if you have the `strsep' function. */ #define HAVE_STRSEP 1 /* Define to 1 if you have the `strspn' function. */ #define HAVE_STRSPN 1 /* Define to 1 if you have the `strstr' function. */ #define HAVE_STRSTR 1 /* Define to 1 if you have the `strtol' function. */ #define HAVE_STRTOL 1 /* Define to 1 if you have the `strtonum' function. */ /* #undef HAVE_STRTONUM */ /* Define to 1 if you have the `strtoul' function. */ #define HAVE_STRTOUL 1 /* Define to 1 if the system has the type `struct ifgroupreq'. */ /* #undef HAVE_STRUCT_IFGROUPREQ */ /* Define to 1 if `fd' is a member of `struct pollfd'. */ #define HAVE_STRUCT_POLLFD_FD 1 /* Define to 1 if `sa_len' is a member of `struct sockaddr'. */ /* #undef HAVE_STRUCT_SOCKADDR_SA_LEN */ /* Define to 1 if the system has the type `struct sockaddr_storage'. */ #define HAVE_STRUCT_SOCKADDR_STORAGE 1 /* Define to 1 if `ss_len' is a member of `struct sockaddr_storage'. */ /* #undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN */ /* Define to 1 if sysconf() present */ #define HAVE_SYSCONF 1 /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_SYS_DIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_IOCTL_H 1 /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_SYS_NDIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_PARAM_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_POLL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_QUEUE_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SELECT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SOCKET_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_TREE_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_TLS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_UTIL_H */ /* Define to 1 if you have the `vfork' function. */ #define HAVE_VFORK 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_VFORK_H */ /* Define to 1 if you have the header file. */ #define HAVE_WCHAR_H 1 /* Define to 1 if you have the `wcwidth' function. */ #define HAVE_WCWIDTH 1 /* Define to 1 if `fork' works. */ #define HAVE_WORKING_FORK 1 /* Define to 1 if `vfork' works. */ #define HAVE_WORKING_VFORK 1 /* Define to 1 if the system has the type `_Bool'. */ #define HAVE__BOOL 1 /* ___progname */ #define HAVE___PROGNAME 1 /* Define to 1 if `lstat' dereferences a symlink specified with a trailing slash. */ #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 /* Name of package */ #define PACKAGE "got-portable" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "thomas@xteddy.org" /* Define to the full name of this package. */ #define PACKAGE_NAME "got-portable" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "got-portable 0.101" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "got-portable" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "0.101" /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #define STDC_HEADERS 1 /* Define to 1 if strerror_r returns char *. */ #define STRERROR_R_CHAR_P 1 /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # define _ALL_SOURCE 1 #endif /* Enable general extensions on macOS. */ #ifndef _DARWIN_C_SOURCE # define _DARWIN_C_SOURCE 1 #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # define __EXTENSIONS__ 1 #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # define _GNU_SOURCE 1 #endif /* Enable X/Open compliant socket functions that do not require linking with -lxnet on HP-UX 11.11. */ #ifndef _HPUX_ALT_XOPEN_SOCKET_API # define _HPUX_ALT_XOPEN_SOCKET_API 1 #endif /* Identify the host operating system as Minix. This macro does not affect the system headers' behavior. A future release of Autoconf may stop defining this macro. */ #ifndef _MINIX /* # undef _MINIX */ #endif /* Enable general extensions on NetBSD. Enable NetBSD compatibility extensions on Minix. */ #ifndef _NETBSD_SOURCE # define _NETBSD_SOURCE 1 #endif /* Enable OpenBSD compatibility extensions on NetBSD. Oddly enough, this does nothing on OpenBSD. */ #ifndef _OPENBSD_SOURCE # define _OPENBSD_SOURCE 1 #endif /* Define to 1 if needed for POSIX-compatible behavior. */ #ifndef _POSIX_SOURCE /* # undef _POSIX_SOURCE */ #endif /* Define to 2 if needed for POSIX-compatible behavior. */ #ifndef _POSIX_1_SOURCE /* # undef _POSIX_1_SOURCE */ #endif /* Enable POSIX-compatible threading on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # define _POSIX_PTHREAD_SEMANTICS 1 #endif /* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ #ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ # define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1 #endif /* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ #ifndef __STDC_WANT_IEC_60559_BFP_EXT__ # define __STDC_WANT_IEC_60559_BFP_EXT__ 1 #endif /* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ #ifndef __STDC_WANT_IEC_60559_DFP_EXT__ # define __STDC_WANT_IEC_60559_DFP_EXT__ 1 #endif /* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ #ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ # define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1 #endif /* Enable extensions specified by ISO/IEC TS 18661-3:2015. */ #ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ # define __STDC_WANT_IEC_60559_TYPES_EXT__ 1 #endif /* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ #ifndef __STDC_WANT_LIB_EXT2__ # define __STDC_WANT_LIB_EXT2__ 1 #endif /* Enable extensions specified by ISO/IEC 24747:2009. */ #ifndef __STDC_WANT_MATH_SPEC_FUNCS__ # define __STDC_WANT_MATH_SPEC_FUNCS__ 1 #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # define _TANDEM_SOURCE 1 #endif /* Enable X/Open extensions. Define to 500 only if necessary to make mbstate_t available. */ #ifndef _XOPEN_SOURCE /* # undef _XOPEN_SOURCE */ #endif /* Version number of package */ #define VERSION 0.101 /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ /* #undef _LARGEFILE_SOURCE */ /* Define for Solaris 2.5.1 so the uint32_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ /* #undef _UINT32_T */ /* Define for Solaris 2.5.1 so the uint64_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ /* #undef _UINT64_T */ /* Define for Solaris 2.5.1 so the uint8_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ /* #undef _UINT8_T */ /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus /* #undef inline */ #endif /* Define to the type of a signed integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ /* #undef int64_t */ /* Define to rpl_malloc if the replacement function should be used. */ /* #undef malloc */ /* Define to `int' if does not define. */ /* #undef mode_t */ /* Define to `long int' if does not define. */ /* #undef off_t */ /* Define as a signed integer type capable of holding a process identifier. */ /* #undef pid_t */ /* Define to rpl_realloc if the replacement function should be used. */ /* #undef realloc */ /* Define to `unsigned int' if does not define. */ /* #undef size_t */ /* Define to `int' if does not define. */ /* #undef ssize_t */ /* Define to the type of an unsigned integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ /* #undef uint16_t */ /* Define to the type of an unsigned integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ /* #undef uint32_t */ /* Define to the type of an unsigned integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ /* #undef uint64_t */ /* Define to the type of an unsigned integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ /* #undef uint8_t */ /* Define as `fork' if `vfork' does not work. */ /* #undef vfork */ #include "got_compat2.h" got-portable-0.101/include/got_keyword.h0000644000175100017510000000376214644143163013744 /* * Copyright (c) 2023 Mark Jamsek * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Commit keywords to specify references in the repository * (cf. svn keywords, fossil special tags, hg revsets). */ #define GOT_KEYWORD_BASE "base" /* work tree base commit */ #define GOT_KEYWORD_HEAD "head" /* worktree/repo HEAD commit */ /* * Parse a commit id string for keywords and/or lineage modifiers "(+|-)[N]". * Valid keywords are "base" or "head" and must be prefixed with a ":". * Lineage modifiers must be prefixed with a ":" and may suffix keywords or * reference names: * :keyword:(+/-)N Nth generation descendant/antecedent of keyword * :keyword:(+/-) 1st generation descendant/antecedent of keyword * :keyword commit pointed to by keyword * ref:(+/-)[N] Nth generation descendant/antecedent of ref * If a match is found, return the corresponding commit id string in the * char ** out parameter, of which the caller takes ownership and must free. * Otherwise it will contain NULL, indicating a match was not found. * If the modifier is greater than the number of ancestors/descendants, the id * string of the oldest/most recent commit (i.e., ROOT/HEAD) will be returned. */ const struct got_error *got_keyword_to_idstr(char **, const char *, struct got_repository *, struct got_worktree *); got-portable-0.101/include/got_compat.h.in0000664000175100017510000003733114644145543014155 /* include/got_compat.h.in. Generated from configure.ac by autoheader. */ /* GoT version string */ #undef GOT_VERSION /* Got version number */ #undef GOT_VERSION_NUMBER /* Define to 1 if you have the `asprintf' function. */ #undef HAVE_ASPRINTF /* define if b64_ntop is present */ #undef HAVE_B64_NTOP /* BSD UUID */ #undef HAVE_BSD_UUID /* Define to 1 if you have the `closefrom' function. */ #undef HAVE_CLOSEFROM /* Curses_h */ #undef HAVE_CURSES_H /* Define to 1 if you have the declaration of `strerror_r', and to 0 if you don't. */ #undef HAVE_DECL_STRERROR_R /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_DIRENT_H /* Define to 1 if you have the `dup2' function. */ #undef HAVE_DUP2 /* libevent2 has event.h */ #undef HAVE_EVENT2_EVENT_H /* libevent */ #undef HAVE_EVENT_H /* Define to 1 if you have the `explicit_bzero' function. */ #undef HAVE_EXPLICIT_BZERO /* Use F_CLOSEM fcntl for closefrom */ #undef HAVE_FCNTL_CLOSEM /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the `flock' function. */ #undef HAVE_FLOCK /* Define to 1 if you have the `fmt_scaled' function. */ #undef HAVE_FMT_SCALED /* Define to 1 if you have the `fork' function. */ #undef HAVE_FORK /* Define to 1 if you have the `freezero' function. */ #undef HAVE_FREEZERO /* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ #undef HAVE_FSEEKO /* Define to 1 if you have the `getcwd' function. */ #undef HAVE_GETCWD /* Define to 1 if you have the `getdtablecount' function. */ #undef HAVE_GETDTABLECOUNT /* Define to 1 if you have the `getline' function. */ #undef HAVE_GETLINE /* Define to 1 if you have the header file. */ #undef HAVE_GETOPT_H /* Define if your getopt(3) defines and uses optreset */ #undef HAVE_GETOPT_OPTRESET /* Define to 1 if you have the `getpagesize' function. */ #undef HAVE_GETPAGESIZE /* Define to 1 if you have the `getprogname' function. */ #undef HAVE_GETPROGNAME /* Define to 1 if imsg is declared in libutil */ #undef HAVE_IMSG /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_LANGINFO_H /* BSD UUID */ #undef HAVE_LIBBSD /* Define to 1 if you have the `panelw' library (-lpanelw). */ #undef HAVE_LIBPANELW /* Define to 1 if you have the header file. */ #undef HAVE_LIBUTIL_H /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_LANDLOCK_H /* Define to 1 if you have the header file. */ #undef HAVE_LOCALE_H /* Define to 1 if you have the `localtime_r' function. */ #undef HAVE_LOCALTIME_R /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #undef HAVE_MALLOC /* Define to 1 if you have the `memchr' function. */ #undef HAVE_MEMCHR /* Define to 1 if you have the `memmove' function. */ #undef HAVE_MEMMOVE /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET /* Define to 1 if you have the `mergesort' function. */ #undef HAVE_MERGESORT /* Define to 1 if you have the header file. */ #undef HAVE_MINIX_CONFIG_H /* Define to 1 if you have the `mkdir' function. */ #undef HAVE_MKDIR /* Define to 1 if you have a working `mmap' system call. */ #undef HAVE_MMAP /* Define to 1 if you have the `munmap' function. */ #undef HAVE_MUNMAP /* NCurses */ #undef HAVE_NCURSES_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the `nl_langinfo' function. */ #undef HAVE_NL_LANGINFO /* Define to 1 if you have the header file. */ #undef HAVE_PATHS_H /* Define to 1 if you have the header file. */ #undef HAVE_POLL_H /* Define if you have /proc/$pid/fd */ #undef HAVE_PROC_PID /* Define if program_invocation_short_name is defined */ #undef HAVE_PROGRAM_INVOCATION_SHORT_NAME /* Define if PR_SET_NAME is defined */ #undef HAVE_PR_SET_NAME /* sys/queue.h */ #undef HAVE_QUEUE_H /* Define to 1 if your system has a GNU libc compatible `realloc' function, and to 0 otherwise. */ #undef HAVE_REALLOC /* Define to 1 if you have the `reallocarray' function. */ #undef HAVE_REALLOCARRAY /* Define to 1 if you have the `realpath' function. */ #undef HAVE_REALPATH /* Define to 1 if you have the `recallocarray' function. */ #undef HAVE_RECALLOCARRAY /* Define to 1 if you have the `regcomp' function. */ #undef HAVE_REGCOMP /* Define to 1 if you have the `rmdir' function. */ #undef HAVE_RMDIR /* Define to 1 if you have the `setlocale' function. */ #undef HAVE_SETLOCALE /* Define to 1 if you have the `setproctitle' function. */ #undef HAVE_SETPROCTITLE /* Define to 1 if you have the `setresgid' function. */ #undef HAVE_SETRESGID /* Define to 1 if you have the `setresuid' function. */ #undef HAVE_SETRESUID /* Define to 1 if you have the header file. */ #undef HAVE_SHA1_H /* Define to 1 if you have the `SHA256Update' function. */ #undef HAVE_SHA256UPDATE /* Define to 1 if you have the header file. */ #undef HAVE_SHA256_H /* Define to 1 if you have the header file. */ #undef HAVE_SHA2_H /* Define to 1 if you have the header file. */ #undef HAVE_SHA_H /* Define to 1 if you have the `SipHash' function. */ #undef HAVE_SIPHASH /* Define to 1 if you have the `socket' function. */ #undef HAVE_SOCKET /* Define to 1 if you have the header file. */ #undef HAVE_STDDEF_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strcasecmp' function. */ #undef HAVE_STRCASECMP /* Define to 1 if you have the `strchr' function. */ #undef HAVE_STRCHR /* Define to 1 if you have the `strcspn' function. */ #undef HAVE_STRCSPN /* Define to 1 if you have the `strdup' function. */ #undef HAVE_STRDUP /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define if you have `strerror_r'. */ #undef HAVE_STRERROR_R /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strlcat' function. */ #undef HAVE_STRLCAT /* Define to 1 if you have the `strlcpy' function. */ #undef HAVE_STRLCPY /* Define to 1 if you have the `strncasecmp' function. */ #undef HAVE_STRNCASECMP /* Define to 1 if you have the `strndup' function. */ #undef HAVE_STRNDUP /* Define to 1 if you have the `strnlen' function. */ #undef HAVE_STRNLEN /* Define to 1 if you have the `strrchr' function. */ #undef HAVE_STRRCHR /* Define to 1 if you have the `strsep' function. */ #undef HAVE_STRSEP /* Define to 1 if you have the `strspn' function. */ #undef HAVE_STRSPN /* Define to 1 if you have the `strstr' function. */ #undef HAVE_STRSTR /* Define to 1 if you have the `strtol' function. */ #undef HAVE_STRTOL /* Define to 1 if you have the `strtonum' function. */ #undef HAVE_STRTONUM /* Define to 1 if you have the `strtoul' function. */ #undef HAVE_STRTOUL /* Define to 1 if the system has the type `struct ifgroupreq'. */ #undef HAVE_STRUCT_IFGROUPREQ /* Define to 1 if `fd' is a member of `struct pollfd'. */ #undef HAVE_STRUCT_POLLFD_FD /* Define to 1 if `sa_len' is a member of `struct sockaddr'. */ #undef HAVE_STRUCT_SOCKADDR_SA_LEN /* Define to 1 if the system has the type `struct sockaddr_storage'. */ #undef HAVE_STRUCT_SOCKADDR_STORAGE /* Define to 1 if `ss_len' is a member of `struct sockaddr_storage'. */ #undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN /* Define to 1 if sysconf() present */ #undef HAVE_SYSCONF /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_DIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_POLL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_QUEUE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TREE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_TLS_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the header file. */ #undef HAVE_UTIL_H /* Define to 1 if you have the `vfork' function. */ #undef HAVE_VFORK /* Define to 1 if you have the header file. */ #undef HAVE_VFORK_H /* Define to 1 if you have the header file. */ #undef HAVE_WCHAR_H /* Define to 1 if you have the `wcwidth' function. */ #undef HAVE_WCWIDTH /* Define to 1 if `fork' works. */ #undef HAVE_WORKING_FORK /* Define to 1 if `vfork' works. */ #undef HAVE_WORKING_VFORK /* Define to 1 if the system has the type `_Bool'. */ #undef HAVE__BOOL /* ___progname */ #undef HAVE___PROGNAME /* Define to 1 if `lstat' dereferences a symlink specified with a trailing slash. */ #undef LSTAT_FOLLOWS_SLASHED_SYMLINK /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #undef STDC_HEADERS /* Define to 1 if strerror_r returns char *. */ #undef STRERROR_R_CHAR_P /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif /* Enable general extensions on macOS. */ #ifndef _DARWIN_C_SOURCE # undef _DARWIN_C_SOURCE #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # undef __EXTENSIONS__ #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # undef _GNU_SOURCE #endif /* Enable X/Open compliant socket functions that do not require linking with -lxnet on HP-UX 11.11. */ #ifndef _HPUX_ALT_XOPEN_SOCKET_API # undef _HPUX_ALT_XOPEN_SOCKET_API #endif /* Identify the host operating system as Minix. This macro does not affect the system headers' behavior. A future release of Autoconf may stop defining this macro. */ #ifndef _MINIX # undef _MINIX #endif /* Enable general extensions on NetBSD. Enable NetBSD compatibility extensions on Minix. */ #ifndef _NETBSD_SOURCE # undef _NETBSD_SOURCE #endif /* Enable OpenBSD compatibility extensions on NetBSD. Oddly enough, this does nothing on OpenBSD. */ #ifndef _OPENBSD_SOURCE # undef _OPENBSD_SOURCE #endif /* Define to 1 if needed for POSIX-compatible behavior. */ #ifndef _POSIX_SOURCE # undef _POSIX_SOURCE #endif /* Define to 2 if needed for POSIX-compatible behavior. */ #ifndef _POSIX_1_SOURCE # undef _POSIX_1_SOURCE #endif /* Enable POSIX-compatible threading on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # undef _POSIX_PTHREAD_SEMANTICS #endif /* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ #ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ # undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ #ifndef __STDC_WANT_IEC_60559_BFP_EXT__ # undef __STDC_WANT_IEC_60559_BFP_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ #ifndef __STDC_WANT_IEC_60559_DFP_EXT__ # undef __STDC_WANT_IEC_60559_DFP_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ #ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ # undef __STDC_WANT_IEC_60559_FUNCS_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-3:2015. */ #ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ # undef __STDC_WANT_IEC_60559_TYPES_EXT__ #endif /* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ #ifndef __STDC_WANT_LIB_EXT2__ # undef __STDC_WANT_LIB_EXT2__ #endif /* Enable extensions specified by ISO/IEC 24747:2009. */ #ifndef __STDC_WANT_MATH_SPEC_FUNCS__ # undef __STDC_WANT_MATH_SPEC_FUNCS__ #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # undef _TANDEM_SOURCE #endif /* Enable X/Open extensions. Define to 500 only if necessary to make mbstate_t available. */ #ifndef _XOPEN_SOURCE # undef _XOPEN_SOURCE #endif /* Version number of package */ #undef VERSION /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ #undef _LARGEFILE_SOURCE /* Define for Solaris 2.5.1 so the uint32_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT32_T /* Define for Solaris 2.5.1 so the uint64_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT64_T /* Define for Solaris 2.5.1 so the uint8_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT8_T /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define to the type of a signed integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ #undef int64_t /* Define to rpl_malloc if the replacement function should be used. */ #undef malloc /* Define to `int' if does not define. */ #undef mode_t /* Define to `long int' if does not define. */ #undef off_t /* Define as a signed integer type capable of holding a process identifier. */ #undef pid_t /* Define to rpl_realloc if the replacement function should be used. */ #undef realloc /* Define to `unsigned int' if does not define. */ #undef size_t /* Define to `int' if does not define. */ #undef ssize_t /* Define to the type of an unsigned integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ #undef uint16_t /* Define to the type of an unsigned integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef uint32_t /* Define to the type of an unsigned integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ #undef uint64_t /* Define to the type of an unsigned integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ #undef uint8_t /* Define as `fork' if `vfork' does not work. */ #undef vfork #include "got_compat2.h" got-portable-0.101/include/got_patch.h0000644000175100017510000000303414644143163013347 /* * Copyright (c) 2022 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * A callback that gets invoked during the patch application. * * Receives the old and new path, a status code, if an error occurred while * applying the patch, and a hunk applied with offset or its error. */ typedef const struct got_error *(*got_patch_progress_cb)(void *, const char *, const char *, unsigned char, const struct got_error *, int, int, int, int, int, int, const struct got_error *); /* * Apply the (already opened) patch to the repository and register the * status of the added and removed files. * * The patch file descriptor *must* be seekable. */ const struct got_error * got_patch(int, struct got_worktree *, struct got_repository *, int, int, int, struct got_object_id *, got_patch_progress_cb, void *, got_cancel_cb, void *); got-portable-0.101/README0000664000175100017510000001474214644143163010475 Game of Trees (Got) is a version control system which prioritizes ease of use and simplicity over flexibility (https://gameoftrees.org) Got is still under development; it is being developed exclusively on OpenBSD and its target audience are OpenBSD developers. Got is ISC-licensed and was designed with pledge(2) and unveil(2) in mind. Got uses Git repositories to store versioned data. Git can be used for any functionality which has not yet been implemented in Got. It will always remain possible to work with both Got and Git on the same repository. A Got release tarball will install files under /usr/local by default. This default can be changed by passing PREFIX=/some/path to make. A build started in Got's Git repository will install files under ~/bin, which may have to be added to $PATH and be created first: $ mkdir ~/bin To compile the Got client tool suite on OpenBSD, run: $ make obj $ make $ make install This will install the following commands: got, the command line interface tog, an ncurses-based interactive Git repository browser several helper programs from the libexec directory man pages (only installed if building sources from a Got release tarball) Tests will pass only after 'make install' because they rely on installed binaries in $PATH. Any tests written as shell scripts also depend on git(1). Tests which use the got clone, fetch, and send commands will fail if 'ssh 127.0.0.1' does not succeed non-interactively. Tests for HTTP protocol support rely on the HTTP::Daemon Perl module. $ doas pkg_add git p5-http-daemon $ make regress To test with packed repositories, run: $ make regress GOT_TEST_PACK=1 To test with packed repositories using the ref-delta representation for deltified objects, run: $ make regress GOT_TEST_PACK=ref-delta Because got unveils the /tmp directory by default using the /tmp directory for test data can hide bugs. However, /tmp remains the default because there is no better alternative that works out of the box. In order to store test data in a directory other than /tmp, such as ~/got-test, run: $ mkdir ~/got-test $ make regress GOT_TEST_ROOT=~/got-test The tog automated test suite is also run with 'make regress'. Like Got, however, individual tests or the entire suite can be run: $ cd regress/tog $ make # run all tests $ ./log.sh # run log view tests Man page files in the Got source tree can be viewed with 'man -l': $ man -l got/got.1 $ man -l got/git-repository.5 $ man -l got/got-worktree.5 $ man -l tog/tog.1 EXAMPLES in got.1 contains a quick-start guide for OpenBSD developers. To compile the Got server tool suite on OpenBSD, run: $ make obj $ make server $ make server-install This will install the following commands: gotd, the repository server program gotctl, the server control utility gotsh, the login shell for users accessing the server via the network gitwrapper, like mailwrapper(8) but for git-upload-pack and git-receive-pack See the following manual page files for information about server setup: $ man -l gotd/gotd.8 $ man -l gotd/gotd.conf.5 $ man -l gotctl/gotctl.8 $ man -l gotsh/gotsh.1 $ man -l gitwrapper/gitwrapper.1 See regress/gotd/README for information about running the server test suite. Game of Trees Web Daemon (gotwebd) is a FastCGI program which displays repository data and is designed to work with httpd(8). To compile gotwebd on OpenBSD, run: $ make webd # make webd-install This will create the following files: the daemon program /usr/local/sbin/gotwebd css and image files in /var/www/htdocs/gotwebd the gotwebd init script in /etc/rc.d man pages (only installed if building sources from a Got release tarball) Documentation is available in manual pages: $ man -l gotwebd/gotwebd.8 $ man -l gotwebd/gotwebd.conf.5 Got can be built with profiling enabled to debug performance issues. Note that profiled builds cannot make use of pledge(2). Profiling should only be enabled for one program at a time. Otherwise, multiple programs will attempt to write to the 'gmon.out' file in the current working directory. For example, to compile got-read-pack with profiling enabled: $ cd libexec/got-read-pack $ make clean $ make PROFILE=1 $ make install Running any Got command which ends up using got-read-pack should now produce the file 'gmon.out' in the current working directory. The gprof2dot program can be used to generate a profile graph: $ doas pkg_add gprof2dot graphviz $ gprof ~/bin/got-read-pack gmon.out | gprof2dot | dot -T png > profile.png Guidelines for reporting problems: All problem/bug reports should include a reproduction recipe in form of a shell script which starts out with an empty repository and runs a series of Got and/or Git commands to trigger the problem, be it a crash or some other undesirable behaviour. The regress/cmdline directory contains plenty of example scripts. An ideal reproduction recipe is written as an xfail ("expected failure") regression test. For a real-world example of an xfail test, see commits 4866d0842a2b34812818685aaa31d3e0a966412d and 2b496619daecc1f25b1bc0c53e01685030dc2c74 in Got's history. Please take this request very seriously; Ask for help with writing your regression test before asking for your problem to be fixed. Time invested in writing a regression test saves time wasted on back-and-forth discussion about how the problem can be reproduced. A regression test will need to be written in any case to verify a fix and prevent the problem from resurfacing. It is also possible to write test cases in C. Various examples of this exist in the regress/ directory. Most such tests are unit tests; it is unlikely that a problem found during regular usage will require a test to be written in C. Please always try to find a way to trigger your problem via the command line interface before reporting a problem without a written test case included. If writing an automated test really turns out to be impossible, please explain in very clear terms how the problem can be reproduced. Mail problem reports to: gameoftrees@openbsd.org Guidelines for submitting patches: Mail patches to: gameoftrees@openbsd.org Pull requests via any Git hosting sites will likely be overlooked. Please keep the intended target audience in mind when contributing to Got. Subscribing to the gameoftrees@openbsd.org mailing list: The mailing list is used for patch reviews, bug reports, and user questions. To subscribe, send mail to majordomo@openbsd.org with a message body of: subscribe gameoftrees See https://www.openbsd.org/mail.html for more information. got-portable-0.101/Makefile.in0000664000175100017510000011007414644145543011661 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ # -portable: re-enable once upstream is happy: cvg # TODO: gotd gotsh template @CVG_ENABLED_TRUE@am__append_1 = cvg @HOST_FREEBSD_TRUE@am__append_2 = -lmd @HOST_FREEBSD_TRUE@am__append_3 = -lmd subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__configure_deps) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = Makefile.common CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir distdir-am dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` DIST_SUBDIRS = compat gitwrapper got gotadmin gotctl gotd gotsh \ gotwebd libexec template tog cvg am__DIST_COMMON = $(srcdir)/Makefile.common.in $(srcdir)/Makefile.in \ $(top_srcdir)/etc/ar-lib $(top_srcdir)/etc/compile \ $(top_srcdir)/etc/config.guess $(top_srcdir)/etc/config.sub \ $(top_srcdir)/etc/install-sh $(top_srcdir)/etc/missing \ $(top_srcdir)/include/got_compat.h.in README TODO etc/ar-lib \ etc/compile etc/config.guess etc/config.sub etc/depcomp \ etc/install-sh etc/missing etc/ylwrap DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip # Exists only to be overridden by the user if desired. AM_DISTCHECK_DVI_TARGET = dvi distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(libbsd_CFLAGS) $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ $(am__append_3) -lm $(zlib_LIBS) $(libbsd_LIBS) \ $(libmd_LIBS) LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ # When creating a distribution tarball, make sure we enable all current # configure flags so that no files are missing. This is irrespective of # whether the end-user will enable this; this step is here so that all the # relevant files are included in the distribution. AM_DISTCHECK_CONFIGURE_FLAGS = --enable-cvg SUBDIRS = compat gitwrapper got gotadmin gotctl gotd gotsh gotwebd \ libexec template tog $(am__append_1) EXTRA_DIST = CHANGES \ CHANGELOG \ LICENCE \ README.portable \ regress \ util/got-portable-ver.sh LDADD = $(LIBOBJS) $(am__append_2) TEST_TARGETS = compat regress-delta regress-deltify regress-fetch regress-idset \ regress-path regress-tog regress-cmdline GOT_TEST_ROOT = /tmp all: all-recursive .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): include/got_compat.h: include/stamp-h1 @test -f $@ || rm -f include/stamp-h1 @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) include/stamp-h1 include/stamp-h1: $(top_srcdir)/include/got_compat.h.in $(top_builddir)/config.status @rm -f include/stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status include/got_compat.h $(top_srcdir)/include/got_compat.h.in: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f include/stamp-h1 touch $@ distclean-hdr: -rm -f include/got_compat.h include/stamp-h1 Makefile.common: $(top_builddir)/config.status $(srcdir)/Makefile.common.in cd $(top_builddir) && $(SHELL) ./config.status $@ # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-zstd: distdir tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ *.tar.zst*) \ zstd -dc $(distdir).tar.zst | $(am__untar) ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build/sub \ && ../../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ dist-zstd distcheck distclean distclean-generic distclean-hdr \ distclean-tags distcleancheck distdir distuninstallcheck dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs installdirs-am \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am .PRECIOUS: Makefile include $(top_builddir)/Makefile.common .PHONY: compat compat: $(MAKE) -C compat tests: $(TEST_TARGETS) regress-cmdline: (export PLATFORM=@PLATFORM@; \ cd $(top_builddir)/regress/cmdline || exit $$?; \ ./checkout.sh -q -r "$(GOT_TEST_ROOT)"; \ ./update.sh -q -r "$(GOT_TEST_ROOT)"; \ ./status.sh -q -r "$(GOT_TEST_ROOT)"; \ ./log.sh -q -r "$(GOT_TEST_ROOT)"; \ ./add.sh -q -r "$(GOT_TEST_ROOT)"; \ ./rm.sh -q -r "$(GOT_TEST_ROOT)"; \ ./diff.sh -q -r "$(GOT_TEST_ROOT)"; \ ./blame.sh -q -r "$(GOT_TEST_ROOT)"; \ ./branch.sh -q -r "$(GOT_TEST_ROOT)"; \ ./tag.sh -q -r "$(GOT_TEST_ROOT)"; \ ./ref.sh -q -r "$(GOT_TEST_ROOT)"; \ ./commit.sh -q -r "$(GOT_TEST_ROOT)"; \ ./revert.sh -q -r "$(GOT_TEST_ROOT)"; \ ./cherrypick.sh -q -r "$(GOT_TEST_ROOT)"; \ ./backout.sh -q -r "$(GOT_TEST_ROOT)"; \ ./rebase.sh -q -r "$(GOT_TEST_ROOT)"; \ ./import.sh -q -r "$(GOT_TEST_ROOT)"; \ ./histedit.sh -q -r "$(GOT_TEST_ROOT)"; \ ./integrate.sh -q -r "$(GOT_TEST_ROOT)"; \ ./merge.sh -q -r "$(GOT_TEST_ROOT)"; \ ./stage.sh -q -r "$(GOT_TEST_ROOT)"; \ ./unstage.sh -q -r "$(GOT_TEST_ROOT)"; \ ./cat.sh -q -r "$(GOT_TEST_ROOT)"; \ ./clone.sh -q -r "$(GOT_TEST_ROOT)"; \ ./fetch.sh -q -r "$(GOT_TEST_ROOT)"; \ ./send.sh -q -r "$(GOT_TEST_ROOT)"; \ ./tree.sh -q -r "$(GOT_TEST_ROOT)"; \ ./patch.sh -q -r "$(GOT_TEST_ROOT)" \ ./pack.sh -q -r "$(GOT_TEST_ROOT)"; \ ./cleanup.sh -q -r "$(GOT_TEST_ROOT)") regress-delta: $(CC) $(DEFS) $(AM_CFLAGS) $(AM_CPPFLAGS) \ -o $(top_builddir)/regress/delta/delta_test \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/regress/delta/delta_test.c \ -L$(top_builddir)/compat -lopenbsd-compat $(LIBS) && \ $(top_builddir)/regress/delta/delta_test regress-deltify: $(CC) $(DEFS) $(AM_CFLAGS) $(AM_CPPFLAGS) \ -o $(top_builddir)/regress/deltify/deltify_test \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/regress/deltify/deltify_test.c \ -L$(top_builddir)/compat -lopenbsd-compat $(LIBS) && \ $(top_builddir)/regress/deltify/deltify_test regress-fetch: $(CC) $(DEFS) $(AM_CFLAGS) $(AM_CPPFLAGS) \ -o $(top_builddir)/regress/fetch/fetch_test \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fetch.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/regress/fetch/fetch_test.c \ -L$(top_builddir)/compat -lopenbsd-compat $(LIBS) -lm && \ $(top_builddir)/regress/fetch/fetch_test regress-idset: $(CC) $(DEFS) $(AM_CFLAGS) $(AM_CPPFLAGS) \ -o $(top_builddir)/regress/idset/idset_test \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fetch.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/regress/idset/idset_test.c \ -L$(top_builddir)/compat -lopenbsd-compat $(LIBS) && \ $(top_builddir)/regress/idset/idset_test regress-path: $(CC) $(DEFS) $(AM_CFLAGS) $(AM_CPPFLAGS) \ -o $(top_builddir)/regress/path/path_test \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fetch.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/regress/path/path_test.c \ -L$(top_builddir)/compat -lopenbsd-compat $(LIBS) && \ $(top_builddir)/regress/path/path_test regress-tog: (cd $(top_builddir)/regress/tog || exit $$?; \ ./log.sh -q -r "$(GOT_TEST_ROOT)"); # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/etc/0000775000175100017510000000000014644145570010444 5got-portable-0.101/etc/ar-lib0000755000175100017510000001336314644145543011464 #! /bin/sh # Wrapper for Microsoft lib.exe me=ar-lib scriptversion=2019-07-04.01; # UTC # Copyright (C) 2010-2021 Free Software Foundation, Inc. # Written by Peter Rosin . # # 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 # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . # func_error message func_error () { echo "$me: $1" 1>&2 exit 1 } file_conv= # func_file_conv build_file # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN* | MSYS*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv in mingw) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin | msys) file=`cygpath -m "$file" || echo "$file"` ;; wine) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_at_file at_file operation archive # Iterate over all members in AT_FILE performing OPERATION on ARCHIVE # for each of them. # When interpreting the content of the @FILE, do NOT use func_file_conv, # since the user would need to supply preconverted file names to # binutils ar, at least for MinGW. func_at_file () { operation=$2 archive=$3 at_file_contents=`cat "$1"` eval set x "$at_file_contents" shift for member do $AR -NOLOGO $operation:"$member" "$archive" || exit $? done } case $1 in '') func_error "no command. Try '$0 --help' for more information." ;; -h | --h*) cat <. # # 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 # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN* | MSYS*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/* | msys/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: got-portable-0.101/etc/config.sub0000755000175100017510000010511614644145543012351 #! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2022 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2022-01-03' # 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 # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. # 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="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2022 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." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. echo "$1" exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Split fields of configuration type # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read field1 field2 field3 field4 <&2 exit 1 ;; *-*-*-*) basic_machine=$field1-$field2 basic_os=$field3-$field4 ;; *-*-*) # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two # parts maybe_os=$field2-$field3 case $maybe_os in nto-qnx* | linux-* | uclinux-uclibc* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ | storm-chaos* | os2-emx* | rtmk-nova*) basic_machine=$field1 basic_os=$maybe_os ;; android-linux) basic_machine=$field1-unknown basic_os=linux-android ;; *) basic_machine=$field1-$field2 basic_os=$field3 ;; esac ;; *-*) # A lone config we happen to match not fitting any pattern case $field1-$field2 in decstation-3100) basic_machine=mips-dec basic_os= ;; *-*) # Second component is usually, but not always the OS case $field2 in # Prevent following clause from handling this valid os sun*os*) basic_machine=$field1 basic_os=$field2 ;; zephyr*) basic_machine=$field1-unknown basic_os=$field2 ;; # Manufacturers dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ | unicom* | ibm* | next | hp | isi* | apollo | altos* \ | convergent* | ncr* | news | 32* | 3600* | 3100* \ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ | ultra | tti* | harris | dolphin | highlevel | gould \ | cbm | ns | masscomp | apple | axis | knuth | cray \ | microblaze* | sim | cisco \ | oki | wec | wrs | winbond) basic_machine=$field1-$field2 basic_os= ;; *) basic_machine=$field1 basic_os=$field2 ;; esac ;; esac ;; *) # Convert single-component short-hands not valid as part of # multi-component configurations. case $field1 in 386bsd) basic_machine=i386-pc basic_os=bsd ;; a29khif) basic_machine=a29k-amd basic_os=udi ;; adobe68k) basic_machine=m68010-adobe basic_os=scout ;; alliant) basic_machine=fx80-alliant basic_os= ;; altos | altos3068) basic_machine=m68k-altos basic_os= ;; am29k) basic_machine=a29k-none basic_os=bsd ;; amdahl) basic_machine=580-amdahl basic_os=sysv ;; amiga) basic_machine=m68k-unknown basic_os= ;; amigaos | amigados) basic_machine=m68k-unknown basic_os=amigaos ;; amigaunix | amix) basic_machine=m68k-unknown basic_os=sysv4 ;; apollo68) basic_machine=m68k-apollo basic_os=sysv ;; apollo68bsd) basic_machine=m68k-apollo basic_os=bsd ;; aros) basic_machine=i386-pc basic_os=aros ;; aux) basic_machine=m68k-apple basic_os=aux ;; balance) basic_machine=ns32k-sequent basic_os=dynix ;; blackfin) basic_machine=bfin-unknown basic_os=linux ;; cegcc) basic_machine=arm-unknown basic_os=cegcc ;; convex-c1) basic_machine=c1-convex basic_os=bsd ;; convex-c2) basic_machine=c2-convex basic_os=bsd ;; convex-c32) basic_machine=c32-convex basic_os=bsd ;; convex-c34) basic_machine=c34-convex basic_os=bsd ;; convex-c38) basic_machine=c38-convex basic_os=bsd ;; cray) basic_machine=j90-cray basic_os=unicos ;; crds | unos) basic_machine=m68k-crds basic_os= ;; da30) basic_machine=m68k-da30 basic_os= ;; decstation | pmax | pmin | dec3100 | decstatn) basic_machine=mips-dec basic_os= ;; delta88) basic_machine=m88k-motorola basic_os=sysv3 ;; dicos) basic_machine=i686-pc basic_os=dicos ;; djgpp) basic_machine=i586-pc basic_os=msdosdjgpp ;; ebmon29k) basic_machine=a29k-amd basic_os=ebmon ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson basic_os=ose ;; gmicro) basic_machine=tron-gmicro basic_os=sysv ;; go32) basic_machine=i386-pc basic_os=go32 ;; h8300hms) basic_machine=h8300-hitachi basic_os=hms ;; h8300xray) basic_machine=h8300-hitachi basic_os=xray ;; h8500hms) basic_machine=h8500-hitachi basic_os=hms ;; harris) basic_machine=m88k-harris basic_os=sysv3 ;; hp300 | hp300hpux) basic_machine=m68k-hp basic_os=hpux ;; hp300bsd) basic_machine=m68k-hp basic_os=bsd ;; hppaosf) basic_machine=hppa1.1-hp basic_os=osf ;; hppro) basic_machine=hppa1.1-hp basic_os=proelf ;; i386mach) basic_machine=i386-mach basic_os=mach ;; isi68 | isi) basic_machine=m68k-isi basic_os=sysv ;; m68knommu) basic_machine=m68k-unknown basic_os=linux ;; magnum | m3230) basic_machine=mips-mips basic_os=sysv ;; merlin) basic_machine=ns32k-utek basic_os=sysv ;; mingw64) basic_machine=x86_64-pc basic_os=mingw64 ;; mingw32) basic_machine=i686-pc basic_os=mingw32 ;; mingw32ce) basic_machine=arm-unknown basic_os=mingw32ce ;; monitor) basic_machine=m68k-rom68k basic_os=coff ;; morphos) basic_machine=powerpc-unknown basic_os=morphos ;; moxiebox) basic_machine=moxie-unknown basic_os=moxiebox ;; msdos) basic_machine=i386-pc basic_os=msdos ;; msys) basic_machine=i686-pc basic_os=msys ;; mvs) basic_machine=i370-ibm basic_os=mvs ;; nacl) basic_machine=le32-unknown basic_os=nacl ;; ncr3000) basic_machine=i486-ncr basic_os=sysv4 ;; netbsd386) basic_machine=i386-pc basic_os=netbsd ;; netwinder) basic_machine=armv4l-rebel basic_os=linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony basic_os=newsos ;; news1000) basic_machine=m68030-sony basic_os=newsos ;; necv70) basic_machine=v70-nec basic_os=sysv ;; nh3000) basic_machine=m68k-harris basic_os=cxux ;; nh[45]000) basic_machine=m88k-harris basic_os=cxux ;; nindy960) basic_machine=i960-intel basic_os=nindy ;; mon960) basic_machine=i960-intel basic_os=mon960 ;; nonstopux) basic_machine=mips-compaq basic_os=nonstopux ;; os400) basic_machine=powerpc-ibm basic_os=os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson basic_os=ose ;; os68k) basic_machine=m68k-none basic_os=os68k ;; paragon) basic_machine=i860-intel basic_os=osf ;; parisc) basic_machine=hppa-unknown basic_os=linux ;; psp) basic_machine=mipsallegrexel-sony basic_os=psp ;; pw32) basic_machine=i586-unknown basic_os=pw32 ;; rdos | rdos64) basic_machine=x86_64-pc basic_os=rdos ;; rdos32) basic_machine=i386-pc basic_os=rdos ;; rom68k) basic_machine=m68k-rom68k basic_os=coff ;; sa29200) basic_machine=a29k-amd basic_os=udi ;; sei) basic_machine=mips-sei basic_os=seiux ;; sequent) basic_machine=i386-sequent basic_os= ;; sps7) basic_machine=m68k-bull basic_os=sysv2 ;; st2000) basic_machine=m68k-tandem basic_os= ;; stratus) basic_machine=i860-stratus basic_os=sysv4 ;; sun2) basic_machine=m68000-sun basic_os= ;; sun2os3) basic_machine=m68000-sun basic_os=sunos3 ;; sun2os4) basic_machine=m68000-sun basic_os=sunos4 ;; sun3) basic_machine=m68k-sun basic_os= ;; sun3os3) basic_machine=m68k-sun basic_os=sunos3 ;; sun3os4) basic_machine=m68k-sun basic_os=sunos4 ;; sun4) basic_machine=sparc-sun basic_os= ;; sun4os3) basic_machine=sparc-sun basic_os=sunos3 ;; sun4os4) basic_machine=sparc-sun basic_os=sunos4 ;; sun4sol2) basic_machine=sparc-sun basic_os=solaris2 ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun basic_os= ;; sv1) basic_machine=sv1-cray basic_os=unicos ;; symmetry) basic_machine=i386-sequent basic_os=dynix ;; t3e) basic_machine=alphaev5-cray basic_os=unicos ;; t90) basic_machine=t90-cray basic_os=unicos ;; toad1) basic_machine=pdp10-xkl basic_os=tops20 ;; tpf) basic_machine=s390x-ibm basic_os=tpf ;; udi29k) basic_machine=a29k-amd basic_os=udi ;; ultra3) basic_machine=a29k-nyu basic_os=sym1 ;; v810 | necv810) basic_machine=v810-nec basic_os=none ;; vaxv) basic_machine=vax-dec basic_os=sysv ;; vms) basic_machine=vax-dec basic_os=vms ;; vsta) basic_machine=i386-pc basic_os=vsta ;; vxworks960) basic_machine=i960-wrs basic_os=vxworks ;; vxworks68) basic_machine=m68k-wrs basic_os=vxworks ;; vxworks29k) basic_machine=a29k-wrs basic_os=vxworks ;; xbox) basic_machine=i686-pc basic_os=mingw32 ;; ymp) basic_machine=ymp-cray basic_os=unicos ;; *) basic_machine=$1 basic_os= ;; esac ;; esac # Decode 1-component or ad-hoc basic machines case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) cpu=hppa1.1 vendor=winbond ;; op50n) cpu=hppa1.1 vendor=oki ;; op60c) cpu=hppa1.1 vendor=oki ;; ibm*) cpu=i370 vendor=ibm ;; orion105) cpu=clipper vendor=highlevel ;; mac | mpw | mac-mpw) cpu=m68k vendor=apple ;; pmac | pmac-mpw) cpu=powerpc vendor=apple ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) cpu=m68000 vendor=att ;; 3b*) cpu=we32k vendor=att ;; bluegene*) cpu=powerpc vendor=ibm basic_os=cnk ;; decsystem10* | dec10*) cpu=pdp10 vendor=dec basic_os=tops10 ;; decsystem20* | dec20*) cpu=pdp10 vendor=dec basic_os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) cpu=m68k vendor=motorola ;; dpx2*) cpu=m68k vendor=bull basic_os=sysv3 ;; encore | umax | mmax) cpu=ns32k vendor=encore ;; elxsi) cpu=elxsi vendor=elxsi basic_os=${basic_os:-bsd} ;; fx2800) cpu=i860 vendor=alliant ;; genix) cpu=ns32k vendor=ns ;; h3050r* | hiux*) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) cpu=m68000 vendor=hp ;; hp9k3[2-9][0-9]) cpu=m68k vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) cpu=hppa1.1 vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; i*86v32) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv32 ;; i*86v4*) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv4 ;; i*86v) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv ;; i*86sol2) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=solaris2 ;; j90 | j90-cray) cpu=j90 vendor=cray basic_os=${basic_os:-unicos} ;; iris | iris4d) cpu=mips vendor=sgi case $basic_os in irix*) ;; *) basic_os=irix4 ;; esac ;; miniframe) cpu=m68000 vendor=convergent ;; *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) cpu=m68k vendor=atari basic_os=mint ;; news-3600 | risc-news) cpu=mips vendor=sony basic_os=newsos ;; next | m*-next) cpu=m68k vendor=next case $basic_os in openstep*) ;; nextstep*) ;; ns2*) basic_os=nextstep2 ;; *) basic_os=nextstep3 ;; esac ;; np1) cpu=np1 vendor=gould ;; op50n-* | op60c-*) cpu=hppa1.1 vendor=oki basic_os=proelf ;; pa-hitachi) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; pbd) cpu=sparc vendor=tti ;; pbb) cpu=m68k vendor=tti ;; pc532) cpu=ns32k vendor=pc532 ;; pn) cpu=pn vendor=gould ;; power) cpu=power vendor=ibm ;; ps2) cpu=i386 vendor=ibm ;; rm[46]00) cpu=mips vendor=siemens ;; rtpc | rtpc-*) cpu=romp vendor=ibm ;; sde) cpu=mipsisa32 vendor=sde basic_os=${basic_os:-elf} ;; simso-wrs) cpu=sparclite vendor=wrs basic_os=vxworks ;; tower | tower-32) cpu=m68k vendor=ncr ;; vpp*|vx|vx-*) cpu=f301 vendor=fujitsu ;; w65) cpu=w65 vendor=wdc ;; w89k-*) cpu=hppa1.1 vendor=winbond basic_os=proelf ;; none) cpu=none vendor=none ;; leon|leon[3-9]) cpu=sparc vendor=$basic_machine ;; leon-*|leon[3-9]-*) cpu=sparc vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read cpu vendor <&2 exit 1 ;; esac ;; esac # Here we canonicalize certain aliases for manufacturers. case $vendor in digital*) vendor=dec ;; commodore*) vendor=cbm ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if test x$basic_os != x then # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. case $basic_os in gnu/linux*) kernel=linux os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` ;; os2-emx) kernel=os2 os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` ;; nto-qnx*) kernel=nto os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read kernel os <&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* ) ;; uclinux-uclibc* ) ;; -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* ) # 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 ;; 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 $cpu-$os in *-riscix*) vendor=acorn ;; *-sunos*) vendor=sun ;; *-cnk* | *-aix*) vendor=ibm ;; *-beos*) vendor=be ;; *-hpux*) vendor=hp ;; *-mpeix*) vendor=hp ;; *-hiux*) vendor=hitachi ;; *-unos*) vendor=crds ;; *-dgux*) vendor=dg ;; *-luna*) vendor=omron ;; *-genix*) vendor=ns ;; *-clix*) vendor=intergraph ;; *-mvs* | *-opened*) vendor=ibm ;; *-os400*) vendor=ibm ;; s390-* | s390x-*) vendor=ibm ;; *-ptx*) vendor=sequent ;; *-tpf*) vendor=ibm ;; *-vxsim* | *-vxworks* | *-windiss*) vendor=wrs ;; *-aux*) vendor=apple ;; *-hms*) vendor=hitachi ;; *-mpw* | *-macos*) vendor=apple ;; *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) vendor=atari ;; *-vos*) vendor=stratus ;; esac ;; esac echo "$cpu-$vendor-${kernel:+$kernel-}$os" exit # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: got-portable-0.101/etc/missing0000755000175100017510000001533614644145543011771 #! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1996-2021 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # 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 # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=https://www.perl.org/ flex_URL=https://github.com/westes/flex gnu_software_URL=https://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: got-portable-0.101/etc/depcomp0000755000175100017510000005602014644145544011743 #! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2018-03-07.03; # UTC # Copyright (C) 1999-2021 Free Software Foundation, Inc. # 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 # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: got-portable-0.101/etc/install-sh0000755000175100017510000003577614644145543012410 #!/bin/sh # install - install a program, script, or datafile scriptversion=2020-11-14.01; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. tab=' ' nl=' ' IFS=" $tab$nl" # Set DOITPROG to "echo" to test this script. doit=${DOITPROG-} doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_mkdir= # Desired mode of installed file. mode=0755 # Create dirs (including intermediate dirs) using mode 755. # This is like GNU 'install' as of coreutils 8.32 (2020). mkdir_umask=22 backupsuffix= chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -p pass -p to $cpprog. -s $stripprog installed files. -S SUFFIX attempt to back up existing files, with suffix SUFFIX. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG By default, rm is invoked with -f; when overridden with RMPROG, it's up to you to specify -f if you want it. If -S is not specified, no backups are attempted. Email bug reports to bug-automake@gnu.org. Automake home page: https://www.gnu.org/software/automake/ " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -p) cpprog="$cpprog -p";; -s) stripcmd=$stripprog;; -S) backupsuffix="$2" shift;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? # Don't chown directories that already exist. if test $dstdir_status = 0; then chowncmd="" fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dstbase=`basename "$src"` case $dst in */) dst=$dst$dstbase;; *) dst=$dst/$dstbase;; esac dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi case $dstdir in */) dstdirslash=$dstdir;; *) dstdirslash=$dstdir/;; esac obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false # The $RANDOM variable is not portable (e.g., dash). Use it # here however when possible just to lower collision chance. tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap ' ret=$? rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null exit $ret ' 0 # Because "mkdir -p" follows existing symlinks and we likely work # directly in world-writeable /tmp, make sure that the '$tmpdir' # directory is successfully created first before we actually test # 'mkdir -p'. if (umask $mkdir_umask && $mkdirprog $mkdir_mode "$tmpdir" && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. test_tmpdir="$tmpdir/a" ls_ld_tmpdir=`ls -ld "$test_tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi trap '' 0;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac oIFS=$IFS IFS=/ set -f set fnord $dstdir shift set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=${dstdirslash}_inst.$$_ rmtmp=${dstdirslash}_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && { test -z "$stripcmd" || { # Create $dsttmp read-write so that cp doesn't create it read-only, # which would cause strip to fail. if test -z "$doit"; then : >"$dsttmp" # No need to fork-exec 'touch'. else $doit touch "$dsttmp" fi } } && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # If $backupsuffix is set, and the file being installed # already exists, attempt a backup. Don't worry if it fails, # e.g., if mv doesn't support -f. if test -n "$backupsuffix" && test -f "$dst"; then $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null fi # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: got-portable-0.101/etc/config.guess0000755000175100017510000014051214644145543012705 #! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2022 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2022-01-09' # 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 # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # 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/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="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2022 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." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 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 # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. tmp= # shellcheck disable=SC2172 trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 set_cc_for_build() { # prevent multiple calls if $tmp is already set test "$tmp" && return 0 : "${TMPDIR=/tmp}" # 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 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } dummy=$tmp/dummy case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in ,,) 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 break fi done if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac } # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH 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_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case $UNAME_SYSTEM in Linux|GNU|GNU/*) LIBC=unknown set_cc_for_build cat <<-EOF > "$dummy.c" #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #elif defined(__GLIBC__) LIBC=gnu #else #include /* First heuristic to detect musl libc. */ #ifdef __DEFINED_va_list LIBC=musl #endif #endif EOF cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` eval "$cc_set_libc" # 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 *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". UNAME_MACHINE_ARCH=`(uname -p 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 aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; 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=$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 earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case $UNAME_MACHINE_ARCH in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # 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 Debian*) release='-gnu' ;; *) release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. GUESS=$machine-${os}${release}${abi-} ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` 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\.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE ;; *:MidnightBSD:*:*) GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE ;; *:ekkoBSD:*:*) GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE ;; *:SolidBSD:*:*) GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE ;; *:OS108:*:*) GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE ;; macppc:MirBSD:*:*) GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE ;; *:MirBSD:*:*) GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE ;; *:Sortix:*:*) GUESS=$UNAME_MACHINE-unknown-sortix ;; *:Twizzler:*:*) GUESS=$UNAME_MACHINE-unknown-twizzler ;; *:Redox:*:*) GUESS=$UNAME_MACHINE-unknown-redox ;; mips:OSF1:*.*) 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}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # 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 "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # 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. 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:*) GUESS=m68k-unknown-sysv4 ;; *:[Aa]miga[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-amigaos ;; *:[Mm]orph[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-morphos ;; *:OS/390:*:*) GUESS=i370-ibm-openedition ;; *:z/VM:*:*) GUESS=s390-ibm-zvmoe ;; *:OS400:*:*) GUESS=powerpc-ibm-os400 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) GUESS=arm-acorn-riscix$UNAME_RELEASE ;; arm*:riscos:*:*|arm*:RISCOS:*:*) GUESS=arm-unknown-riscos ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) 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. case `(/bin/universe) 2>/dev/null` in att) GUESS=pyramid-pyramid-sysv3 ;; *) GUESS=pyramid-pyramid-bsd ;; esac ;; NILE*:*:*:dcosx) GUESS=pyramid-pyramid-svr4 ;; DRS?6000:unix:4.0:6*) GUESS=sparc-icl-nx6 ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) GUESS=sparc-icl-nx7 ;; esac ;; s390x:SunOS:*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL ;; sun4H:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-hal-solaris2$SUN_REL ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris2$SUN_REL ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) 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 test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi 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. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris3$SUN_REL ;; sun4*:SunOS:*:*) 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'. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` GUESS=sparc-sun-sunos$SUN_REL ;; sun3*:SunOS:*:*) 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 sun3) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun4) GUESS=sparc-sun-sunos$UNAME_RELEASE ;; esac ;; aushp:SunOS:*:*) 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 # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) GUESS=m68k-milan-mint$UNAME_RELEASE ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) GUESS=m68k-hades-mint$UNAME_RELEASE ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) GUESS=m68k-unknown-mint$UNAME_RELEASE ;; m68k:machten:*:*) GUESS=m68k-apple-machten$UNAME_RELEASE ;; powerpc:machten:*:*) GUESS=powerpc-apple-machten$UNAME_RELEASE ;; RISC*:Mach:*:*) GUESS=mips-dec-mach_bsd4.3 ;; RISC*:ULTRIX:*:*) GUESS=mips-dec-ultrix$UNAME_RELEASE ;; VAX*:ULTRIX*:*:*) GUESS=vax-dec-ultrix$UNAME_RELEASE ;; 2020:CLIX:*:* | 2430:CLIX:*:*) GUESS=clipper-intergraph-clix$UNAME_RELEASE ;; mips:*:*:UMIPS | mips:*:*:RISCos) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } GUESS=mips-mips-riscos$UNAME_RELEASE ;; Motorola:PowerMAX_OS:*:*) GUESS=powerpc-motorola-powermax ;; Motorola:*:4.3:PL8-*) GUESS=powerpc-harris-powermax ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) GUESS=powerpc-harris-powermax ;; Night_Hawk:Power_UNIX:*:*) GUESS=powerpc-harris-powerunix ;; m88k:CX/UX:7*:*) GUESS=m88k-harris-cxux7 ;; m88k:*:4*:R4*) GUESS=m88k-motorola-sysv4 ;; m88k:*:3*:R3*) GUESS=m88k-motorola-sysv3 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ test "$TARGET_BINARY_INTERFACE"x = x then GUESS=m88k-dg-dgux$UNAME_RELEASE else GUESS=m88k-dg-dguxbcs$UNAME_RELEASE fi else GUESS=i586-dg-dgux$UNAME_RELEASE fi ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) GUESS=m88k-dolphin-sysv3 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 GUESS=m88k-motorola-sysv3 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) GUESS=m88k-tektronix-sysv3 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) GUESS=m68k-tektronix-bsd ;; *:IRIX*:*:*) 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. GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) GUESS=i386-ibm-aix ;; ia64:AIX:*:*) if test -x /usr/bin/oslevel ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi 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 sed 's/^ //' << EOF > "$dummy.c" #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then GUESS=$SYSTEM_NAME else GUESS=rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then GUESS=rs6000-ibm-aix3.2.4 else GUESS=rs6000-ibm-aix3.2 fi ;; *: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 IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi 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 fi GUESS=$IBM_ARCH-ibm-aix$IBM_REV ;; *:AIX:*:*) GUESS=rs6000-ibm-aix ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) GUESS=romp-ibm-bsd4.4 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) GUESS=rs6000-bull-bosx ;; DPX/2?00:B.O.S.:*:*) GUESS=m68k-bull-sysv3 ;; 9000/[34]??:4.3bsd:1.*:*) GUESS=m68k-hp-bsd ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) GUESS=m68k-hp-bsd4.4 ;; 9000/[34678]??:HP-UX:*:*) 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 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 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 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if test "$HP_ARCH" = ""; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if test "$HP_ARCH" = hppa2.0w then set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi GUESS=$HP_ARCH-hp-hpux$HPUX_REV ;; ia64:HP-UX:*:*) 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" #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } GUESS=unknown-hitachi-hiuxwe2 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) GUESS=hppa1.1-hp-bsd ;; 9000/8??:4.3bsd:*:*) GUESS=hppa1.0-hp-bsd ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) GUESS=hppa1.0-hp-mpeix ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) GUESS=hppa1.1-hp-osf ;; hp8??:OSF1:*:*) GUESS=hppa1.0-hp-osf ;; i*86:OSF1:*:*) if test -x /usr/sbin/sysversion ; then GUESS=$UNAME_MACHINE-unknown-osf1mk else GUESS=$UNAME_MACHINE-unknown-osf1 fi ;; parisc*:Lites*:*:*) GUESS=hppa1.1-hp-lites ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) GUESS=c1-convex-bsd ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) GUESS=c34-convex-bsd ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) GUESS=c38-convex-bsd ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) GUESS=c4-convex-bsd ;; CRAY*Y-MP:*:*:*) 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/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=t90-cray-unicos$CRAY_REL ;; CRAY*T3E:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=alphaev5-cray-unicosmk$CRAY_REL ;; CRAY*SV1:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=sv1-cray-unicos$CRAY_REL ;; *:UNICOS/mp:*:*) 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/ /_/'` 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/ /_/'` GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE ;; sparc*:BSD/OS:*:*) GUESS=sparc-unknown-bsdi$UNAME_RELEASE ;; *:BSD/OS:*:*) 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 FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi else FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf fi ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case $UNAME_PROCESSOR in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL ;; i*:CYGWIN*:*) GUESS=$UNAME_MACHINE-pc-cygwin ;; *:MINGW64*:*) GUESS=$UNAME_MACHINE-pc-mingw64 ;; *:MINGW*:*) GUESS=$UNAME_MACHINE-pc-mingw32 ;; *:MSYS*:*) GUESS=$UNAME_MACHINE-pc-msys ;; i*:PW*:*) GUESS=$UNAME_MACHINE-pc-pw32 ;; *:SerenityOS:*:*) GUESS=$UNAME_MACHINE-pc-serenity ;; *:Interix*:*) case $UNAME_MACHINE in x86) GUESS=i586-pc-interix$UNAME_RELEASE ;; authenticamd | genuineintel | EM64T) GUESS=x86_64-unknown-interix$UNAME_RELEASE ;; IA64) GUESS=ia64-unknown-interix$UNAME_RELEASE ;; esac ;; i*:UWIN*:*) GUESS=$UNAME_MACHINE-pc-uwin ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) GUESS=x86_64-pc-cygwin ;; prep*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=powerpcle-unknown-solaris2$SUN_REL ;; *:GNU:*:*) # the GNU system 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 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 ;; *:Minix:*:*) GUESS=$UNAME_MACHINE-unknown-minix ;; aarch64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be 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 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi 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 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 GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi else GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf fi fi ;; avr32*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; cris:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; crisv32:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; e2k:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; frv:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; hexagon:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:Linux:*:*) GUESS=$UNAME_MACHINE-pc-linux-$LIBC ;; ia64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; k1om:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m32r*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m68*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; mips:Linux:*:* | mips64:Linux:*:*) set_cc_for_build IS_GLIBC=0 test x"${LIBC}" = xgnu && IS_GLIBC=1 sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef mips #undef mipsel #undef mips64 #undef mips64el #if ${IS_GLIBC} && defined(_ABI64) LIBCABI=gnuabi64 #else #if ${IS_GLIBC} && defined(_ABIN32) LIBCABI=gnuabin32 #else LIBCABI=${LIBC} #endif #endif #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa64r6 #else #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa32r6 #else #if defined(__mips64) CPU=mips64 #else CPU=mips #endif #endif #endif #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) MIPS_ENDIAN=el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) MIPS_ENDIAN= #else MIPS_ENDIAN= #endif #endif EOF 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:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; openrisc*:Linux:*:*) GUESS=or1k-unknown-linux-$LIBC ;; or32:Linux:*:* | or1k*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; padre:Linux:*:*) GUESS=sparc-unknown-linux-$LIBC ;; parisc64:Linux:*:* | hppa64:Linux:*:*) 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*) GUESS=hppa1.1-unknown-linux-$LIBC ;; PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; *) GUESS=hppa-unknown-linux-$LIBC ;; esac ;; ppc64:Linux:*:*) GUESS=powerpc64-unknown-linux-$LIBC ;; ppc:Linux:*:*) GUESS=powerpc-unknown-linux-$LIBC ;; ppc64le:Linux:*:*) GUESS=powerpc64le-unknown-linux-$LIBC ;; ppcle:Linux:*:*) GUESS=powerpcle-unknown-linux-$LIBC ;; riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; s390:Linux:*:* | s390x:Linux:*:*) GUESS=$UNAME_MACHINE-ibm-linux-$LIBC ;; sh64*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sh*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sparc:Linux:*:* | sparc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; tile*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; vax:Linux:*:*) GUESS=$UNAME_MACHINE-dec-linux-$LIBC ;; x86_64:Linux:*:*) set_cc_for_build LIBCABI=$LIBC if test "$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 fi GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI ;; xtensa*:Linux:*:*) 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. 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. 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. GUESS=$UNAME_MACHINE-pc-os2-emx ;; i*86:XTS-300:*:STOP) GUESS=$UNAME_MACHINE-unknown-stop ;; i*86:atheos:*:*) GUESS=$UNAME_MACHINE-unknown-atheos ;; i*86:syllable:*:*) GUESS=$UNAME_MACHINE-pc-syllable ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) GUESS=i386-unknown-lynxos$UNAME_RELEASE ;; i*86:*DOS:*:*) 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 GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL fi ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac 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 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv32 fi ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # 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. GUESS=i586-pc-msdosdjgpp ;; Intel:Mach:3*:*) GUESS=i386-pc-mach3 ;; paragon:*:*:*) GUESS=i860-intel-osf1 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 fi ;; mini*:CTIX:SYS*5:*) # "miniframe" GUESS=m68010-convergent-sysv ;; mc68k:UNIX:SYSTEM5:3.51m) GUESS=m68k-convergent-sysv ;; M680?0:D-NIX:5.3:*) 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) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /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*:*) GUESS=m68k-unknown-lynxos$UNAME_RELEASE ;; mc68030:UNIX_System_V:4.*:*) GUESS=m68k-atari-sysv4 ;; TSUNAMI:LynxOS:2.*:*) GUESS=sparc-unknown-lynxos$UNAME_RELEASE ;; rs6000:LynxOS:2.*:*) GUESS=rs6000-unknown-lynxos$UNAME_RELEASE ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) GUESS=powerpc-unknown-lynxos$UNAME_RELEASE ;; SM[BE]S:UNIX_SV:*:*) GUESS=mips-dde-sysv$UNAME_RELEASE ;; RM*:ReliantUNIX-*:*:*) GUESS=mips-sni-sysv4 ;; RM*:SINIX-*:*:*) GUESS=mips-sni-sysv4 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` GUESS=$UNAME_MACHINE-sni-sysv4 else GUESS=ns32k-sni-sysv fi ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says GUESS=i586-unisys-sysv4 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm GUESS=hppa1.1-stratus-sysv4 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. GUESS=i860-stratus-sysv4 ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. GUESS=$UNAME_MACHINE-stratus-vos ;; *:VOS:*:*) # From Paul.Green@stratus.com. GUESS=hppa1.1-stratus-vos ;; mc68*:A/UX:*:*) GUESS=m68k-apple-aux$UNAME_RELEASE ;; news*:NEWS-OS:6*:*) GUESS=mips-sony-newsos6 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if test -d /usr/nec; then GUESS=mips-nec-sysv$UNAME_RELEASE else GUESS=mips-unknown-sysv$UNAME_RELEASE fi ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. GUESS=powerpc-be-beos ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. GUESS=powerpc-apple-beos ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. GUESS=i586-pc-beos ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. GUESS=i586-pc-haiku ;; x86_64:Haiku:*:*) GUESS=x86_64-unknown-haiku ;; SX-4:SUPER-UX:*:*) GUESS=sx4-nec-superux$UNAME_RELEASE ;; SX-5:SUPER-UX:*:*) GUESS=sx5-nec-superux$UNAME_RELEASE ;; SX-6:SUPER-UX:*:*) GUESS=sx6-nec-superux$UNAME_RELEASE ;; SX-7:SUPER-UX:*:*) GUESS=sx7-nec-superux$UNAME_RELEASE ;; SX-8:SUPER-UX:*:*) GUESS=sx8-nec-superux$UNAME_RELEASE ;; SX-8R:SUPER-UX:*:*) GUESS=sx8r-nec-superux$UNAME_RELEASE ;; SX-ACE:SUPER-UX:*:*) GUESS=sxace-nec-superux$UNAME_RELEASE ;; Power*:Rhapsody:*:*) GUESS=powerpc-apple-rhapsody$UNAME_RELEASE ;; *:Rhapsody:*:*) GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE ;; arm64:Darwin:*:*) GUESS=aarch64-apple-darwin$UNAME_RELEASE ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac if command -v xcode-select > /dev/null 2> /dev/null && \ ! xcode-select --print-path > /dev/null 2> /dev/null ; then # Avoid executing cc if there is no toolchain installed as # cc will be a stub that puts up a graphical alert # prompting the user to install developer tools. CC_FOR_BUILD=no_compiler_found else set_cc_for_build fi 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 then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc fi elif test "$UNAME_PROCESSOR" = i386 ; then # uname -m returns i386 or x86_64 UNAME_PROCESSOR=$UNAME_MACHINE fi 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 GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE ;; *:QNX:*:4*) GUESS=i386-pc-qnx ;; NEO-*:NONSTOP_KERNEL:*:*) GUESS=neo-tandem-nsk$UNAME_RELEASE ;; NSE-*:NONSTOP_KERNEL:*:*) GUESS=nse-tandem-nsk$UNAME_RELEASE ;; NSR-*:NONSTOP_KERNEL:*:*) GUESS=nsr-tandem-nsk$UNAME_RELEASE ;; NSV-*:NONSTOP_KERNEL:*:*) GUESS=nsv-tandem-nsk$UNAME_RELEASE ;; NSX-*:NONSTOP_KERNEL:*:*) GUESS=nsx-tandem-nsk$UNAME_RELEASE ;; *:NonStop-UX:*:*) GUESS=mips-compaq-nonstopux ;; BS2000:POSIX*:*:*) GUESS=bs2000-siemens-sysv ;; DS/*:UNIX_System_V:*:*) 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. if test "${cputype-}" = 386; then UNAME_MACHINE=i386 elif test "x${cputype-}" != x; then UNAME_MACHINE=$cputype fi GUESS=$UNAME_MACHINE-unknown-plan9 ;; *:TOPS-10:*:*) GUESS=pdp10-unknown-tops10 ;; *:TENEX:*:*) GUESS=pdp10-unknown-tenex ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) GUESS=pdp10-dec-tops20 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) GUESS=pdp10-xkl-tops20 ;; *:TOPS-20:*:*) GUESS=pdp10-unknown-tops20 ;; *:ITS:*:*) GUESS=pdp10-unknown-its ;; SEI:*:*:SEIUX) GUESS=mips-sei-seiux$UNAME_RELEASE ;; *:DragonFly:*:*) 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*) GUESS=alpha-dec-vms ;; I*) GUESS=ia64-dec-vms ;; V*) GUESS=vax-dec-vms ;; esac ;; *:XENIX:*:SysV) GUESS=i386-pc-xenix ;; i*86:skyos:*:*) SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL ;; i*86:rdos:*:*) GUESS=$UNAME_MACHINE-pc-rdos ;; i*86:Fiwix:*:*) GUESS=$UNAME_MACHINE-pc-fiwix ;; *:AROS:*:*) GUESS=$UNAME_MACHINE-unknown-aros ;; x86_64:VMkernel:*:*) GUESS=$UNAME_MACHINE-unknown-esx ;; amd64:Isilon\ OneFS:*:*) GUESS=x86_64-unknown-onefs ;; *:Unleashed:*:*) 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" < #include #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #include #if defined(_SIZE_T_) || defined(SIGLOST) #include #endif #endif #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) #if !defined (ultrix) #include #if defined (BSD) #if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); #else #if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); #else printf ("vax-dec-bsd\n"); exit (0); #endif #endif #else printf ("vax-dec-bsd\n"); exit (0); #endif #else #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname un; uname (&un); printf ("vax-dec-ultrix%s\n", un.release); exit (0); #else printf ("vax-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname *un; uname (&un); printf ("mips-dec-ultrix%s\n", un.release); exit (0); #else printf ("mips-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $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. test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } echo "$0: unable to guess system type" >&2 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 </dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" UNAME_SYSTEM = "$UNAME_SYSTEM" UNAME_VERSION = "$UNAME_VERSION" EOF fi exit 1 # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: got-portable-0.101/etc/ylwrap0000755000175100017510000001531414644145543011632 #! /bin/sh # ylwrap - wrapper for lex/yacc invocations. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1996-2021 Free Software Foundation, Inc. # # Written by Tom Tromey . # # 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 # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . get_dirname () { case $1 in */*|*\\*) printf '%s\n' "$1" | sed -e 's|\([\\/]\)[^\\/]*$|\1|';; # Otherwise, we want the empty string (not "."). esac } # guard FILE # ---------- # The CPP macro used to guard inclusion of FILE. guard () { printf '%s\n' "$1" \ | sed \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g' \ -e 's/__*/_/g' } # quote_for_sed [STRING] # ---------------------- # Return STRING (or stdin) quoted to be used as a sed pattern. quote_for_sed () { case $# in 0) cat;; 1) printf '%s\n' "$1";; esac \ | sed -e 's|[][\\.*]|\\&|g' } case "$1" in '') echo "$0: No files given. Try '$0 --help' for more information." 1>&2 exit 1 ;; --basedir) basedir=$2 shift 2 ;; -h|--h*) cat <<\EOF Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]... Wrapper for lex/yacc invocations, renaming files as desired. INPUT is the input file OUTPUT is one file PROG generates DESIRED is the file we actually want instead of OUTPUT PROGRAM is program to run ARGS are passed to PROG Any number of OUTPUT,DESIRED pairs may be used. Report bugs to . EOF exit $? ;; -v|--v*) echo "ylwrap $scriptversion" exit $? ;; esac # The input. input=$1 shift # We'll later need for a correct munging of "#line" directives. input_sub_rx=`get_dirname "$input" | quote_for_sed` case $input in [\\/]* | ?:[\\/]*) # Absolute path; do nothing. ;; *) # Relative path. Make it absolute. input=`pwd`/$input ;; esac input_rx=`get_dirname "$input" | quote_for_sed` # Since DOS filename conventions don't allow two dots, # the DOS version of Bison writes out y_tab.c instead of y.tab.c # and y_tab.h instead of y.tab.h. Test to see if this is the case. y_tab_nodot=false if test -f y_tab.c || test -f y_tab.h; then y_tab_nodot=true fi # The parser itself, the first file, is the destination of the .y.c # rule in the Makefile. parser=$1 # A sed program to s/FROM/TO/g for all the FROM/TO so that, for # instance, we rename #include "y.tab.h" into #include "parse.h" # during the conversion from y.tab.c to parse.c. sed_fix_filenames= # Also rename header guards, as Bison 2.7 for instance uses its header # guard in its implementation file. sed_fix_header_guards= while test $# -ne 0; do if test x"$1" = x"--"; then shift break fi from=$1 # Handle y_tab.c and y_tab.h output by DOS if $y_tab_nodot; then case $from in "y.tab.c") from=y_tab.c;; "y.tab.h") from=y_tab.h;; esac fi shift to=$1 shift sed_fix_filenames="${sed_fix_filenames}s|"`quote_for_sed "$from"`"|$to|g;" sed_fix_header_guards="${sed_fix_header_guards}s|"`guard "$from"`"|"`guard "$to"`"|g;" done # The program to run. prog=$1 shift # Make any relative path in $prog absolute. case $prog in [\\/]* | ?:[\\/]*) ;; *[\\/]*) prog=`pwd`/$prog ;; esac dirname=ylwrap$$ do_exit="cd '`pwd`' && rm -rf $dirname > /dev/null 2>&1;"' (exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 mkdir $dirname || exit 1 cd $dirname case $# in 0) "$prog" "$input" ;; *) "$prog" "$@" "$input" ;; esac ret=$? if test $ret -eq 0; then for from in * do to=`printf '%s\n' "$from" | sed "$sed_fix_filenames"` if test -f "$from"; then # If $2 is an absolute path name, then just use that, # otherwise prepend '../'. case $to in [\\/]* | ?:[\\/]*) target=$to;; *) target=../$to;; esac # Do not overwrite unchanged header files to avoid useless # recompilations. Always update the parser itself: it is the # destination of the .y.c rule in the Makefile. Divert the # output of all other files to a temporary file so we can # compare them to existing versions. if test $from != $parser; then realtarget=$target target=tmp-`printf '%s\n' "$target" | sed 's|.*[\\/]||g'` fi # Munge "#line" or "#" directives. Don't let the resulting # debug information point at an absolute srcdir. Use the real # output file name, not yy.lex.c for instance. Adjust the # include guards too. sed -e "/^#/!b" \ -e "s|$input_rx|$input_sub_rx|" \ -e "$sed_fix_filenames" \ -e "$sed_fix_header_guards" \ "$from" >"$target" || ret=$? # Check whether files must be updated. if test "$from" != "$parser"; then if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then echo "$to is unchanged" rm -f "$target" else echo "updating $to" mv -f "$target" "$realtarget" fi fi else # A missing file is only an error for the parser. This is a # blatant hack to let us support using "yacc -d". If -d is not # specified, don't fail when the header file is "missing". if test "$from" = "$parser"; then ret=1 fi fi done fi # Remove the directory. cd .. rm -rf $dirname exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: got-portable-0.101/tog/0000775000175100017510000000000014644145571010463 5got-portable-0.101/tog/Makefile.am0000664000175100017510000000422014644144735012436 bin_PROGRAMS = tog include $(top_builddir)/Makefile.common tog_SOURCES = tog.c \ $(top_srcdir)/lib/blame.c \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/commit_graph.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/diff.c \ $(top_srcdir)/lib/diff3.c \ $(top_srcdir)/lib/diff_atomize_text.c \ $(top_srcdir)/lib/diff_main.c \ $(top_srcdir)/lib/diff_myers.c \ $(top_srcdir)/lib/diff_output.c \ $(top_srcdir)/lib/diff_output_edscript.c \ $(top_srcdir)/lib/diff_output_plain.c \ $(top_srcdir)/lib/diff_output_unidiff.c \ $(top_srcdir)/lib/diff_patience.c \ $(top_srcdir)/lib/diffreg.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fetch.c \ $(top_srcdir)/lib/fileindex.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/keyword.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/rcsutil.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/lib/utf8.c \ $(top_srcdir)/lib/worktree.c \ $(top_srcdir)/lib/worktree_open.c tog_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a man1_MANS = tog.1 EXTRA_DIST = tog.1 LDADD = -L$(top_builddir)/compat -lopenbsd-compat -lpthread -lm LDADD += $(libbsd_LIBS) $(libncurses_LIBS) $(libuuid_LIBS) $(zlib_LIBS) \ $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(libbsd_CFLAGS) $(libncurses_CFLAGS) $(libuuid_CFLAGS) \ $(libmd_CFLAGS) got-portable-0.101/tog/tog.c0000664000175100017510000074247114644144735011360 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #if defined(__FreeBSD__) || defined(__APPLE__) #define _XOPEN_SOURCE_EXTENDED /* for ncurses wide-character functions */ #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_version.h" #include "got_error.h" #include "got_object.h" #include "got_reference.h" #include "got_repository.h" #include "got_diff.h" #include "got_opentemp.h" #include "got_utf8.h" #include "got_cancel.h" #include "got_commit_graph.h" #include "got_blame.h" #include "got_privsep.h" #include "got_path.h" #include "got_worktree.h" #include "got_keyword.h" #ifndef MIN #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) #endif #ifndef MAX #define MAX(_a,_b) ((_a) > (_b) ? (_a) : (_b)) #endif #ifndef CTRL #define CTRL(x) ((x) & 0x1f) #endif #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif struct tog_cmd { const char *name; const struct got_error *(*cmd_main)(int, char *[]); void (*cmd_usage)(void); }; __dead static void usage(int, int); __dead static void usage_log(void); __dead static void usage_diff(void); __dead static void usage_blame(void); __dead static void usage_tree(void); __dead static void usage_ref(void); static const struct got_error* cmd_log(int, char *[]); static const struct got_error* cmd_diff(int, char *[]); static const struct got_error* cmd_blame(int, char *[]); static const struct got_error* cmd_tree(int, char *[]); static const struct got_error* cmd_ref(int, char *[]); static const struct tog_cmd tog_commands[] = { { "log", cmd_log, usage_log }, { "diff", cmd_diff, usage_diff }, { "blame", cmd_blame, usage_blame }, { "tree", cmd_tree, usage_tree }, { "ref", cmd_ref, usage_ref }, }; enum tog_view_type { TOG_VIEW_DIFF, TOG_VIEW_LOG, TOG_VIEW_BLAME, TOG_VIEW_TREE, TOG_VIEW_REF, TOG_VIEW_HELP }; /* Match _DIFF to _HELP with enum tog_view_type TOG_VIEW_* counterparts. */ enum tog_keymap_type { TOG_KEYMAP_KEYS = -2, TOG_KEYMAP_GLOBAL, TOG_KEYMAP_DIFF, TOG_KEYMAP_LOG, TOG_KEYMAP_BLAME, TOG_KEYMAP_TREE, TOG_KEYMAP_REF, TOG_KEYMAP_HELP }; enum tog_view_mode { TOG_VIEW_SPLIT_NONE, TOG_VIEW_SPLIT_VERT, TOG_VIEW_SPLIT_HRZN }; #define HSPLIT_SCALE 0.3f /* default horizontal split scale */ #define TOG_EOF_STRING "(END)" struct commit_queue_entry { TAILQ_ENTRY(commit_queue_entry) entry; struct got_object_id *id; struct got_commit_object *commit; int idx; }; TAILQ_HEAD(commit_queue_head, commit_queue_entry); struct commit_queue { int ncommits; struct commit_queue_head head; }; struct tog_color { STAILQ_ENTRY(tog_color) entry; regex_t regex; short colorpair; }; STAILQ_HEAD(tog_colors, tog_color); static struct got_reflist_head tog_refs = TAILQ_HEAD_INITIALIZER(tog_refs); static struct got_reflist_object_id_map *tog_refs_idmap; static struct { struct got_object_id *id; int idx; char marker; } tog_base_commit; static enum got_diff_algorithm tog_diff_algo = GOT_DIFF_ALGORITHM_PATIENCE; static const struct got_error * tog_ref_cmp_by_name(void *arg, int *cmp, struct got_reference *re1, struct got_reference* re2) { const char *name1 = got_ref_get_name(re1); const char *name2 = got_ref_get_name(re2); int isbackup1, isbackup2; /* Sort backup refs towards the bottom of the list. */ isbackup1 = strncmp(name1, "refs/got/backup/", 16) == 0; isbackup2 = strncmp(name2, "refs/got/backup/", 16) == 0; if (!isbackup1 && isbackup2) { *cmp = -1; return NULL; } else if (isbackup1 && !isbackup2) { *cmp = 1; return NULL; } *cmp = got_path_cmp(name1, name2, strlen(name1), strlen(name2)); return NULL; } static const struct got_error * tog_load_refs(struct got_repository *repo, int sort_by_date) { const struct got_error *err; err = got_ref_list(&tog_refs, repo, NULL, sort_by_date ? got_ref_cmp_by_commit_timestamp_descending : tog_ref_cmp_by_name, repo); if (err) return err; return got_reflist_object_id_map_create(&tog_refs_idmap, &tog_refs, repo); } static void tog_free_refs(void) { if (tog_refs_idmap) { got_reflist_object_id_map_free(tog_refs_idmap); tog_refs_idmap = NULL; } got_ref_list_free(&tog_refs); } static const struct got_error * add_color(struct tog_colors *colors, const char *pattern, int idx, short color) { const struct got_error *err = NULL; struct tog_color *tc; int regerr = 0; if (idx < 1 || idx > COLOR_PAIRS - 1) return NULL; init_pair(idx, color, -1); tc = calloc(1, sizeof(*tc)); if (tc == NULL) return got_error_from_errno("calloc"); regerr = regcomp(&tc->regex, pattern, REG_EXTENDED | REG_NOSUB | REG_NEWLINE); if (regerr) { static char regerr_msg[512]; static char err_msg[512]; regerror(regerr, &tc->regex, regerr_msg, sizeof(regerr_msg)); snprintf(err_msg, sizeof(err_msg), "regcomp: %s", regerr_msg); err = got_error_msg(GOT_ERR_REGEX, err_msg); free(tc); return err; } tc->colorpair = idx; STAILQ_INSERT_HEAD(colors, tc, entry); return NULL; } static void free_colors(struct tog_colors *colors) { struct tog_color *tc; while (!STAILQ_EMPTY(colors)) { tc = STAILQ_FIRST(colors); STAILQ_REMOVE_HEAD(colors, entry); regfree(&tc->regex); free(tc); } } static struct tog_color * get_color(struct tog_colors *colors, int colorpair) { struct tog_color *tc = NULL; STAILQ_FOREACH(tc, colors, entry) { if (tc->colorpair == colorpair) return tc; } return NULL; } static int default_color_value(const char *envvar) { if (strcmp(envvar, "TOG_COLOR_DIFF_MINUS") == 0) return COLOR_MAGENTA; if (strcmp(envvar, "TOG_COLOR_DIFF_PLUS") == 0) return COLOR_CYAN; if (strcmp(envvar, "TOG_COLOR_DIFF_CHUNK_HEADER") == 0) return COLOR_YELLOW; if (strcmp(envvar, "TOG_COLOR_DIFF_META") == 0) return COLOR_GREEN; if (strcmp(envvar, "TOG_COLOR_TREE_SUBMODULE") == 0) return COLOR_MAGENTA; if (strcmp(envvar, "TOG_COLOR_TREE_SYMLINK") == 0) return COLOR_MAGENTA; if (strcmp(envvar, "TOG_COLOR_TREE_DIRECTORY") == 0) return COLOR_CYAN; if (strcmp(envvar, "TOG_COLOR_TREE_EXECUTABLE") == 0) return COLOR_GREEN; if (strcmp(envvar, "TOG_COLOR_COMMIT") == 0) return COLOR_GREEN; if (strcmp(envvar, "TOG_COLOR_AUTHOR") == 0) return COLOR_CYAN; if (strcmp(envvar, "TOG_COLOR_DATE") == 0) return COLOR_YELLOW; if (strcmp(envvar, "TOG_COLOR_REFS_HEADS") == 0) return COLOR_GREEN; if (strcmp(envvar, "TOG_COLOR_REFS_TAGS") == 0) return COLOR_MAGENTA; if (strcmp(envvar, "TOG_COLOR_REFS_REMOTES") == 0) return COLOR_YELLOW; if (strcmp(envvar, "TOG_COLOR_REFS_BACKUP") == 0) return COLOR_CYAN; return -1; } static int get_color_value(const char *envvar) { const char *val = getenv(envvar); if (val == NULL) return default_color_value(envvar); if (strcasecmp(val, "black") == 0) return COLOR_BLACK; if (strcasecmp(val, "red") == 0) return COLOR_RED; if (strcasecmp(val, "green") == 0) return COLOR_GREEN; if (strcasecmp(val, "yellow") == 0) return COLOR_YELLOW; if (strcasecmp(val, "blue") == 0) return COLOR_BLUE; if (strcasecmp(val, "magenta") == 0) return COLOR_MAGENTA; if (strcasecmp(val, "cyan") == 0) return COLOR_CYAN; if (strcasecmp(val, "white") == 0) return COLOR_WHITE; if (strcasecmp(val, "default") == 0) return -1; return default_color_value(envvar); } struct tog_diff_view_state { struct got_object_id *id1, *id2; const char *label1, *label2; FILE *f, *f1, *f2; int fd1, fd2; int lineno; int first_displayed_line; int last_displayed_line; int eof; int diff_context; int ignore_whitespace; int force_text_diff; struct got_repository *repo; struct got_diff_line *lines; size_t nlines; int matched_line; int selected_line; /* passed from log or blame view; may be NULL */ struct tog_view *parent_view; }; pthread_mutex_t tog_mutex = PTHREAD_MUTEX_INITIALIZER; static volatile sig_atomic_t tog_thread_error; struct tog_log_thread_args { pthread_cond_t need_commits; pthread_cond_t commit_loaded; int commits_needed; int load_all; struct got_commit_graph *graph; struct commit_queue *real_commits; const char *in_repo_path; struct got_object_id *start_id; struct got_repository *repo; int *pack_fds; int log_complete; pthread_cond_t log_loaded; sig_atomic_t *quit; struct commit_queue_entry **first_displayed_entry; struct commit_queue_entry **selected_entry; int *searching; int *search_next_done; regex_t *regex; int *limiting; int limit_match; regex_t *limit_regex; struct commit_queue *limit_commits; struct got_worktree *worktree; int need_commit_marker; }; struct tog_log_view_state { struct commit_queue *commits; struct commit_queue_entry *first_displayed_entry; struct commit_queue_entry *last_displayed_entry; struct commit_queue_entry *selected_entry; struct commit_queue real_commits; int selected; char *in_repo_path; char *head_ref_name; int log_branches; struct got_repository *repo; struct got_object_id *start_id; sig_atomic_t quit; pthread_t thread; struct tog_log_thread_args thread_args; struct commit_queue_entry *matched_entry; struct commit_queue_entry *search_entry; struct tog_colors colors; int use_committer; int limit_view; regex_t limit_regex; struct commit_queue limit_commits; }; #define TOG_COLOR_DIFF_MINUS 1 #define TOG_COLOR_DIFF_PLUS 2 #define TOG_COLOR_DIFF_CHUNK_HEADER 3 #define TOG_COLOR_DIFF_META 4 #define TOG_COLOR_TREE_SUBMODULE 5 #define TOG_COLOR_TREE_SYMLINK 6 #define TOG_COLOR_TREE_DIRECTORY 7 #define TOG_COLOR_TREE_EXECUTABLE 8 #define TOG_COLOR_COMMIT 9 #define TOG_COLOR_AUTHOR 10 #define TOG_COLOR_DATE 11 #define TOG_COLOR_REFS_HEADS 12 #define TOG_COLOR_REFS_TAGS 13 #define TOG_COLOR_REFS_REMOTES 14 #define TOG_COLOR_REFS_BACKUP 15 struct tog_blame_cb_args { struct tog_blame_line *lines; /* one per line */ int nlines; struct tog_view *view; struct got_object_id *commit_id; int *quit; }; struct tog_blame_thread_args { const char *path; struct got_repository *repo; struct tog_blame_cb_args *cb_args; int *complete; got_cancel_cb cancel_cb; void *cancel_arg; pthread_cond_t blame_complete; }; struct tog_blame { FILE *f; off_t filesize; struct tog_blame_line *lines; int nlines; off_t *line_offsets; pthread_t thread; struct tog_blame_thread_args thread_args; struct tog_blame_cb_args cb_args; const char *path; int *pack_fds; }; struct tog_blame_view_state { int first_displayed_line; int last_displayed_line; int selected_line; int last_diffed_line; int blame_complete; int eof; int done; struct got_object_id_queue blamed_commits; struct got_object_qid *blamed_commit; char *path; struct got_repository *repo; struct got_object_id *commit_id; struct got_object_id *id_to_log; struct tog_blame blame; int matched_line; struct tog_colors colors; }; struct tog_parent_tree { TAILQ_ENTRY(tog_parent_tree) entry; struct got_tree_object *tree; struct got_tree_entry *first_displayed_entry; struct got_tree_entry *selected_entry; int selected; }; TAILQ_HEAD(tog_parent_trees, tog_parent_tree); struct tog_tree_view_state { char *tree_label; struct got_object_id *commit_id;/* commit which this tree belongs to */ struct got_tree_object *root; /* the commit's root tree entry */ struct got_tree_object *tree; /* currently displayed (sub-)tree */ struct got_tree_entry *first_displayed_entry; struct got_tree_entry *last_displayed_entry; struct got_tree_entry *selected_entry; int ndisplayed, selected, show_ids; struct tog_parent_trees parents; /* parent trees of current sub-tree */ char *head_ref_name; struct got_repository *repo; struct got_tree_entry *matched_entry; struct tog_colors colors; }; struct tog_reflist_entry { TAILQ_ENTRY(tog_reflist_entry) entry; struct got_reference *ref; int idx; }; TAILQ_HEAD(tog_reflist_head, tog_reflist_entry); struct tog_ref_view_state { struct tog_reflist_head refs; struct tog_reflist_entry *first_displayed_entry; struct tog_reflist_entry *last_displayed_entry; struct tog_reflist_entry *selected_entry; int nrefs, ndisplayed, selected, show_date, show_ids, sort_by_date; struct got_repository *repo; struct tog_reflist_entry *matched_entry; struct tog_colors colors; }; struct tog_help_view_state { FILE *f; off_t *line_offsets; size_t nlines; int lineno; int first_displayed_line; int last_displayed_line; int eof; int matched_line; int selected_line; int all; enum tog_keymap_type type; }; #define GENERATE_HELP \ KEYMAP_("Global", TOG_KEYMAP_GLOBAL), \ KEY_("H F1", "Open view-specific help (double tap for all help)"), \ KEY_("k C-p Up", "Move cursor or page up one line"), \ KEY_("j C-n Down", "Move cursor or page down one line"), \ KEY_("C-b b PgUp", "Scroll the view up one page"), \ KEY_("C-f f PgDn Space", "Scroll the view down one page"), \ KEY_("C-u u", "Scroll the view up one half page"), \ KEY_("C-d d", "Scroll the view down one half page"), \ KEY_("g", "Go to line N (default: first line)"), \ KEY_("Home =", "Go to the first line"), \ KEY_("G", "Go to line N (default: last line)"), \ KEY_("End *", "Go to the last line"), \ KEY_("l Right", "Scroll the view right"), \ KEY_("h Left", "Scroll the view left"), \ KEY_("$", "Scroll view to the rightmost position"), \ KEY_("0", "Scroll view to the leftmost position"), \ KEY_("-", "Decrease size of the focussed split"), \ KEY_("+", "Increase size of the focussed split"), \ KEY_("Tab", "Switch focus between views"), \ KEY_("F", "Toggle fullscreen mode"), \ KEY_("S", "Switch split-screen layout"), \ KEY_("/", "Open prompt to enter search term"), \ KEY_("n", "Find next line/token matching the current search term"), \ KEY_("N", "Find previous line/token matching the current search term"),\ KEY_("q", "Quit the focussed view; Quit help screen"), \ KEY_("Q", "Quit tog"), \ \ KEYMAP_("Log view", TOG_KEYMAP_LOG), \ KEY_("< ,", "Move cursor up one commit"), \ KEY_("> .", "Move cursor down one commit"), \ KEY_("Enter", "Open diff view of the selected commit"), \ KEY_("B", "Reload the log view and toggle display of merged commits"), \ KEY_("R", "Open ref view of all repository references"), \ KEY_("T", "Display tree view of the repository from the selected" \ " commit"), \ KEY_("@", "Toggle between displaying author and committer name"), \ KEY_("&", "Open prompt to enter term to limit commits displayed"), \ KEY_("C-g Backspace", "Cancel current search or log operation"), \ KEY_("C-l", "Reload the log view with new commits in the repository"), \ \ KEYMAP_("Diff view", TOG_KEYMAP_DIFF), \ KEY_("K < ,", "Display diff of next line in the file/log entry"), \ KEY_("J > .", "Display diff of previous line in the file/log entry"), \ KEY_("A", "Toggle between Myers and Patience diff algorithm"), \ KEY_("a", "Toggle treatment of file as ASCII irrespective of binary" \ " data"), \ KEY_("(", "Go to the previous file in the diff"), \ KEY_(")", "Go to the next file in the diff"), \ KEY_("{", "Go to the previous hunk in the diff"), \ KEY_("}", "Go to the next hunk in the diff"), \ KEY_("[", "Decrease the number of context lines"), \ KEY_("]", "Increase the number of context lines"), \ KEY_("w", "Toggle ignore whitespace-only changes in the diff"), \ \ KEYMAP_("Blame view", TOG_KEYMAP_BLAME), \ KEY_("Enter", "Display diff view of the selected line's commit"), \ KEY_("A", "Toggle diff algorithm between Myers and Patience"), \ KEY_("L", "Open log view for the currently selected annotated line"), \ KEY_("C", "Reload view with the previously blamed commit"), \ KEY_("c", "Reload view with the version of the file found in the" \ " selected line's commit"), \ KEY_("p", "Reload view with the version of the file found in the" \ " selected line's parent commit"), \ \ KEYMAP_("Tree view", TOG_KEYMAP_TREE), \ KEY_("Enter", "Enter selected directory or open blame view of the" \ " selected file"), \ KEY_("L", "Open log view for the selected entry"), \ KEY_("R", "Open ref view of all repository references"), \ KEY_("i", "Show object IDs for all tree entries"), \ KEY_("Backspace", "Return to the parent directory"), \ \ KEYMAP_("Ref view", TOG_KEYMAP_REF), \ KEY_("Enter", "Display log view of the selected reference"), \ KEY_("T", "Display tree view of the selected reference"), \ KEY_("i", "Toggle display of IDs for all non-symbolic references"), \ KEY_("m", "Toggle display of last modified date for each reference"), \ KEY_("o", "Toggle reference sort order (name -> timestamp)"), \ KEY_("C-l", "Reload view with all repository references") struct tog_key_map { const char *keys; const char *info; enum tog_keymap_type type; }; /* curses io for tog regress */ struct tog_io { FILE *cin; FILE *cout; FILE *f; FILE *sdump; char *input_str; int wait_for_ui; } tog_io; static int using_mock_io; #define TOG_KEY_SCRDUMP SHRT_MIN /* * We implement two types of views: parent views and child views. * * The 'Tab' key switches focus between a parent view and its child view. * Child views are shown side-by-side to their parent view, provided * there is enough screen estate. * * When a new view is opened from within a parent view, this new view * becomes a child view of the parent view, replacing any existing child. * * When a new view is opened from within a child view, this new view * becomes a parent view which will obscure the views below until the * user quits the new parent view by typing 'q'. * * This list of views contains parent views only. * Child views are only pointed to by their parent view. */ TAILQ_HEAD(tog_view_list_head, tog_view); struct tog_view { TAILQ_ENTRY(tog_view) entry; WINDOW *window; PANEL *panel; int nlines, ncols, begin_y, begin_x; /* based on split height/width */ int resized_y, resized_x; /* begin_y/x based on user resizing */ int maxx, x; /* max column and current start column */ int lines, cols; /* copies of LINES and COLS */ int nscrolled, offset; /* lines scrolled and hsplit line offset */ int gline, hiline; /* navigate to and highlight this nG line */ int ch, count; /* current keymap and count prefix */ int resized; /* set when in a resize event */ int focussed; /* Only set on one parent or child view at a time. */ int dying; struct tog_view *parent; struct tog_view *child; /* * This flag is initially set on parent views when a new child view * is created. It gets toggled when the 'Tab' key switches focus * between parent and child. * The flag indicates whether focus should be passed on to our child * view if this parent view gets picked for focus after another parent * view was closed. This prevents child views from losing focus in such * situations. */ int focus_child; enum tog_view_mode mode; /* type-specific state */ enum tog_view_type type; union { struct tog_diff_view_state diff; struct tog_log_view_state log; struct tog_blame_view_state blame; struct tog_tree_view_state tree; struct tog_ref_view_state ref; struct tog_help_view_state help; } state; const struct got_error *(*show)(struct tog_view *); const struct got_error *(*input)(struct tog_view **, struct tog_view *, int); const struct got_error *(*reset)(struct tog_view *); const struct got_error *(*resize)(struct tog_view *, int); const struct got_error *(*close)(struct tog_view *); const struct got_error *(*search_start)(struct tog_view *); const struct got_error *(*search_next)(struct tog_view *); void (*search_setup)(struct tog_view *, FILE **, off_t **, size_t *, int **, int **, int **, int **); int search_started; int searching; #define TOG_SEARCH_FORWARD 1 #define TOG_SEARCH_BACKWARD 2 int search_next_done; #define TOG_SEARCH_HAVE_MORE 1 #define TOG_SEARCH_NO_MORE 2 #define TOG_SEARCH_HAVE_NONE 3 regex_t regex; regmatch_t regmatch; const char *action; }; static const struct got_error *open_diff_view(struct tog_view *, struct got_object_id *, struct got_object_id *, const char *, const char *, int, int, int, struct tog_view *, struct got_repository *); static const struct got_error *show_diff_view(struct tog_view *); static const struct got_error *input_diff_view(struct tog_view **, struct tog_view *, int); static const struct got_error *reset_diff_view(struct tog_view *); static const struct got_error* close_diff_view(struct tog_view *); static const struct got_error *search_start_diff_view(struct tog_view *); static void search_setup_diff_view(struct tog_view *, FILE **, off_t **, size_t *, int **, int **, int **, int **); static const struct got_error *search_next_view_match(struct tog_view *); static const struct got_error *open_log_view(struct tog_view *, struct got_object_id *, struct got_repository *, const char *, const char *, int, struct got_worktree *); static const struct got_error * show_log_view(struct tog_view *); static const struct got_error *input_log_view(struct tog_view **, struct tog_view *, int); static const struct got_error *resize_log_view(struct tog_view *, int); static const struct got_error *close_log_view(struct tog_view *); static const struct got_error *search_start_log_view(struct tog_view *); static const struct got_error *search_next_log_view(struct tog_view *); static const struct got_error *open_blame_view(struct tog_view *, char *, struct got_object_id *, struct got_repository *); static const struct got_error *show_blame_view(struct tog_view *); static const struct got_error *input_blame_view(struct tog_view **, struct tog_view *, int); static const struct got_error *reset_blame_view(struct tog_view *); static const struct got_error *close_blame_view(struct tog_view *); static const struct got_error *search_start_blame_view(struct tog_view *); static void search_setup_blame_view(struct tog_view *, FILE **, off_t **, size_t *, int **, int **, int **, int **); static const struct got_error *open_tree_view(struct tog_view *, struct got_object_id *, const char *, struct got_repository *); static const struct got_error *show_tree_view(struct tog_view *); static const struct got_error *input_tree_view(struct tog_view **, struct tog_view *, int); static const struct got_error *close_tree_view(struct tog_view *); static const struct got_error *search_start_tree_view(struct tog_view *); static const struct got_error *search_next_tree_view(struct tog_view *); static const struct got_error *open_ref_view(struct tog_view *, struct got_repository *); static const struct got_error *show_ref_view(struct tog_view *); static const struct got_error *input_ref_view(struct tog_view **, struct tog_view *, int); static const struct got_error *close_ref_view(struct tog_view *); static const struct got_error *search_start_ref_view(struct tog_view *); static const struct got_error *search_next_ref_view(struct tog_view *); static const struct got_error *open_help_view(struct tog_view *, struct tog_view *); static const struct got_error *show_help_view(struct tog_view *); static const struct got_error *input_help_view(struct tog_view **, struct tog_view *, int); static const struct got_error *reset_help_view(struct tog_view *); static const struct got_error* close_help_view(struct tog_view *); static const struct got_error *search_start_help_view(struct tog_view *); static void search_setup_help_view(struct tog_view *, FILE **, off_t **, size_t *, int **, int **, int **, int **); static volatile sig_atomic_t tog_sigwinch_received; static volatile sig_atomic_t tog_sigpipe_received; static volatile sig_atomic_t tog_sigcont_received; static volatile sig_atomic_t tog_sigint_received; static volatile sig_atomic_t tog_sigterm_received; static void tog_sigwinch(int signo) { tog_sigwinch_received = 1; } static void tog_sigpipe(int signo) { tog_sigpipe_received = 1; } static void tog_sigcont(int signo) { tog_sigcont_received = 1; } static void tog_sigint(int signo) { tog_sigint_received = 1; } static void tog_sigterm(int signo) { tog_sigterm_received = 1; } static int tog_fatal_signal_received(void) { return (tog_sigpipe_received || tog_sigint_received || tog_sigterm_received); } static const struct got_error * view_close(struct tog_view *view) { const struct got_error *err = NULL, *child_err = NULL; if (view->child) { child_err = view_close(view->child); view->child = NULL; } if (view->close) err = view->close(view); if (view->panel) del_panel(view->panel); if (view->window) delwin(view->window); free(view); return err ? err : child_err; } static struct tog_view * view_open(int nlines, int ncols, int begin_y, int begin_x, enum tog_view_type type) { struct tog_view *view = calloc(1, sizeof(*view)); if (view == NULL) return NULL; view->type = type; view->lines = LINES; view->cols = COLS; view->nlines = nlines ? nlines : LINES - begin_y; view->ncols = ncols ? ncols : COLS - begin_x; view->begin_y = begin_y; view->begin_x = begin_x; view->window = newwin(nlines, ncols, begin_y, begin_x); if (view->window == NULL) { view_close(view); return NULL; } view->panel = new_panel(view->window); if (view->panel == NULL || set_panel_userptr(view->panel, view) != OK) { view_close(view); return NULL; } keypad(view->window, TRUE); return view; } static int view_split_begin_x(int begin_x) { if (begin_x > 0 || COLS < 120) return 0; return (COLS - MAX(COLS / 2, 80)); } /* XXX Stub till we decide what to do. */ static int view_split_begin_y(int lines) { return lines * HSPLIT_SCALE; } static const struct got_error *view_resize(struct tog_view *); static const struct got_error * view_splitscreen(struct tog_view *view) { const struct got_error *err = NULL; if (!view->resized && view->mode == TOG_VIEW_SPLIT_HRZN) { if (view->resized_y && view->resized_y < view->lines) view->begin_y = view->resized_y; else view->begin_y = view_split_begin_y(view->nlines); view->begin_x = 0; } else if (!view->resized) { if (view->resized_x && view->resized_x < view->cols - 1 && view->cols > 119) view->begin_x = view->resized_x; else view->begin_x = view_split_begin_x(0); view->begin_y = 0; } view->nlines = LINES - view->begin_y; view->ncols = COLS - view->begin_x; view->lines = LINES; view->cols = COLS; err = view_resize(view); if (err) return err; if (view->parent && view->mode == TOG_VIEW_SPLIT_HRZN) view->parent->nlines = view->begin_y; if (mvwin(view->window, view->begin_y, view->begin_x) == ERR) return got_error_from_errno("mvwin"); return NULL; } static const struct got_error * view_fullscreen(struct tog_view *view) { const struct got_error *err = NULL; view->begin_x = 0; view->begin_y = view->resized ? view->begin_y : 0; view->nlines = view->resized ? view->nlines : LINES; view->ncols = COLS; view->lines = LINES; view->cols = COLS; err = view_resize(view); if (err) return err; if (mvwin(view->window, view->begin_y, view->begin_x) == ERR) return got_error_from_errno("mvwin"); return NULL; } static int view_is_parent_view(struct tog_view *view) { return view->parent == NULL; } static int view_is_splitscreen(struct tog_view *view) { return view->begin_x > 0 || view->begin_y > 0; } static int view_is_fullscreen(struct tog_view *view) { return view->nlines == LINES && view->ncols == COLS; } static int view_is_hsplit_top(struct tog_view *view) { return view->mode == TOG_VIEW_SPLIT_HRZN && view->child && view_is_splitscreen(view->child); } static void view_border(struct tog_view *view) { PANEL *panel; const struct tog_view *view_above; if (view->parent) return view_border(view->parent); panel = panel_above(view->panel); if (panel == NULL) return; view_above = panel_userptr(panel); if (view->mode == TOG_VIEW_SPLIT_HRZN) mvwhline(view->window, view_above->begin_y - 1, view->begin_x, ACS_HLINE, view->ncols); else mvwvline(view->window, view->begin_y, view_above->begin_x - 1, ACS_VLINE, view->nlines); } static const struct got_error *view_init_hsplit(struct tog_view *, int); static const struct got_error *request_log_commits(struct tog_view *); static const struct got_error *offset_selection_down(struct tog_view *); static void offset_selection_up(struct tog_view *); static void view_get_split(struct tog_view *, int *, int *); static const struct got_error * view_resize(struct tog_view *view) { const struct got_error *err = NULL; int dif, nlines, ncols; dif = LINES - view->lines; /* line difference */ if (view->lines > LINES) nlines = view->nlines - (view->lines - LINES); else nlines = view->nlines + (LINES - view->lines); if (view->cols > COLS) ncols = view->ncols - (view->cols - COLS); else ncols = view->ncols + (COLS - view->cols); if (view->child) { int hs = view->child->begin_y; if (!view_is_fullscreen(view)) view->child->begin_x = view_split_begin_x(view->begin_x); if (view->mode == TOG_VIEW_SPLIT_HRZN || view->child->begin_x == 0) { ncols = COLS; view_fullscreen(view->child); if (view->child->focussed) show_panel(view->child->panel); else show_panel(view->panel); } else { ncols = view->child->begin_x; view_splitscreen(view->child); show_panel(view->child->panel); } /* * XXX This is ugly and needs to be moved into the above * logic but "works" for now and my attempts at moving it * break either 'tab' or 'F' key maps in horizontal splits. */ if (hs) { err = view_splitscreen(view->child); if (err) return err; if (dif < 0) { /* top split decreased */ err = offset_selection_down(view); if (err) return err; } view_border(view); update_panels(); doupdate(); show_panel(view->child->panel); nlines = view->nlines; } } else if (view->parent == NULL) ncols = COLS; if (view->resize && dif > 0) { err = view->resize(view, dif); if (err) return err; } if (wresize(view->window, nlines, ncols) == ERR) return got_error_from_errno("wresize"); if (replace_panel(view->panel, view->window) == ERR) return got_error_from_errno("replace_panel"); wclear(view->window); view->nlines = nlines; view->ncols = ncols; view->lines = LINES; view->cols = COLS; return NULL; } static const struct got_error * resize_log_view(struct tog_view *view, int increase) { struct tog_log_view_state *s = &view->state.log; const struct got_error *err = NULL; int n = 0; if (s->selected_entry) n = s->selected_entry->idx + view->lines - s->selected; /* * Request commits to account for the increased * height so we have enough to populate the view. */ if (s->commits->ncommits < n) { view->nscrolled = n - s->commits->ncommits + increase + 1; err = request_log_commits(view); } return err; } static void view_adjust_offset(struct tog_view *view, int n) { if (n == 0) return; if (view->parent && view->parent->offset) { if (view->parent->offset + n >= 0) view->parent->offset += n; else view->parent->offset = 0; } else if (view->offset) { if (view->offset - n >= 0) view->offset -= n; else view->offset = 0; } } static const struct got_error * view_resize_split(struct tog_view *view, int resize) { const struct got_error *err = NULL; struct tog_view *v = NULL; if (view->parent) v = view->parent; else v = view; if (!v->child || !view_is_splitscreen(v->child)) return NULL; v->resized = v->child->resized = resize; /* lock for resize event */ if (view->mode == TOG_VIEW_SPLIT_HRZN) { if (v->child->resized_y) v->child->begin_y = v->child->resized_y; if (view->parent) v->child->begin_y -= resize; else v->child->begin_y += resize; if (v->child->begin_y < 3) { view->count = 0; v->child->begin_y = 3; } else if (v->child->begin_y > LINES - 1) { view->count = 0; v->child->begin_y = LINES - 1; } v->ncols = COLS; v->child->ncols = COLS; view_adjust_offset(view, resize); err = view_init_hsplit(v, v->child->begin_y); if (err) return err; v->child->resized_y = v->child->begin_y; } else { if (v->child->resized_x) v->child->begin_x = v->child->resized_x; if (view->parent) v->child->begin_x -= resize; else v->child->begin_x += resize; if (v->child->begin_x < 11) { view->count = 0; v->child->begin_x = 11; } else if (v->child->begin_x > COLS - 1) { view->count = 0; v->child->begin_x = COLS - 1; } v->child->resized_x = v->child->begin_x; } v->child->mode = v->mode; v->child->nlines = v->lines - v->child->begin_y; v->child->ncols = v->cols - v->child->begin_x; v->focus_child = 1; err = view_fullscreen(v); if (err) return err; err = view_splitscreen(v->child); if (err) return err; if (v->mode == TOG_VIEW_SPLIT_HRZN) { err = offset_selection_down(v->child); if (err) return err; } if (v->resize) err = v->resize(v, 0); else if (v->child->resize) err = v->child->resize(v->child, 0); v->resized = v->child->resized = 0; return err; } static void view_transfer_size(struct tog_view *dst, struct tog_view *src) { struct tog_view *v = src->child ? src->child : src; dst->resized_x = v->resized_x; dst->resized_y = v->resized_y; } static const struct got_error * view_close_child(struct tog_view *view) { const struct got_error *err = NULL; if (view->child == NULL) return NULL; err = view_close(view->child); view->child = NULL; return err; } static const struct got_error * view_set_child(struct tog_view *view, struct tog_view *child) { const struct got_error *err = NULL; view->child = child; child->parent = view; err = view_resize(view); if (err) return err; if (view->child->resized_x || view->child->resized_y) err = view_resize_split(view, 0); return err; } static const struct got_error *view_dispatch_request(struct tog_view **, struct tog_view *, enum tog_view_type, int, int); static const struct got_error * view_request_new(struct tog_view **requested, struct tog_view *view, enum tog_view_type request) { struct tog_view *new_view = NULL; const struct got_error *err; int y = 0, x = 0; *requested = NULL; if (view_is_parent_view(view) && request != TOG_VIEW_HELP) view_get_split(view, &y, &x); err = view_dispatch_request(&new_view, view, request, y, x); if (err) return err; if (view_is_parent_view(view) && view->mode == TOG_VIEW_SPLIT_HRZN && request != TOG_VIEW_HELP) { err = view_init_hsplit(view, y); if (err) return err; } view->focussed = 0; new_view->focussed = 1; new_view->mode = view->mode; new_view->nlines = request == TOG_VIEW_HELP ? view->lines : view->lines - y; if (view_is_parent_view(view) && request != TOG_VIEW_HELP) { view_transfer_size(new_view, view); err = view_close_child(view); if (err) return err; err = view_set_child(view, new_view); if (err) return err; view->focus_child = 1; } else *requested = new_view; return NULL; } static void tog_resizeterm(void) { int cols, lines; struct winsize size; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &size) < 0) { cols = 80; /* Default */ lines = 24; } else { cols = size.ws_col; lines = size.ws_row; } resize_term(lines, cols); } static const struct got_error * view_search_start(struct tog_view *view, int fast_refresh) { const struct got_error *err = NULL; struct tog_view *v = view; char pattern[1024]; int ret; if (view->search_started) { regfree(&view->regex); view->searching = 0; memset(&view->regmatch, 0, sizeof(view->regmatch)); } view->search_started = 0; if (view->nlines < 1) return NULL; if (view_is_hsplit_top(view)) v = view->child; else if (view->mode == TOG_VIEW_SPLIT_VERT && view->parent) v = view->parent; if (tog_io.input_str != NULL) { if (strlcpy(pattern, tog_io.input_str, sizeof(pattern)) >= sizeof(pattern)) return got_error(GOT_ERR_NO_SPACE); } else { mvwaddstr(v->window, v->nlines - 1, 0, "/"); wclrtoeol(v->window); nodelay(v->window, FALSE); /* block for search term input */ nocbreak(); echo(); ret = wgetnstr(v->window, pattern, sizeof(pattern)); wrefresh(v->window); cbreak(); noecho(); nodelay(v->window, TRUE); if (!fast_refresh && !using_mock_io) halfdelay(10); if (ret == ERR) return NULL; } if (regcomp(&view->regex, pattern, REG_EXTENDED | REG_NEWLINE) == 0) { err = view->search_start(view); if (err) { regfree(&view->regex); return err; } view->search_started = 1; view->searching = TOG_SEARCH_FORWARD; view->search_next_done = 0; view->search_next(view); } return NULL; } /* Switch split mode. If view is a parent or child, draw the new splitscreen. */ static const struct got_error * switch_split(struct tog_view *view) { const struct got_error *err = NULL; struct tog_view *v = NULL; if (view->parent) v = view->parent; else v = view; if (v->mode == TOG_VIEW_SPLIT_HRZN) v->mode = TOG_VIEW_SPLIT_VERT; else v->mode = TOG_VIEW_SPLIT_HRZN; if (!v->child) return NULL; else if (v->mode == TOG_VIEW_SPLIT_VERT && v->cols < 120) v->mode = TOG_VIEW_SPLIT_NONE; view_get_split(v, &v->child->begin_y, &v->child->begin_x); if (v->mode == TOG_VIEW_SPLIT_HRZN && v->child->resized_y) v->child->begin_y = v->child->resized_y; else if (v->mode == TOG_VIEW_SPLIT_VERT && v->child->resized_x) v->child->begin_x = v->child->resized_x; if (v->mode == TOG_VIEW_SPLIT_HRZN) { v->ncols = COLS; v->child->ncols = COLS; v->child->nscrolled = LINES - v->child->nlines; err = view_init_hsplit(v, v->child->begin_y); if (err) return err; } v->child->mode = v->mode; v->child->nlines = v->lines - v->child->begin_y; v->focus_child = 1; err = view_fullscreen(v); if (err) return err; err = view_splitscreen(v->child); if (err) return err; if (v->mode == TOG_VIEW_SPLIT_NONE) v->mode = TOG_VIEW_SPLIT_VERT; if (v->mode == TOG_VIEW_SPLIT_HRZN) { err = offset_selection_down(v); if (err) return err; err = offset_selection_down(v->child); if (err) return err; } else { offset_selection_up(v); offset_selection_up(v->child); } if (v->resize) err = v->resize(v, 0); else if (v->child->resize) err = v->child->resize(v->child, 0); return err; } /* * Strip trailing whitespace from str starting at byte *n; * if *n < 0, use strlen(str). Return new str length in *n. */ static void strip_trailing_ws(char *str, int *n) { size_t x = *n; if (str == NULL || *str == '\0') return; if (x < 0) x = strlen(str); while (x-- > 0 && isspace((unsigned char)str[x])) str[x] = '\0'; *n = x + 1; } /* * Extract visible substring of line y from the curses screen * and strip trailing whitespace. If vline is set, overwrite * line[vline] with '|' because the ACS_VLINE character is * written out as 'x'. Write the line to file f. */ static const struct got_error * view_write_line(FILE *f, int y, int vline) { char line[COLS * MB_LEN_MAX]; /* allow for multibyte chars */ int r, w; r = mvwinnstr(curscr, y, 0, line, sizeof(line)); if (r == ERR) return got_error_fmt(GOT_ERR_RANGE, "failed to extract line %d", y); /* * In some views, lines are padded with blanks to COLS width. * Strip them so we can diff without the -b flag when testing. */ strip_trailing_ws(line, &r); if (vline > 0) line[vline] = '|'; w = fprintf(f, "%s\n", line); if (w != r + 1) /* \n */ return got_ferror(f, GOT_ERR_IO); return NULL; } /* * Capture the visible curses screen by writing each line to the * file at the path set via the TOG_SCR_DUMP environment variable. */ static const struct got_error * screendump(struct tog_view *view) { const struct got_error *err; int i; err = got_opentemp_truncate(tog_io.sdump); if (err) return err; if ((view->child && view->child->begin_x) || (view->parent && view->begin_x)) { int ncols = view->child ? view->ncols : view->parent->ncols; /* vertical splitscreen */ for (i = 0; i < view->nlines; ++i) { err = view_write_line(tog_io.sdump, i, ncols - 1); if (err) goto done; } } else { int hline = 0; /* fullscreen or horizontal splitscreen */ if ((view->child && view->child->begin_y) || (view->parent && view->begin_y)) /* hsplit */ hline = view->child ? view->child->begin_y : view->begin_y; for (i = 0; i < view->lines; i++) { if (hline && i == hline - 1) { int c; /* ACS_HLINE writes out as 'q', overwrite it */ for (c = 0; c < view->cols; ++c) fputc('-', tog_io.sdump); fputc('\n', tog_io.sdump); continue; } err = view_write_line(tog_io.sdump, i, 0); if (err) goto done; } } done: return err; } /* * Compute view->count from numeric input. Assign total to view->count and * return first non-numeric key entered. */ static int get_compound_key(struct tog_view *view, int c) { struct tog_view *v = view; int x, n = 0; if (view_is_hsplit_top(view)) v = view->child; else if (view->mode == TOG_VIEW_SPLIT_VERT && view->parent) v = view->parent; view->count = 0; cbreak(); /* block for input */ nodelay(view->window, FALSE); wmove(v->window, v->nlines - 1, 0); wclrtoeol(v->window); waddch(v->window, ':'); do { x = getcurx(v->window); if (x != ERR && x < view->ncols) { waddch(v->window, c); wrefresh(v->window); } /* * Don't overflow. Max valid request should be the greatest * between the longest and total lines; cap at 10 million. */ if (n >= 9999999) n = 9999999; else n = n * 10 + (c - '0'); } while (((c = wgetch(view->window))) >= '0' && c <= '9' && c != ERR); if (c == 'G' || c == 'g') { /* nG key map */ view->gline = view->hiline = n; n = 0; c = 0; } /* Massage excessive or inapplicable values at the input handler. */ view->count = n; return c; } static void action_report(struct tog_view *view) { struct tog_view *v = view; if (view_is_hsplit_top(view)) v = view->child; else if (view->mode == TOG_VIEW_SPLIT_VERT && view->parent) v = view->parent; wmove(v->window, v->nlines - 1, 0); wclrtoeol(v->window); wprintw(v->window, ":%s", view->action); wrefresh(v->window); /* * Clear action status report. Only clear in blame view * once annotating is complete, otherwise it's too fast. */ if (view->type == TOG_VIEW_BLAME) { if (view->state.blame.blame_complete) view->action = NULL; } else view->action = NULL; } /* * Read the next line from the test script and assign * key instruction to *ch. If at EOF, set the *done flag. */ static const struct got_error * tog_read_script_key(FILE *script, struct tog_view *view, int *ch, int *done) { const struct got_error *err = NULL; char *line = NULL; size_t linesz = 0; ssize_t n; if (view->count && --view->count) { *ch = view->ch; return NULL; } else *ch = -1; if ((n = getline(&line, &linesz, script)) == -1) { if (feof(script)) { *done = 1; goto done; } else { err = got_ferror(script, GOT_ERR_IO); goto done; } } if (strncasecmp(line, "WAIT_FOR_UI", 11) == 0) tog_io.wait_for_ui = 1; else if (strncasecmp(line, "KEY_ENTER", 9) == 0) *ch = KEY_ENTER; else if (strncasecmp(line, "KEY_RIGHT", 9) == 0) *ch = KEY_RIGHT; else if (strncasecmp(line, "KEY_LEFT", 8) == 0) *ch = KEY_LEFT; else if (strncasecmp(line, "KEY_DOWN", 8) == 0) *ch = KEY_DOWN; else if (strncasecmp(line, "KEY_UP", 6) == 0) *ch = KEY_UP; else if (strncasecmp(line, "TAB", 3) == 0) *ch = '\t'; else if (strncasecmp(line, "SCREENDUMP", 10) == 0) *ch = TOG_KEY_SCRDUMP; else if (isdigit((unsigned char)*line)) { char *t = line; while (isdigit((unsigned char)*t)) ++t; view->ch = *ch = *t; *t = '\0'; /* ignore error, view->count is 0 if instruction is invalid */ view->count = strtonum(line, 0, INT_MAX, NULL); } else { *ch = *line; if (n > 2 && (*ch == '/' || *ch == '&')) { /* skip leading keymap and trim trailing newline */ tog_io.input_str = strndup(line + 1, n - 2); if (tog_io.input_str == NULL) { err = got_error_from_errno("strndup"); goto done; } } } done: free(line); return err; } static const struct got_error * view_input(struct tog_view **new, int *done, struct tog_view *view, struct tog_view_list_head *views, int fast_refresh) { const struct got_error *err = NULL; struct tog_view *v; int ch, errcode; *new = NULL; if (view->action) action_report(view); /* Clear "no matches" indicator. */ if (view->search_next_done == TOG_SEARCH_NO_MORE || view->search_next_done == TOG_SEARCH_HAVE_NONE) { view->search_next_done = TOG_SEARCH_HAVE_MORE; view->count = 0; } if (view->searching && !view->search_next_done) { view->search_next(view); return NULL; } /* Allow threads to make progress while we are waiting for input. */ errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_unlock"); if (using_mock_io) { err = tog_read_script_key(tog_io.f, view, &ch, done); if (err) { errcode = pthread_mutex_lock(&tog_mutex); return err; } } else if (view->count && --view->count) { cbreak(); nodelay(view->window, TRUE); ch = wgetch(view->window); /* let C-g or backspace abort unfinished count */ if (ch == CTRL('g') || ch == KEY_BACKSPACE) view->count = 0; else ch = view->ch; } else { ch = wgetch(view->window); if (ch >= '1' && ch <= '9') view->ch = ch = get_compound_key(view, ch); } if (view->hiline && ch != ERR && ch != 0) view->hiline = 0; /* key pressed, clear line highlight */ nodelay(view->window, TRUE); errcode = pthread_mutex_lock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_lock"); if (tog_sigwinch_received || tog_sigcont_received) { tog_resizeterm(); tog_sigwinch_received = 0; tog_sigcont_received = 0; TAILQ_FOREACH(v, views, entry) { err = view_resize(v); if (err) return err; err = v->input(new, v, KEY_RESIZE); if (err) return err; if (v->child) { err = view_resize(v->child); if (err) return err; err = v->child->input(new, v->child, KEY_RESIZE); if (err) return err; if (v->child->resized_x || v->child->resized_y) { err = view_resize_split(v, 0); if (err) return err; } } } } switch (ch) { case '?': case 'H': case KEY_F(1): if (view->type == TOG_VIEW_HELP) err = view->reset(view); else err = view_request_new(new, view, TOG_VIEW_HELP); break; case '\t': view->count = 0; if (view->child) { view->focussed = 0; view->child->focussed = 1; view->focus_child = 1; } else if (view->parent) { view->focussed = 0; view->parent->focussed = 1; view->parent->focus_child = 0; if (!view_is_splitscreen(view)) { if (view->parent->resize) { err = view->parent->resize(view->parent, 0); if (err) return err; } offset_selection_up(view->parent); err = view_fullscreen(view->parent); if (err) return err; } } break; case 'q': if (view->parent && view->mode == TOG_VIEW_SPLIT_HRZN) { if (view->parent->resize) { /* might need more commits to fill fullscreen */ err = view->parent->resize(view->parent, 0); if (err) break; } offset_selection_up(view->parent); } err = view->input(new, view, ch); view->dying = 1; break; case 'Q': *done = 1; break; case 'F': view->count = 0; if (view_is_parent_view(view)) { if (view->child == NULL) break; if (view_is_splitscreen(view->child)) { view->focussed = 0; view->child->focussed = 1; err = view_fullscreen(view->child); } else { err = view_splitscreen(view->child); if (!err) err = view_resize_split(view, 0); } if (err) break; err = view->child->input(new, view->child, KEY_RESIZE); } else { if (view_is_splitscreen(view)) { view->parent->focussed = 0; view->focussed = 1; err = view_fullscreen(view); } else { err = view_splitscreen(view); if (!err && view->mode != TOG_VIEW_SPLIT_HRZN) err = view_resize(view->parent); if (!err) err = view_resize_split(view, 0); } if (err) break; err = view->input(new, view, KEY_RESIZE); } if (err) break; if (view->resize) { err = view->resize(view, 0); if (err) break; } if (view->parent) { if (view->parent->resize) { err = view->parent->resize(view->parent, 0); if (err != NULL) break; } err = offset_selection_down(view->parent); if (err != NULL) break; } err = offset_selection_down(view); break; case 'S': view->count = 0; err = switch_split(view); break; case '-': err = view_resize_split(view, -1); break; case '+': err = view_resize_split(view, 1); break; case KEY_RESIZE: break; case '/': view->count = 0; if (view->search_start) view_search_start(view, fast_refresh); else err = view->input(new, view, ch); break; case 'N': case 'n': if (view->search_started && view->search_next) { view->searching = (ch == 'n' ? TOG_SEARCH_FORWARD : TOG_SEARCH_BACKWARD); view->search_next_done = 0; view->search_next(view); } else err = view->input(new, view, ch); break; case 'A': if (tog_diff_algo == GOT_DIFF_ALGORITHM_MYERS) { tog_diff_algo = GOT_DIFF_ALGORITHM_PATIENCE; view->action = "Patience diff algorithm"; } else { tog_diff_algo = GOT_DIFF_ALGORITHM_MYERS; view->action = "Myers diff algorithm"; } TAILQ_FOREACH(v, views, entry) { if (v->reset) { err = v->reset(v); if (err) return err; } if (v->child && v->child->reset) { err = v->child->reset(v->child); if (err) return err; } } break; case TOG_KEY_SCRDUMP: err = screendump(view); break; default: err = view->input(new, view, ch); break; } return err; } static int view_needs_focus_indication(struct tog_view *view) { if (view_is_parent_view(view)) { if (view->child == NULL || view->child->focussed) return 0; if (!view_is_splitscreen(view->child)) return 0; } else if (!view_is_splitscreen(view)) return 0; return view->focussed; } static const struct got_error * tog_io_close(void) { const struct got_error *err = NULL; if (tog_io.cin && fclose(tog_io.cin) == EOF) err = got_ferror(tog_io.cin, GOT_ERR_IO); if (tog_io.cout && fclose(tog_io.cout) == EOF && err == NULL) err = got_ferror(tog_io.cout, GOT_ERR_IO); if (tog_io.f && fclose(tog_io.f) == EOF && err == NULL) err = got_ferror(tog_io.f, GOT_ERR_IO); if (tog_io.sdump && fclose(tog_io.sdump) == EOF && err == NULL) err = got_ferror(tog_io.sdump, GOT_ERR_IO); if (tog_io.input_str != NULL) free(tog_io.input_str); return err; } static const struct got_error * view_loop(struct tog_view *view) { const struct got_error *err = NULL; struct tog_view_list_head views; struct tog_view *new_view; char *mode; int fast_refresh = 10; int done = 0, errcode; mode = getenv("TOG_VIEW_SPLIT_MODE"); if (!mode || !(*mode == 'h' || *mode == 'H')) view->mode = TOG_VIEW_SPLIT_VERT; else view->mode = TOG_VIEW_SPLIT_HRZN; errcode = pthread_mutex_lock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_lock"); TAILQ_INIT(&views); TAILQ_INSERT_HEAD(&views, view, entry); view->focussed = 1; err = view->show(view); if (err) return err; update_panels(); doupdate(); while (!TAILQ_EMPTY(&views) && !done && !tog_thread_error && !tog_fatal_signal_received()) { /* Refresh fast during initialization, then become slower. */ if (fast_refresh && --fast_refresh == 0 && !using_mock_io) halfdelay(10); /* switch to once per second */ err = view_input(&new_view, &done, view, &views, fast_refresh); if (err) break; if (view->dying && view == TAILQ_FIRST(&views) && TAILQ_NEXT(view, entry) == NULL) done = 1; if (done) { struct tog_view *v; /* * When we quit, scroll the screen up a single line * so we don't lose any information. */ TAILQ_FOREACH(v, &views, entry) { wmove(v->window, 0, 0); wdeleteln(v->window); wnoutrefresh(v->window); if (v->child && !view_is_fullscreen(v)) { wmove(v->child->window, 0, 0); wdeleteln(v->child->window); wnoutrefresh(v->child->window); } } doupdate(); } if (view->dying) { struct tog_view *v, *prev = NULL; if (view_is_parent_view(view)) prev = TAILQ_PREV(view, tog_view_list_head, entry); else if (view->parent) prev = view->parent; if (view->parent) { view->parent->child = NULL; view->parent->focus_child = 0; /* Restore fullscreen line height. */ view->parent->nlines = view->parent->lines; err = view_resize(view->parent); if (err) break; /* Make resized splits persist. */ view_transfer_size(view->parent, view); } else TAILQ_REMOVE(&views, view, entry); err = view_close(view); if (err) goto done; view = NULL; TAILQ_FOREACH(v, &views, entry) { if (v->focussed) break; } if (view == NULL && new_view == NULL) { /* No view has focus. Try to pick one. */ if (prev) view = prev; else if (!TAILQ_EMPTY(&views)) { view = TAILQ_LAST(&views, tog_view_list_head); } if (view) { if (view->focus_child) { view->child->focussed = 1; view = view->child; } else view->focussed = 1; } } } if (new_view) { struct tog_view *v, *t; /* Only allow one parent view per type. */ TAILQ_FOREACH_SAFE(v, &views, entry, t) { if (v->type != new_view->type) continue; TAILQ_REMOVE(&views, v, entry); err = view_close(v); if (err) goto done; break; } TAILQ_INSERT_TAIL(&views, new_view, entry); view = new_view; } if (view && !done) { if (view_is_parent_view(view)) { if (view->child && view->child->focussed) view = view->child; } else { if (view->parent && view->parent->focussed) view = view->parent; } show_panel(view->panel); if (view->child && view_is_splitscreen(view->child)) show_panel(view->child->panel); if (view->parent && view_is_splitscreen(view)) { err = view->parent->show(view->parent); if (err) goto done; } err = view->show(view); if (err) goto done; if (view->child) { err = view->child->show(view->child); if (err) goto done; } update_panels(); doupdate(); } } done: while (!TAILQ_EMPTY(&views)) { const struct got_error *close_err; view = TAILQ_FIRST(&views); TAILQ_REMOVE(&views, view, entry); close_err = view_close(view); if (close_err && err == NULL) err = close_err; } errcode = pthread_mutex_unlock(&tog_mutex); if (errcode && err == NULL) err = got_error_set_errno(errcode, "pthread_mutex_unlock"); return err; } __dead static void usage_log(void) { endwin(); fprintf(stderr, "usage: %s log [-b] [-c commit] [-r repository-path] [path]\n", getprogname()); exit(1); } /* Create newly allocated wide-character string equivalent to a byte string. */ static const struct got_error * mbs2ws(wchar_t **ws, size_t *wlen, const char *s) { char *vis = NULL; const struct got_error *err = NULL; *ws = NULL; *wlen = mbstowcs(NULL, s, 0); if (*wlen == (size_t)-1) { int vislen; if (errno != EILSEQ) return got_error_from_errno("mbstowcs"); /* byte string invalid in current encoding; try to "fix" it */ err = got_mbsavis(&vis, &vislen, s); if (err) return err; *wlen = mbstowcs(NULL, vis, 0); if (*wlen == (size_t)-1) { err = got_error_from_errno("mbstowcs"); /* give up */ goto done; } } *ws = calloc(*wlen + 1, sizeof(**ws)); if (*ws == NULL) { err = got_error_from_errno("calloc"); goto done; } if (mbstowcs(*ws, vis ? vis : s, *wlen) != *wlen) err = got_error_from_errno("mbstowcs"); done: free(vis); if (err) { free(*ws); *ws = NULL; *wlen = 0; } return err; } static const struct got_error * expand_tab(char **ptr, const char *src) { char *dst; size_t len, n, idx = 0, sz = 0; *ptr = NULL; n = len = strlen(src); dst = malloc(n + 1); if (dst == NULL) return got_error_from_errno("malloc"); while (idx < len && src[idx]) { const char c = src[idx]; if (c == '\t') { size_t nb = TABSIZE - sz % TABSIZE; char *p; p = realloc(dst, n + nb); if (p == NULL) { free(dst); return got_error_from_errno("realloc"); } dst = p; n += nb; memset(dst + sz, ' ', nb); sz += nb; } else dst[sz++] = src[idx]; ++idx; } dst[sz] = '\0'; *ptr = dst; return NULL; } /* * Advance at most n columns from wline starting at offset off. * Return the index to the first character after the span operation. * Return the combined column width of all spanned wide characters in * *rcol. */ static int span_wline(int *rcol, int off, wchar_t *wline, int n, int col_tab_align) { int width, i, cols = 0; if (n == 0) { *rcol = cols; return off; } for (i = off; wline[i] != L'\0'; ++i) { if (wline[i] == L'\t') width = TABSIZE - ((cols + col_tab_align) % TABSIZE); else width = wcwidth(wline[i]); if (width == -1) { width = 1; wline[i] = L'.'; } if (cols + width > n) break; cols += width; } *rcol = cols; return i; } /* * Format a line for display, ensuring that it won't overflow a width limit. * With scrolling, the width returned refers to the scrolled version of the * line, which starts at (*wlinep)[*scrollxp]. The caller must free *wlinep. */ static const struct got_error * format_line(wchar_t **wlinep, int *widthp, int *scrollxp, const char *line, int nscroll, int wlimit, int col_tab_align, int expand) { const struct got_error *err = NULL; int cols; wchar_t *wline = NULL; char *exstr = NULL; size_t wlen; int i, scrollx; *wlinep = NULL; *widthp = 0; if (expand) { err = expand_tab(&exstr, line); if (err) return err; } err = mbs2ws(&wline, &wlen, expand ? exstr : line); free(exstr); if (err) return err; if (wlen > 0 && wline[wlen - 1] == L'\n') { wline[wlen - 1] = L'\0'; wlen--; } if (wlen > 0 && wline[wlen - 1] == L'\r') { wline[wlen - 1] = L'\0'; wlen--; } scrollx = span_wline(&cols, 0, wline, nscroll, col_tab_align); i = span_wline(&cols, scrollx, wline, wlimit, col_tab_align); wline[i] = L'\0'; if (widthp) *widthp = cols; if (scrollxp) *scrollxp = scrollx; if (err) free(wline); else *wlinep = wline; return err; } static const struct got_error* build_refs_str(char **refs_str, struct got_reflist_head *refs, struct got_object_id *id, struct got_repository *repo) { static const struct got_error *err = NULL; struct got_reflist_entry *re; char *s; const char *name; *refs_str = NULL; if (refs == NULL) return NULL; TAILQ_FOREACH(re, refs, entry) { struct got_tag_object *tag = NULL; struct got_object_id *ref_id; int cmp; name = got_ref_get_name(re->ref); if (strcmp(name, GOT_REF_HEAD) == 0) continue; if (strncmp(name, "refs/", 5) == 0) name += 5; if (strncmp(name, "got/", 4) == 0) continue; if (strncmp(name, "heads/", 6) == 0) name += 6; if (strncmp(name, "remotes/", 8) == 0) { name += 8; s = strstr(name, "/" GOT_REF_HEAD); if (s != NULL && strcmp(s, "/" GOT_REF_HEAD) == 0) continue; } err = got_ref_resolve(&ref_id, repo, re->ref); if (err) break; if (strncmp(name, "tags/", 5) == 0) { err = got_object_open_as_tag(&tag, repo, ref_id); if (err) { if (err->code != GOT_ERR_OBJ_TYPE) { free(ref_id); break; } /* Ref points at something other than a tag. */ err = NULL; tag = NULL; } } cmp = got_object_id_cmp(tag ? got_object_tag_get_object_id(tag) : ref_id, id); free(ref_id); if (tag) got_object_tag_close(tag); if (cmp != 0) continue; s = *refs_str; if (asprintf(refs_str, "%s%s%s", s ? s : "", s ? ", " : "", name) == -1) { err = got_error_from_errno("asprintf"); free(s); *refs_str = NULL; break; } free(s); } return err; } static const struct got_error * format_author(wchar_t **wauthor, int *author_width, char *author, int limit, int col_tab_align) { char *smallerthan; smallerthan = strchr(author, '<'); if (smallerthan && smallerthan[1] != '\0') author = smallerthan + 1; author[strcspn(author, "@>")] = '\0'; return format_line(wauthor, author_width, NULL, author, 0, limit, col_tab_align, 0); } static const struct got_error * draw_commit(struct tog_view *view, struct commit_queue_entry *entry, const size_t date_display_cols, int author_display_cols) { struct tog_log_view_state *s = &view->state.log; const struct got_error *err = NULL; struct got_commit_object *commit = entry->commit; struct got_object_id *id = entry->id; char datebuf[12]; /* YYYY-MM-DD + SPACE + NUL */ char *refs_str = NULL; char *logmsg0 = NULL, *logmsg = NULL; char *author = NULL; wchar_t *wrefstr = NULL, *wlogmsg = NULL, *wauthor = NULL; int author_width, refstr_width, logmsg_width; char *newline, *line = NULL; int col, limit, scrollx, logmsg_x; const int avail = view->ncols, marker_column = author_display_cols + 1; struct tm tm; time_t committer_time; struct tog_color *tc; struct got_reflist_head *refs; if (tog_base_commit.id != NULL && tog_base_commit.idx == -1 && got_object_id_cmp(id, tog_base_commit.id) == 0) tog_base_commit.idx = entry->idx; if (tog_io.wait_for_ui && s->thread_args.need_commit_marker) { int rc; rc = pthread_cond_wait(&s->thread_args.log_loaded, &tog_mutex); if (rc) return got_error_set_errno(rc, "pthread_cond_wait"); } committer_time = got_object_commit_get_committer_time(commit); if (gmtime_r(&committer_time, &tm) == NULL) return got_error_from_errno("gmtime_r"); if (strftime(datebuf, sizeof(datebuf), "%F ", &tm) == 0) return got_error(GOT_ERR_NO_SPACE); if (avail <= date_display_cols) limit = MIN(sizeof(datebuf) - 1, avail); else limit = MIN(date_display_cols, sizeof(datebuf) - 1); tc = get_color(&s->colors, TOG_COLOR_DATE); if (tc) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); waddnstr(view->window, datebuf, limit); if (tc) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); col = limit; if (col > avail) goto done; if (avail >= 120) { char *id_str; err = got_object_id_str(&id_str, id); if (err) goto done; tc = get_color(&s->colors, TOG_COLOR_COMMIT); if (tc) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); wprintw(view->window, "%.8s ", id_str); if (tc) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); free(id_str); col += 9; if (col > avail) goto done; } if (s->use_committer) author = strdup(got_object_commit_get_committer(commit)); else author = strdup(got_object_commit_get_author(commit)); if (author == NULL) { err = got_error_from_errno("strdup"); goto done; } err = format_author(&wauthor, &author_width, author, avail - col, col); if (err) goto done; tc = get_color(&s->colors, TOG_COLOR_AUTHOR); if (tc) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); waddwstr(view->window, wauthor); col += author_width; while (col < avail && author_width < author_display_cols + 2) { if (tog_base_commit.marker != GOT_WORKTREE_STATE_UNKNOWN && author_width == marker_column && entry->idx == tog_base_commit.idx && !s->limit_view) { tc = get_color(&s->colors, TOG_COLOR_COMMIT); if (tc) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); waddch(view->window, tog_base_commit.marker); if (tc) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); } else waddch(view->window, ' '); col++; author_width++; } if (tc) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); if (col > avail) goto done; err = got_object_commit_get_logmsg(&logmsg0, commit); if (err) goto done; logmsg = logmsg0; while (*logmsg == '\n') logmsg++; newline = strchr(logmsg, '\n'); if (newline) *newline = '\0'; limit = avail - col; if (view->child && !view_is_hsplit_top(view) && limit > 0) limit--; /* for the border */ /* Prepend reference labels to log message if possible .*/ refs = got_reflist_object_id_map_lookup(tog_refs_idmap, id); err = build_refs_str(&refs_str, refs, id, s->repo); if (err) goto done; if (refs_str) { char *rs; if (asprintf(&rs, "[%s]", refs_str) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = format_line(&wrefstr, &refstr_width, &scrollx, rs, view->x, limit, col, 1); free(rs); if (err) goto done; tc = get_color(&s->colors, TOG_COLOR_COMMIT); if (tc) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); waddwstr(view->window, &wrefstr[scrollx]); if (tc) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); col += MAX(refstr_width, 0); if (col > avail) goto done; if (col < avail) { waddch(view->window, ' '); col++; } if (refstr_width > 0) logmsg_x = 0; else { int unscrolled_refstr_width; size_t len = wcslen(wrefstr); /* * No need to check for -1 return value here since * unprintables have been replaced by span_wline(). */ unscrolled_refstr_width = wcswidth(wrefstr, len); unscrolled_refstr_width += 1; /* trailing space */ logmsg_x = view->x - unscrolled_refstr_width; } limit = avail - col; if (view->child && !view_is_hsplit_top(view) && limit > 0) limit--; /* for the border */ } else logmsg_x = view->x; err = format_line(&wlogmsg, &logmsg_width, &scrollx, logmsg, logmsg_x, limit, col, 1); if (err) goto done; waddwstr(view->window, &wlogmsg[scrollx]); col += MAX(logmsg_width, 0); while (col < avail) { waddch(view->window, ' '); col++; } done: free(logmsg0); free(wlogmsg); free(wrefstr); free(refs_str); free(author); free(wauthor); free(line); return err; } static struct commit_queue_entry * alloc_commit_queue_entry(struct got_commit_object *commit, struct got_object_id *id) { struct commit_queue_entry *entry; struct got_object_id *dup; entry = calloc(1, sizeof(*entry)); if (entry == NULL) return NULL; dup = got_object_id_dup(id); if (dup == NULL) { free(entry); return NULL; } entry->id = dup; entry->commit = commit; return entry; } static void pop_commit(struct commit_queue *commits) { struct commit_queue_entry *entry; entry = TAILQ_FIRST(&commits->head); TAILQ_REMOVE(&commits->head, entry, entry); got_object_commit_close(entry->commit); commits->ncommits--; free(entry->id); free(entry); } static void free_commits(struct commit_queue *commits) { while (!TAILQ_EMPTY(&commits->head)) pop_commit(commits); } static const struct got_error * match_commit(int *have_match, struct got_object_id *id, struct got_commit_object *commit, regex_t *regex) { const struct got_error *err = NULL; regmatch_t regmatch; char *id_str = NULL, *logmsg = NULL; *have_match = 0; err = got_object_id_str(&id_str, id); if (err) return err; err = got_object_commit_get_logmsg(&logmsg, commit); if (err) goto done; if (regexec(regex, got_object_commit_get_author(commit), 1, ®match, 0) == 0 || regexec(regex, got_object_commit_get_committer(commit), 1, ®match, 0) == 0 || regexec(regex, id_str, 1, ®match, 0) == 0 || regexec(regex, logmsg, 1, ®match, 0) == 0) *have_match = 1; done: free(id_str); free(logmsg); return err; } static const struct got_error * queue_commits(struct tog_log_thread_args *a) { const struct got_error *err = NULL; /* * We keep all commits open throughout the lifetime of the log * view in order to avoid having to re-fetch commits from disk * while updating the display. */ do { struct got_object_id id; struct got_commit_object *commit; struct commit_queue_entry *entry; int limit_match = 0; int errcode; err = got_commit_graph_iter_next(&id, a->graph, a->repo, NULL, NULL); if (err) break; err = got_object_open_as_commit(&commit, a->repo, &id); if (err) break; entry = alloc_commit_queue_entry(commit, &id); if (entry == NULL) { err = got_error_from_errno("alloc_commit_queue_entry"); break; } errcode = pthread_mutex_lock(&tog_mutex); if (errcode) { err = got_error_set_errno(errcode, "pthread_mutex_lock"); break; } entry->idx = a->real_commits->ncommits; TAILQ_INSERT_TAIL(&a->real_commits->head, entry, entry); a->real_commits->ncommits++; if (*a->limiting) { err = match_commit(&limit_match, &id, commit, a->limit_regex); if (err) break; if (limit_match) { struct commit_queue_entry *matched; matched = alloc_commit_queue_entry( entry->commit, entry->id); if (matched == NULL) { err = got_error_from_errno( "alloc_commit_queue_entry"); break; } matched->commit = entry->commit; got_object_commit_retain(entry->commit); matched->idx = a->limit_commits->ncommits; TAILQ_INSERT_TAIL(&a->limit_commits->head, matched, entry); a->limit_commits->ncommits++; } /* * This is how we signal log_thread() that we * have found a match, and that it should be * counted as a new entry for the view. */ a->limit_match = limit_match; } if (*a->searching == TOG_SEARCH_FORWARD && !*a->search_next_done) { int have_match; err = match_commit(&have_match, &id, commit, a->regex); if (err) break; if (*a->limiting) { if (limit_match && have_match) *a->search_next_done = TOG_SEARCH_HAVE_MORE; } else if (have_match) *a->search_next_done = TOG_SEARCH_HAVE_MORE; } errcode = pthread_mutex_unlock(&tog_mutex); if (errcode && err == NULL) err = got_error_set_errno(errcode, "pthread_mutex_unlock"); if (err) break; } while (*a->searching == TOG_SEARCH_FORWARD && !*a->search_next_done); return err; } static void select_commit(struct tog_log_view_state *s) { struct commit_queue_entry *entry; int ncommits = 0; entry = s->first_displayed_entry; while (entry) { if (ncommits == s->selected) { s->selected_entry = entry; break; } entry = TAILQ_NEXT(entry, entry); ncommits++; } } static const struct got_error * draw_commits(struct tog_view *view) { const struct got_error *err = NULL; struct tog_log_view_state *s = &view->state.log; struct commit_queue_entry *entry = s->selected_entry; int limit = view->nlines; int width; int ncommits, author_cols = 4, refstr_cols; char *id_str = NULL, *header = NULL, *ncommits_str = NULL; char *refs_str = NULL; wchar_t *wline; struct tog_color *tc; static const size_t date_display_cols = 12; struct got_reflist_head *refs; if (view_is_hsplit_top(view)) --limit; /* account for border */ if (s->selected_entry && !(view->searching && view->search_next_done == 0)) { err = got_object_id_str(&id_str, s->selected_entry->id); if (err) return err; refs = got_reflist_object_id_map_lookup(tog_refs_idmap, s->selected_entry->id); err = build_refs_str(&refs_str, refs, s->selected_entry->id, s->repo); if (err) goto done; } if (s->thread_args.commits_needed == 0 && !using_mock_io) halfdelay(10); /* disable fast refresh */ if (s->thread_args.commits_needed > 0 || s->thread_args.load_all) { if (asprintf(&ncommits_str, " [%d/%d] %s", entry ? entry->idx + 1 : 0, s->commits->ncommits, (view->searching && !view->search_next_done) ? "searching..." : "loading...") == -1) { err = got_error_from_errno("asprintf"); goto done; } } else { const char *search_str = NULL; const char *limit_str = NULL; if (view->searching) { if (view->search_next_done == TOG_SEARCH_NO_MORE) search_str = "no more matches"; else if (view->search_next_done == TOG_SEARCH_HAVE_NONE) search_str = "no matches found"; else if (!view->search_next_done) search_str = "searching..."; } if (s->limit_view && s->commits->ncommits == 0) limit_str = "no matches found"; if (asprintf(&ncommits_str, " [%d/%d] %s %s", entry ? entry->idx + 1 : 0, s->commits->ncommits, search_str ? search_str : (refs_str ? refs_str : ""), limit_str ? limit_str : "") == -1) { err = got_error_from_errno("asprintf"); goto done; } } free(refs_str); refs_str = NULL; if (s->in_repo_path && strcmp(s->in_repo_path, "/") != 0) { if (asprintf(&header, "commit %s %s%s", id_str ? id_str : "........................................", s->in_repo_path, ncommits_str) == -1) { err = got_error_from_errno("asprintf"); header = NULL; goto done; } } else if (asprintf(&header, "commit %s%s", id_str ? id_str : "........................................", ncommits_str) == -1) { err = got_error_from_errno("asprintf"); header = NULL; goto done; } err = format_line(&wline, &width, NULL, header, 0, view->ncols, 0, 0); if (err) goto done; werase(view->window); if (view_needs_focus_indication(view)) wstandout(view->window); tc = get_color(&s->colors, TOG_COLOR_COMMIT); if (tc) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); waddwstr(view->window, wline); while (width < view->ncols) { waddch(view->window, ' '); width++; } if (tc) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); if (view_needs_focus_indication(view)) wstandend(view->window); free(wline); if (limit <= 1) goto done; /* Grow author column size if necessary, and set view->maxx. */ entry = s->first_displayed_entry; ncommits = 0; view->maxx = 0; while (entry) { struct got_commit_object *c = entry->commit; char *author, *eol, *msg, *msg0; wchar_t *wauthor, *wmsg; int width; if (ncommits >= limit - 1) break; if (s->use_committer) author = strdup(got_object_commit_get_committer(c)); else author = strdup(got_object_commit_get_author(c)); if (author == NULL) { err = got_error_from_errno("strdup"); goto done; } err = format_author(&wauthor, &width, author, COLS, date_display_cols); if (author_cols < width) author_cols = width; free(wauthor); free(author); if (err) goto done; refs = got_reflist_object_id_map_lookup(tog_refs_idmap, entry->id); err = build_refs_str(&refs_str, refs, entry->id, s->repo); if (err) goto done; if (refs_str) { wchar_t *ws; err = format_line(&ws, &width, NULL, refs_str, 0, INT_MAX, date_display_cols + author_cols, 0); free(ws); free(refs_str); refs_str = NULL; if (err) goto done; refstr_cols = width + 3; /* account for [ ] + space */ } else refstr_cols = 0; err = got_object_commit_get_logmsg(&msg0, c); if (err) goto done; msg = msg0; while (*msg == '\n') ++msg; if ((eol = strchr(msg, '\n'))) *eol = '\0'; err = format_line(&wmsg, &width, NULL, msg, 0, INT_MAX, date_display_cols + author_cols + refstr_cols, 0); if (err) goto done; view->maxx = MAX(view->maxx, width + refstr_cols); free(msg0); free(wmsg); ncommits++; entry = TAILQ_NEXT(entry, entry); } entry = s->first_displayed_entry; s->last_displayed_entry = s->first_displayed_entry; ncommits = 0; while (entry) { if (ncommits >= limit - 1) break; if (ncommits == s->selected) wstandout(view->window); err = draw_commit(view, entry, date_display_cols, author_cols); if (ncommits == s->selected) wstandend(view->window); if (err) goto done; ncommits++; s->last_displayed_entry = entry; entry = TAILQ_NEXT(entry, entry); } view_border(view); done: free(id_str); free(refs_str); free(ncommits_str); free(header); return err; } static void log_scroll_up(struct tog_log_view_state *s, int maxscroll) { struct commit_queue_entry *entry; int nscrolled = 0; entry = TAILQ_FIRST(&s->commits->head); if (s->first_displayed_entry == entry) return; entry = s->first_displayed_entry; while (entry && nscrolled < maxscroll) { entry = TAILQ_PREV(entry, commit_queue_head, entry); if (entry) { s->first_displayed_entry = entry; nscrolled++; } } } static const struct got_error * trigger_log_thread(struct tog_view *view, int wait) { struct tog_log_thread_args *ta = &view->state.log.thread_args; int errcode; if (!using_mock_io) halfdelay(1); /* fast refresh while loading commits */ while (!ta->log_complete && !tog_thread_error && (ta->commits_needed > 0 || ta->load_all)) { /* Wake the log thread. */ errcode = pthread_cond_signal(&ta->need_commits); if (errcode) return got_error_set_errno(errcode, "pthread_cond_signal"); /* * The mutex will be released while the view loop waits * in wgetch(), at which time the log thread will run. */ if (!wait) break; /* Display progress update in log view. */ show_log_view(view); update_panels(); doupdate(); /* Wait right here while next commit is being loaded. */ errcode = pthread_cond_wait(&ta->commit_loaded, &tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_cond_wait"); /* Display progress update in log view. */ show_log_view(view); update_panels(); doupdate(); } return NULL; } static const struct got_error * request_log_commits(struct tog_view *view) { struct tog_log_view_state *state = &view->state.log; const struct got_error *err = NULL; if (state->thread_args.log_complete) return NULL; state->thread_args.commits_needed += view->nscrolled; err = trigger_log_thread(view, 1); view->nscrolled = 0; return err; } static const struct got_error * log_scroll_down(struct tog_view *view, int maxscroll) { struct tog_log_view_state *s = &view->state.log; const struct got_error *err = NULL; struct commit_queue_entry *pentry; int nscrolled = 0, ncommits_needed; if (s->last_displayed_entry == NULL) return NULL; ncommits_needed = s->last_displayed_entry->idx + 2 + maxscroll; if (s->commits->ncommits < ncommits_needed && !s->thread_args.log_complete) { /* * Ask the log thread for required amount of commits. */ s->thread_args.commits_needed += ncommits_needed - s->commits->ncommits; err = trigger_log_thread(view, 1); if (err) return err; } do { pentry = TAILQ_NEXT(s->last_displayed_entry, entry); if (pentry == NULL && view->mode != TOG_VIEW_SPLIT_HRZN) break; s->last_displayed_entry = pentry ? pentry : s->last_displayed_entry; pentry = TAILQ_NEXT(s->first_displayed_entry, entry); if (pentry == NULL) break; s->first_displayed_entry = pentry; } while (++nscrolled < maxscroll); if (view->mode == TOG_VIEW_SPLIT_HRZN && !s->thread_args.log_complete) view->nscrolled += nscrolled; else view->nscrolled = 0; return err; } static const struct got_error * open_diff_view_for_commit(struct tog_view **new_view, int begin_y, int begin_x, struct got_commit_object *commit, struct got_object_id *commit_id, struct tog_view *log_view, struct got_repository *repo) { const struct got_error *err; struct got_object_qid *parent_id; struct tog_view *diff_view; diff_view = view_open(0, 0, begin_y, begin_x, TOG_VIEW_DIFF); if (diff_view == NULL) return got_error_from_errno("view_open"); parent_id = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); err = open_diff_view(diff_view, parent_id ? &parent_id->id : NULL, commit_id, NULL, NULL, 3, 0, 0, log_view, repo); if (err == NULL) *new_view = diff_view; return err; } static const struct got_error * tree_view_visit_subtree(struct tog_tree_view_state *s, struct got_tree_object *subtree) { struct tog_parent_tree *parent; parent = calloc(1, sizeof(*parent)); if (parent == NULL) return got_error_from_errno("calloc"); parent->tree = s->tree; parent->first_displayed_entry = s->first_displayed_entry; parent->selected_entry = s->selected_entry; parent->selected = s->selected; TAILQ_INSERT_HEAD(&s->parents, parent, entry); s->tree = subtree; s->selected = 0; s->first_displayed_entry = NULL; return NULL; } static const struct got_error * tree_view_walk_path(struct tog_tree_view_state *s, struct got_commit_object *commit, const char *path) { const struct got_error *err = NULL; struct got_tree_object *tree = NULL; const char *p; char *slash, *subpath = NULL; /* Walk the path and open corresponding tree objects. */ p = path; while (*p) { struct got_tree_entry *te; struct got_object_id *tree_id; char *te_name; while (p[0] == '/') p++; /* Ensure the correct subtree entry is selected. */ slash = strchr(p, '/'); if (slash == NULL) te_name = strdup(p); else te_name = strndup(p, slash - p); if (te_name == NULL) { err = got_error_from_errno("strndup"); break; } te = got_object_tree_find_entry(s->tree, te_name); if (te == NULL) { err = got_error_path(te_name, GOT_ERR_NO_TREE_ENTRY); free(te_name); break; } free(te_name); s->first_displayed_entry = s->selected_entry = te; if (!S_ISDIR(got_tree_entry_get_mode(s->selected_entry))) break; /* jump to this file's entry */ slash = strchr(p, '/'); if (slash) subpath = strndup(path, slash - path); else subpath = strdup(path); if (subpath == NULL) { err = got_error_from_errno("strdup"); break; } err = got_object_id_by_path(&tree_id, s->repo, commit, subpath); if (err) break; err = got_object_open_as_tree(&tree, s->repo, tree_id); free(tree_id); if (err) break; err = tree_view_visit_subtree(s, tree); if (err) { got_object_tree_close(tree); break; } if (slash == NULL) break; free(subpath); subpath = NULL; p = slash; } free(subpath); return err; } static const struct got_error * browse_commit_tree(struct tog_view **new_view, int begin_y, int begin_x, struct commit_queue_entry *entry, const char *path, const char *head_ref_name, struct got_repository *repo) { const struct got_error *err = NULL; struct tog_tree_view_state *s; struct tog_view *tree_view; tree_view = view_open(0, 0, begin_y, begin_x, TOG_VIEW_TREE); if (tree_view == NULL) return got_error_from_errno("view_open"); err = open_tree_view(tree_view, entry->id, head_ref_name, repo); if (err) return err; s = &tree_view->state.tree; *new_view = tree_view; if (got_path_is_root_dir(path)) return NULL; return tree_view_walk_path(s, entry->commit, path); } static const struct got_error * block_signals_used_by_main_thread(void) { sigset_t sigset; int errcode; if (sigemptyset(&sigset) == -1) return got_error_from_errno("sigemptyset"); /* tog handles SIGWINCH, SIGCONT, SIGINT, SIGTERM */ if (sigaddset(&sigset, SIGWINCH) == -1) return got_error_from_errno("sigaddset"); if (sigaddset(&sigset, SIGCONT) == -1) return got_error_from_errno("sigaddset"); if (sigaddset(&sigset, SIGINT) == -1) return got_error_from_errno("sigaddset"); if (sigaddset(&sigset, SIGTERM) == -1) return got_error_from_errno("sigaddset"); /* ncurses handles SIGTSTP */ if (sigaddset(&sigset, SIGTSTP) == -1) return got_error_from_errno("sigaddset"); errcode = pthread_sigmask(SIG_BLOCK, &sigset, NULL); if (errcode) return got_error_set_errno(errcode, "pthread_sigmask"); return NULL; } static void * log_thread(void *arg) { const struct got_error *err = NULL; int errcode = 0; struct tog_log_thread_args *a = arg; int done = 0; /* * Sync startup with main thread such that we begin our * work once view_input() has released the mutex. */ errcode = pthread_mutex_lock(&tog_mutex); if (errcode) { err = got_error_set_errno(errcode, "pthread_mutex_lock"); return (void *)err; } err = block_signals_used_by_main_thread(); if (err) { pthread_mutex_unlock(&tog_mutex); goto done; } while (!done && !err && !tog_fatal_signal_received()) { errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) { err = got_error_set_errno(errcode, "pthread_mutex_unlock"); goto done; } err = queue_commits(a); if (err) { if (err->code != GOT_ERR_ITER_COMPLETED) goto done; err = NULL; done = 1; a->commits_needed = 0; } else if (a->commits_needed > 0 && !a->load_all) { if (*a->limiting) { if (a->limit_match) a->commits_needed--; } else a->commits_needed--; } errcode = pthread_mutex_lock(&tog_mutex); if (errcode) { err = got_error_set_errno(errcode, "pthread_mutex_lock"); goto done; } else if (*a->quit) done = 1; else if (*a->limiting && *a->first_displayed_entry == NULL) { *a->first_displayed_entry = TAILQ_FIRST(&a->limit_commits->head); *a->selected_entry = *a->first_displayed_entry; } else if (*a->first_displayed_entry == NULL) { *a->first_displayed_entry = TAILQ_FIRST(&a->real_commits->head); *a->selected_entry = *a->first_displayed_entry; } errcode = pthread_cond_signal(&a->commit_loaded); if (errcode) { err = got_error_set_errno(errcode, "pthread_cond_signal"); pthread_mutex_unlock(&tog_mutex); goto done; } if (a->commits_needed == 0 && a->need_commit_marker && a->worktree) { errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) { err = got_error_set_errno(errcode, "pthread_mutex_unlock"); goto done; } err = got_worktree_get_state(&tog_base_commit.marker, a->repo, a->worktree, NULL, NULL); if (err) goto done; errcode = pthread_mutex_lock(&tog_mutex); if (errcode) { err = got_error_set_errno(errcode, "pthread_mutex_lock"); goto done; } a->need_commit_marker = 0; /* * The main thread did not close this * work tree yet. Close it now. */ got_worktree_close(a->worktree); a->worktree = NULL; if (*a->quit) done = 1; } if (done) a->commits_needed = 0; else { if (a->commits_needed == 0 && !a->load_all) { if (tog_io.wait_for_ui) { errcode = pthread_cond_signal( &a->log_loaded); if (errcode && err == NULL) err = got_error_set_errno( errcode, "pthread_cond_signal"); } errcode = pthread_cond_wait(&a->need_commits, &tog_mutex); if (errcode) { err = got_error_set_errno(errcode, "pthread_cond_wait"); pthread_mutex_unlock(&tog_mutex); goto done; } if (*a->quit) done = 1; } } } a->log_complete = 1; if (tog_io.wait_for_ui) { errcode = pthread_cond_signal(&a->log_loaded); if (errcode && err == NULL) err = got_error_set_errno(errcode, "pthread_cond_signal"); } errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) err = got_error_set_errno(errcode, "pthread_mutex_unlock"); done: if (err) { tog_thread_error = 1; pthread_cond_signal(&a->commit_loaded); if (a->worktree) { got_worktree_close(a->worktree); a->worktree = NULL; } } return (void *)err; } static const struct got_error * stop_log_thread(struct tog_log_view_state *s) { const struct got_error *err = NULL, *thread_err = NULL; int errcode; if (s->thread) { s->quit = 1; errcode = pthread_cond_signal(&s->thread_args.need_commits); if (errcode) return got_error_set_errno(errcode, "pthread_cond_signal"); errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_unlock"); errcode = pthread_join(s->thread, (void **)&thread_err); if (errcode) return got_error_set_errno(errcode, "pthread_join"); errcode = pthread_mutex_lock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_lock"); s->thread = 0; //NULL; } if (s->thread_args.repo) { err = got_repo_close(s->thread_args.repo); s->thread_args.repo = NULL; } if (s->thread_args.pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(s->thread_args.pack_fds); if (err == NULL) err = pack_err; s->thread_args.pack_fds = NULL; } if (s->thread_args.graph) { got_commit_graph_close(s->thread_args.graph); s->thread_args.graph = NULL; } return err ? err : thread_err; } static const struct got_error * close_log_view(struct tog_view *view) { const struct got_error *err = NULL; struct tog_log_view_state *s = &view->state.log; int errcode; err = stop_log_thread(s); errcode = pthread_cond_destroy(&s->thread_args.need_commits); if (errcode && err == NULL) err = got_error_set_errno(errcode, "pthread_cond_destroy"); errcode = pthread_cond_destroy(&s->thread_args.commit_loaded); if (errcode && err == NULL) err = got_error_set_errno(errcode, "pthread_cond_destroy"); free_commits(&s->limit_commits); free_commits(&s->real_commits); free_colors(&s->colors); free(s->in_repo_path); s->in_repo_path = NULL; free(s->start_id); s->start_id = NULL; free(s->head_ref_name); s->head_ref_name = NULL; return err; } /* * We use two queues to implement the limit feature: first consists of * commits matching the current limit_regex; second is the real queue * of all known commits (real_commits). When the user starts limiting, * we swap queues such that all movement and displaying functionality * works with very slight change. */ static const struct got_error * limit_log_view(struct tog_view *view) { struct tog_log_view_state *s = &view->state.log; struct commit_queue_entry *entry; struct tog_view *v = view; const struct got_error *err = NULL; char pattern[1024]; int ret; if (view_is_hsplit_top(view)) v = view->child; else if (view->mode == TOG_VIEW_SPLIT_VERT && view->parent) v = view->parent; if (tog_io.input_str != NULL) { if (strlcpy(pattern, tog_io.input_str, sizeof(pattern)) >= sizeof(pattern)) return got_error(GOT_ERR_NO_SPACE); } else { wmove(v->window, v->nlines - 1, 0); wclrtoeol(v->window); mvwaddstr(v->window, v->nlines - 1, 0, "&/"); nodelay(v->window, FALSE); nocbreak(); echo(); ret = wgetnstr(v->window, pattern, sizeof(pattern)); cbreak(); noecho(); nodelay(v->window, TRUE); if (ret == ERR) return NULL; } if (*pattern == '\0') { /* * Safety measure for the situation where the user * resets limit without previously limiting anything. */ if (!s->limit_view) return NULL; /* * User could have pressed Ctrl+L, which refreshed the * commit queues, it means we can't save previously * (before limit took place) displayed entries, * because they would point to already free'ed memory, * so we are forced to always select first entry of * the queue. */ s->commits = &s->real_commits; s->first_displayed_entry = TAILQ_FIRST(&s->real_commits.head); s->selected_entry = s->first_displayed_entry; s->selected = 0; s->limit_view = 0; return NULL; } if (regcomp(&s->limit_regex, pattern, REG_EXTENDED | REG_NEWLINE)) return NULL; s->limit_view = 1; /* Clear the screen while loading limit view */ s->first_displayed_entry = NULL; s->last_displayed_entry = NULL; s->selected_entry = NULL; s->commits = &s->limit_commits; /* Prepare limit queue for new search */ free_commits(&s->limit_commits); s->limit_commits.ncommits = 0; /* First process commits, which are in queue already */ TAILQ_FOREACH(entry, &s->real_commits.head, entry) { int have_match = 0; err = match_commit(&have_match, entry->id, entry->commit, &s->limit_regex); if (err) return err; if (have_match) { struct commit_queue_entry *matched; matched = alloc_commit_queue_entry(entry->commit, entry->id); if (matched == NULL) { err = got_error_from_errno( "alloc_commit_queue_entry"); break; } matched->commit = entry->commit; got_object_commit_retain(entry->commit); matched->idx = s->limit_commits.ncommits; TAILQ_INSERT_TAIL(&s->limit_commits.head, matched, entry); s->limit_commits.ncommits++; } } /* Second process all the commits, until we fill the screen */ if (s->limit_commits.ncommits < view->nlines - 1 && !s->thread_args.log_complete) { s->thread_args.commits_needed += view->nlines - s->limit_commits.ncommits - 1; err = trigger_log_thread(view, 1); if (err) return err; } s->first_displayed_entry = TAILQ_FIRST(&s->commits->head); s->selected_entry = TAILQ_FIRST(&s->commits->head); s->selected = 0; return NULL; } static const struct got_error * search_start_log_view(struct tog_view *view) { struct tog_log_view_state *s = &view->state.log; s->matched_entry = NULL; s->search_entry = NULL; return NULL; } static const struct got_error * search_next_log_view(struct tog_view *view) { const struct got_error *err = NULL; struct tog_log_view_state *s = &view->state.log; struct commit_queue_entry *entry; /* Display progress update in log view. */ show_log_view(view); update_panels(); doupdate(); if (s->search_entry) { if (!using_mock_io) { int errcode, ch; errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_unlock"); ch = wgetch(view->window); errcode = pthread_mutex_lock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_lock"); if (ch == CTRL('g') || ch == KEY_BACKSPACE) { view->search_next_done = TOG_SEARCH_HAVE_MORE; return NULL; } } if (view->searching == TOG_SEARCH_FORWARD) entry = TAILQ_NEXT(s->search_entry, entry); else entry = TAILQ_PREV(s->search_entry, commit_queue_head, entry); } else if (s->matched_entry) { /* * If the user has moved the cursor after we hit a match, * the position from where we should continue searching * might have changed. */ if (view->searching == TOG_SEARCH_FORWARD) entry = TAILQ_NEXT(s->selected_entry, entry); else entry = TAILQ_PREV(s->selected_entry, commit_queue_head, entry); } else { entry = s->selected_entry; } while (1) { int have_match = 0; if (entry == NULL) { if (s->thread_args.log_complete || view->searching == TOG_SEARCH_BACKWARD) { view->search_next_done = (s->matched_entry == NULL ? TOG_SEARCH_HAVE_NONE : TOG_SEARCH_NO_MORE); s->search_entry = NULL; return NULL; } /* * Poke the log thread for more commits and return, * allowing the main loop to make progress. Search * will resume at s->search_entry once we come back. */ s->search_entry = s->selected_entry; s->thread_args.commits_needed++; return trigger_log_thread(view, 0); } err = match_commit(&have_match, entry->id, entry->commit, &view->regex); if (err) break; if (have_match) { view->search_next_done = TOG_SEARCH_HAVE_MORE; s->matched_entry = entry; break; } s->search_entry = entry; if (view->searching == TOG_SEARCH_FORWARD) entry = TAILQ_NEXT(entry, entry); else entry = TAILQ_PREV(entry, commit_queue_head, entry); } if (s->matched_entry) { int cur = s->selected_entry->idx; while (cur < s->matched_entry->idx) { err = input_log_view(NULL, view, KEY_DOWN); if (err) return err; cur++; } while (cur > s->matched_entry->idx) { err = input_log_view(NULL, view, KEY_UP); if (err) return err; cur--; } } s->search_entry = NULL; return NULL; } static const struct got_error * open_log_view(struct tog_view *view, struct got_object_id *start_id, struct got_repository *repo, const char *head_ref_name, const char *in_repo_path, int log_branches, struct got_worktree *worktree) { const struct got_error *err = NULL; struct tog_log_view_state *s = &view->state.log; struct got_repository *thread_repo = NULL; struct got_commit_graph *thread_graph = NULL; int errcode; if (in_repo_path != s->in_repo_path) { free(s->in_repo_path); s->in_repo_path = strdup(in_repo_path); if (s->in_repo_path == NULL) { err = got_error_from_errno("strdup"); goto done; } } /* The commit queue only contains commits being displayed. */ TAILQ_INIT(&s->real_commits.head); s->real_commits.ncommits = 0; s->commits = &s->real_commits; TAILQ_INIT(&s->limit_commits.head); s->limit_view = 0; s->limit_commits.ncommits = 0; s->repo = repo; if (head_ref_name) { s->head_ref_name = strdup(head_ref_name); if (s->head_ref_name == NULL) { err = got_error_from_errno("strdup"); goto done; } } s->start_id = got_object_id_dup(start_id); if (s->start_id == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } s->log_branches = log_branches; s->use_committer = 1; STAILQ_INIT(&s->colors); if (has_colors() && getenv("TOG_COLORS") != NULL) { err = add_color(&s->colors, "^$", TOG_COLOR_COMMIT, get_color_value("TOG_COLOR_COMMIT")); if (err) goto done; err = add_color(&s->colors, "^$", TOG_COLOR_AUTHOR, get_color_value("TOG_COLOR_AUTHOR")); if (err) goto done; err = add_color(&s->colors, "^$", TOG_COLOR_DATE, get_color_value("TOG_COLOR_DATE")); if (err) goto done; } view->show = show_log_view; view->input = input_log_view; view->resize = resize_log_view; view->close = close_log_view; view->search_start = search_start_log_view; view->search_next = search_next_log_view; if (s->thread_args.pack_fds == NULL) { err = got_repo_pack_fds_open(&s->thread_args.pack_fds); if (err) goto done; } err = got_repo_open(&thread_repo, got_repo_get_path(repo), NULL, s->thread_args.pack_fds); if (err) goto done; err = got_commit_graph_open(&thread_graph, s->in_repo_path, !s->log_branches); if (err) goto done; err = got_commit_graph_bfsort(thread_graph, s->start_id, s->repo, NULL, NULL); if (err) goto done; errcode = pthread_cond_init(&s->thread_args.need_commits, NULL); if (errcode) { err = got_error_set_errno(errcode, "pthread_cond_init"); goto done; } errcode = pthread_cond_init(&s->thread_args.commit_loaded, NULL); if (errcode) { err = got_error_set_errno(errcode, "pthread_cond_init"); goto done; } if (using_mock_io) { int rc; rc = pthread_cond_init(&s->thread_args.log_loaded, NULL); if (rc) return got_error_set_errno(rc, "pthread_cond_init"); } s->thread_args.commits_needed = view->nlines; s->thread_args.graph = thread_graph; s->thread_args.real_commits = &s->real_commits; s->thread_args.limit_commits = &s->limit_commits; s->thread_args.in_repo_path = s->in_repo_path; s->thread_args.start_id = s->start_id; s->thread_args.repo = thread_repo; s->thread_args.log_complete = 0; s->thread_args.quit = &s->quit; s->thread_args.first_displayed_entry = &s->first_displayed_entry; s->thread_args.selected_entry = &s->selected_entry; s->thread_args.searching = &view->searching; s->thread_args.search_next_done = &view->search_next_done; s->thread_args.regex = &view->regex; s->thread_args.limiting = &s->limit_view; s->thread_args.limit_regex = &s->limit_regex; s->thread_args.limit_commits = &s->limit_commits; s->thread_args.worktree = worktree; if (worktree) s->thread_args.need_commit_marker = 1; done: if (err) { if (view->close == NULL) close_log_view(view); view_close(view); } return err; } static const struct got_error * show_log_view(struct tog_view *view) { const struct got_error *err; struct tog_log_view_state *s = &view->state.log; if (s->thread == 0) { //NULL) { int errcode = pthread_create(&s->thread, NULL, log_thread, &s->thread_args); if (errcode) return got_error_set_errno(errcode, "pthread_create"); if (s->thread_args.commits_needed > 0) { err = trigger_log_thread(view, 1); if (err) return err; } } return draw_commits(view); } static void log_move_cursor_up(struct tog_view *view, int page, int home) { struct tog_log_view_state *s = &view->state.log; if (s->first_displayed_entry == NULL) return; if (s->selected_entry->idx == 0) view->count = 0; if ((page && TAILQ_FIRST(&s->commits->head) == s->first_displayed_entry) || home) s->selected = home ? 0 : MAX(0, s->selected - page - 1); if (!page && !home && s->selected > 0) --s->selected; else log_scroll_up(s, home ? s->commits->ncommits : MAX(page, 1)); select_commit(s); return; } static const struct got_error * log_move_cursor_down(struct tog_view *view, int page) { struct tog_log_view_state *s = &view->state.log; const struct got_error *err = NULL; int eos = view->nlines - 2; if (s->first_displayed_entry == NULL) return NULL; if (s->thread_args.log_complete && s->selected_entry->idx >= s->commits->ncommits - 1) return NULL; if (view_is_hsplit_top(view)) --eos; /* border consumes the last line */ if (!page) { if (s->selected < MIN(eos, s->commits->ncommits - 1)) ++s->selected; else err = log_scroll_down(view, 1); } else if (s->thread_args.load_all && s->thread_args.log_complete) { struct commit_queue_entry *entry; int n; s->selected = 0; entry = TAILQ_LAST(&s->commits->head, commit_queue_head); s->last_displayed_entry = entry; for (n = 0; n <= eos; n++) { if (entry == NULL) break; s->first_displayed_entry = entry; entry = TAILQ_PREV(entry, commit_queue_head, entry); } if (n > 0) s->selected = n - 1; } else { if (s->last_displayed_entry->idx == s->commits->ncommits - 1 && s->thread_args.log_complete) s->selected += MIN(page, s->commits->ncommits - s->selected_entry->idx - 1); else err = log_scroll_down(view, page); } if (err) return err; /* * We might necessarily overshoot in horizontal * splits; if so, select the last displayed commit. */ if (view_is_hsplit_top(view) && s->first_displayed_entry && s->last_displayed_entry) { s->selected = MIN(s->selected, s->last_displayed_entry->idx - s->first_displayed_entry->idx); } select_commit(s); if (s->thread_args.log_complete && s->selected_entry->idx == s->commits->ncommits - 1) view->count = 0; return NULL; } static void view_get_split(struct tog_view *view, int *y, int *x) { *x = 0; *y = 0; if (view->mode == TOG_VIEW_SPLIT_HRZN) { if (view->child && view->child->resized_y) *y = view->child->resized_y; else if (view->resized_y) *y = view->resized_y; else *y = view_split_begin_y(view->lines); } else if (view->mode == TOG_VIEW_SPLIT_VERT) { if (view->child && view->child->resized_x) *x = view->child->resized_x; else if (view->resized_x) *x = view->resized_x; else *x = view_split_begin_x(view->begin_x); } } /* Split view horizontally at y and offset view->state->selected line. */ static const struct got_error * view_init_hsplit(struct tog_view *view, int y) { const struct got_error *err = NULL; view->nlines = y; view->ncols = COLS; err = view_resize(view); if (err) return err; err = offset_selection_down(view); return err; } static const struct got_error * log_goto_line(struct tog_view *view, int nlines) { const struct got_error *err = NULL; struct tog_log_view_state *s = &view->state.log; int g, idx = s->selected_entry->idx; if (s->first_displayed_entry == NULL || s->last_displayed_entry == NULL) return NULL; g = view->gline; view->gline = 0; if (g >= s->first_displayed_entry->idx + 1 && g <= s->last_displayed_entry->idx + 1 && g - s->first_displayed_entry->idx - 1 < nlines) { s->selected = g - s->first_displayed_entry->idx - 1; select_commit(s); return NULL; } if (idx + 1 < g) { err = log_move_cursor_down(view, g - idx - 1); if (!err && g > s->selected_entry->idx + 1) err = log_move_cursor_down(view, g - s->first_displayed_entry->idx - 1); if (err) return err; } else if (idx + 1 > g) log_move_cursor_up(view, idx - g + 1, 0); if (g < nlines && s->first_displayed_entry->idx == 0) s->selected = g - 1; select_commit(s); return NULL; } static void horizontal_scroll_input(struct tog_view *view, int ch) { switch (ch) { case KEY_LEFT: case 'h': view->x -= MIN(view->x, 2); if (view->x <= 0) view->count = 0; break; case KEY_RIGHT: case 'l': if (view->x + view->ncols / 2 < view->maxx) view->x += 2; else view->count = 0; break; case '0': view->x = 0; break; case '$': view->x = MAX(view->maxx - view->ncols / 2, 0); view->count = 0; break; default: break; } } static const struct got_error * input_log_view(struct tog_view **new_view, struct tog_view *view, int ch) { const struct got_error *err = NULL; struct tog_log_view_state *s = &view->state.log; int eos, nscroll; if (s->thread_args.load_all) { if (ch == CTRL('g') || ch == KEY_BACKSPACE) s->thread_args.load_all = 0; else if (s->thread_args.log_complete) { err = log_move_cursor_down(view, s->commits->ncommits); s->thread_args.load_all = 0; } if (err) return err; } eos = nscroll = view->nlines - 1; if (view_is_hsplit_top(view)) --eos; /* border */ if (view->gline) return log_goto_line(view, eos); switch (ch) { case '&': err = limit_log_view(view); break; case 'q': s->quit = 1; break; case '0': case '$': case KEY_RIGHT: case 'l': case KEY_LEFT: case 'h': horizontal_scroll_input(view, ch); break; case 'k': case KEY_UP: case '<': case ',': case CTRL('p'): log_move_cursor_up(view, 0, 0); break; case 'g': case '=': case KEY_HOME: log_move_cursor_up(view, 0, 1); view->count = 0; break; case CTRL('u'): case 'u': nscroll /= 2; /* FALL THROUGH */ case KEY_PPAGE: case CTRL('b'): case 'b': log_move_cursor_up(view, nscroll, 0); break; case 'j': case KEY_DOWN: case '>': case '.': case CTRL('n'): err = log_move_cursor_down(view, 0); break; case '@': s->use_committer = !s->use_committer; view->action = s->use_committer ? "show committer" : "show commit author"; break; case 'G': case '*': case KEY_END: { /* We don't know yet how many commits, so we're forced to * traverse them all. */ view->count = 0; s->thread_args.load_all = 1; if (!s->thread_args.log_complete) return trigger_log_thread(view, 0); err = log_move_cursor_down(view, s->commits->ncommits); s->thread_args.load_all = 0; break; } case CTRL('d'): case 'd': nscroll /= 2; /* FALL THROUGH */ case KEY_NPAGE: case CTRL('f'): case 'f': case ' ': err = log_move_cursor_down(view, nscroll); break; case KEY_RESIZE: if (s->selected > view->nlines - 2) s->selected = view->nlines - 2; if (s->selected > s->commits->ncommits - 1) s->selected = s->commits->ncommits - 1; select_commit(s); if (s->commits->ncommits < view->nlines - 1 && !s->thread_args.log_complete) { s->thread_args.commits_needed += (view->nlines - 1) - s->commits->ncommits; err = trigger_log_thread(view, 1); } break; case KEY_ENTER: case '\r': view->count = 0; if (s->selected_entry == NULL) break; err = view_request_new(new_view, view, TOG_VIEW_DIFF); break; case 'T': view->count = 0; if (s->selected_entry == NULL) break; err = view_request_new(new_view, view, TOG_VIEW_TREE); break; case KEY_BACKSPACE: case CTRL('l'): case 'B': view->count = 0; if (ch == KEY_BACKSPACE && got_path_is_root_dir(s->in_repo_path)) break; err = stop_log_thread(s); if (err) return err; if (ch == KEY_BACKSPACE) { char *parent_path; err = got_path_dirname(&parent_path, s->in_repo_path); if (err) return err; free(s->in_repo_path); s->in_repo_path = parent_path; s->thread_args.in_repo_path = s->in_repo_path; } else if (ch == CTRL('l')) { struct got_object_id *start_id; err = got_repo_match_object_id(&start_id, NULL, s->head_ref_name ? s->head_ref_name : GOT_REF_HEAD, GOT_OBJ_TYPE_COMMIT, &tog_refs, s->repo); if (err) { if (s->head_ref_name == NULL || err->code != GOT_ERR_NOT_REF) return err; /* Try to cope with deleted references. */ free(s->head_ref_name); s->head_ref_name = NULL; err = got_repo_match_object_id(&start_id, NULL, GOT_REF_HEAD, GOT_OBJ_TYPE_COMMIT, &tog_refs, s->repo); if (err) return err; } free(s->start_id); s->start_id = start_id; s->thread_args.start_id = s->start_id; } else /* 'B' */ s->log_branches = !s->log_branches; if (s->thread_args.pack_fds == NULL) { err = got_repo_pack_fds_open(&s->thread_args.pack_fds); if (err) return err; } err = got_repo_open(&s->thread_args.repo, got_repo_get_path(s->repo), NULL, s->thread_args.pack_fds); if (err) return err; tog_free_refs(); err = tog_load_refs(s->repo, 0); if (err) return err; err = got_commit_graph_open(&s->thread_args.graph, s->in_repo_path, !s->log_branches); if (err) return err; err = got_commit_graph_bfsort(s->thread_args.graph, s->start_id, s->repo, NULL, NULL); if (err) return err; free_commits(&s->real_commits); free_commits(&s->limit_commits); s->first_displayed_entry = NULL; s->last_displayed_entry = NULL; s->selected_entry = NULL; s->selected = 0; s->thread_args.log_complete = 0; s->quit = 0; s->thread_args.commits_needed = view->lines; s->matched_entry = NULL; s->search_entry = NULL; view->offset = 0; break; case 'R': view->count = 0; err = view_request_new(new_view, view, TOG_VIEW_REF); break; default: view->count = 0; break; } return err; } static const struct got_error * apply_unveil(const char *repo_path, const char *worktree_path) { const struct got_error *error; #ifdef PROFILE if (unveil("gmon.out", "rwc") != 0) return got_error_from_errno2("unveil", "gmon.out"); #endif if (repo_path && unveil(repo_path, "r") != 0) return got_error_from_errno2("unveil", repo_path); if (worktree_path && unveil(worktree_path, "rwc") != 0) return got_error_from_errno2("unveil", worktree_path); if (unveil(GOT_TMPDIR_STR, "rwc") != 0) return got_error_from_errno2("unveil", GOT_TMPDIR_STR); error = got_privsep_unveil_exec_helpers(); if (error != NULL) return error; if (unveil(NULL, NULL) != 0) return got_error_from_errno("unveil"); return NULL; } static const struct got_error * init_mock_term(const char *test_script_path) { const struct got_error *err = NULL; const char *screen_dump_path; int in; if (test_script_path == NULL || *test_script_path == '\0') return got_error_msg(GOT_ERR_IO, "TOG_TEST_SCRIPT not defined"); tog_io.f = fopen(test_script_path, "re"); if (tog_io.f == NULL) { err = got_error_from_errno_fmt("fopen: %s", test_script_path); goto done; } /* test mode, we don't want any output */ tog_io.cout = fopen("/dev/null", "w+"); if (tog_io.cout == NULL) { err = got_error_from_errno2("fopen", "/dev/null"); goto done; } in = dup(fileno(tog_io.cout)); if (in == -1) { err = got_error_from_errno("dup"); goto done; } tog_io.cin = fdopen(in, "r"); if (tog_io.cin == NULL) { err = got_error_from_errno("fdopen"); close(in); goto done; } screen_dump_path = getenv("TOG_SCR_DUMP"); if (screen_dump_path == NULL || *screen_dump_path == '\0') return got_error_msg(GOT_ERR_IO, "TOG_SCR_DUMP not defined"); tog_io.sdump = fopen(screen_dump_path, "we"); if (tog_io.sdump == NULL) { err = got_error_from_errno2("fopen", screen_dump_path); goto done; } if (fseeko(tog_io.f, 0L, SEEK_SET) == -1) { err = got_error_from_errno("fseeko"); goto done; } if (newterm(NULL, tog_io.cout, tog_io.cin) == NULL) err = got_error_msg(GOT_ERR_IO, "newterm: failed to initialise curses"); using_mock_io = 1; done: if (err) tog_io_close(); return err; } static void init_curses(void) { if (using_mock_io) /* In test mode we use a fake terminal */ return; initscr(); cbreak(); halfdelay(1); /* Fast refresh while initial view is loading. */ noecho(); nonl(); intrflush(stdscr, FALSE); keypad(stdscr, TRUE); curs_set(0); if (getenv("TOG_COLORS") != NULL) { start_color(); use_default_colors(); } return; } static const struct got_error * set_tog_base_commit(struct got_repository *repo, struct got_worktree *worktree) { tog_base_commit.id = got_object_id_dup( got_worktree_get_base_commit_id(worktree)); if (tog_base_commit.id == NULL) return got_error_from_errno( "got_object_id_dup"); return NULL; } static const struct got_error * get_in_repo_path_from_argv0(char **in_repo_path, int argc, char *argv[], struct got_repository *repo, struct got_worktree *worktree) { const struct got_error *err = NULL; if (argc == 0) { *in_repo_path = strdup("/"); if (*in_repo_path == NULL) return got_error_from_errno("strdup"); return NULL; } if (worktree) { const char *prefix = got_worktree_get_path_prefix(worktree); char *p; err = got_worktree_resolve_path(&p, worktree, argv[0]); if (err) return err; if (asprintf(in_repo_path, "%s%s%s", prefix, (p[0] != '\0' && !got_path_is_root_dir(prefix)) ? "/" : "", p) == -1) { err = got_error_from_errno("asprintf"); *in_repo_path = NULL; } free(p); } else err = got_repo_map_path(in_repo_path, repo, argv[0]); return err; } static const struct got_error * cmd_log(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; struct got_object_id *start_id = NULL; char *in_repo_path = NULL, *repo_path = NULL, *cwd = NULL; char *keyword_idstr = NULL, *start_commit = NULL, *label = NULL; struct got_reference *ref = NULL; const char *head_ref_name = NULL; int ch, log_branches = 0; struct tog_view *view; int *pack_fds = NULL; while ((ch = getopt(argc, argv, "bc:r:")) != -1) { switch (ch) { case 'b': log_branches = 1; break; case 'c': start_commit = optarg; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); break; default: usage_log(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc > 1) usage_log(); error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_worktree_open(&worktree, cwd, NULL); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; if (worktree) repo_path = strdup(got_worktree_get_repo_path(worktree)); else repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; error = get_in_repo_path_from_argv0(&in_repo_path, argc, argv, repo, worktree); if (error) goto done; init_curses(); error = apply_unveil(got_repo_get_path(repo), worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; /* already loaded by tog_log_with_path()? */ if (TAILQ_EMPTY(&tog_refs)) { error = tog_load_refs(repo, 0); if (error) goto done; } if (start_commit == NULL) { error = got_repo_match_object_id(&start_id, &label, worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, GOT_OBJ_TYPE_COMMIT, &tog_refs, repo); if (error) goto done; head_ref_name = label; } else { error = got_keyword_to_idstr(&keyword_idstr, start_commit, repo, worktree); if (error != NULL) goto done; if (keyword_idstr != NULL) start_commit = keyword_idstr; error = got_ref_open(&ref, repo, start_commit, 0); if (error == NULL) head_ref_name = got_ref_get_name(ref); else if (error->code != GOT_ERR_NOT_REF) goto done; error = got_repo_match_object_id(&start_id, NULL, start_commit, GOT_OBJ_TYPE_COMMIT, &tog_refs, repo); if (error) goto done; } view = view_open(0, 0, 0, 0, TOG_VIEW_LOG); if (view == NULL) { error = got_error_from_errno("view_open"); goto done; } if (worktree) { error = set_tog_base_commit(repo, worktree); if (error != NULL) goto done; } error = open_log_view(view, start_id, repo, head_ref_name, in_repo_path, log_branches, worktree); if (error) goto done; if (worktree) { /* The work tree will be closed by the log thread. */ worktree = NULL; } error = view_loop(view); done: free(tog_base_commit.id); free(keyword_idstr); free(in_repo_path); free(repo_path); free(cwd); free(start_id); free(label); if (ref) got_ref_close(ref); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } tog_free_refs(); return error; } __dead static void usage_diff(void) { endwin(); fprintf(stderr, "usage: %s diff [-aw] [-C number] [-r repository-path] " "object1 object2\n", getprogname()); exit(1); } static int match_line(const char *line, regex_t *regex, size_t nmatch, regmatch_t *regmatch) { return regexec(regex, line, nmatch, regmatch, 0) == 0; } static struct tog_color * match_color(struct tog_colors *colors, const char *line) { struct tog_color *tc = NULL; STAILQ_FOREACH(tc, colors, entry) { if (match_line(line, &tc->regex, 0, NULL)) return tc; } return NULL; } static const struct got_error * add_matched_line(int *wtotal, const char *line, int wlimit, int col_tab_align, WINDOW *window, int skipcol, regmatch_t *regmatch) { const struct got_error *err = NULL; char *exstr = NULL; wchar_t *wline = NULL; int rme, rms, n, width, scrollx; int width0 = 0, width1 = 0, width2 = 0; char *seg0 = NULL, *seg1 = NULL, *seg2 = NULL; *wtotal = 0; rms = regmatch->rm_so; rme = regmatch->rm_eo; err = expand_tab(&exstr, line); if (err) return err; /* Split the line into 3 segments, according to match offsets. */ seg0 = strndup(exstr, rms); if (seg0 == NULL) { err = got_error_from_errno("strndup"); goto done; } seg1 = strndup(exstr + rms, rme - rms); if (seg1 == NULL) { err = got_error_from_errno("strndup"); goto done; } seg2 = strdup(exstr + rme); if (seg2 == NULL) { err = got_error_from_errno("strndup"); goto done; } /* draw up to matched token if we haven't scrolled past it */ err = format_line(&wline, &width0, NULL, seg0, 0, wlimit, col_tab_align, 1); if (err) goto done; n = MAX(width0 - skipcol, 0); if (n) { free(wline); err = format_line(&wline, &width, &scrollx, seg0, skipcol, wlimit, col_tab_align, 1); if (err) goto done; waddwstr(window, &wline[scrollx]); wlimit -= width; *wtotal += width; } if (wlimit > 0) { int i = 0, w = 0; size_t wlen; free(wline); err = format_line(&wline, &width1, NULL, seg1, 0, wlimit, col_tab_align, 1); if (err) goto done; wlen = wcslen(wline); while (i < wlen) { width = wcwidth(wline[i]); if (width == -1) { /* should not happen, tabs are expanded */ err = got_error(GOT_ERR_RANGE); goto done; } if (width0 + w + width > skipcol) break; w += width; i++; } /* draw (visible part of) matched token (if scrolled into it) */ if (width1 - w > 0) { wattron(window, A_STANDOUT); waddwstr(window, &wline[i]); wattroff(window, A_STANDOUT); wlimit -= (width1 - w); *wtotal += (width1 - w); } } if (wlimit > 0) { /* draw rest of line */ free(wline); if (skipcol > width0 + width1) { err = format_line(&wline, &width2, &scrollx, seg2, skipcol - (width0 + width1), wlimit, col_tab_align, 1); if (err) goto done; waddwstr(window, &wline[scrollx]); } else { err = format_line(&wline, &width2, NULL, seg2, 0, wlimit, col_tab_align, 1); if (err) goto done; waddwstr(window, wline); } *wtotal += width2; } done: free(wline); free(exstr); free(seg0); free(seg1); free(seg2); return err; } static int gotoline(struct tog_view *view, int *lineno, int *nprinted) { FILE *f = NULL; int *eof, *first, *selected; if (view->type == TOG_VIEW_DIFF) { struct tog_diff_view_state *s = &view->state.diff; first = &s->first_displayed_line; selected = first; eof = &s->eof; f = s->f; } else if (view->type == TOG_VIEW_HELP) { struct tog_help_view_state *s = &view->state.help; first = &s->first_displayed_line; selected = first; eof = &s->eof; f = s->f; } else if (view->type == TOG_VIEW_BLAME) { struct tog_blame_view_state *s = &view->state.blame; first = &s->first_displayed_line; selected = &s->selected_line; eof = &s->eof; f = s->blame.f; } else return 0; /* Center gline in the middle of the page like vi(1). */ if (*lineno < view->gline - (view->nlines - 3) / 2) return 0; if (*first != 1 && (*lineno > view->gline - (view->nlines - 3) / 2)) { rewind(f); *eof = 0; *first = 1; *lineno = 0; *nprinted = 0; return 0; } *selected = view->gline <= (view->nlines - 3) / 2 ? view->gline : (view->nlines - 3) / 2 + 1; view->gline = 0; return 1; } static const struct got_error * draw_file(struct tog_view *view, const char *header) { struct tog_diff_view_state *s = &view->state.diff; regmatch_t *regmatch = &view->regmatch; const struct got_error *err; int nprinted = 0; char *line; size_t linesize = 0; ssize_t linelen; wchar_t *wline; int width; int max_lines = view->nlines; int nlines = s->nlines; off_t line_offset; s->lineno = s->first_displayed_line - 1; line_offset = s->lines[s->first_displayed_line - 1].offset; if (fseeko(s->f, line_offset, SEEK_SET) == -1) return got_error_from_errno("fseek"); werase(view->window); if (view->gline > s->nlines - 1) view->gline = s->nlines - 1; if (header) { int ln = view->gline ? view->gline <= (view->nlines - 3) / 2 ? 1 : view->gline - (view->nlines - 3) / 2 : s->lineno + s->selected_line; if (asprintf(&line, "[%d/%d] %s", ln, nlines, header) == -1) return got_error_from_errno("asprintf"); err = format_line(&wline, &width, NULL, line, 0, view->ncols, 0, 0); free(line); if (err) return err; if (view_needs_focus_indication(view)) wstandout(view->window); waddwstr(view->window, wline); free(wline); wline = NULL; while (width++ < view->ncols) waddch(view->window, ' '); if (view_needs_focus_indication(view)) wstandend(view->window); if (max_lines <= 1) return NULL; max_lines--; } s->eof = 0; view->maxx = 0; line = NULL; while (max_lines > 0 && nprinted < max_lines) { enum got_diff_line_type linetype; attr_t attr = 0; linelen = getline(&line, &linesize, s->f); if (linelen == -1) { if (feof(s->f)) { s->eof = 1; break; } free(line); return got_ferror(s->f, GOT_ERR_IO); } if (++s->lineno < s->first_displayed_line) continue; if (view->gline && !gotoline(view, &s->lineno, &nprinted)) continue; if (s->lineno == view->hiline) attr = A_STANDOUT; /* Set view->maxx based on full line length. */ err = format_line(&wline, &width, NULL, line, 0, INT_MAX, 0, view->x ? 1 : 0); if (err) { free(line); return err; } view->maxx = MAX(view->maxx, width); free(wline); wline = NULL; linetype = s->lines[s->lineno].type; if (linetype > GOT_DIFF_LINE_LOGMSG && linetype < GOT_DIFF_LINE_CONTEXT) attr |= COLOR_PAIR(linetype); if (attr) wattron(view->window, attr); if (s->first_displayed_line + nprinted == s->matched_line && regmatch->rm_so >= 0 && regmatch->rm_so < regmatch->rm_eo) { err = add_matched_line(&width, line, view->ncols, 0, view->window, view->x, regmatch); if (err) { free(line); return err; } } else { int skip; err = format_line(&wline, &width, &skip, line, view->x, view->ncols, 0, view->x ? 1 : 0); if (err) { free(line); return err; } waddwstr(view->window, &wline[skip]); free(wline); wline = NULL; } if (s->lineno == view->hiline) { /* highlight full gline length */ while (width++ < view->ncols) waddch(view->window, ' '); } else { if (width <= view->ncols - 1) waddch(view->window, '\n'); } if (attr) wattroff(view->window, attr); if (++nprinted == 1) s->first_displayed_line = s->lineno; } free(line); if (nprinted >= 1) s->last_displayed_line = s->first_displayed_line + (nprinted - 1); else s->last_displayed_line = s->first_displayed_line; view_border(view); if (s->eof) { while (nprinted < view->nlines) { waddch(view->window, '\n'); nprinted++; } err = format_line(&wline, &width, NULL, TOG_EOF_STRING, 0, view->ncols, 0, 0); if (err) { return err; } wstandout(view->window); waddwstr(view->window, wline); free(wline); wline = NULL; wstandend(view->window); } return NULL; } static char * get_datestr(time_t *time, char *datebuf) { struct tm mytm, *tm; char *p, *s; tm = gmtime_r(time, &mytm); if (tm == NULL) return NULL; s = asctime_r(tm, datebuf); if (s == NULL) return NULL; p = strchr(s, '\n'); if (p) *p = '\0'; return s; } static const struct got_error * add_line_metadata(struct got_diff_line **lines, size_t *nlines, off_t off, uint8_t type) { struct got_diff_line *p; p = reallocarray(*lines, *nlines + 1, sizeof(**lines)); if (p == NULL) return got_error_from_errno("reallocarray"); *lines = p; (*lines)[*nlines].offset = off; (*lines)[*nlines].type = type; (*nlines)++; return NULL; } static const struct got_error * cat_diff(FILE *dst, FILE *src, struct got_diff_line **d_lines, size_t *d_nlines, struct got_diff_line *s_lines, size_t s_nlines) { struct got_diff_line *p; char buf[BUFSIZ]; size_t i, r; if (fseeko(src, 0L, SEEK_SET) == -1) return got_error_from_errno("fseeko"); for (;;) { r = fread(buf, 1, sizeof(buf), src); if (r == 0) { if (ferror(src)) return got_error_from_errno("fread"); if (feof(src)) break; } if (fwrite(buf, 1, r, dst) != r) return got_ferror(dst, GOT_ERR_IO); } if (s_nlines == 0 && *d_nlines == 0) return NULL; /* * If commit info was in dst, increment line offsets * of the appended diff content, but skip s_lines[0] * because offset zero is already in *d_lines. */ if (*d_nlines > 0) { for (i = 1; i < s_nlines; ++i) s_lines[i].offset += (*d_lines)[*d_nlines - 1].offset; if (s_nlines > 0) { --s_nlines; ++s_lines; } } p = reallocarray(*d_lines, *d_nlines + s_nlines, sizeof(*p)); if (p == NULL) { /* d_lines is freed in close_diff_view() */ return got_error_from_errno("reallocarray"); } *d_lines = p; memcpy(*d_lines + *d_nlines, s_lines, s_nlines * sizeof(*s_lines)); *d_nlines += s_nlines; return NULL; } static const struct got_error * write_commit_info(struct got_diff_line **lines, size_t *nlines, struct got_object_id *commit_id, struct got_reflist_head *refs, struct got_repository *repo, int ignore_ws, int force_text_diff, struct got_diffstat_cb_arg *dsa, FILE *outfile) { const struct got_error *err = NULL; char datebuf[26], *datestr; struct got_commit_object *commit; char *id_str = NULL, *logmsg = NULL, *s = NULL, *line; time_t committer_time; const char *author, *committer; char *refs_str = NULL; struct got_pathlist_entry *pe; off_t outoff = 0; int n; err = build_refs_str(&refs_str, refs, commit_id, repo); if (err) return err; err = got_object_open_as_commit(&commit, repo, commit_id); if (err) return err; err = got_object_id_str(&id_str, commit_id); if (err) { err = got_error_from_errno("got_object_id_str"); goto done; } err = add_line_metadata(lines, nlines, 0, GOT_DIFF_LINE_NONE); if (err) goto done; n = fprintf(outfile, "commit %s%s%s%s\n", id_str, refs_str ? " (" : "", refs_str ? refs_str : "", refs_str ? ")" : ""); if (n < 0) { err = got_error_from_errno("fprintf"); goto done; } outoff += n; err = add_line_metadata(lines, nlines, outoff, GOT_DIFF_LINE_META); if (err) goto done; n = fprintf(outfile, "from: %s\n", got_object_commit_get_author(commit)); if (n < 0) { err = got_error_from_errno("fprintf"); goto done; } outoff += n; err = add_line_metadata(lines, nlines, outoff, GOT_DIFF_LINE_AUTHOR); if (err) goto done; author = got_object_commit_get_author(commit); committer = got_object_commit_get_committer(commit); if (strcmp(author, committer) != 0) { n = fprintf(outfile, "via: %s\n", committer); if (n < 0) { err = got_error_from_errno("fprintf"); goto done; } outoff += n; err = add_line_metadata(lines, nlines, outoff, GOT_DIFF_LINE_AUTHOR); if (err) goto done; } committer_time = got_object_commit_get_committer_time(commit); datestr = get_datestr(&committer_time, datebuf); if (datestr) { n = fprintf(outfile, "date: %s UTC\n", datestr); if (n < 0) { err = got_error_from_errno("fprintf"); goto done; } outoff += n; err = add_line_metadata(lines, nlines, outoff, GOT_DIFF_LINE_DATE); if (err) goto done; } if (got_object_commit_get_nparents(commit) > 1) { const struct got_object_id_queue *parent_ids; struct got_object_qid *qid; int pn = 1; parent_ids = got_object_commit_get_parent_ids(commit); STAILQ_FOREACH(qid, parent_ids, entry) { err = got_object_id_str(&id_str, &qid->id); if (err) goto done; n = fprintf(outfile, "parent %d: %s\n", pn++, id_str); if (n < 0) { err = got_error_from_errno("fprintf"); goto done; } outoff += n; err = add_line_metadata(lines, nlines, outoff, GOT_DIFF_LINE_META); if (err) goto done; free(id_str); id_str = NULL; } } err = got_object_commit_get_logmsg(&logmsg, commit); if (err) goto done; s = logmsg; while ((line = strsep(&s, "\n")) != NULL) { n = fprintf(outfile, "%s\n", line); if (n < 0) { err = got_error_from_errno("fprintf"); goto done; } outoff += n; err = add_line_metadata(lines, nlines, outoff, GOT_DIFF_LINE_LOGMSG); if (err) goto done; } TAILQ_FOREACH(pe, dsa->paths, entry) { struct got_diff_changed_path *cp = pe->data; int pad = dsa->max_path_len - pe->path_len + 1; n = fprintf(outfile, "%c %s%*c | %*d+ %*d-\n", cp->status, pe->path, pad, ' ', dsa->add_cols + 1, cp->add, dsa->rm_cols + 1, cp->rm); if (n < 0) { err = got_error_from_errno("fprintf"); goto done; } outoff += n; err = add_line_metadata(lines, nlines, outoff, GOT_DIFF_LINE_CHANGES); if (err) goto done; } fputc('\n', outfile); outoff++; err = add_line_metadata(lines, nlines, outoff, GOT_DIFF_LINE_NONE); if (err) goto done; n = fprintf(outfile, "%d file%s changed, %d insertion%s(+), %d deletion%s(-)\n", dsa->nfiles, dsa->nfiles > 1 ? "s" : "", dsa->ins, dsa->ins != 1 ? "s" : "", dsa->del, dsa->del != 1 ? "s" : ""); if (n < 0) { err = got_error_from_errno("fprintf"); goto done; } outoff += n; err = add_line_metadata(lines, nlines, outoff, GOT_DIFF_LINE_NONE); if (err) goto done; fputc('\n', outfile); outoff++; err = add_line_metadata(lines, nlines, outoff, GOT_DIFF_LINE_NONE); done: free(id_str); free(logmsg); free(refs_str); got_object_commit_close(commit); if (err) { free(*lines); *lines = NULL; *nlines = 0; } return err; } static const struct got_error * create_diff(struct tog_diff_view_state *s) { const struct got_error *err = NULL; FILE *tmp_diff_file = NULL; int obj_type; struct got_diff_line *lines = NULL; struct got_pathlist_head changed_paths; struct got_commit_object *commit2 = NULL; TAILQ_INIT(&changed_paths); free(s->lines); s->lines = malloc(sizeof(*s->lines)); if (s->lines == NULL) return got_error_from_errno("malloc"); s->nlines = 0; if (s->f && fclose(s->f) == EOF) { s->f = NULL; return got_error_from_errno("fclose"); } s->f = got_opentemp(); if (s->f == NULL) return got_error_from_errno("got_opentemp"); tmp_diff_file = got_opentemp(); if (tmp_diff_file == NULL) return got_error_from_errno("got_opentemp"); if (s->id1) err = got_object_get_type(&obj_type, s->repo, s->id1); else err = got_object_get_type(&obj_type, s->repo, s->id2); if (err) goto done; switch (obj_type) { case GOT_OBJ_TYPE_BLOB: err = got_diff_objects_as_blobs(&s->lines, &s->nlines, s->f1, s->f2, s->fd1, s->fd2, s->id1, s->id2, s->label1, s->label2, tog_diff_algo, s->diff_context, s->ignore_whitespace, s->force_text_diff, NULL, s->repo, s->f); break; case GOT_OBJ_TYPE_TREE: err = got_diff_objects_as_trees(&s->lines, &s->nlines, s->f1, s->f2, s->fd1, s->fd2, s->id1, s->id2, NULL, "", "", tog_diff_algo, s->diff_context, s->ignore_whitespace, s->force_text_diff, NULL, s->repo, s->f); break; case GOT_OBJ_TYPE_COMMIT: { const struct got_object_id_queue *parent_ids; struct got_object_qid *pid; struct got_reflist_head *refs; size_t nlines = 0; struct got_diffstat_cb_arg dsa = { 0, 0, 0, 0, 0, 0, &changed_paths, s->ignore_whitespace, s->force_text_diff, tog_diff_algo }; lines = malloc(sizeof(*lines)); if (lines == NULL) { err = got_error_from_errno("malloc"); goto done; } /* build diff first in tmp file then append to commit info */ err = got_diff_objects_as_commits(&lines, &nlines, s->f1, s->f2, s->fd1, s->fd2, s->id1, s->id2, NULL, tog_diff_algo, s->diff_context, s->ignore_whitespace, s->force_text_diff, &dsa, s->repo, tmp_diff_file); if (err) break; refs = got_reflist_object_id_map_lookup(tog_refs_idmap, s->id2); /* Show commit info if we're diffing to a parent/root commit. */ if (s->id1 == NULL) { err = write_commit_info(&s->lines, &s->nlines, s->id2, refs, s->repo, s->ignore_whitespace, s->force_text_diff, &dsa, s->f); if (err) goto done; } else { err = got_object_open_as_commit(&commit2, s->repo, s->id2); if (err) goto done; parent_ids = got_object_commit_get_parent_ids(commit2); STAILQ_FOREACH(pid, parent_ids, entry) { if (got_object_id_cmp(s->id1, &pid->id) == 0) { err = write_commit_info(&s->lines, &s->nlines, s->id2, refs, s->repo, s->ignore_whitespace, s->force_text_diff, &dsa, s->f); if (err) goto done; break; } } } err = cat_diff(s->f, tmp_diff_file, &s->lines, &s->nlines, lines, nlines); break; } default: err = got_error(GOT_ERR_OBJ_TYPE); break; } done: free(lines); if (commit2 != NULL) got_object_commit_close(commit2); got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL); if (s->f && fflush(s->f) != 0 && err == NULL) err = got_error_from_errno("fflush"); if (tmp_diff_file && fclose(tmp_diff_file) == EOF && err == NULL) err = got_error_from_errno("fclose"); return err; } static void diff_view_indicate_progress(struct tog_view *view) { mvwaddstr(view->window, 0, 0, "diffing..."); update_panels(); doupdate(); } static const struct got_error * search_start_diff_view(struct tog_view *view) { struct tog_diff_view_state *s = &view->state.diff; s->matched_line = 0; return NULL; } static void search_setup_diff_view(struct tog_view *view, FILE **f, off_t **line_offsets, size_t *nlines, int **first, int **last, int **match, int **selected) { struct tog_diff_view_state *s = &view->state.diff; *f = s->f; *nlines = s->nlines; *line_offsets = NULL; *match = &s->matched_line; *first = &s->first_displayed_line; *last = &s->last_displayed_line; *selected = &s->selected_line; } static const struct got_error * search_next_view_match(struct tog_view *view) { const struct got_error *err = NULL; FILE *f; int lineno; char *line = NULL; size_t linesize = 0; ssize_t linelen; off_t *line_offsets; size_t nlines = 0; int *first, *last, *match, *selected; if (!view->search_setup) return got_error_msg(GOT_ERR_NOT_IMPL, "view search not supported"); view->search_setup(view, &f, &line_offsets, &nlines, &first, &last, &match, &selected); if (!view->searching) { view->search_next_done = TOG_SEARCH_HAVE_MORE; return NULL; } if (*match) { if (view->searching == TOG_SEARCH_FORWARD) lineno = *first + 1; else lineno = *first - 1; } else lineno = *first - 1 + *selected; while (1) { off_t offset; if (lineno <= 0 || lineno > nlines) { if (*match == 0) { view->search_next_done = TOG_SEARCH_HAVE_MORE; break; } if (view->searching == TOG_SEARCH_FORWARD) lineno = 1; else lineno = nlines; } offset = view->type == TOG_VIEW_DIFF ? view->state.diff.lines[lineno - 1].offset : line_offsets[lineno - 1]; if (fseeko(f, offset, SEEK_SET) != 0) { free(line); return got_error_from_errno("fseeko"); } linelen = getline(&line, &linesize, f); if (linelen != -1) { char *exstr; err = expand_tab(&exstr, line); if (err) break; if (match_line(exstr, &view->regex, 1, &view->regmatch)) { view->search_next_done = TOG_SEARCH_HAVE_MORE; *match = lineno; free(exstr); break; } free(exstr); } if (view->searching == TOG_SEARCH_FORWARD) lineno++; else lineno--; } free(line); if (*match) { *first = *match; *selected = 1; } return err; } static const struct got_error * close_diff_view(struct tog_view *view) { const struct got_error *err = NULL; struct tog_diff_view_state *s = &view->state.diff; free(s->id1); s->id1 = NULL; free(s->id2); s->id2 = NULL; if (s->f && fclose(s->f) == EOF) err = got_error_from_errno("fclose"); s->f = NULL; if (s->f1 && fclose(s->f1) == EOF && err == NULL) err = got_error_from_errno("fclose"); s->f1 = NULL; if (s->f2 && fclose(s->f2) == EOF && err == NULL) err = got_error_from_errno("fclose"); s->f2 = NULL; if (s->fd1 != -1 && close(s->fd1) == -1 && err == NULL) err = got_error_from_errno("close"); s->fd1 = -1; if (s->fd2 != -1 && close(s->fd2) == -1 && err == NULL) err = got_error_from_errno("close"); s->fd2 = -1; free(s->lines); s->lines = NULL; s->nlines = 0; return err; } static const struct got_error * open_diff_view(struct tog_view *view, struct got_object_id *id1, struct got_object_id *id2, const char *label1, const char *label2, int diff_context, int ignore_whitespace, int force_text_diff, struct tog_view *parent_view, struct got_repository *repo) { const struct got_error *err; struct tog_diff_view_state *s = &view->state.diff; memset(s, 0, sizeof(*s)); s->fd1 = -1; s->fd2 = -1; if (id1 != NULL && id2 != NULL) { int type1, type2; err = got_object_get_type(&type1, repo, id1); if (err) goto done; err = got_object_get_type(&type2, repo, id2); if (err) goto done; if (type1 != type2) { err = got_error(GOT_ERR_OBJ_TYPE); goto done; } } s->first_displayed_line = 1; s->last_displayed_line = view->nlines; s->selected_line = 1; s->repo = repo; s->label1 = label1; s->label2 = label2; if (id1) { s->id1 = got_object_id_dup(id1); if (s->id1 == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } } else s->id1 = NULL; s->id2 = got_object_id_dup(id2); if (s->id2 == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } s->f1 = got_opentemp(); if (s->f1 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } s->f2 = got_opentemp(); if (s->f2 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } s->fd1 = got_opentempfd(); if (s->fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } s->fd2 = got_opentempfd(); if (s->fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } s->diff_context = diff_context; s->ignore_whitespace = ignore_whitespace; s->force_text_diff = force_text_diff; s->parent_view = parent_view; s->repo = repo; if (has_colors() && getenv("TOG_COLORS") != NULL && !using_mock_io) { int rc; rc = init_pair(GOT_DIFF_LINE_MINUS, get_color_value("TOG_COLOR_DIFF_MINUS"), -1); if (rc != ERR) rc = init_pair(GOT_DIFF_LINE_PLUS, get_color_value("TOG_COLOR_DIFF_PLUS"), -1); if (rc != ERR) rc = init_pair(GOT_DIFF_LINE_HUNK, get_color_value("TOG_COLOR_DIFF_CHUNK_HEADER"), -1); if (rc != ERR) rc = init_pair(GOT_DIFF_LINE_META, get_color_value("TOG_COLOR_DIFF_META"), -1); if (rc != ERR) rc = init_pair(GOT_DIFF_LINE_CHANGES, get_color_value("TOG_COLOR_DIFF_META"), -1); if (rc != ERR) rc = init_pair(GOT_DIFF_LINE_BLOB_MIN, get_color_value("TOG_COLOR_DIFF_META"), -1); if (rc != ERR) rc = init_pair(GOT_DIFF_LINE_BLOB_PLUS, get_color_value("TOG_COLOR_DIFF_META"), -1); if (rc != ERR) rc = init_pair(GOT_DIFF_LINE_AUTHOR, get_color_value("TOG_COLOR_AUTHOR"), -1); if (rc != ERR) rc = init_pair(GOT_DIFF_LINE_DATE, get_color_value("TOG_COLOR_DATE"), -1); if (rc == ERR) { err = got_error(GOT_ERR_RANGE); goto done; } } if (parent_view && parent_view->type == TOG_VIEW_LOG && view_is_splitscreen(view)) show_log_view(parent_view); /* draw border */ diff_view_indicate_progress(view); err = create_diff(s); view->show = show_diff_view; view->input = input_diff_view; view->reset = reset_diff_view; view->close = close_diff_view; view->search_start = search_start_diff_view; view->search_setup = search_setup_diff_view; view->search_next = search_next_view_match; done: if (err) { if (view->close == NULL) close_diff_view(view); view_close(view); } return err; } static const struct got_error * show_diff_view(struct tog_view *view) { const struct got_error *err; struct tog_diff_view_state *s = &view->state.diff; char *id_str1 = NULL, *id_str2, *header; const char *label1, *label2; if (s->id1) { err = got_object_id_str(&id_str1, s->id1); if (err) return err; label1 = s->label1 ? s->label1 : id_str1; } else label1 = "/dev/null"; err = got_object_id_str(&id_str2, s->id2); if (err) return err; label2 = s->label2 ? s->label2 : id_str2; if (asprintf(&header, "diff %s %s", label1, label2) == -1) { err = got_error_from_errno("asprintf"); free(id_str1); free(id_str2); return err; } free(id_str1); free(id_str2); err = draw_file(view, header); free(header); return err; } static const struct got_error * set_selected_commit(struct tog_diff_view_state *s, struct commit_queue_entry *entry) { const struct got_error *err; const struct got_object_id_queue *parent_ids; struct got_commit_object *selected_commit; struct got_object_qid *pid; free(s->id2); s->id2 = got_object_id_dup(entry->id); if (s->id2 == NULL) return got_error_from_errno("got_object_id_dup"); err = got_object_open_as_commit(&selected_commit, s->repo, entry->id); if (err) return err; parent_ids = got_object_commit_get_parent_ids(selected_commit); free(s->id1); pid = STAILQ_FIRST(parent_ids); s->id1 = pid ? got_object_id_dup(&pid->id) : NULL; got_object_commit_close(selected_commit); return NULL; } static const struct got_error * reset_diff_view(struct tog_view *view) { struct tog_diff_view_state *s = &view->state.diff; view->count = 0; wclear(view->window); s->first_displayed_line = 1; s->last_displayed_line = view->nlines; s->matched_line = 0; diff_view_indicate_progress(view); return create_diff(s); } static void diff_prev_index(struct tog_diff_view_state *s, enum got_diff_line_type type) { int start, i; i = start = s->first_displayed_line - 1; while (s->lines[i].type != type) { if (i == 0) i = s->nlines - 1; if (--i == start) return; /* do nothing, requested type not in file */ } s->selected_line = 1; s->first_displayed_line = i; } static void diff_next_index(struct tog_diff_view_state *s, enum got_diff_line_type type) { int start, i; i = start = s->first_displayed_line + 1; while (s->lines[i].type != type) { if (i == s->nlines - 1) i = 0; if (++i == start) return; /* do nothing, requested type not in file */ } s->selected_line = 1; s->first_displayed_line = i; } static struct got_object_id *get_selected_commit_id(struct tog_blame_line *, int, int, int); static struct got_object_id *get_annotation_for_line(struct tog_blame_line *, int, int); static const struct got_error * input_diff_view(struct tog_view **new_view, struct tog_view *view, int ch) { const struct got_error *err = NULL; struct tog_diff_view_state *s = &view->state.diff; struct tog_log_view_state *ls; struct commit_queue_entry *old_selected_entry; char *line = NULL; size_t linesize = 0; ssize_t linelen; int i, nscroll = view->nlines - 1, up = 0; s->lineno = s->first_displayed_line - 1 + s->selected_line; switch (ch) { case '0': case '$': case KEY_RIGHT: case 'l': case KEY_LEFT: case 'h': horizontal_scroll_input(view, ch); break; case 'a': case 'w': if (ch == 'a') { s->force_text_diff = !s->force_text_diff; view->action = s->force_text_diff ? "force ASCII text enabled" : "force ASCII text disabled"; } else if (ch == 'w') { s->ignore_whitespace = !s->ignore_whitespace; view->action = s->ignore_whitespace ? "ignore whitespace enabled" : "ignore whitespace disabled"; } err = reset_diff_view(view); break; case 'g': case KEY_HOME: s->first_displayed_line = 1; view->count = 0; break; case 'G': case KEY_END: view->count = 0; if (s->eof) break; s->first_displayed_line = (s->nlines - view->nlines) + 2; s->eof = 1; break; case 'k': case KEY_UP: case CTRL('p'): if (s->first_displayed_line > 1) s->first_displayed_line--; else view->count = 0; break; case CTRL('u'): case 'u': nscroll /= 2; /* FALL THROUGH */ case KEY_PPAGE: case CTRL('b'): case 'b': if (s->first_displayed_line == 1) { view->count = 0; break; } i = 0; while (i++ < nscroll && s->first_displayed_line > 1) s->first_displayed_line--; break; case 'j': case KEY_DOWN: case CTRL('n'): if (!s->eof) s->first_displayed_line++; else view->count = 0; break; case CTRL('d'): case 'd': nscroll /= 2; /* FALL THROUGH */ case KEY_NPAGE: case CTRL('f'): case 'f': case ' ': if (s->eof) { view->count = 0; break; } i = 0; while (!s->eof && i++ < nscroll) { linelen = getline(&line, &linesize, s->f); s->first_displayed_line++; if (linelen == -1) { if (feof(s->f)) { s->eof = 1; } else err = got_ferror(s->f, GOT_ERR_IO); break; } } free(line); break; case '(': diff_prev_index(s, GOT_DIFF_LINE_BLOB_MIN); break; case ')': diff_next_index(s, GOT_DIFF_LINE_BLOB_MIN); break; case '{': diff_prev_index(s, GOT_DIFF_LINE_HUNK); break; case '}': diff_next_index(s, GOT_DIFF_LINE_HUNK); break; case '[': if (s->diff_context > 0) { s->diff_context--; s->matched_line = 0; diff_view_indicate_progress(view); err = create_diff(s); if (s->first_displayed_line + view->nlines - 1 > s->nlines) { s->first_displayed_line = 1; s->last_displayed_line = view->nlines; } } else view->count = 0; break; case ']': if (s->diff_context < GOT_DIFF_MAX_CONTEXT) { s->diff_context++; s->matched_line = 0; diff_view_indicate_progress(view); err = create_diff(s); } else view->count = 0; break; case '<': case ',': case 'K': up = 1; /* FALL THROUGH */ case '>': case '.': case 'J': if (s->parent_view == NULL) { view->count = 0; break; } s->parent_view->count = view->count; if (s->parent_view->type == TOG_VIEW_LOG) { ls = &s->parent_view->state.log; old_selected_entry = ls->selected_entry; err = input_log_view(NULL, s->parent_view, up ? KEY_UP : KEY_DOWN); if (err) break; view->count = s->parent_view->count; if (old_selected_entry == ls->selected_entry) break; err = set_selected_commit(s, ls->selected_entry); if (err) break; } else if (s->parent_view->type == TOG_VIEW_BLAME) { struct tog_blame_view_state *bs; struct got_object_id *id, *prev_id; bs = &s->parent_view->state.blame; prev_id = get_annotation_for_line(bs->blame.lines, bs->blame.nlines, bs->last_diffed_line); err = input_blame_view(&view, s->parent_view, up ? KEY_UP : KEY_DOWN); if (err) break; view->count = s->parent_view->count; if (prev_id == NULL) break; id = get_selected_commit_id(bs->blame.lines, bs->blame.nlines, bs->first_displayed_line, bs->selected_line); if (id == NULL) break; if (!got_object_id_cmp(prev_id, id)) break; err = input_blame_view(&view, s->parent_view, KEY_ENTER); if (err) break; } s->first_displayed_line = 1; s->last_displayed_line = view->nlines; s->matched_line = 0; view->x = 0; diff_view_indicate_progress(view); err = create_diff(s); break; default: view->count = 0; break; } return err; } static const struct got_error * cmd_diff(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; struct got_object_id *id1 = NULL, *id2 = NULL; char *repo_path = NULL, *cwd = NULL; char *id_str1 = NULL, *id_str2 = NULL; char *keyword_idstr1 = NULL, *keyword_idstr2 = NULL; char *label1 = NULL, *label2 = NULL; int diff_context = 3, ignore_whitespace = 0; int ch, force_text_diff = 0; const char *errstr; struct tog_view *view; int *pack_fds = NULL; while ((ch = getopt(argc, argv, "aC:r:w")) != -1) { switch (ch) { case 'a': force_text_diff = 1; break; case 'C': diff_context = strtonum(optarg, 0, GOT_DIFF_MAX_CONTEXT, &errstr); if (errstr != NULL) errx(1, "number of context lines is %s: %s", errstr, errstr); break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; case 'w': ignore_whitespace = 1; break; default: usage_diff(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc == 0) { usage_diff(); /* TODO show local worktree changes */ } else if (argc == 2) { id_str1 = argv[0]; id_str2 = argv[1]; } else usage_diff(); error = got_repo_pack_fds_open(&pack_fds); if (error) goto done; if (repo_path == NULL) { cwd = getcwd(NULL, 0); if (cwd == NULL) return got_error_from_errno("getcwd"); error = got_worktree_open(&worktree, cwd, NULL); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; if (worktree) repo_path = strdup(got_worktree_get_repo_path(worktree)); else repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error) goto done; init_curses(); error = apply_unveil(got_repo_get_path(repo), NULL); if (error) goto done; error = tog_load_refs(repo, 0); if (error) goto done; if (id_str1 != NULL) { error = got_keyword_to_idstr(&keyword_idstr1, id_str1, repo, worktree); if (error != NULL) goto done; if (keyword_idstr1 != NULL) id_str1 = keyword_idstr1; } if (id_str2 != NULL) { error = got_keyword_to_idstr(&keyword_idstr2, id_str2, repo, worktree); if (error != NULL) goto done; if (keyword_idstr2 != NULL) id_str2 = keyword_idstr2; } error = got_repo_match_object_id(&id1, &label1, id_str1, GOT_OBJ_TYPE_ANY, &tog_refs, repo); if (error) goto done; error = got_repo_match_object_id(&id2, &label2, id_str2, GOT_OBJ_TYPE_ANY, &tog_refs, repo); if (error) goto done; view = view_open(0, 0, 0, 0, TOG_VIEW_DIFF); if (view == NULL) { error = got_error_from_errno("view_open"); goto done; } error = open_diff_view(view, id1, id2, label1, label2, diff_context, ignore_whitespace, force_text_diff, NULL, repo); if (error) goto done; if (worktree) { error = set_tog_base_commit(repo, worktree); if (error != NULL) goto done; /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } error = view_loop(view); done: free(tog_base_commit.id); free(keyword_idstr1); free(keyword_idstr2); free(label1); free(label2); free(id1); free(id2); free(repo_path); free(cwd); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } tog_free_refs(); return error; } __dead static void usage_blame(void) { endwin(); fprintf(stderr, "usage: %s blame [-c commit] [-r repository-path] path\n", getprogname()); exit(1); } struct tog_blame_line { int annotated; struct got_object_id *id; }; static const struct got_error * draw_blame(struct tog_view *view) { struct tog_blame_view_state *s = &view->state.blame; struct tog_blame *blame = &s->blame; regmatch_t *regmatch = &view->regmatch; const struct got_error *err; int lineno = 0, nprinted = 0; char *line = NULL; size_t linesize = 0; ssize_t linelen; wchar_t *wline; int width; struct tog_blame_line *blame_line; struct got_object_id *prev_id = NULL; char *id_str; struct tog_color *tc; err = got_object_id_str(&id_str, &s->blamed_commit->id); if (err) return err; rewind(blame->f); werase(view->window); if (asprintf(&line, "commit %s", id_str) == -1) { err = got_error_from_errno("asprintf"); free(id_str); return err; } err = format_line(&wline, &width, NULL, line, 0, view->ncols, 0, 0); free(line); line = NULL; if (err) return err; if (view_needs_focus_indication(view)) wstandout(view->window); tc = get_color(&s->colors, TOG_COLOR_COMMIT); if (tc) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); waddwstr(view->window, wline); while (width++ < view->ncols) waddch(view->window, ' '); if (tc) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); if (view_needs_focus_indication(view)) wstandend(view->window); free(wline); wline = NULL; if (view->gline > blame->nlines) view->gline = blame->nlines; if (tog_io.wait_for_ui) { struct tog_blame_thread_args *bta = &s->blame.thread_args; int rc; rc = pthread_cond_wait(&bta->blame_complete, &tog_mutex); if (rc) return got_error_set_errno(rc, "pthread_cond_wait"); tog_io.wait_for_ui = 0; } if (asprintf(&line, "[%d/%d] %s%s", view->gline ? view->gline : s->first_displayed_line - 1 + s->selected_line, blame->nlines, s->blame_complete ? "" : "annotating... ", s->path) == -1) { free(id_str); return got_error_from_errno("asprintf"); } free(id_str); err = format_line(&wline, &width, NULL, line, 0, view->ncols, 0, 0); free(line); line = NULL; if (err) return err; waddwstr(view->window, wline); free(wline); wline = NULL; if (width < view->ncols - 1) waddch(view->window, '\n'); s->eof = 0; view->maxx = 0; while (nprinted < view->nlines - 2) { linelen = getline(&line, &linesize, blame->f); if (linelen == -1) { if (feof(blame->f)) { s->eof = 1; break; } free(line); return got_ferror(blame->f, GOT_ERR_IO); } if (++lineno < s->first_displayed_line) continue; if (view->gline && !gotoline(view, &lineno, &nprinted)) continue; /* Set view->maxx based on full line length. */ err = format_line(&wline, &width, NULL, line, 0, INT_MAX, 9, 1); if (err) { free(line); return err; } free(wline); wline = NULL; view->maxx = MAX(view->maxx, width); if (nprinted == s->selected_line - 1) wstandout(view->window); if (blame->nlines > 0) { blame_line = &blame->lines[lineno - 1]; if (blame_line->annotated && prev_id && got_object_id_cmp(prev_id, blame_line->id) == 0 && !(nprinted == s->selected_line - 1)) { waddstr(view->window, " "); } else if (blame_line->annotated) { char *id_str; err = got_object_id_str(&id_str, blame_line->id); if (err) { free(line); return err; } tc = get_color(&s->colors, TOG_COLOR_COMMIT); if (tc) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); wprintw(view->window, "%.8s", id_str); if (tc) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); free(id_str); prev_id = blame_line->id; } else { waddstr(view->window, "........"); prev_id = NULL; } } else { waddstr(view->window, "........"); prev_id = NULL; } if (nprinted == s->selected_line - 1) wstandend(view->window); waddstr(view->window, " "); if (view->ncols <= 9) { width = 9; } else if (s->first_displayed_line + nprinted == s->matched_line && regmatch->rm_so >= 0 && regmatch->rm_so < regmatch->rm_eo) { err = add_matched_line(&width, line, view->ncols - 9, 9, view->window, view->x, regmatch); if (err) { free(line); return err; } width += 9; } else { int skip; err = format_line(&wline, &width, &skip, line, view->x, view->ncols - 9, 9, 1); if (err) { free(line); return err; } waddwstr(view->window, &wline[skip]); width += 9; free(wline); wline = NULL; } if (width <= view->ncols - 1) waddch(view->window, '\n'); if (++nprinted == 1) s->first_displayed_line = lineno; } free(line); s->last_displayed_line = lineno; view_border(view); return NULL; } static const struct got_error * blame_cb(void *arg, int nlines, int lineno, struct got_commit_object *commit, struct got_object_id *id) { const struct got_error *err = NULL; struct tog_blame_cb_args *a = arg; struct tog_blame_line *line; int errcode; if (nlines != a->nlines || (lineno != -1 && lineno < 1) || lineno > a->nlines) return got_error(GOT_ERR_RANGE); errcode = pthread_mutex_lock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_lock"); if (*a->quit) { /* user has quit the blame view */ err = got_error(GOT_ERR_ITER_COMPLETED); goto done; } if (lineno == -1) goto done; /* no change in this commit */ line = &a->lines[lineno - 1]; if (line->annotated) goto done; line->id = got_object_id_dup(id); if (line->id == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } line->annotated = 1; done: errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) err = got_error_set_errno(errcode, "pthread_mutex_unlock"); return err; } static void * blame_thread(void *arg) { const struct got_error *err, *close_err; struct tog_blame_thread_args *ta = arg; struct tog_blame_cb_args *a = ta->cb_args; int errcode, fd1 = -1, fd2 = -1; FILE *f1 = NULL, *f2 = NULL; fd1 = got_opentempfd(); if (fd1 == -1) return (void *)got_error_from_errno("got_opentempfd"); fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } f1 = got_opentemp(); if (f1 == NULL) { err = (void *)got_error_from_errno("got_opentemp"); goto done; } f2 = got_opentemp(); if (f2 == NULL) { err = (void *)got_error_from_errno("got_opentemp"); goto done; } err = block_signals_used_by_main_thread(); if (err) goto done; err = got_blame(ta->path, a->commit_id, ta->repo, tog_diff_algo, blame_cb, ta->cb_args, ta->cancel_cb, ta->cancel_arg, fd1, fd2, f1, f2); if (err && err->code == GOT_ERR_CANCELLED) err = NULL; errcode = pthread_mutex_lock(&tog_mutex); if (errcode) { err = got_error_set_errno(errcode, "pthread_mutex_lock"); goto done; } close_err = got_repo_close(ta->repo); if (err == NULL) err = close_err; ta->repo = NULL; *ta->complete = 1; if (tog_io.wait_for_ui) { errcode = pthread_cond_signal(&ta->blame_complete); if (errcode && err == NULL) err = got_error_set_errno(errcode, "pthread_cond_signal"); } errcode = pthread_mutex_unlock(&tog_mutex); if (errcode && err == NULL) err = got_error_set_errno(errcode, "pthread_mutex_unlock"); done: if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno("close"); if (f1 && fclose(f1) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (f2 && fclose(f2) == EOF && err == NULL) err = got_error_from_errno("fclose"); return (void *)err; } static struct got_object_id * get_selected_commit_id(struct tog_blame_line *lines, int nlines, int first_displayed_line, int selected_line) { struct tog_blame_line *line; if (nlines <= 0) return NULL; line = &lines[first_displayed_line - 1 + selected_line - 1]; if (!line->annotated) return NULL; return line->id; } static struct got_object_id * get_annotation_for_line(struct tog_blame_line *lines, int nlines, int lineno) { struct tog_blame_line *line; if (nlines <= 0 || lineno >= nlines) return NULL; line = &lines[lineno - 1]; if (!line->annotated) return NULL; return line->id; } static const struct got_error * stop_blame(struct tog_blame *blame) { const struct got_error *err = NULL; int i; if (blame->thread) { int errcode; errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_unlock"); errcode = pthread_join(blame->thread, (void **)&err); if (errcode) return got_error_set_errno(errcode, "pthread_join"); errcode = pthread_mutex_lock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_lock"); if (err && err->code == GOT_ERR_ITER_COMPLETED) err = NULL; blame->thread = 0; //NULL; } if (blame->thread_args.repo) { const struct got_error *close_err; close_err = got_repo_close(blame->thread_args.repo); if (err == NULL) err = close_err; blame->thread_args.repo = NULL; } if (blame->f) { if (fclose(blame->f) == EOF && err == NULL) err = got_error_from_errno("fclose"); blame->f = NULL; } if (blame->lines) { for (i = 0; i < blame->nlines; i++) free(blame->lines[i].id); free(blame->lines); blame->lines = NULL; } free(blame->cb_args.commit_id); blame->cb_args.commit_id = NULL; if (blame->pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(blame->pack_fds); if (err == NULL) err = pack_err; blame->pack_fds = NULL; } free(blame->line_offsets); blame->line_offsets = NULL; return err; } static const struct got_error * cancel_blame_view(void *arg) { const struct got_error *err = NULL; int *done = arg; int errcode; errcode = pthread_mutex_lock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_unlock"); if (*done) err = got_error(GOT_ERR_CANCELLED); errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_lock"); return err; } static const struct got_error * run_blame(struct tog_view *view) { struct tog_blame_view_state *s = &view->state.blame; struct tog_blame *blame = &s->blame; const struct got_error *err = NULL; struct got_commit_object *commit = NULL; struct got_blob_object *blob = NULL; struct got_repository *thread_repo = NULL; struct got_object_id *obj_id = NULL; int obj_type, fd = -1; int *pack_fds = NULL; err = got_object_open_as_commit(&commit, s->repo, &s->blamed_commit->id); if (err) return err; fd = got_opentempfd(); if (fd == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } err = got_object_id_by_path(&obj_id, s->repo, commit, s->path); if (err) goto done; err = got_object_get_type(&obj_type, s->repo, obj_id); if (err) goto done; if (obj_type != GOT_OBJ_TYPE_BLOB) { err = got_error(GOT_ERR_OBJ_TYPE); goto done; } err = got_object_open_as_blob(&blob, s->repo, obj_id, 8192, fd); if (err) goto done; blame->f = got_opentemp(); if (blame->f == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } err = got_object_blob_dump_to_file(&blame->filesize, &blame->nlines, &blame->line_offsets, blame->f, blob); if (err) goto done; if (blame->nlines == 0) { s->blame_complete = 1; goto done; } /* Don't include \n at EOF in the blame line count. */ if (blame->line_offsets[blame->nlines - 1] == blame->filesize) blame->nlines--; blame->lines = calloc(blame->nlines, sizeof(*blame->lines)); if (blame->lines == NULL) { err = got_error_from_errno("calloc"); goto done; } err = got_repo_pack_fds_open(&pack_fds); if (err) goto done; err = got_repo_open(&thread_repo, got_repo_get_path(s->repo), NULL, pack_fds); if (err) goto done; blame->pack_fds = pack_fds; blame->cb_args.view = view; blame->cb_args.lines = blame->lines; blame->cb_args.nlines = blame->nlines; blame->cb_args.commit_id = got_object_id_dup(&s->blamed_commit->id); if (blame->cb_args.commit_id == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } blame->cb_args.quit = &s->done; blame->thread_args.path = s->path; blame->thread_args.repo = thread_repo; blame->thread_args.cb_args = &blame->cb_args; blame->thread_args.complete = &s->blame_complete; blame->thread_args.cancel_cb = cancel_blame_view; blame->thread_args.cancel_arg = &s->done; s->blame_complete = 0; if (s->first_displayed_line + view->nlines - 1 > blame->nlines) { s->first_displayed_line = 1; s->last_displayed_line = view->nlines; s->selected_line = 1; } s->matched_line = 0; done: if (commit) got_object_commit_close(commit); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob) got_object_blob_close(blob); free(obj_id); if (err) stop_blame(blame); return err; } static const struct got_error * open_blame_view(struct tog_view *view, char *path, struct got_object_id *commit_id, struct got_repository *repo) { const struct got_error *err = NULL; struct tog_blame_view_state *s = &view->state.blame; STAILQ_INIT(&s->blamed_commits); s->path = strdup(path); if (s->path == NULL) return got_error_from_errno("strdup"); err = got_object_qid_alloc(&s->blamed_commit, commit_id); if (err) { free(s->path); return err; } STAILQ_INSERT_HEAD(&s->blamed_commits, s->blamed_commit, entry); s->first_displayed_line = 1; s->last_displayed_line = view->nlines; s->selected_line = 1; s->blame_complete = 0; s->repo = repo; s->commit_id = commit_id; memset(&s->blame, 0, sizeof(s->blame)); STAILQ_INIT(&s->colors); if (has_colors() && getenv("TOG_COLORS") != NULL) { err = add_color(&s->colors, "^", TOG_COLOR_COMMIT, get_color_value("TOG_COLOR_COMMIT")); if (err) return err; } view->show = show_blame_view; view->input = input_blame_view; view->reset = reset_blame_view; view->close = close_blame_view; view->search_start = search_start_blame_view; view->search_setup = search_setup_blame_view; view->search_next = search_next_view_match; if (using_mock_io) { struct tog_blame_thread_args *bta = &s->blame.thread_args; int rc; rc = pthread_cond_init(&bta->blame_complete, NULL); if (rc) return got_error_set_errno(rc, "pthread_cond_init"); } return run_blame(view); } static const struct got_error * close_blame_view(struct tog_view *view) { const struct got_error *err = NULL; struct tog_blame_view_state *s = &view->state.blame; if (s->blame.thread) err = stop_blame(&s->blame); while (!STAILQ_EMPTY(&s->blamed_commits)) { struct got_object_qid *blamed_commit; blamed_commit = STAILQ_FIRST(&s->blamed_commits); STAILQ_REMOVE_HEAD(&s->blamed_commits, entry); got_object_qid_free(blamed_commit); } if (using_mock_io) { struct tog_blame_thread_args *bta = &s->blame.thread_args; int rc; rc = pthread_cond_destroy(&bta->blame_complete); if (rc && err == NULL) err = got_error_set_errno(rc, "pthread_cond_destroy"); } free(s->path); free_colors(&s->colors); return err; } static const struct got_error * search_start_blame_view(struct tog_view *view) { struct tog_blame_view_state *s = &view->state.blame; s->matched_line = 0; return NULL; } static void search_setup_blame_view(struct tog_view *view, FILE **f, off_t **line_offsets, size_t *nlines, int **first, int **last, int **match, int **selected) { struct tog_blame_view_state *s = &view->state.blame; *f = s->blame.f; *nlines = s->blame.nlines; *line_offsets = s->blame.line_offsets; *match = &s->matched_line; *first = &s->first_displayed_line; *last = &s->last_displayed_line; *selected = &s->selected_line; } static const struct got_error * show_blame_view(struct tog_view *view) { const struct got_error *err = NULL; struct tog_blame_view_state *s = &view->state.blame; int errcode; if (s->blame.thread == 0 && !s->blame_complete) { errcode = pthread_create(&s->blame.thread, NULL, blame_thread, &s->blame.thread_args); if (errcode) return got_error_set_errno(errcode, "pthread_create"); if (!using_mock_io) halfdelay(1); /* fast refresh while annotating */ } if (s->blame_complete && !using_mock_io) halfdelay(10); /* disable fast refresh */ err = draw_blame(view); view_border(view); return err; } static const struct got_error * log_annotated_line(struct tog_view **new_view, int begin_y, int begin_x, struct got_repository *repo, struct got_object_id *id) { struct tog_view *log_view; const struct got_error *err = NULL; *new_view = NULL; log_view = view_open(0, 0, begin_y, begin_x, TOG_VIEW_LOG); if (log_view == NULL) return got_error_from_errno("view_open"); err = open_log_view(log_view, id, repo, GOT_REF_HEAD, "", 0, NULL); if (err) view_close(log_view); else *new_view = log_view; return err; } static const struct got_error * input_blame_view(struct tog_view **new_view, struct tog_view *view, int ch) { const struct got_error *err = NULL, *thread_err = NULL; struct tog_view *diff_view; struct tog_blame_view_state *s = &view->state.blame; int eos, nscroll, begin_y = 0, begin_x = 0; eos = nscroll = view->nlines - 2; if (view_is_hsplit_top(view)) --eos; /* border */ switch (ch) { case '0': case '$': case KEY_RIGHT: case 'l': case KEY_LEFT: case 'h': horizontal_scroll_input(view, ch); break; case 'q': s->done = 1; break; case 'g': case KEY_HOME: s->selected_line = 1; s->first_displayed_line = 1; view->count = 0; break; case 'G': case KEY_END: if (s->blame.nlines < eos) { s->selected_line = s->blame.nlines; s->first_displayed_line = 1; } else { s->selected_line = eos; s->first_displayed_line = s->blame.nlines - (eos - 1); } view->count = 0; break; case 'k': case KEY_UP: case CTRL('p'): if (s->selected_line > 1) s->selected_line--; else if (s->selected_line == 1 && s->first_displayed_line > 1) s->first_displayed_line--; else view->count = 0; break; case CTRL('u'): case 'u': nscroll /= 2; /* FALL THROUGH */ case KEY_PPAGE: case CTRL('b'): case 'b': if (s->first_displayed_line == 1) { if (view->count > 1) nscroll += nscroll; s->selected_line = MAX(1, s->selected_line - nscroll); view->count = 0; break; } if (s->first_displayed_line > nscroll) s->first_displayed_line -= nscroll; else s->first_displayed_line = 1; break; case 'j': case KEY_DOWN: case CTRL('n'): if (s->selected_line < eos && s->first_displayed_line + s->selected_line <= s->blame.nlines) s->selected_line++; else if (s->first_displayed_line < s->blame.nlines - (eos - 1)) s->first_displayed_line++; else view->count = 0; break; case 'c': case 'p': { struct got_object_id *id = NULL; view->count = 0; id = get_selected_commit_id(s->blame.lines, s->blame.nlines, s->first_displayed_line, s->selected_line); if (id == NULL) break; if (ch == 'p') { struct got_commit_object *commit, *pcommit; struct got_object_qid *pid; struct got_object_id *blob_id = NULL; int obj_type; err = got_object_open_as_commit(&commit, s->repo, id); if (err) break; pid = STAILQ_FIRST( got_object_commit_get_parent_ids(commit)); if (pid == NULL) { got_object_commit_close(commit); break; } /* Check if path history ends here. */ err = got_object_open_as_commit(&pcommit, s->repo, &pid->id); if (err) break; err = got_object_id_by_path(&blob_id, s->repo, pcommit, s->path); got_object_commit_close(pcommit); if (err) { if (err->code == GOT_ERR_NO_TREE_ENTRY) err = NULL; got_object_commit_close(commit); break; } err = got_object_get_type(&obj_type, s->repo, blob_id); free(blob_id); /* Can't blame non-blob type objects. */ if (obj_type != GOT_OBJ_TYPE_BLOB) { got_object_commit_close(commit); break; } err = got_object_qid_alloc(&s->blamed_commit, &pid->id); got_object_commit_close(commit); } else { if (got_object_id_cmp(id, &s->blamed_commit->id) == 0) break; err = got_object_qid_alloc(&s->blamed_commit, id); } if (err) break; s->done = 1; thread_err = stop_blame(&s->blame); s->done = 0; if (thread_err) break; STAILQ_INSERT_HEAD(&s->blamed_commits, s->blamed_commit, entry); err = run_blame(view); if (err) break; break; } case 'C': { struct got_object_qid *first; view->count = 0; first = STAILQ_FIRST(&s->blamed_commits); if (!got_object_id_cmp(&first->id, s->commit_id)) break; s->done = 1; thread_err = stop_blame(&s->blame); s->done = 0; if (thread_err) break; STAILQ_REMOVE_HEAD(&s->blamed_commits, entry); got_object_qid_free(s->blamed_commit); s->blamed_commit = STAILQ_FIRST(&s->blamed_commits); err = run_blame(view); if (err) break; break; } case 'L': view->count = 0; s->id_to_log = get_selected_commit_id(s->blame.lines, s->blame.nlines, s->first_displayed_line, s->selected_line); if (s->id_to_log) err = view_request_new(new_view, view, TOG_VIEW_LOG); break; case KEY_ENTER: case '\r': { struct got_object_id *id = NULL; struct got_object_qid *pid; struct got_commit_object *commit = NULL; view->count = 0; id = get_selected_commit_id(s->blame.lines, s->blame.nlines, s->first_displayed_line, s->selected_line); if (id == NULL) break; err = got_object_open_as_commit(&commit, s->repo, id); if (err) break; pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); if (*new_view) { /* traversed from diff view, release diff resources */ err = close_diff_view(*new_view); if (err) break; diff_view = *new_view; } else { if (view_is_parent_view(view)) view_get_split(view, &begin_y, &begin_x); diff_view = view_open(0, 0, begin_y, begin_x, TOG_VIEW_DIFF); if (diff_view == NULL) { got_object_commit_close(commit); err = got_error_from_errno("view_open"); break; } } err = open_diff_view(diff_view, pid ? &pid->id : NULL, id, NULL, NULL, 3, 0, 0, view, s->repo); got_object_commit_close(commit); if (err) break; s->last_diffed_line = s->first_displayed_line - 1 + s->selected_line; if (*new_view) break; /* still open from active diff view */ if (view_is_parent_view(view) && view->mode == TOG_VIEW_SPLIT_HRZN) { err = view_init_hsplit(view, begin_y); if (err) break; } view->focussed = 0; diff_view->focussed = 1; diff_view->mode = view->mode; diff_view->nlines = view->lines - begin_y; if (view_is_parent_view(view)) { view_transfer_size(diff_view, view); err = view_close_child(view); if (err) break; err = view_set_child(view, diff_view); if (err) break; view->focus_child = 1; } else *new_view = diff_view; if (err) break; break; } case CTRL('d'): case 'd': nscroll /= 2; /* FALL THROUGH */ case KEY_NPAGE: case CTRL('f'): case 'f': case ' ': if (s->last_displayed_line >= s->blame.nlines && s->selected_line >= MIN(s->blame.nlines, view->nlines - 2)) { view->count = 0; break; } if (s->last_displayed_line >= s->blame.nlines && s->selected_line < view->nlines - 2) { s->selected_line += MIN(nscroll, s->last_displayed_line - s->first_displayed_line - s->selected_line + 1); } if (s->last_displayed_line + nscroll <= s->blame.nlines) s->first_displayed_line += nscroll; else s->first_displayed_line = s->blame.nlines - (view->nlines - 3); break; case KEY_RESIZE: if (s->selected_line > view->nlines - 2) { s->selected_line = MIN(s->blame.nlines, view->nlines - 2); } break; default: view->count = 0; break; } return thread_err ? thread_err : err; } static const struct got_error * reset_blame_view(struct tog_view *view) { const struct got_error *err; struct tog_blame_view_state *s = &view->state.blame; view->count = 0; s->done = 1; err = stop_blame(&s->blame); s->done = 0; if (err) return err; return run_blame(view); } static const struct got_error * cmd_blame(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL; char *link_target = NULL; struct got_object_id *commit_id = NULL; struct got_commit_object *commit = NULL; char *keyword_idstr = NULL, *commit_id_str = NULL; int ch; struct tog_view *view = NULL; int *pack_fds = NULL; while ((ch = getopt(argc, argv, "c:r:")) != -1) { switch (ch) { case 'c': commit_id_str = optarg; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); break; default: usage_blame(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc != 1) usage_blame(); error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { cwd = getcwd(NULL, 0); if (cwd == NULL) return got_error_from_errno("getcwd"); error = got_worktree_open(&worktree, cwd, NULL); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; if (worktree) repo_path = strdup(got_worktree_get_repo_path(worktree)); else repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; error = get_in_repo_path_from_argv0(&in_repo_path, argc, argv, repo, worktree); if (error) goto done; init_curses(); error = apply_unveil(got_repo_get_path(repo), NULL); if (error) goto done; error = tog_load_refs(repo, 0); if (error) goto done; if (commit_id_str == NULL) { struct got_reference *head_ref; error = got_ref_open(&head_ref, repo, worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, 0); if (error != NULL) goto done; error = got_ref_resolve(&commit_id, repo, head_ref); got_ref_close(head_ref); } else { error = got_keyword_to_idstr(&keyword_idstr, commit_id_str, repo, worktree); if (error != NULL) goto done; if (keyword_idstr != NULL) commit_id_str = keyword_idstr; error = got_repo_match_object_id(&commit_id, NULL, commit_id_str, GOT_OBJ_TYPE_COMMIT, &tog_refs, repo); } if (error != NULL) goto done; error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; error = got_object_resolve_symlinks(&link_target, in_repo_path, commit, repo); if (error) goto done; view = view_open(0, 0, 0, 0, TOG_VIEW_BLAME); if (view == NULL) { error = got_error_from_errno("view_open"); goto done; } error = open_blame_view(view, link_target ? link_target : in_repo_path, commit_id, repo); if (error != NULL) { if (view->close == NULL) close_blame_view(view); view_close(view); goto done; } if (worktree) { error = set_tog_base_commit(repo, worktree); if (error != NULL) goto done; /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } error = view_loop(view); done: free(tog_base_commit.id); free(repo_path); free(in_repo_path); free(link_target); free(cwd); free(commit_id); free(keyword_idstr); if (commit) got_object_commit_close(commit); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } tog_free_refs(); return error; } static const struct got_error * draw_tree_entries(struct tog_view *view, const char *parent_path) { struct tog_tree_view_state *s = &view->state.tree; const struct got_error *err = NULL; struct got_tree_entry *te; wchar_t *wline; char *index = NULL; struct tog_color *tc; int width, n, nentries, scrollx, i = 1; int limit = view->nlines; s->ndisplayed = 0; if (view_is_hsplit_top(view)) --limit; /* border */ werase(view->window); if (limit == 0) return NULL; err = format_line(&wline, &width, NULL, s->tree_label, 0, view->ncols, 0, 0); if (err) return err; if (view_needs_focus_indication(view)) wstandout(view->window); tc = get_color(&s->colors, TOG_COLOR_COMMIT); if (tc) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); waddwstr(view->window, wline); free(wline); wline = NULL; while (width++ < view->ncols) waddch(view->window, ' '); if (tc) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); if (view_needs_focus_indication(view)) wstandend(view->window); if (--limit <= 0) return NULL; i += s->selected; if (s->first_displayed_entry) { i += got_tree_entry_get_index(s->first_displayed_entry); if (s->tree != s->root) ++i; /* account for ".." entry */ } nentries = got_object_tree_get_nentries(s->tree); if (asprintf(&index, "[%d/%d] %s", i, nentries + (s->tree == s->root ? 0 : 1), parent_path) == -1) return got_error_from_errno("asprintf"); err = format_line(&wline, &width, NULL, index, 0, view->ncols, 0, 0); free(index); if (err) return err; waddwstr(view->window, wline); free(wline); wline = NULL; if (width < view->ncols - 1) waddch(view->window, '\n'); if (--limit <= 0) return NULL; waddch(view->window, '\n'); if (--limit <= 0) return NULL; if (s->first_displayed_entry == NULL) { te = got_object_tree_get_first_entry(s->tree); if (s->selected == 0) { if (view->focussed) wstandout(view->window); s->selected_entry = NULL; } waddstr(view->window, " ..\n"); /* parent directory */ if (s->selected == 0 && view->focussed) wstandend(view->window); s->ndisplayed++; if (--limit <= 0) return NULL; n = 1; } else { n = 0; te = s->first_displayed_entry; } view->maxx = 0; for (i = got_tree_entry_get_index(te); i < nentries; i++) { char *line = NULL, *id_str = NULL, *link_target = NULL; const char *modestr = ""; mode_t mode; te = got_object_tree_get_entry(s->tree, i); mode = got_tree_entry_get_mode(te); if (s->show_ids) { err = got_object_id_str(&id_str, got_tree_entry_get_id(te)); if (err) return got_error_from_errno( "got_object_id_str"); } if (got_object_tree_entry_is_submodule(te)) modestr = "$"; else if (S_ISLNK(mode)) { int i; err = got_tree_entry_get_symlink_target(&link_target, te, s->repo); if (err) { free(id_str); return err; } for (i = 0; link_target[i] != '\0'; i++) { if (!isprint((unsigned char)link_target[i])) link_target[i] = '?'; } modestr = "@"; } else if (S_ISDIR(mode)) modestr = "/"; else if (mode & S_IXUSR) modestr = "*"; if (asprintf(&line, "%s %s%s%s%s", id_str ? id_str : "", got_tree_entry_get_name(te), modestr, link_target ? " -> ": "", link_target ? link_target : "") == -1) { free(id_str); free(link_target); return got_error_from_errno("asprintf"); } free(id_str); free(link_target); /* use full line width to determine view->maxx */ err = format_line(&wline, &width, NULL, line, 0, INT_MAX, 0, 0); if (err) { free(line); break; } view->maxx = MAX(view->maxx, width); free(wline); wline = NULL; err = format_line(&wline, &width, &scrollx, line, view->x, view->ncols, 0, 0); if (err) { free(line); break; } if (n == s->selected) { if (view->focussed) wstandout(view->window); s->selected_entry = te; } tc = match_color(&s->colors, line); if (tc) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); waddwstr(view->window, &wline[scrollx]); if (tc) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); if (width < view->ncols) waddch(view->window, '\n'); if (n == s->selected && view->focussed) wstandend(view->window); free(line); free(wline); wline = NULL; n++; s->ndisplayed++; s->last_displayed_entry = te; if (--limit <= 0) break; } return err; } static void tree_scroll_up(struct tog_tree_view_state *s, int maxscroll) { struct got_tree_entry *te; int isroot = s->tree == s->root; int i = 0; if (s->first_displayed_entry == NULL) return; te = got_tree_entry_get_prev(s->tree, s->first_displayed_entry); while (i++ < maxscroll) { if (te == NULL) { if (!isroot) s->first_displayed_entry = NULL; break; } s->first_displayed_entry = te; te = got_tree_entry_get_prev(s->tree, te); } } static const struct got_error * tree_scroll_down(struct tog_view *view, int maxscroll) { struct tog_tree_view_state *s = &view->state.tree; struct got_tree_entry *next, *last; int n = 0; if (s->first_displayed_entry) next = got_tree_entry_get_next(s->tree, s->first_displayed_entry); else next = got_object_tree_get_first_entry(s->tree); last = s->last_displayed_entry; while (next && n++ < maxscroll) { if (last) { s->last_displayed_entry = last; last = got_tree_entry_get_next(s->tree, last); } if (last || (view->mode == TOG_VIEW_SPLIT_HRZN && next)) { s->first_displayed_entry = next; next = got_tree_entry_get_next(s->tree, next); } } return NULL; } static const struct got_error * tree_entry_path(char **path, struct tog_parent_trees *parents, struct got_tree_entry *te) { const struct got_error *err = NULL; struct tog_parent_tree *pt; size_t len = 2; /* for leading slash and NUL */ TAILQ_FOREACH(pt, parents, entry) len += strlen(got_tree_entry_get_name(pt->selected_entry)) + 1 /* slash */; if (te) len += strlen(got_tree_entry_get_name(te)); *path = calloc(1, len); if (path == NULL) return got_error_from_errno("calloc"); (*path)[0] = '/'; pt = TAILQ_LAST(parents, tog_parent_trees); while (pt) { const char *name = got_tree_entry_get_name(pt->selected_entry); if (strlcat(*path, name, len) >= len) { err = got_error(GOT_ERR_NO_SPACE); goto done; } if (strlcat(*path, "/", len) >= len) { err = got_error(GOT_ERR_NO_SPACE); goto done; } pt = TAILQ_PREV(pt, tog_parent_trees, entry); } if (te) { if (strlcat(*path, got_tree_entry_get_name(te), len) >= len) { err = got_error(GOT_ERR_NO_SPACE); goto done; } } done: if (err) { free(*path); *path = NULL; } return err; } static const struct got_error * blame_tree_entry(struct tog_view **new_view, int begin_y, int begin_x, struct got_tree_entry *te, struct tog_parent_trees *parents, struct got_object_id *commit_id, struct got_repository *repo) { const struct got_error *err = NULL; char *path; struct tog_view *blame_view; *new_view = NULL; err = tree_entry_path(&path, parents, te); if (err) return err; blame_view = view_open(0, 0, begin_y, begin_x, TOG_VIEW_BLAME); if (blame_view == NULL) { err = got_error_from_errno("view_open"); goto done; } err = open_blame_view(blame_view, path, commit_id, repo); if (err) { if (err->code == GOT_ERR_CANCELLED) err = NULL; view_close(blame_view); } else *new_view = blame_view; done: free(path); return err; } static const struct got_error * log_selected_tree_entry(struct tog_view **new_view, int begin_y, int begin_x, struct tog_tree_view_state *s) { struct tog_view *log_view; const struct got_error *err = NULL; char *path; *new_view = NULL; log_view = view_open(0, 0, begin_y, begin_x, TOG_VIEW_LOG); if (log_view == NULL) return got_error_from_errno("view_open"); err = tree_entry_path(&path, &s->parents, s->selected_entry); if (err) return err; err = open_log_view(log_view, s->commit_id, s->repo, s->head_ref_name, path, 0, NULL); if (err) view_close(log_view); else *new_view = log_view; free(path); return err; } static const struct got_error * open_tree_view(struct tog_view *view, struct got_object_id *commit_id, const char *head_ref_name, struct got_repository *repo) { const struct got_error *err = NULL; char *commit_id_str = NULL; struct tog_tree_view_state *s = &view->state.tree; struct got_commit_object *commit = NULL; TAILQ_INIT(&s->parents); STAILQ_INIT(&s->colors); s->commit_id = got_object_id_dup(commit_id); if (s->commit_id == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } err = got_object_open_as_commit(&commit, repo, commit_id); if (err) goto done; /* * The root is opened here and will be closed when the view is closed. * Any visited subtrees and their path-wise parents are opened and * closed on demand. */ err = got_object_open_as_tree(&s->root, repo, got_object_commit_get_tree_id(commit)); if (err) goto done; s->tree = s->root; err = got_object_id_str(&commit_id_str, commit_id); if (err != NULL) goto done; if (asprintf(&s->tree_label, "commit %s", commit_id_str) == -1) { err = got_error_from_errno("asprintf"); goto done; } s->first_displayed_entry = got_object_tree_get_entry(s->tree, 0); s->selected_entry = got_object_tree_get_entry(s->tree, 0); if (head_ref_name) { s->head_ref_name = strdup(head_ref_name); if (s->head_ref_name == NULL) { err = got_error_from_errno("strdup"); goto done; } } s->repo = repo; if (has_colors() && getenv("TOG_COLORS") != NULL) { err = add_color(&s->colors, "\\$$", TOG_COLOR_TREE_SUBMODULE, get_color_value("TOG_COLOR_TREE_SUBMODULE")); if (err) goto done; err = add_color(&s->colors, "@$", TOG_COLOR_TREE_SYMLINK, get_color_value("TOG_COLOR_TREE_SYMLINK")); if (err) goto done; err = add_color(&s->colors, "/$", TOG_COLOR_TREE_DIRECTORY, get_color_value("TOG_COLOR_TREE_DIRECTORY")); if (err) goto done; err = add_color(&s->colors, "\\*$", TOG_COLOR_TREE_EXECUTABLE, get_color_value("TOG_COLOR_TREE_EXECUTABLE")); if (err) goto done; err = add_color(&s->colors, "^$", TOG_COLOR_COMMIT, get_color_value("TOG_COLOR_COMMIT")); if (err) goto done; } view->show = show_tree_view; view->input = input_tree_view; view->close = close_tree_view; view->search_start = search_start_tree_view; view->search_next = search_next_tree_view; done: free(commit_id_str); if (commit) got_object_commit_close(commit); if (err) { if (view->close == NULL) close_tree_view(view); view_close(view); } return err; } static const struct got_error * close_tree_view(struct tog_view *view) { struct tog_tree_view_state *s = &view->state.tree; free_colors(&s->colors); free(s->tree_label); s->tree_label = NULL; free(s->commit_id); s->commit_id = NULL; free(s->head_ref_name); s->head_ref_name = NULL; while (!TAILQ_EMPTY(&s->parents)) { struct tog_parent_tree *parent; parent = TAILQ_FIRST(&s->parents); TAILQ_REMOVE(&s->parents, parent, entry); if (parent->tree != s->root) got_object_tree_close(parent->tree); free(parent); } if (s->tree != NULL && s->tree != s->root) got_object_tree_close(s->tree); if (s->root) got_object_tree_close(s->root); return NULL; } static const struct got_error * search_start_tree_view(struct tog_view *view) { struct tog_tree_view_state *s = &view->state.tree; s->matched_entry = NULL; return NULL; } static int match_tree_entry(struct got_tree_entry *te, regex_t *regex) { regmatch_t regmatch; return regexec(regex, got_tree_entry_get_name(te), 1, ®match, 0) == 0; } static const struct got_error * search_next_tree_view(struct tog_view *view) { struct tog_tree_view_state *s = &view->state.tree; struct got_tree_entry *te = NULL; if (!view->searching) { view->search_next_done = TOG_SEARCH_HAVE_MORE; return NULL; } if (s->matched_entry) { if (view->searching == TOG_SEARCH_FORWARD) { if (s->selected_entry) te = got_tree_entry_get_next(s->tree, s->selected_entry); else te = got_object_tree_get_first_entry(s->tree); } else { if (s->selected_entry == NULL) te = got_object_tree_get_last_entry(s->tree); else te = got_tree_entry_get_prev(s->tree, s->selected_entry); } } else { if (s->selected_entry) te = s->selected_entry; else if (view->searching == TOG_SEARCH_FORWARD) te = got_object_tree_get_first_entry(s->tree); else te = got_object_tree_get_last_entry(s->tree); } while (1) { if (te == NULL) { if (s->matched_entry == NULL) { view->search_next_done = TOG_SEARCH_HAVE_MORE; return NULL; } if (view->searching == TOG_SEARCH_FORWARD) te = got_object_tree_get_first_entry(s->tree); else te = got_object_tree_get_last_entry(s->tree); } if (match_tree_entry(te, &view->regex)) { view->search_next_done = TOG_SEARCH_HAVE_MORE; s->matched_entry = te; break; } if (view->searching == TOG_SEARCH_FORWARD) te = got_tree_entry_get_next(s->tree, te); else te = got_tree_entry_get_prev(s->tree, te); } if (s->matched_entry) { s->first_displayed_entry = s->matched_entry; s->selected = 0; } return NULL; } static const struct got_error * show_tree_view(struct tog_view *view) { const struct got_error *err = NULL; struct tog_tree_view_state *s = &view->state.tree; char *parent_path; err = tree_entry_path(&parent_path, &s->parents, NULL); if (err) return err; err = draw_tree_entries(view, parent_path); free(parent_path); view_border(view); return err; } static const struct got_error * tree_goto_line(struct tog_view *view, int nlines) { const struct got_error *err = NULL; struct tog_tree_view_state *s = &view->state.tree; struct got_tree_entry **fte, **lte, **ste; int g, last, first = 1, i = 1; int root = s->tree == s->root; int off = root ? 1 : 2; g = view->gline; view->gline = 0; if (g == 0) g = 1; else if (g > got_object_tree_get_nentries(s->tree)) g = got_object_tree_get_nentries(s->tree) + (root ? 0 : 1); fte = &s->first_displayed_entry; lte = &s->last_displayed_entry; ste = &s->selected_entry; if (*fte != NULL) { first = got_tree_entry_get_index(*fte); first += off; /* account for ".." */ } last = got_tree_entry_get_index(*lte); last += off; if (g >= first && g <= last && g - first < nlines) { s->selected = g - first; return NULL; /* gline is on the current page */ } if (*ste != NULL) { i = got_tree_entry_get_index(*ste); i += off; } if (i < g) { err = tree_scroll_down(view, g - i); if (err) return err; if (got_tree_entry_get_index(*lte) >= got_object_tree_get_nentries(s->tree) - 1 && first + s->selected < g && s->selected < s->ndisplayed - 1) { first = got_tree_entry_get_index(*fte); first += off; s->selected = g - first; } } else if (i > g) tree_scroll_up(s, i - g); if (g < nlines && (*fte == NULL || (root && !got_tree_entry_get_index(*fte)))) s->selected = g - 1; return NULL; } static const struct got_error * input_tree_view(struct tog_view **new_view, struct tog_view *view, int ch) { const struct got_error *err = NULL; struct tog_tree_view_state *s = &view->state.tree; struct got_tree_entry *te; int n, nscroll = view->nlines - 3; if (view->gline) return tree_goto_line(view, nscroll); switch (ch) { case '0': case '$': case KEY_RIGHT: case 'l': case KEY_LEFT: case 'h': horizontal_scroll_input(view, ch); break; case 'i': s->show_ids = !s->show_ids; view->count = 0; break; case 'L': view->count = 0; if (!s->selected_entry) break; err = view_request_new(new_view, view, TOG_VIEW_LOG); break; case 'R': view->count = 0; err = view_request_new(new_view, view, TOG_VIEW_REF); break; case 'g': case '=': case KEY_HOME: s->selected = 0; view->count = 0; if (s->tree == s->root) s->first_displayed_entry = got_object_tree_get_first_entry(s->tree); else s->first_displayed_entry = NULL; break; case 'G': case '*': case KEY_END: { int eos = view->nlines - 3; if (view->mode == TOG_VIEW_SPLIT_HRZN) --eos; /* border */ s->selected = 0; view->count = 0; te = got_object_tree_get_last_entry(s->tree); for (n = 0; n < eos; n++) { if (te == NULL) { if (s->tree != s->root) { s->first_displayed_entry = NULL; n++; } break; } s->first_displayed_entry = te; te = got_tree_entry_get_prev(s->tree, te); } if (n > 0) s->selected = n - 1; break; } case 'k': case KEY_UP: case CTRL('p'): if (s->selected > 0) { s->selected--; break; } tree_scroll_up(s, 1); if (s->selected_entry == NULL || (s->tree == s->root && s->selected_entry == got_object_tree_get_first_entry(s->tree))) view->count = 0; break; case CTRL('u'): case 'u': nscroll /= 2; /* FALL THROUGH */ case KEY_PPAGE: case CTRL('b'): case 'b': if (s->tree == s->root) { if (got_object_tree_get_first_entry(s->tree) == s->first_displayed_entry) s->selected -= MIN(s->selected, nscroll); } else { if (s->first_displayed_entry == NULL) s->selected -= MIN(s->selected, nscroll); } tree_scroll_up(s, MAX(0, nscroll)); if (s->selected_entry == NULL || (s->tree == s->root && s->selected_entry == got_object_tree_get_first_entry(s->tree))) view->count = 0; break; case 'j': case KEY_DOWN: case CTRL('n'): if (s->selected < s->ndisplayed - 1) { s->selected++; break; } if (got_tree_entry_get_next(s->tree, s->last_displayed_entry) == NULL) { /* can't scroll any further */ view->count = 0; break; } tree_scroll_down(view, 1); break; case CTRL('d'): case 'd': nscroll /= 2; /* FALL THROUGH */ case KEY_NPAGE: case CTRL('f'): case 'f': case ' ': if (got_tree_entry_get_next(s->tree, s->last_displayed_entry) == NULL) { /* can't scroll any further; move cursor down */ if (s->selected < s->ndisplayed - 1) s->selected += MIN(nscroll, s->ndisplayed - s->selected - 1); else view->count = 0; break; } tree_scroll_down(view, nscroll); break; case KEY_ENTER: case '\r': case KEY_BACKSPACE: if (s->selected_entry == NULL || ch == KEY_BACKSPACE) { struct tog_parent_tree *parent; /* user selected '..' */ if (s->tree == s->root) { view->count = 0; break; } parent = TAILQ_FIRST(&s->parents); TAILQ_REMOVE(&s->parents, parent, entry); got_object_tree_close(s->tree); s->tree = parent->tree; s->first_displayed_entry = parent->first_displayed_entry; s->selected_entry = parent->selected_entry; s->selected = parent->selected; if (s->selected > view->nlines - 3) { err = offset_selection_down(view); if (err) break; } free(parent); } else if (S_ISDIR(got_tree_entry_get_mode( s->selected_entry))) { struct got_tree_object *subtree; view->count = 0; err = got_object_open_as_tree(&subtree, s->repo, got_tree_entry_get_id(s->selected_entry)); if (err) break; err = tree_view_visit_subtree(s, subtree); if (err) { got_object_tree_close(subtree); break; } } else if (S_ISREG(got_tree_entry_get_mode(s->selected_entry))) err = view_request_new(new_view, view, TOG_VIEW_BLAME); break; case KEY_RESIZE: if (view->nlines >= 4 && s->selected >= view->nlines - 3) s->selected = view->nlines - 4; view->count = 0; break; default: view->count = 0; break; } return err; } __dead static void usage_tree(void) { endwin(); fprintf(stderr, "usage: %s tree [-c commit] [-r repository-path] [path]\n", getprogname()); exit(1); } static const struct got_error * cmd_tree(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL; struct got_object_id *commit_id = NULL; struct got_commit_object *commit = NULL; const char *commit_id_arg = NULL; char *keyword_idstr = NULL, *label = NULL; struct got_reference *ref = NULL; const char *head_ref_name = NULL; int ch; struct tog_view *view; int *pack_fds = NULL; while ((ch = getopt(argc, argv, "c:r:")) != -1) { switch (ch) { case 'c': commit_id_arg = optarg; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); break; default: usage_tree(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc > 1) usage_tree(); error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { cwd = getcwd(NULL, 0); if (cwd == NULL) return got_error_from_errno("getcwd"); error = got_worktree_open(&worktree, cwd, NULL); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; if (worktree) repo_path = strdup(got_worktree_get_repo_path(worktree)); else repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; error = get_in_repo_path_from_argv0(&in_repo_path, argc, argv, repo, worktree); if (error) goto done; init_curses(); error = apply_unveil(got_repo_get_path(repo), NULL); if (error) goto done; error = tog_load_refs(repo, 0); if (error) goto done; if (commit_id_arg == NULL) { error = got_repo_match_object_id(&commit_id, &label, worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, GOT_OBJ_TYPE_COMMIT, &tog_refs, repo); if (error) goto done; head_ref_name = label; } else { error = got_keyword_to_idstr(&keyword_idstr, commit_id_arg, repo, worktree); if (error != NULL) goto done; if (keyword_idstr != NULL) commit_id_arg = keyword_idstr; error = got_ref_open(&ref, repo, commit_id_arg, 0); if (error == NULL) head_ref_name = got_ref_get_name(ref); else if (error->code != GOT_ERR_NOT_REF) goto done; error = got_repo_match_object_id(&commit_id, NULL, commit_id_arg, GOT_OBJ_TYPE_COMMIT, &tog_refs, repo); if (error) goto done; } error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; view = view_open(0, 0, 0, 0, TOG_VIEW_TREE); if (view == NULL) { error = got_error_from_errno("view_open"); goto done; } error = open_tree_view(view, commit_id, head_ref_name, repo); if (error) goto done; if (!got_path_is_root_dir(in_repo_path)) { error = tree_view_walk_path(&view->state.tree, commit, in_repo_path); if (error) goto done; } if (worktree) { error = set_tog_base_commit(repo, worktree); if (error != NULL) goto done; /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } error = view_loop(view); done: free(tog_base_commit.id); free(keyword_idstr); free(repo_path); free(cwd); free(commit_id); free(label); if (commit != NULL) got_object_commit_close(commit); if (ref) got_ref_close(ref); if (worktree != NULL) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } tog_free_refs(); return error; } static const struct got_error * ref_view_load_refs(struct tog_ref_view_state *s) { struct got_reflist_entry *sre; struct tog_reflist_entry *re; s->nrefs = 0; TAILQ_FOREACH(sre, &tog_refs, entry) { if (strncmp(got_ref_get_name(sre->ref), "refs/got/", 9) == 0 && strncmp(got_ref_get_name(sre->ref), "refs/got/backup/", 16) != 0) continue; re = malloc(sizeof(*re)); if (re == NULL) return got_error_from_errno("malloc"); re->ref = got_ref_dup(sre->ref); if (re->ref == NULL) return got_error_from_errno("got_ref_dup"); re->idx = s->nrefs++; TAILQ_INSERT_TAIL(&s->refs, re, entry); } s->first_displayed_entry = TAILQ_FIRST(&s->refs); return NULL; } static void ref_view_free_refs(struct tog_ref_view_state *s) { struct tog_reflist_entry *re; while (!TAILQ_EMPTY(&s->refs)) { re = TAILQ_FIRST(&s->refs); TAILQ_REMOVE(&s->refs, re, entry); got_ref_close(re->ref); free(re); } } static const struct got_error * open_ref_view(struct tog_view *view, struct got_repository *repo) { const struct got_error *err = NULL; struct tog_ref_view_state *s = &view->state.ref; s->selected_entry = 0; s->repo = repo; TAILQ_INIT(&s->refs); STAILQ_INIT(&s->colors); err = ref_view_load_refs(s); if (err) goto done; if (has_colors() && getenv("TOG_COLORS") != NULL) { err = add_color(&s->colors, "^refs/heads/", TOG_COLOR_REFS_HEADS, get_color_value("TOG_COLOR_REFS_HEADS")); if (err) goto done; err = add_color(&s->colors, "^refs/tags/", TOG_COLOR_REFS_TAGS, get_color_value("TOG_COLOR_REFS_TAGS")); if (err) goto done; err = add_color(&s->colors, "^refs/remotes/", TOG_COLOR_REFS_REMOTES, get_color_value("TOG_COLOR_REFS_REMOTES")); if (err) goto done; err = add_color(&s->colors, "^refs/got/backup/", TOG_COLOR_REFS_BACKUP, get_color_value("TOG_COLOR_REFS_BACKUP")); if (err) goto done; } view->show = show_ref_view; view->input = input_ref_view; view->close = close_ref_view; view->search_start = search_start_ref_view; view->search_next = search_next_ref_view; done: if (err) { if (view->close == NULL) close_ref_view(view); view_close(view); } return err; } static const struct got_error * close_ref_view(struct tog_view *view) { struct tog_ref_view_state *s = &view->state.ref; ref_view_free_refs(s); free_colors(&s->colors); return NULL; } static const struct got_error * resolve_reflist_entry(struct got_object_id **commit_id, struct tog_reflist_entry *re, struct got_repository *repo) { const struct got_error *err = NULL; struct got_object_id *obj_id; struct got_tag_object *tag = NULL; int obj_type; *commit_id = NULL; err = got_ref_resolve(&obj_id, repo, re->ref); if (err) return err; err = got_object_get_type(&obj_type, repo, obj_id); if (err) goto done; switch (obj_type) { case GOT_OBJ_TYPE_COMMIT: *commit_id = obj_id; break; case GOT_OBJ_TYPE_TAG: err = got_object_open_as_tag(&tag, repo, obj_id); if (err) goto done; free(obj_id); err = got_object_get_type(&obj_type, repo, got_object_tag_get_object_id(tag)); if (err) goto done; if (obj_type != GOT_OBJ_TYPE_COMMIT) { err = got_error(GOT_ERR_OBJ_TYPE); goto done; } *commit_id = got_object_id_dup( got_object_tag_get_object_id(tag)); if (*commit_id == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } break; default: err = got_error(GOT_ERR_OBJ_TYPE); break; } done: if (tag) got_object_tag_close(tag); if (err) { free(*commit_id); *commit_id = NULL; } return err; } static const struct got_error * log_ref_entry(struct tog_view **new_view, int begin_y, int begin_x, struct tog_reflist_entry *re, struct got_repository *repo) { struct tog_view *log_view; const struct got_error *err = NULL; struct got_object_id *commit_id = NULL; *new_view = NULL; err = resolve_reflist_entry(&commit_id, re, repo); if (err) { if (err->code != GOT_ERR_OBJ_TYPE) return err; else return NULL; } log_view = view_open(0, 0, begin_y, begin_x, TOG_VIEW_LOG); if (log_view == NULL) { err = got_error_from_errno("view_open"); goto done; } err = open_log_view(log_view, commit_id, repo, got_ref_get_name(re->ref), "", 0, NULL); done: if (err) view_close(log_view); else *new_view = log_view; free(commit_id); return err; } static void ref_scroll_up(struct tog_ref_view_state *s, int maxscroll) { struct tog_reflist_entry *re; int i = 0; if (s->first_displayed_entry == TAILQ_FIRST(&s->refs)) return; re = TAILQ_PREV(s->first_displayed_entry, tog_reflist_head, entry); while (i++ < maxscroll) { if (re == NULL) break; s->first_displayed_entry = re; re = TAILQ_PREV(re, tog_reflist_head, entry); } } static const struct got_error * ref_scroll_down(struct tog_view *view, int maxscroll) { struct tog_ref_view_state *s = &view->state.ref; struct tog_reflist_entry *next, *last; int n = 0; if (s->first_displayed_entry) next = TAILQ_NEXT(s->first_displayed_entry, entry); else next = TAILQ_FIRST(&s->refs); last = s->last_displayed_entry; while (next && n++ < maxscroll) { if (last) { s->last_displayed_entry = last; last = TAILQ_NEXT(last, entry); } if (last || (view->mode == TOG_VIEW_SPLIT_HRZN)) { s->first_displayed_entry = next; next = TAILQ_NEXT(next, entry); } } return NULL; } static const struct got_error * search_start_ref_view(struct tog_view *view) { struct tog_ref_view_state *s = &view->state.ref; s->matched_entry = NULL; return NULL; } static int match_reflist_entry(struct tog_reflist_entry *re, regex_t *regex) { regmatch_t regmatch; return regexec(regex, got_ref_get_name(re->ref), 1, ®match, 0) == 0; } static const struct got_error * search_next_ref_view(struct tog_view *view) { struct tog_ref_view_state *s = &view->state.ref; struct tog_reflist_entry *re = NULL; if (!view->searching) { view->search_next_done = TOG_SEARCH_HAVE_MORE; return NULL; } if (s->matched_entry) { if (view->searching == TOG_SEARCH_FORWARD) { if (s->selected_entry) re = TAILQ_NEXT(s->selected_entry, entry); else re = TAILQ_PREV(s->selected_entry, tog_reflist_head, entry); } else { if (s->selected_entry == NULL) re = TAILQ_LAST(&s->refs, tog_reflist_head); else re = TAILQ_PREV(s->selected_entry, tog_reflist_head, entry); } } else { if (s->selected_entry) re = s->selected_entry; else if (view->searching == TOG_SEARCH_FORWARD) re = TAILQ_FIRST(&s->refs); else re = TAILQ_LAST(&s->refs, tog_reflist_head); } while (1) { if (re == NULL) { if (s->matched_entry == NULL) { view->search_next_done = TOG_SEARCH_HAVE_MORE; return NULL; } if (view->searching == TOG_SEARCH_FORWARD) re = TAILQ_FIRST(&s->refs); else re = TAILQ_LAST(&s->refs, tog_reflist_head); } if (match_reflist_entry(re, &view->regex)) { view->search_next_done = TOG_SEARCH_HAVE_MORE; s->matched_entry = re; break; } if (view->searching == TOG_SEARCH_FORWARD) re = TAILQ_NEXT(re, entry); else re = TAILQ_PREV(re, tog_reflist_head, entry); } if (s->matched_entry) { s->first_displayed_entry = s->matched_entry; s->selected = 0; } return NULL; } static const struct got_error * show_ref_view(struct tog_view *view) { const struct got_error *err = NULL; struct tog_ref_view_state *s = &view->state.ref; struct tog_reflist_entry *re; char *line = NULL; wchar_t *wline; struct tog_color *tc; int width, n, scrollx; int limit = view->nlines; werase(view->window); s->ndisplayed = 0; if (view_is_hsplit_top(view)) --limit; /* border */ if (limit == 0) return NULL; re = s->first_displayed_entry; if (asprintf(&line, "references [%d/%d]", re->idx + s->selected + 1, s->nrefs) == -1) return got_error_from_errno("asprintf"); err = format_line(&wline, &width, NULL, line, 0, view->ncols, 0, 0); if (err) { free(line); return err; } if (view_needs_focus_indication(view)) wstandout(view->window); waddwstr(view->window, wline); while (width++ < view->ncols) waddch(view->window, ' '); if (view_needs_focus_indication(view)) wstandend(view->window); free(wline); wline = NULL; free(line); line = NULL; if (--limit <= 0) return NULL; n = 0; view->maxx = 0; while (re && limit > 0) { char *line = NULL; char ymd[13]; /* YYYY-MM-DD + " " + NUL */ if (s->show_date) { struct got_commit_object *ci; struct got_tag_object *tag; struct got_object_id *id; struct tm tm; time_t t; err = got_ref_resolve(&id, s->repo, re->ref); if (err) return err; err = got_object_open_as_tag(&tag, s->repo, id); if (err) { if (err->code != GOT_ERR_OBJ_TYPE) { free(id); return err; } err = got_object_open_as_commit(&ci, s->repo, id); if (err) { free(id); return err; } t = got_object_commit_get_committer_time(ci); got_object_commit_close(ci); } else { t = got_object_tag_get_tagger_time(tag); got_object_tag_close(tag); } free(id); if (gmtime_r(&t, &tm) == NULL) return got_error_from_errno("gmtime_r"); if (strftime(ymd, sizeof(ymd), "%F ", &tm) == 0) return got_error(GOT_ERR_NO_SPACE); } if (got_ref_is_symbolic(re->ref)) { if (asprintf(&line, "%s%s -> %s", s->show_date ? ymd : "", got_ref_get_name(re->ref), got_ref_get_symref_target(re->ref)) == -1) return got_error_from_errno("asprintf"); } else if (s->show_ids) { struct got_object_id *id; char *id_str; err = got_ref_resolve(&id, s->repo, re->ref); if (err) return err; err = got_object_id_str(&id_str, id); if (err) { free(id); return err; } if (asprintf(&line, "%s%s: %s", s->show_date ? ymd : "", got_ref_get_name(re->ref), id_str) == -1) { err = got_error_from_errno("asprintf"); free(id); free(id_str); return err; } free(id); free(id_str); } else if (asprintf(&line, "%s%s", s->show_date ? ymd : "", got_ref_get_name(re->ref)) == -1) return got_error_from_errno("asprintf"); /* use full line width to determine view->maxx */ err = format_line(&wline, &width, NULL, line, 0, INT_MAX, 0, 0); if (err) { free(line); return err; } view->maxx = MAX(view->maxx, width); free(wline); wline = NULL; err = format_line(&wline, &width, &scrollx, line, view->x, view->ncols, 0, 0); if (err) { free(line); return err; } if (n == s->selected) { if (view->focussed) wstandout(view->window); s->selected_entry = re; } tc = match_color(&s->colors, got_ref_get_name(re->ref)); if (tc) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); waddwstr(view->window, &wline[scrollx]); if (tc) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); if (width < view->ncols) waddch(view->window, '\n'); if (n == s->selected && view->focussed) wstandend(view->window); free(line); free(wline); wline = NULL; n++; s->ndisplayed++; s->last_displayed_entry = re; limit--; re = TAILQ_NEXT(re, entry); } view_border(view); return err; } static const struct got_error * browse_ref_tree(struct tog_view **new_view, int begin_y, int begin_x, struct tog_reflist_entry *re, struct got_repository *repo) { const struct got_error *err = NULL; struct got_object_id *commit_id = NULL; struct tog_view *tree_view; *new_view = NULL; err = resolve_reflist_entry(&commit_id, re, repo); if (err) { if (err->code != GOT_ERR_OBJ_TYPE) return err; else return NULL; } tree_view = view_open(0, 0, begin_y, begin_x, TOG_VIEW_TREE); if (tree_view == NULL) { err = got_error_from_errno("view_open"); goto done; } err = open_tree_view(tree_view, commit_id, got_ref_get_name(re->ref), repo); if (err) goto done; *new_view = tree_view; done: free(commit_id); return err; } static const struct got_error * ref_goto_line(struct tog_view *view, int nlines) { const struct got_error *err = NULL; struct tog_ref_view_state *s = &view->state.ref; int g, idx = s->selected_entry->idx; g = view->gline; view->gline = 0; if (g == 0) g = 1; else if (g > s->nrefs) g = s->nrefs; if (g >= s->first_displayed_entry->idx + 1 && g <= s->last_displayed_entry->idx + 1 && g - s->first_displayed_entry->idx - 1 < nlines) { s->selected = g - s->first_displayed_entry->idx - 1; return NULL; } if (idx + 1 < g) { err = ref_scroll_down(view, g - idx - 1); if (err) return err; if (TAILQ_NEXT(s->last_displayed_entry, entry) == NULL && s->first_displayed_entry->idx + s->selected < g && s->selected < s->ndisplayed - 1) s->selected = g - s->first_displayed_entry->idx - 1; } else if (idx + 1 > g) ref_scroll_up(s, idx - g + 1); if (g < nlines && s->first_displayed_entry->idx == 0) s->selected = g - 1; return NULL; } static const struct got_error * input_ref_view(struct tog_view **new_view, struct tog_view *view, int ch) { const struct got_error *err = NULL; struct tog_ref_view_state *s = &view->state.ref; struct tog_reflist_entry *re; int n, nscroll = view->nlines - 1; if (view->gline) return ref_goto_line(view, nscroll); switch (ch) { case '0': case '$': case KEY_RIGHT: case 'l': case KEY_LEFT: case 'h': horizontal_scroll_input(view, ch); break; case 'i': s->show_ids = !s->show_ids; view->count = 0; break; case 'm': s->show_date = !s->show_date; view->count = 0; break; case 'o': s->sort_by_date = !s->sort_by_date; view->action = s->sort_by_date ? "sort by date" : "sort by name"; view->count = 0; err = got_reflist_sort(&tog_refs, s->sort_by_date ? got_ref_cmp_by_commit_timestamp_descending : tog_ref_cmp_by_name, s->repo); if (err) break; got_reflist_object_id_map_free(tog_refs_idmap); err = got_reflist_object_id_map_create(&tog_refs_idmap, &tog_refs, s->repo); if (err) break; ref_view_free_refs(s); err = ref_view_load_refs(s); break; case KEY_ENTER: case '\r': view->count = 0; if (!s->selected_entry) break; err = view_request_new(new_view, view, TOG_VIEW_LOG); break; case 'T': view->count = 0; if (!s->selected_entry) break; err = view_request_new(new_view, view, TOG_VIEW_TREE); break; case 'g': case '=': case KEY_HOME: s->selected = 0; view->count = 0; s->first_displayed_entry = TAILQ_FIRST(&s->refs); break; case 'G': case '*': case KEY_END: { int eos = view->nlines - 1; if (view->mode == TOG_VIEW_SPLIT_HRZN) --eos; /* border */ s->selected = 0; view->count = 0; re = TAILQ_LAST(&s->refs, tog_reflist_head); for (n = 0; n < eos; n++) { if (re == NULL) break; s->first_displayed_entry = re; re = TAILQ_PREV(re, tog_reflist_head, entry); } if (n > 0) s->selected = n - 1; break; } case 'k': case KEY_UP: case CTRL('p'): if (s->selected > 0) { s->selected--; break; } ref_scroll_up(s, 1); if (s->selected_entry == TAILQ_FIRST(&s->refs)) view->count = 0; break; case CTRL('u'): case 'u': nscroll /= 2; /* FALL THROUGH */ case KEY_PPAGE: case CTRL('b'): case 'b': if (s->first_displayed_entry == TAILQ_FIRST(&s->refs)) s->selected -= MIN(nscroll, s->selected); ref_scroll_up(s, MAX(0, nscroll)); if (s->selected_entry == TAILQ_FIRST(&s->refs)) view->count = 0; break; case 'j': case KEY_DOWN: case CTRL('n'): if (s->selected < s->ndisplayed - 1) { s->selected++; break; } if (TAILQ_NEXT(s->last_displayed_entry, entry) == NULL) { /* can't scroll any further */ view->count = 0; break; } ref_scroll_down(view, 1); break; case CTRL('d'): case 'd': nscroll /= 2; /* FALL THROUGH */ case KEY_NPAGE: case CTRL('f'): case 'f': case ' ': if (TAILQ_NEXT(s->last_displayed_entry, entry) == NULL) { /* can't scroll any further; move cursor down */ if (s->selected < s->ndisplayed - 1) s->selected += MIN(nscroll, s->ndisplayed - s->selected - 1); if (view->count > 1 && s->selected < s->ndisplayed - 1) s->selected += s->ndisplayed - s->selected - 1; view->count = 0; break; } ref_scroll_down(view, nscroll); break; case CTRL('l'): view->count = 0; tog_free_refs(); err = tog_load_refs(s->repo, s->sort_by_date); if (err) break; ref_view_free_refs(s); err = ref_view_load_refs(s); break; case KEY_RESIZE: if (view->nlines >= 2 && s->selected >= view->nlines - 1) s->selected = view->nlines - 2; break; default: view->count = 0; break; } return err; } __dead static void usage_ref(void) { endwin(); fprintf(stderr, "usage: %s ref [-r repository-path]\n", getprogname()); exit(1); } static const struct got_error * cmd_ref(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL; int ch; struct tog_view *view; int *pack_fds = NULL; while ((ch = getopt(argc, argv, "r:")) != -1) { switch (ch) { case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); break; default: usage_ref(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc > 1) usage_ref(); error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { cwd = getcwd(NULL, 0); if (cwd == NULL) return got_error_from_errno("getcwd"); error = got_worktree_open(&worktree, cwd, NULL); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; if (worktree) repo_path = strdup(got_worktree_get_repo_path(worktree)); else repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; init_curses(); error = apply_unveil(got_repo_get_path(repo), NULL); if (error) goto done; error = tog_load_refs(repo, 0); if (error) goto done; view = view_open(0, 0, 0, 0, TOG_VIEW_REF); if (view == NULL) { error = got_error_from_errno("view_open"); goto done; } error = open_ref_view(view, repo); if (error) goto done; if (worktree) { error = set_tog_base_commit(repo, worktree); if (error != NULL) goto done; /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } error = view_loop(view); done: free(tog_base_commit.id); free(repo_path); free(cwd); if (worktree != NULL) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (close_err) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } tog_free_refs(); return error; } static const struct got_error* win_draw_center(WINDOW *win, size_t y, size_t x, size_t maxx, int focus, const char *str) { size_t len; if (win == NULL) win = stdscr; len = strlen(str); x = x ? x : maxx > len ? (maxx - len) / 2 : 0; if (focus) wstandout(win); if (mvwprintw(win, y, x, "%s", str) == ERR) return got_error_msg(GOT_ERR_RANGE, "mvwprintw"); if (focus) wstandend(win); return NULL; } static const struct got_error * add_line_offset(off_t **line_offsets, size_t *nlines, off_t off) { off_t *p; p = reallocarray(*line_offsets, *nlines + 1, sizeof(off_t)); if (p == NULL) { free(*line_offsets); *line_offsets = NULL; return got_error_from_errno("reallocarray"); } *line_offsets = p; (*line_offsets)[*nlines] = off; ++(*nlines); return NULL; } static const struct got_error * max_key_str(int *ret, const struct tog_key_map *km, size_t n) { *ret = 0; for (;n > 0; --n, ++km) { char *t0, *t, *k; size_t len = 1; if (km->keys == NULL) continue; t = t0 = strdup(km->keys); if (t0 == NULL) return got_error_from_errno("strdup"); len += strlen(t); while ((k = strsep(&t, " ")) != NULL) len += strlen(k) > 1 ? 2 : 0; free(t0); *ret = MAX(*ret, len); } return NULL; } /* * Write keymap section headers, keys, and key info in km to f. * Save line offset to *off. If terminal has UTF8 encoding enabled, * wrap control and symbolic keys in guillemets, else use <>. */ static const struct got_error * format_help_line(off_t *off, FILE *f, const struct tog_key_map *km, int width) { int n, len = width; if (km->keys) { static const char *u8_glyph[] = { "\xe2\x80\xb9", /* U+2039 (utf8 <) */ "\xe2\x80\xba" /* U+203A (utf8 >) */ }; char *t0, *t, *k; int cs, s, first = 1; cs = got_locale_is_utf8(); t = t0 = strdup(km->keys); if (t0 == NULL) return got_error_from_errno("strdup"); len = strlen(km->keys); while ((k = strsep(&t, " ")) != NULL) { s = strlen(k) > 1; /* control or symbolic key */ n = fprintf(f, "%s%s%s%s%s", first ? " " : "", cs && s ? u8_glyph[0] : s ? "<" : "", k, cs && s ? u8_glyph[1] : s ? ">" : "", t ? " " : ""); if (n < 0) { free(t0); return got_error_from_errno("fprintf"); } first = 0; len += s ? 2 : 0; *off += n; } free(t0); } n = fprintf(f, "%*s%s\n", width - len, width - len ? " " : "", km->info); if (n < 0) return got_error_from_errno("fprintf"); *off += n; return NULL; } static const struct got_error * format_help(struct tog_help_view_state *s) { const struct got_error *err = NULL; off_t off = 0; int i, max, n, show = s->all; static const struct tog_key_map km[] = { #define KEYMAP_(info, type) { NULL, (info), type } #define KEY_(keys, info) { (keys), (info), TOG_KEYMAP_KEYS } GENERATE_HELP #undef KEYMAP_ #undef KEY_ }; err = add_line_offset(&s->line_offsets, &s->nlines, 0); if (err) return err; n = nitems(km); err = max_key_str(&max, km, n); if (err) return err; for (i = 0; i < n; ++i) { if (km[i].keys == NULL) { show = s->all; if (km[i].type == TOG_KEYMAP_GLOBAL || km[i].type == s->type || s->all) show = 1; } if (show) { err = format_help_line(&off, s->f, &km[i], max); if (err) return err; err = add_line_offset(&s->line_offsets, &s->nlines, off); if (err) return err; } } fputc('\n', s->f); ++off; err = add_line_offset(&s->line_offsets, &s->nlines, off); return err; } static const struct got_error * create_help(struct tog_help_view_state *s) { FILE *f; const struct got_error *err; free(s->line_offsets); s->line_offsets = NULL; s->nlines = 0; f = got_opentemp(); if (f == NULL) return got_error_from_errno("got_opentemp"); s->f = f; err = format_help(s); if (err) return err; if (s->f && fflush(s->f) != 0) return got_error_from_errno("fflush"); return NULL; } static const struct got_error * search_start_help_view(struct tog_view *view) { view->state.help.matched_line = 0; return NULL; } static void search_setup_help_view(struct tog_view *view, FILE **f, off_t **line_offsets, size_t *nlines, int **first, int **last, int **match, int **selected) { struct tog_help_view_state *s = &view->state.help; *f = s->f; *nlines = s->nlines; *line_offsets = s->line_offsets; *match = &s->matched_line; *first = &s->first_displayed_line; *last = &s->last_displayed_line; *selected = &s->selected_line; } static const struct got_error * show_help_view(struct tog_view *view) { struct tog_help_view_state *s = &view->state.help; const struct got_error *err; regmatch_t *regmatch = &view->regmatch; wchar_t *wline; char *line; ssize_t linelen; size_t linesz = 0; int width, nprinted = 0, rc = 0; int eos = view->nlines; if (view_is_hsplit_top(view)) --eos; /* account for border */ s->lineno = 0; rewind(s->f); werase(view->window); if (view->gline > s->nlines - 1) view->gline = s->nlines - 1; err = win_draw_center(view->window, 0, 0, view->ncols, view_needs_focus_indication(view), "tog help (press q to return to tog)"); if (err) return err; if (eos <= 1) return NULL; waddstr(view->window, "\n\n"); eos -= 2; s->eof = 0; view->maxx = 0; line = NULL; while (eos > 0 && nprinted < eos) { attr_t attr = 0; linelen = getline(&line, &linesz, s->f); if (linelen == -1) { if (!feof(s->f)) { free(line); return got_ferror(s->f, GOT_ERR_IO); } s->eof = 1; break; } if (++s->lineno < s->first_displayed_line) continue; if (view->gline && !gotoline(view, &s->lineno, &nprinted)) continue; if (s->lineno == view->hiline) attr = A_STANDOUT; err = format_line(&wline, &width, NULL, line, 0, INT_MAX, 0, view->x ? 1 : 0); if (err) { free(line); return err; } view->maxx = MAX(view->maxx, width); free(wline); wline = NULL; if (attr) wattron(view->window, attr); if (s->first_displayed_line + nprinted == s->matched_line && regmatch->rm_so >= 0 && regmatch->rm_so < regmatch->rm_eo) { err = add_matched_line(&width, line, view->ncols - 1, 0, view->window, view->x, regmatch); if (err) { free(line); return err; } } else { int skip; err = format_line(&wline, &width, &skip, line, view->x, view->ncols, 0, view->x ? 1 : 0); if (err) { free(line); return err; } waddwstr(view->window, &wline[skip]); free(wline); wline = NULL; } if (s->lineno == view->hiline) { while (width++ < view->ncols) waddch(view->window, ' '); } else { if (width < view->ncols) waddch(view->window, '\n'); } if (attr) wattroff(view->window, attr); if (++nprinted == 1) s->first_displayed_line = s->lineno; } free(line); if (nprinted > 0) s->last_displayed_line = s->first_displayed_line + nprinted - 1; else s->last_displayed_line = s->first_displayed_line; view_border(view); if (s->eof) { rc = waddnstr(view->window, "See the tog(1) manual page for full documentation", view->ncols - 1); if (rc == ERR) return got_error_msg(GOT_ERR_RANGE, "waddnstr"); } else { wmove(view->window, view->nlines - 1, 0); wclrtoeol(view->window); wstandout(view->window); rc = waddnstr(view->window, "scroll down for more...", view->ncols - 1); if (rc == ERR) return got_error_msg(GOT_ERR_RANGE, "waddnstr"); if (getcurx(view->window) < view->ncols - 6) { rc = wprintw(view->window, "[%.0f%%]", 100.00 * s->last_displayed_line / s->nlines); if (rc == ERR) return got_error_msg(GOT_ERR_IO, "wprintw"); } wstandend(view->window); } return NULL; } static const struct got_error * input_help_view(struct tog_view **new_view, struct tog_view *view, int ch) { struct tog_help_view_state *s = &view->state.help; const struct got_error *err = NULL; char *line = NULL; ssize_t linelen; size_t linesz = 0; int eos, nscroll; eos = nscroll = view->nlines; if (view_is_hsplit_top(view)) --eos; /* border */ s->lineno = s->first_displayed_line - 1 + s->selected_line; switch (ch) { case '0': case '$': case KEY_RIGHT: case 'l': case KEY_LEFT: case 'h': horizontal_scroll_input(view, ch); break; case 'g': case KEY_HOME: s->first_displayed_line = 1; view->count = 0; break; case 'G': case KEY_END: view->count = 0; if (s->eof) break; s->first_displayed_line = (s->nlines - eos) + 3; s->eof = 1; break; case 'k': case KEY_UP: if (s->first_displayed_line > 1) --s->first_displayed_line; else view->count = 0; break; case CTRL('u'): case 'u': nscroll /= 2; /* FALL THROUGH */ case KEY_PPAGE: case CTRL('b'): case 'b': if (s->first_displayed_line == 1) { view->count = 0; break; } while (--nscroll > 0 && s->first_displayed_line > 1) s->first_displayed_line--; break; case 'j': case KEY_DOWN: case CTRL('n'): if (!s->eof) ++s->first_displayed_line; else view->count = 0; break; case CTRL('d'): case 'd': nscroll /= 2; /* FALL THROUGH */ case KEY_NPAGE: case CTRL('f'): case 'f': case ' ': if (s->eof) { view->count = 0; break; } while (!s->eof && --nscroll > 0) { linelen = getline(&line, &linesz, s->f); s->first_displayed_line++; if (linelen == -1) { if (feof(s->f)) s->eof = 1; else err = got_ferror(s->f, GOT_ERR_IO); break; } } free(line); break; default: view->count = 0; break; } return err; } static const struct got_error * close_help_view(struct tog_view *view) { struct tog_help_view_state *s = &view->state.help; free(s->line_offsets); s->line_offsets = NULL; if (fclose(s->f) == EOF) return got_error_from_errno("fclose"); return NULL; } static const struct got_error * reset_help_view(struct tog_view *view) { struct tog_help_view_state *s = &view->state.help; if (s->f && fclose(s->f) == EOF) return got_error_from_errno("fclose"); wclear(view->window); view->count = 0; view->x = 0; s->all = !s->all; s->first_displayed_line = 1; s->last_displayed_line = view->nlines; s->matched_line = 0; return create_help(s); } static const struct got_error * open_help_view(struct tog_view *view, struct tog_view *parent) { const struct got_error *err = NULL; struct tog_help_view_state *s = &view->state.help; s->type = (enum tog_keymap_type)parent->type; s->first_displayed_line = 1; s->last_displayed_line = view->nlines; s->selected_line = 1; view->show = show_help_view; view->input = input_help_view; view->reset = reset_help_view; view->close = close_help_view; view->search_start = search_start_help_view; view->search_setup = search_setup_help_view; view->search_next = search_next_view_match; err = create_help(s); return err; } static const struct got_error * view_dispatch_request(struct tog_view **new_view, struct tog_view *view, enum tog_view_type request, int y, int x) { const struct got_error *err = NULL; *new_view = NULL; switch (request) { case TOG_VIEW_DIFF: if (view->type == TOG_VIEW_LOG) { struct tog_log_view_state *s = &view->state.log; err = open_diff_view_for_commit(new_view, y, x, s->selected_entry->commit, s->selected_entry->id, view, s->repo); } else return got_error_msg(GOT_ERR_NOT_IMPL, "parent/child view pair not supported"); break; case TOG_VIEW_BLAME: if (view->type == TOG_VIEW_TREE) { struct tog_tree_view_state *s = &view->state.tree; err = blame_tree_entry(new_view, y, x, s->selected_entry, &s->parents, s->commit_id, s->repo); } else return got_error_msg(GOT_ERR_NOT_IMPL, "parent/child view pair not supported"); break; case TOG_VIEW_LOG: if (view->type == TOG_VIEW_BLAME) err = log_annotated_line(new_view, y, x, view->state.blame.repo, view->state.blame.id_to_log); else if (view->type == TOG_VIEW_TREE) err = log_selected_tree_entry(new_view, y, x, &view->state.tree); else if (view->type == TOG_VIEW_REF) err = log_ref_entry(new_view, y, x, view->state.ref.selected_entry, view->state.ref.repo); else return got_error_msg(GOT_ERR_NOT_IMPL, "parent/child view pair not supported"); break; case TOG_VIEW_TREE: if (view->type == TOG_VIEW_LOG) err = browse_commit_tree(new_view, y, x, view->state.log.selected_entry, view->state.log.in_repo_path, view->state.log.head_ref_name, view->state.log.repo); else if (view->type == TOG_VIEW_REF) err = browse_ref_tree(new_view, y, x, view->state.ref.selected_entry, view->state.ref.repo); else return got_error_msg(GOT_ERR_NOT_IMPL, "parent/child view pair not supported"); break; case TOG_VIEW_REF: *new_view = view_open(0, 0, y, x, TOG_VIEW_REF); if (*new_view == NULL) return got_error_from_errno("view_open"); if (view->type == TOG_VIEW_LOG) err = open_ref_view(*new_view, view->state.log.repo); else if (view->type == TOG_VIEW_TREE) err = open_ref_view(*new_view, view->state.tree.repo); else err = got_error_msg(GOT_ERR_NOT_IMPL, "parent/child view pair not supported"); if (err) view_close(*new_view); break; case TOG_VIEW_HELP: *new_view = view_open(0, 0, 0, 0, TOG_VIEW_HELP); if (*new_view == NULL) return got_error_from_errno("view_open"); err = open_help_view(*new_view, view); if (err) view_close(*new_view); break; default: return got_error_msg(GOT_ERR_NOT_IMPL, "invalid view"); } return err; } /* * If view was scrolled down to move the selected line into view when opening a * horizontal split, scroll back up when closing the split/toggling fullscreen. */ static void offset_selection_up(struct tog_view *view) { switch (view->type) { case TOG_VIEW_BLAME: { struct tog_blame_view_state *s = &view->state.blame; if (s->first_displayed_line == 1) { s->selected_line = MAX(s->selected_line - view->offset, 1); break; } if (s->first_displayed_line > view->offset) s->first_displayed_line -= view->offset; else s->first_displayed_line = 1; s->selected_line += view->offset; break; } case TOG_VIEW_LOG: log_scroll_up(&view->state.log, view->offset); view->state.log.selected += view->offset; break; case TOG_VIEW_REF: ref_scroll_up(&view->state.ref, view->offset); view->state.ref.selected += view->offset; break; case TOG_VIEW_TREE: tree_scroll_up(&view->state.tree, view->offset); view->state.tree.selected += view->offset; break; default: break; } view->offset = 0; } /* * If the selected line is in the section of screen covered by the bottom split, * scroll down offset lines to move it into view and index its new position. */ static const struct got_error * offset_selection_down(struct tog_view *view) { const struct got_error *err = NULL; const struct got_error *(*scrolld)(struct tog_view *, int); int *selected = NULL; int header, offset; switch (view->type) { case TOG_VIEW_BLAME: { struct tog_blame_view_state *s = &view->state.blame; header = 3; scrolld = NULL; if (s->selected_line > view->nlines - header) { offset = abs(view->nlines - s->selected_line - header); s->first_displayed_line += offset; s->selected_line -= offset; view->offset = offset; } break; } case TOG_VIEW_LOG: { struct tog_log_view_state *s = &view->state.log; scrolld = &log_scroll_down; header = view_is_parent_view(view) ? 3 : 2; selected = &s->selected; break; } case TOG_VIEW_REF: { struct tog_ref_view_state *s = &view->state.ref; scrolld = &ref_scroll_down; header = 3; selected = &s->selected; break; } case TOG_VIEW_TREE: { struct tog_tree_view_state *s = &view->state.tree; scrolld = &tree_scroll_down; header = 5; selected = &s->selected; break; } default: selected = NULL; scrolld = NULL; header = 0; break; } if (selected && *selected > view->nlines - header) { offset = abs(view->nlines - *selected - header); view->offset = offset; if (scrolld && offset) { err = scrolld(view, offset); *selected -= offset; } } return err; } static void list_commands(FILE *fp) { size_t i; fprintf(fp, "commands:"); for (i = 0; i < nitems(tog_commands); i++) { const struct tog_cmd *cmd = &tog_commands[i]; fprintf(fp, " %s", cmd->name); } fputc('\n', fp); } __dead static void usage(int hflag, int status) { FILE *fp = (status == 0) ? stdout : stderr; fprintf(fp, "usage: %s [-hV] command [arg ...]\n", getprogname()); if (hflag) { fprintf(fp, "lazy usage: %s path\n", getprogname()); list_commands(fp); } exit(status); } static char ** make_argv(int argc, ...) { va_list ap; char **argv; int i; va_start(ap, argc); argv = calloc(argc, sizeof(char *)); if (argv == NULL) err(1, "calloc"); for (i = 0; i < argc; i++) { argv[i] = strdup(va_arg(ap, char *)); if (argv[i] == NULL) err(1, "strdup"); } va_end(ap); return argv; } /* * Try to convert 'tog path' into a 'tog log path' command. * The user could simply have mistyped the command rather than knowingly * provided a path. So check whether argv[0] can in fact be resolved * to a path in the HEAD commit and print a special error if not. * This hack is for mpi@ <3 */ static const struct got_error * tog_log_with_path(int argc, char *argv[]) { const struct got_error *error = NULL, *close_err; const struct tog_cmd *cmd = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; struct got_object_id *commit_id = NULL, *id = NULL; struct got_commit_object *commit = NULL; char *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL; char *commit_id_str = NULL, **cmd_argv = NULL; int *pack_fds = NULL; cwd = getcwd(NULL, 0); if (cwd == NULL) return got_error_from_errno("getcwd"); error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, NULL); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; if (worktree) repo_path = strdup(got_worktree_get_repo_path(worktree)); else repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; error = get_in_repo_path_from_argv0(&in_repo_path, argc, argv, repo, worktree); if (error) goto done; error = tog_load_refs(repo, 0); if (error) goto done; error = got_repo_match_object_id(&commit_id, NULL, worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, GOT_OBJ_TYPE_COMMIT, &tog_refs, repo); if (error) goto done; if (worktree) { got_worktree_close(worktree); worktree = NULL; } error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; error = got_object_id_by_path(&id, repo, commit, in_repo_path); if (error) { if (error->code != GOT_ERR_NO_TREE_ENTRY) goto done; fprintf(stderr, "%s: '%s' is no known command or path\n", getprogname(), argv[0]); usage(1, 1); /* not reached */ } error = got_object_id_str(&commit_id_str, commit_id); if (error) goto done; cmd = &tog_commands[0]; /* log */ argc = 4; cmd_argv = make_argv(argc, cmd->name, "-c", commit_id_str, argv[0]); error = cmd->cmd_main(argc, cmd_argv); done: if (repo) { close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (commit) got_object_commit_close(commit); if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } free(id); free(commit_id_str); free(commit_id); free(cwd); free(repo_path); free(in_repo_path); if (cmd_argv) { int i; for (i = 0; i < argc; i++) free(cmd_argv[i]); free(cmd_argv); } tog_free_refs(); return error; } int main(int argc, char *argv[]) { const struct got_error *io_err, *error = NULL; const struct tog_cmd *cmd = NULL; int ch, hflag = 0, Vflag = 0; char **cmd_argv = NULL; static const struct option longopts[] = { { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0} }; char *diff_algo_str = NULL; const char *test_script_path; setlocale(LC_CTYPE, ""); /* * Override default signal handlers before starting ncurses. * This should prevent ncurses from installing its own * broken cleanup() signal handler. */ signal(SIGWINCH, tog_sigwinch); signal(SIGPIPE, tog_sigpipe); signal(SIGCONT, tog_sigcont); signal(SIGINT, tog_sigint); signal(SIGTERM, tog_sigterm); /* * Test mode init must happen before pledge() because "tty" will * not allow TTY-related ioctls to occur via regular files. */ test_script_path = getenv("TOG_TEST_SCRIPT"); if (test_script_path != NULL) { error = init_mock_term(test_script_path); if (error) { fprintf(stderr, "%s: %s\n", getprogname(), error->msg); return 1; } } else if (!isatty(STDIN_FILENO)) errx(1, "standard input is not a tty"); #if !defined(PROFILE) if (pledge("stdio rpath wpath cpath flock proc tty exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt_long(argc, argv, "+hV", longopts, NULL)) != -1) { switch (ch) { case 'h': hflag = 1; break; case 'V': Vflag = 1; break; default: usage(hflag, 1); /* NOTREACHED */ } } argc -= optind; argv += optind; optind = 1; optreset = 1; if (Vflag) { got_version_print_str(); return 0; } if (argc == 0) { if (hflag) usage(hflag, 0); /* Build an argument vector which runs a default command. */ cmd = &tog_commands[0]; argc = 1; cmd_argv = make_argv(argc, cmd->name); } else { size_t i; /* Did the user specify a command? */ for (i = 0; i < nitems(tog_commands); i++) { if (strncmp(tog_commands[i].name, argv[0], strlen(argv[0])) == 0) { cmd = &tog_commands[i]; break; } } } diff_algo_str = getenv("TOG_DIFF_ALGORITHM"); if (diff_algo_str) { if (strcasecmp(diff_algo_str, "patience") == 0) tog_diff_algo = GOT_DIFF_ALGORITHM_PATIENCE; if (strcasecmp(diff_algo_str, "myers") == 0) tog_diff_algo = GOT_DIFF_ALGORITHM_MYERS; } tog_base_commit.idx = -1; tog_base_commit.marker = GOT_WORKTREE_STATE_UNKNOWN; if (cmd == NULL) { if (argc != 1) usage(0, 1); /* No command specified; try log with a path */ error = tog_log_with_path(argc, argv); } else { if (hflag) cmd->cmd_usage(); else error = cmd->cmd_main(argc, cmd_argv ? cmd_argv : argv); } if (using_mock_io) { io_err = tog_io_close(); if (error == NULL) error = io_err; } endwin(); if (cmd_argv) { int i; for (i = 0; i < argc; i++) free(cmd_argv[i]); free(cmd_argv); } if (error && error->code != GOT_ERR_CANCELLED && error->code != GOT_ERR_EOF && error->code != GOT_ERR_PRIVSEP_EXIT && error->code != GOT_ERR_PRIVSEP_PIPE && !(error->code == GOT_ERR_ERRNO && errno == EINTR)) { fprintf(stderr, "%s: %s\n", getprogname(), error->msg); return 1; } return 0; } got-portable-0.101/tog/Makefile.in0000664000175100017510000013400014644145544012446 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = tog$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = tog ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" PROGRAMS = $(bin_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_tog_OBJECTS = tog.$(OBJEXT) $(top_builddir)/lib/blame.$(OBJEXT) \ $(top_builddir)/lib/bloom.$(OBJEXT) \ $(top_builddir)/lib/buf.$(OBJEXT) \ $(top_builddir)/lib/commit_graph.$(OBJEXT) \ $(top_builddir)/lib/date.$(OBJEXT) \ $(top_builddir)/lib/deflate.$(OBJEXT) \ $(top_builddir)/lib/delta.$(OBJEXT) \ $(top_builddir)/lib/delta_cache.$(OBJEXT) \ $(top_builddir)/lib/dial.$(OBJEXT) \ $(top_builddir)/lib/diff.$(OBJEXT) \ $(top_builddir)/lib/diff3.$(OBJEXT) \ $(top_builddir)/lib/diff_atomize_text.$(OBJEXT) \ $(top_builddir)/lib/diff_main.$(OBJEXT) \ $(top_builddir)/lib/diff_myers.$(OBJEXT) \ $(top_builddir)/lib/diff_output.$(OBJEXT) \ $(top_builddir)/lib/diff_output_edscript.$(OBJEXT) \ $(top_builddir)/lib/diff_output_plain.$(OBJEXT) \ $(top_builddir)/lib/diff_output_unidiff.$(OBJEXT) \ $(top_builddir)/lib/diff_patience.$(OBJEXT) \ $(top_builddir)/lib/diffreg.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/fetch.$(OBJEXT) \ $(top_builddir)/lib/fileindex.$(OBJEXT) \ $(top_builddir)/lib/gotconfig.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/keyword.$(OBJEXT) \ $(top_builddir)/lib/lockfile.$(OBJEXT) \ $(top_builddir)/lib/murmurhash2.$(OBJEXT) \ $(top_builddir)/lib/object.$(OBJEXT) \ $(top_builddir)/lib/object_cache.$(OBJEXT) \ $(top_builddir)/lib/object_create.$(OBJEXT) \ $(top_builddir)/lib/object_idset.$(OBJEXT) \ $(top_builddir)/lib/object_open_privsep.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/opentemp.$(OBJEXT) \ $(top_builddir)/lib/pack.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) \ $(top_builddir)/lib/rcsutil.$(OBJEXT) \ $(top_builddir)/lib/read_gitconfig_privsep.$(OBJEXT) \ $(top_builddir)/lib/read_gotconfig_privsep.$(OBJEXT) \ $(top_builddir)/lib/reference.$(OBJEXT) \ $(top_builddir)/lib/reference_parse.$(OBJEXT) \ $(top_builddir)/lib/repository.$(OBJEXT) \ $(top_builddir)/lib/sigs.$(OBJEXT) \ $(top_builddir)/lib/utf8.$(OBJEXT) \ $(top_builddir)/lib/worktree.$(OBJEXT) \ $(top_builddir)/lib/worktree_open.$(OBJEXT) tog_OBJECTS = $(am_tog_OBJECTS) tog_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/blame.Po \ $(top_builddir)/lib/$(DEPDIR)/bloom.Po \ $(top_builddir)/lib/$(DEPDIR)/buf.Po \ $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po \ $(top_builddir)/lib/$(DEPDIR)/date.Po \ $(top_builddir)/lib/$(DEPDIR)/deflate.Po \ $(top_builddir)/lib/$(DEPDIR)/delta.Po \ $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/dial.Po \ $(top_builddir)/lib/$(DEPDIR)/diff.Po \ $(top_builddir)/lib/$(DEPDIR)/diff3.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_main.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po \ $(top_builddir)/lib/$(DEPDIR)/diffreg.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/fetch.Po \ $(top_builddir)/lib/$(DEPDIR)/fileindex.Po \ $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/keyword.Po \ $(top_builddir)/lib/$(DEPDIR)/lockfile.Po \ $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po \ $(top_builddir)/lib/$(DEPDIR)/object.Po \ $(top_builddir)/lib/$(DEPDIR)/object_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/object_create.Po \ $(top_builddir)/lib/$(DEPDIR)/object_idset.Po \ $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/opentemp.Po \ $(top_builddir)/lib/$(DEPDIR)/pack.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po \ $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/reference.Po \ $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/repository.Po \ $(top_builddir)/lib/$(DEPDIR)/sigs.Po \ $(top_builddir)/lib/$(DEPDIR)/utf8.Po \ $(top_builddir)/lib/$(DEPDIR)/worktree.Po \ $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po \ ./$(DEPDIR)/tog.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(tog_SOURCES) DIST_SOURCES = $(tog_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } man1dir = $(mandir)/man1 NROFF = nroff MANS = $(man1_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(libbsd_CFLAGS) $(libncurses_CFLAGS) \ $(libuuid_CFLAGS) $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ tog_SOURCES = tog.c \ $(top_srcdir)/lib/blame.c \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/commit_graph.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/diff.c \ $(top_srcdir)/lib/diff3.c \ $(top_srcdir)/lib/diff_atomize_text.c \ $(top_srcdir)/lib/diff_main.c \ $(top_srcdir)/lib/diff_myers.c \ $(top_srcdir)/lib/diff_output.c \ $(top_srcdir)/lib/diff_output_edscript.c \ $(top_srcdir)/lib/diff_output_plain.c \ $(top_srcdir)/lib/diff_output_unidiff.c \ $(top_srcdir)/lib/diff_patience.c \ $(top_srcdir)/lib/diffreg.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fetch.c \ $(top_srcdir)/lib/fileindex.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/keyword.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/rcsutil.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/lib/utf8.c \ $(top_srcdir)/lib/worktree.c \ $(top_srcdir)/lib/worktree_open.c tog_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a man1_MANS = tog.1 EXTRA_DIST = tog.1 LDADD = -L$(top_builddir)/compat -lopenbsd-compat -lpthread -lm \ $(libbsd_LIBS) $(libncurses_LIBS) $(libuuid_LIBS) $(zlib_LIBS) \ $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tog/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign tog/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: > $(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: > $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/blame.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/bloom.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/buf.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/commit_graph.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/date.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/deflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/dial.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff3.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_atomize_text.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_main.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_myers.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_edscript.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_plain.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_unidiff.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_patience.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diffreg.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/fetch.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/fileindex.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gotconfig.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/keyword.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/lockfile.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/murmurhash2.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_create.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_idset.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_open_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/opentemp.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/rcsutil.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/read_gitconfig_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/read_gotconfig_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/repository.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/sigs.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/utf8.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/worktree.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/worktree_open.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) tog$(EXEEXT): $(tog_OBJECTS) $(tog_DEPENDENCIES) $(EXTRA_tog_DEPENDENCIES) @rm -f tog$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tog_OBJECTS) $(tog_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/blame.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/bloom.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/buf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/commit_graph.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/date.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/deflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/dial.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff3.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_myers.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_patience.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diffreg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/fetch.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/fileindex.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gotconfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/keyword.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/lockfile.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_create.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_idset.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/opentemp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/rcsutil.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/repository.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/sigs.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/utf8.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/worktree.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/worktree_open.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tog.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` install-man1: $(man1_MANS) @$(NORMAL_INSTALL) @list1='$(man1_MANS)'; \ list2=''; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list='$(man1_MANS)'; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(MANS) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/blame.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/bloom.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/buf.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/date.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/dial.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff3.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_main.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diffreg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fetch.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fileindex.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/keyword.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/lockfile.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/sigs.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/utf8.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po -rm -f ./$(DEPDIR)/tog.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/blame.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/bloom.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/buf.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/date.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/dial.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff3.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_main.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diffreg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fetch.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fileindex.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/keyword.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/lockfile.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/sigs.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/utf8.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po -rm -f ./$(DEPDIR)/tog.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-man uninstall-man: uninstall-man1 .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-binPROGRAMS clean-generic cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-binPROGRAMS install-data install-data-am \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-man1 install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-man uninstall-man1 .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/tog/tog.10000644000175100017510000006471614644143163011265 .\" .\" Copyright (c) 2018 Stefan Sperling .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt TOG 1 .Os .Sh NAME .Nm tog .Nd Git repository browser .Sh SYNOPSIS .Nm .Op Fl hV .Ar command .Op Ar arg ... .Pp .Nm .Ar path .Sh DESCRIPTION .Nm is an interactive read-only browser for Git repositories. This repository format is described in .Xr git-repository 5 . .Pp .Nm supports several types of views which display repository data: .Bl -tag -width Ds .It Log view Displays commits in the repository's history. This view is displayed initially if no .Ar command is specified, or if just a .Ar path is specified. .It Diff view Displays changes made in a particular commit. .It Blame view Displays the line-by-line history of a file. .It Tree view Displays the tree corresponding to a particular commit. .It Ref view Displays references in the repository. .El .Pp .Nm provides global and command-specific key bindings and options. Some command-specific key bindings may be prefixed with an integer, which is denoted by N in the descriptions below, and is used as a modifier to the operation as indicated. .Nm will echo digits to the screen when count modifiers are entered, and complete the sequence upon input of the first non-numeric character. Count modifiers can be aborted by entering an unmapped key. Once a compound command is executed, the operation can be cancelled with .Cm C-g or .Cm Backspace . .Pp Global options must precede the command name, and are as follows: .Bl -tag -width tenletters .It Fl h Display usage information. .It Fl V , -version Display program version and exit immediately. .El .Pp The global key bindings are: .Bl -tag -width Ds .It Cm H, F1 Display run-time help. Key bindings for the focussed view will be displayed. Pressing this again inside the help view will toggle the display of key bindings for all .Nm views. .It Cm Q Quit .Nm . .It Cm q Quit the view which is in focus. .It Cm Tab Switch focus between views. .It Cm F Toggle fullscreen mode for a split-screen view. .Nm will automatically use vertical split-screen views if the size of the terminal window is sufficiently large. .It Cm S Switch the current split-screen layout, and render all active views in this new layout. The split-screen layout can be either vertical or horizontal. If the terminal is not wide enough when switching to a vertical split, views will render in fullscreen. .It Cm - When in a split-screen view, decrease the size of the focussed split N increments (default: 1). .It Cm + When in a split-screen view, increase the size of the focussed split N increments (default: 1). .It Cm G Go to line N in the view (default: last line). .It Cm g Go to line N in the view (default: first line). .It Cm Right-arrow, l Scroll view to the right N increments (default: 1). .br Output moves left on the screen. .It Cm Left-arrow, h Scroll view to the left N increments (default: 1). .br Output moves right on the screen. .It Cm $ Scroll view to the rightmost position. .It Cm 0 Scroll view left to the start of the line. .El .Pp The commands for .Nm are as follows: .Bl -tag -width blame .It Xo .Cm log .Op Fl b .Op Fl c Ar commit .Op Fl r Ar repository-path .Op Ar path .Xc Display history of a repository. If a .Ar path is specified, show only commits which modified this path. If invoked in a work tree, the .Ar path is interpreted relative to the current working directory, and the work tree's path prefix is implicitly prepended. Otherwise, the path is interpreted relative to the repository root. .Pp If invoked in a work tree, the log entry of the work tree's base commit will be prefixed with one of the following annotations: .Bl -column YXZ description .It * Ta work tree's base commit and the base commit of all tracked files matches the branch tip .It \(a~ Ta work tree comprises mixed commits or its base commit is out-of-date .El .Pp This command is also executed if no explicit command is specified. .Pp The key bindings for .Cm tog log are as follows (N denotes optional prefixed count modifier): .Bl -tag -width Ds .It Cm Down-arrow, j, >, Full stop, Ctrl-n Move the selection cursor down N lines (default: 1). .It Cm Up-arrow, k, <, Comma, Ctrl-p Move the selection cursor up N lines (default: 1). .It Cm Page-down, Space, Ctrl+f, f Move the selection cursor down N pages (default: 1). .It Cm Page-up, Ctrl+b, b Move the selection cursor up N pages (default: 1). .It Cm Ctrl+d, d Move the selection cursor down N half pages (default: 1). .It Cm Ctrl+u, u Move the selection cursor up N half pages (default: 1). .It Cm Home, = Move the cursor to the newest commit. .It Cm End, * Move the cursor to the oldest commit. This will traverse all commits on the current branch which may take a long time depending on the number of commits in branch history. If needed, this operation can be cancelled with .Cm C-g or .Cm Backspace . .It Cm g Move the cursor to commit N (default: 1). .It Cm G Like .Cm g but defaults to the oldest commit. .It Cm Enter Open a .Cm diff view showing file changes made in the currently selected commit. .It Cm T Open a .Cm tree view showing the tree for the currently selected commit. .It Cm Backspace Show log entries for the parent directory of the currently selected path. However when an active search is in progress or when additional commits are loaded, .Cm Backspace aborts the running operation. .It Cm / Prompt for a search pattern and start searching for matching commits. The search pattern is an extended regular expression which is matched against a commit's author name, committer name, log message, and commit ID SHA1 hash. Regular expression syntax is documented in .Xr re_format 7 . .It Cm & Prompt for a pattern and limit the log view's list of commits to those which match the pattern. If no pattern is specified, i.e. the .Cm & prompt is immediately closed with the Enter key, then the pattern is cleared. Until the pattern is cleared, the limited list of commits replaces the full list of commits for all operations supported by the log view. For example, a search started with .Cm / will search the limited list of commits, rather than searching all commits. The pattern is an extended regular expression which is matched against a commit's author name, committer name, log message, and commit ID SHA1 hash. Regular expression syntax is documented in .Xr re_format 7 . .It Cm n Find the Nth next commit which matches the current search pattern (default: 1). .br Searching continues until either a match is found or .Cm C-g or the .Cm Backspace key is pressed. .It Cm N Find the Nth previous commit which matches the current search pattern (default: 1). .br Searching continues until either a match is found or .Cm C-g or the .Cm Backspace key is pressed. .It Cm Ctrl+l Reload the .Cm log view with new commits found in the repository. .It Cm B Reload the .Cm log view and toggle display of merged commits. The .Fl b option determines whether merged commits are displayed initially. .It Cm R Open a .Cm ref view listing all references in the repository. This can then be used to open a new .Cm log view for arbitrary branches and tags. .It Cm @ Toggle between showing the committer name and the author name. .El .Pp The options for .Cm tog log are as follows: .Bl -tag -width Ds .It Fl b Display individual commits which were merged into the current branch from other branches. By default, .Cm tog log shows the linear history of the current branch only. The .Cm B key binding can be used to toggle display of merged commits at run-time. .It Fl c Ar commit Start traversing history at the specified .Ar commit . The expected argument is a commit ID SHA1 hash, or a reference name or keyword which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full SHA1 hash automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the work tree's base commit and branch head, respectively. The former is only valid if invoked in a work tree, while the latter will resolve to the tip of the work tree's current branch if invoked in a work tree, otherwise it will resolve to the repository's HEAD reference. Keywords and references may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent by first parent traversal, respectively; for example, .Sy :head:-2 denotes the work tree branch head's 2nd generation ancestor, and .Sy :base:+4 denotes the 4th generation descendant of the work tree's base commit. Similarly, .Sy foobar:+3 will denote the 3rd generation descendant of the commit resolved by the .Qq foobar reference. A .Qq :+ or .Qq :- modifier without a trailing integer has an implicit .Qq 1 appended .Po e.g., .Sy :base:+ is equivalent to .Sy :base:+1 .Pc . .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Xr got 1 work tree, use the repository path associated with this work tree. .El .It Xo .Cm diff .Op Fl aw .Op Fl C Ar number .Op Fl r Ar repository-path .Ar object1 .Ar object2 .Xc Display the differences between two objects in the repository. Treat each of the two arguments as a reference, a tag name, an object ID SHA1 hash, or a keyword and display differences between the corresponding objects. Both objects must be of the same type (blobs, trees, or commits). An abbreviated hash argument will be expanded to a full SHA1 hash automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the work tree's base commit and branch head, respectively. The former is only valid if invoked in a work tree, while the latter will resolve to the tip of the work tree's current branch if invoked in a work tree, otherwise it will resolve to the repository's HEAD reference. Keywords and references may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent by first parent traversal, respectively; for example, .Sy :head:-2 denotes the work tree branch head's 2nd generation ancestor, and .Sy :base:+4 denotes the 4th generation descendant of the work tree's base commit. Similarly, .Sy foobar:+3 will denote the 3rd generation descendant of the commit resolved by the .Qq foobar reference. A .Qq :+ or .Qq :- modifier without a trailing integer has an implicit .Qq 1 appended .Po e.g., .Sy :base:+ is equivalent to .Sy :base:+1 .Pc . .Pp The key bindings for .Cm tog diff are as follows (N denotes optional prefixed count modifier): .Bl -tag -width Ds .It Cm a Toggle treatment of file contents as ASCII text even if binary data was detected. .It Cm Down-arrow, j, Ctrl-n Scroll down N lines (default: 1). .It Cm Up-arrow, k, Ctrl-p Scroll up N lines (default: 1). .It Cm Page-down, Space, Ctrl+f, f Scroll down N pages (default: 1). .It Cm Page-up, Ctrl+b, b Scroll up N pages (default: 1). .It Cm Ctrl+d, d Scroll down N half pages (default: 1). .It Cm Ctrl+u, u Scroll up N half pages (default: 1). .It Cm Home Scroll to the top of the view. .It Cm End Scroll to the bottom of the view. .It Cm g Scroll to line N (default: 1). .It Cm G Like .Cm g but defaults to the last line in the diff. .It Cm \&( Navigate to the Nth previous file in the diff (default: 1). .It Cm \&) Navigate to the Nth next file in the diff (default: 1). .It Cm \&{ Navigate to the Nth previous hunk in the diff (default: 1). .It Cm \&} Navigate to the Nth next hunk in the diff (default: 1). .It Cm \&[ Reduce diff context by N lines (default: 1). .It Cm \&] Increase diff context by N lines (default: 1). .It Cm <, Comma, K If the .Cm diff view was opened via the .Cm log view, move to the Nth previous (younger) commit. If the diff was opened via the .Cm blame view, move to the Nth previous line and load the corresponding commit (default: 1). .It Cm >, Full stop, J If the .Cm diff view was opened via the .Cm log view, move to the Nth next (older) commit. If the diff was opened via the .Cm blame view, move to the Nth next line and load the corresponding commit (default: 1). .It Cm / Prompt for a search pattern and start searching for matching lines. The search pattern is an extended regular expression. Regular expression syntax is documented in .Xr re_format 7 . .It Cm n Find the Nth next line which matches the current search pattern (default: 1). .It Cm N Find the Nth previous line which matches the current search pattern (default: 1). .It Cm w Toggle display of whitespace-only changes. .It Cm A Change the diff algorithm. Supported diff algorithms are Myers (quick and dirty) and Patience (slow and tidy). This is a global setting which also affects the .Cm blame view. .El .Pp The options for .Cm tog diff are as follows: .Bl -tag -width Ds .It Fl a Treat file contents as ASCII text even if binary data is detected. .It Fl C Ar number Set the number of context lines shown in the diff. By default, 3 lines of context are shown. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Xr got 1 work tree, use the repository path associated with this work tree. .It Fl w Ignore whitespace-only changes. .El .It Xo .Cm blame .Op Fl c Ar commit .Op Fl r Ar repository-path .Ar path .Xc Display line-by-line history of a file at the specified path. .Pp The key bindings for .Cm tog blame are as follows (N denotes optional prefixed count modifier): .Bl -tag -width Ds .It Cm Down-arrow, j, Ctrl-n Move the selection cursor down N pages (default: 1). .It Cm Up-arrow, k, Ctrl-p Move the selection cursor up N pages (default: 1). .It Cm Page-down, Space, Ctrl+f, f Move the selection cursor down N pages (default: 1). .It Cm Page-up, Ctrl+b, b Move the selection cursor up N pages (default: 1). .It Cm Ctrl+d, d Move the selection cursor down N half pages (default: 1). .It Cm Ctrl+u, u Move the selection cursor up N half pages (default: 1). .It Cm Home Move the selection cursor to the first line of the file. .It Cm End Move the selection cursor to the last line of the file. .It Cm g Move the selection cursor to line N (default: 1). .It Cm G Like .Cm g but defaults to the last line in the file. .It Cm Enter Open a .Cm diff view for the currently selected line's commit. .It Cm c Reload the .Cm blame view with the version of the file as found in the currently selected line's commit. .It Cm p Reload the .Cm blame view with the version of the file as found in the parent commit of the currently selected line's commit. .It Cm C Reload the .Cm blame view with the previously blamed commit. .It Cm L Open a .Cm log view for the currently selected annotated line. .It Cm / Prompt for a search pattern and start searching for matching lines. The search pattern is an extended regular expression. Regular expression syntax is documented in .Xr re_format 7 . .It Cm n Find the Nth next line which matches the current search pattern (default: 1). .It Cm N Find the Nth previous line which matches the current search pattern (default: 1). .It Cm A Change the diff algorithm. Supported diff algorithms are Myers (quick and dirty) and Patience (slow and tidy). This is a global setting which also affects the .Cm diff view. .El .Pp The options for .Cm tog blame are as follows: .Bl -tag -width Ds .It Fl c Ar commit Start traversing history at the specified .Ar commit . The expected argument is a commit ID SHA1 hash, or a reference name or keyword which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full SHA1 hash automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the work tree's base commit and branch head, respectively. The former is only valid if invoked in a work tree, while the latter will resolve to the tip of the work tree's current branch if invoked in a work tree, otherwise it will resolve to the repository's HEAD reference. Keywords and references may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent by first parent traversal, respectively; for example, .Sy :head:-2 denotes the work tree branch head's 2nd generation ancestor, and .Sy :base:+4 denotes the 4th generation descendant of the work tree's base commit. Similarly, .Sy foobar:+3 will denote the 3rd generation descendant of the commit resolved by the .Qq foobar reference. A .Qq :+ or .Qq :- modifier without a trailing integer has an implicit .Qq 1 appended .Po e.g., .Sy :base:+ is equivalent to .Sy :base:+1 .Pc . .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Xr got 1 work tree, use the repository path associated with this work tree. .El .It Xo .Cm tree .Op Fl c Ar commit .Op Fl r Ar repository-path .Op Ar path .Xc Display the repository tree. If a .Ar path is specified, show tree entries at this path. .Pp Displayed tree entries may carry one of the following trailing annotations: .Bl -column YXZ description .It @ Ta entry is a symbolic link .It / Ta entry is a directory .It * Ta entry is an executable file .It $ Ta entry is a Git submodule .El .Pp Symbolic link entries are also annotated with the target path of the link. .Pp The key bindings for .Cm tog tree are as follows (N denotes optional prefixed count modifier): .Bl -tag -width Ds .It Cm Down-arrow, j, Ctrl-n Move the selection cursor down N lines (default: 1). .It Cm Up-arrow, k, Ctrl-p Move the selection cursor up N lines (default: 1). .It Cm Page-down, Space, Ctrl+f, f Move the selection cursor down N pages (default: 1). .It Cm Page-up, Ctrl+b, b Move the selection cursor up N pages (default: 1). .It Cm Ctrl+d, d Move the selection cursor down N half pages (default: 1). .It Cm Ctrl+u, u Move the selection cursor up N half pages (default: 1). .It Cm Home, = Move the selection cursor to the first entry. .It Cm End, * Move the selection cursor to the last entry. .It Cm g Move the selection cursor to entry N (default: 1). .It Cm G Like .Cm g but defaults to the last entry. .It Cm Enter Enter the currently selected directory, or switch to the .Cm blame view for the currently selected file. .It Cm L Open a .Cm log view for the currently selected tree entry. .It Cm R Open a .Cm ref view listing all references in the repository. This can then be used to open a new .Cm tree view for arbitrary branches and tags. .It Cm Backspace Move back to the Nth parent directory (default: 1). .It Cm i Show object IDs for all objects displayed in the .Cm tree view. .It Cm / Prompt for a search pattern and start searching for matching tree entries. The search pattern is an extended regular expression which is matched against the tree entry's name. Regular expression syntax is documented in .Xr re_format 7 . .It Cm n Find the Nth next tree entry which matches the current search pattern (default: 1). .It Cm N Find the Nth previous tree entry which matches the current search pattern (default: 1). .El .Pp The options for .Cm tog tree are as follows: .Bl -tag -width Ds .It Fl c Ar commit Start traversing history at the specified .Ar commit . The expected argument is a commit ID SHA1 hash, or a reference name or keyword which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full SHA1 hash automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the work tree's base commit and branch head, respectively. The former is only valid if invoked in a work tree, while the latter will resolve to the tip of the work tree's current branch if invoked in a work tree, otherwise it will resolve to the repository's HEAD reference. Keywords and references may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent by first parent traversal, respectively; for example, .Sy :head:-2 denotes the work tree branch head's 2nd generation ancestor, and .Sy :base:+4 denotes the 4th generation descendant of the work tree's base commit. Similarly, .Sy foobar:+3 will denote the 3rd generation descendant of the commit resolved by the .Qq foobar reference. A .Qq :+ or .Qq :- modifier without a trailing integer has an implicit .Qq 1 appended .Po e.g., .Sy :base:+ is equivalent to .Sy :base:+1 .Pc . .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Xr got 1 work tree, use the repository path associated with this work tree. .El .It Cm ref Op Fl r Ar repository-path Display references in the repository. .Pp The key bindings for .Cm tog ref are as follows (N denotes optional prefixed count modifier): .Bl -tag -width Ds .It Cm Down-arrow, j, Ctrl-n Move the selection cursor down N lines (default: 1). .It Cm Up-arrow, k, Ctrl-p Move the selection cursor up N lines (default: 1). .It Cm Page-down, Space, Ctrl+f, f Move the selection cursor down N pages (default: 1). .It Cm Page-up, Ctrl+b, b Move the selection cursor up N pages (default: 1). .It Cm Ctrl+d, d Move the selection cursor down N half pages (default: 1). .It Cm Ctrl+u, u Move the selection cursor up N half pages (default: 1). .It Cm Home, = Move the selection cursor to the first reference. .It Cm End, * Move the selection cursor to the last reference. .It Cm g Move the selection cursor to reference N (default: 1). .It Cm G Like .Cm g but defaults to the last reference. .It Cm Enter Open a .Cm log view which begins traversing history at the commit resolved via the currently selected reference. .It Cm T Open a .Cm tree view showing the tree resolved via the currently selected reference. .It Cm i Show object IDs for all non-symbolic references displayed in the .Cm ref view. .It Cm m Show last modified date of each displayed reference. .It Cm o Toggle display order of references between sort by name and sort by timestamp. .It Cm / Prompt for a search pattern and start searching for matching references. The search pattern is an extended regular expression which is matched against absolute reference names. Regular expression syntax is documented in .Xr re_format 7 . .It Cm n Find the Nth next reference which matches the current search pattern (default: 1). .It Cm N Find the Nth previous reference which matches the current search pattern (default: 1). .It Cm Ctrl+l Reload the list of references displayed by the .Cm ref view. .El .Pp The options for .Cm tog ref are as follows: .Bl -tag -width Ds .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Xr got 1 work tree, use the repository path associated with this work tree. .El .El .Sh ENVIRONMENT .Bl -tag -width TOG_VIEW_SPLIT_MODE .It Ev TOG_COLORS .Nm shows colorized output if this variable is set to a non-empty value. The default color scheme can be modified by setting the environment variables documented below. The colors available in color schemes are .Dq black , .Dq red , .Dq green , .Dq yellow , .Dq blue , .Dq magenta , .Dq cyan , and .Dq default which maps to the terminal's default foreground color. .It Ev TOG_COLOR_AUTHOR The color used to mark up author information. If not set, the default value .Dq cyan is used. .It Ev TOG_COLOR_COMMIT The color used to mark up commit IDs. If not set, the default value .Dq green is used. .It Ev TOG_COLOR_DATE The color used to mark up date information. If not set, the default value .Dq yellow is used. .It Ev TOG_COLOR_DIFF_CHUNK_HEADER The color used to mark up chunk header lines in diffs. If not set, the default value .Dq yellow is used. .It Ev TOG_COLOR_DIFF_META The color used to mark up meta data in diffs. If not set, the default value .Dq green is used. .It Ev TOG_COLOR_DIFF_MINUS The color used to mark up removed lines in diffs. If not set, the default value .Dq magenta is used. .It Ev TOG_COLOR_DIFF_PLUS The color used to mark up added lines in diffs. If not set, the default value .Dq cyan is used. .It Ev TOG_COLOR_REFS_BACKUP The color used to mark up references in the .Dq refs/got/backup/ namespace. If not set, the default value .Dq cyan is used. .It Ev TOG_COLOR_REFS_HEADS The color used to mark up references in the .Dq refs/heads/ namespace. If not set, the default value .Dq green is used. .It Ev TOG_COLOR_REFS_REMOTES The color used to mark up references in the .Dq refs/remotes/ namespace. If not set, the default value .Dq yellow is used. .It Ev TOG_COLOR_REFS_TAGS The color used to mark up references in the .Dq refs/tags/ namespace. If not set, the default value .Dq magenta is used. .It Ev TOG_COLOR_TREE_DIRECTORY The color used to mark up directory tree entries. If not set, the default value .Dq cyan is used. .It Ev TOG_COLOR_TREE_EXECUTABLE The color used to mark up executable file tree entries. If not set, the default value .Dq green is used. .It Ev TOG_COLOR_TREE_SUBMODULE The color used to mark up submodule tree entries. If not set, the default value .Dq magenta is used. .It Ev TOG_COLOR_TREE_SYMLINK The color used to mark up symbolic link tree entries. If not set, the default value .Dq magenta is used. .It Ev TOG_DIFF_ALGORITHM Determines the default diff algorithm used by .Nm . Supported diff algorithms are Myers (quick and dirty) and Patience (slow and tidy). Valid values for .Ev TOG_DIFF_ALGORITHM are .Dq patience and .Dq myers . If unset, the Patience diff algorithm will be used by default. .It Ev TOG_VIEW_SPLIT_MODE Determines the default layout of split-screen views. If set to .Dq h or .Dq H , .Nm will use horizontal split by default. Otherwise, vertical split will be used. The .Cm S key can be used to switch between vertical and horizontal split layout at run-time. .El .Sh EXIT STATUS .Ex -std tog .Sh SEE ALSO .Xr got 1 , .Xr git-repository 5 , .Xr re_format 7 .Sh AUTHORS .An Christian Weisgerber Aq Mt naddy@openbsd.org .An Josh Rickmar Aq Mt jrick@zettaport.com .An Joshua Stein Aq Mt jcs@openbsd.org .An Mark Jamsek Aq Mt mark@jamsek.dev .An Martin Pieuchot Aq Mt mpi@openbsd.org .An Omar Polo Aq Mt op@openbsd.org .An Stefan Sperling Aq Mt stsp@openbsd.org .An Klemens Nanni Aq Mt kn@openbsd.org got-portable-0.101/LICENCE0000644000175100017510000000160214644143163010567 Copyright (c) 2017, 2018, 2019, 2020, 2021, 2022, 2023 Stefan Sperling Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. See the individual source code files for additional licence statements by other copyright holders. got-portable-0.101/gotwebd/0000775000175100017510000000000014644145570011324 5got-portable-0.101/gotwebd/Makefile.am0000664000175100017510000000675114644144735013313 sbin_PROGRAMS = gotwebd include $(top_builddir)/Makefile.common # /home/n6tadam/projects/got/gotwebd/../template/template -o pages.c pages.tmpl BUILT_SOURCES = pages.c CLEANFILES = pages.c parse.c pages.c: $(top_srcdir)/gotwebd/pages.tmpl ${MAKE} -C $(top_builddir)/template $(top_builddir)/template/template -o pages.c $(top_srcdir)/gotwebd/pages.tmpl gotwebd_SOURCES = config.c \ $(top_srcdir)/lib/blame.c \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/commit_graph.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/diff.c \ $(top_srcdir)/lib/diff3.c \ $(top_srcdir)/lib/diff_atomize_text.c \ $(top_srcdir)/lib/diff_main.c \ $(top_srcdir)/lib/diff_myers.c \ $(top_srcdir)/lib/diff_output.c \ $(top_srcdir)/lib/diff_output_edscript.c \ $(top_srcdir)/lib/diff_output_plain.c \ $(top_srcdir)/lib/diff_output_unidiff.c \ $(top_srcdir)/lib/diff_patience.c \ $(top_srcdir)/lib/diffreg.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fileindex.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/log.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/patch.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/rcsutil.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/lib/utf8.c \ $(top_srcdir)/lib/worktree.c \ $(top_srcdir)/lib/worktree_open.c \ $(top_srcdir)/template/tmpl.c \ fcgi.c \ got_operations.c \ gotweb.c \ gotwebd.c \ pages.c \ parse.y \ sockets.c gotwebd_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = $(top_srcdir)/gotwebd/*.h \ $(top_srcdir)/gotwebd/*.tmpl \ $(top_srcdir)/template/tmpl.h \ gotwebd.8 gotwebd.conf.5 man5_MANS = gotwebd.conf.5 man8_MANS = gotwebd.8 LDADD = -L$(top_builddir)/compat -L$(top_builddir)/template \ -lopenbsd-compat -lm LDADD += $(libbsd_LIBS) \ $(libevent_LIBS) \ $(zlib_LIBS) \ $(libuuid_LIBS) \ $(libutil_LIBS) \ $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(libbsd_CFLAGS) $(libevent_CFLAGS) $(zlib_CFLAGS) \ $(libuuid_CFLAGS) $(libmd_CFLAGS) #realinstall: # if [ ! -d ${DESTDIR}${PUB_REPOS_DIR}/. ]; then \ # ${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${PUB_REPOS_DIR}; \ # fi # ${INSTALL} -c -o root -g daemon -m 0755 ${PROG} ${BINDIR}/${PROG} # if [ ! -d ${DESTDIR}${HTTPD_DIR}/. ]; then \ # ${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${HTTPD_DIR}; \ # fi # if [ ! -d ${DESTDIR}${PROG_DIR}/. ]; then \ # ${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${PROG_DIR}; \ # fi # ${INSTALL} -c -o ${WWWUSR} -g ${WWWGRP} -m 0755 \ # ${.CURDIR}/files/htdocs/${PROG}/* ${DESTDIR}${PROG_DIR} # #.include got-portable-0.101/gotwebd/sockets.c0000664000175100017510000003411114644144735013065 /* * Copyright (c) 2016, 2019, 2020-2021 Tracey Emery * Copyright (c) 2015 Mike Larkin * Copyright (c) 2013 David Gwynne * Copyright (c) 2013 Florian Obser * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_opentemp.h" #include "got_reference.h" #include "got_repository.h" #include "got_privsep.h" #include "gotwebd.h" #include "log.h" #include "tmpl.h" #define SOCKS_BACKLOG 5 #define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) volatile int client_cnt; static struct timeval timeout = { TIMEOUT_DEFAULT, 0 }; static void sockets_sighdlr(int, short, void *); static void sockets_shutdown(void); static void sockets_launch(void); static void sockets_purge(struct gotwebd *); static void sockets_accept_paused(int, short, void *); static void sockets_rlimit(int); static void sockets_dispatch_main(int, short, void *); static int sockets_unix_socket_listen(struct gotwebd *, struct socket *); static int sockets_create_socket(struct address *); static int sockets_accept_reserve(int, struct sockaddr *, socklen_t *, int, volatile int *); static struct socket *sockets_conf_new_socket(struct gotwebd *, int, struct address *); int cgi_inflight = 0; void sockets(struct gotwebd *env, int fd) { struct event sighup, sigint, sigusr1, sigchld, sigterm; event_init(); sockets_rlimit(-1); if (config_init(env) == -1) fatal("failed to initialize configuration"); if ((env->iev_parent = malloc(sizeof(*env->iev_parent))) == NULL) fatal("malloc"); imsg_init(&env->iev_parent->ibuf, fd); env->iev_parent->handler = sockets_dispatch_main; env->iev_parent->data = env->iev_parent; event_set(&env->iev_parent->ev, fd, EV_READ, sockets_dispatch_main, env->iev_parent); event_add(&env->iev_parent->ev, NULL); signal(SIGPIPE, SIG_IGN); signal_set(&sighup, SIGHUP, sockets_sighdlr, env); signal_add(&sighup, NULL); signal_set(&sigint, SIGINT, sockets_sighdlr, env); signal_add(&sigint, NULL); signal_set(&sigusr1, SIGUSR1, sockets_sighdlr, env); signal_add(&sigusr1, NULL); signal_set(&sigchld, SIGCHLD, sockets_sighdlr, env); signal_add(&sigchld, NULL); signal_set(&sigterm, SIGTERM, sockets_sighdlr, env); signal_add(&sigterm, NULL); #ifndef PROFILE if (pledge("stdio rpath inet recvfd proc exec sendfd unveil", NULL) == -1) fatal("pledge"); #endif event_dispatch(); sockets_shutdown(); } void sockets_parse_sockets(struct gotwebd *env) { struct address *a; struct socket *new_sock = NULL; int sock_id = 1; TAILQ_FOREACH(a, &env->addresses, entry) { new_sock = sockets_conf_new_socket(env, sock_id, a); if (new_sock) { sock_id++; TAILQ_INSERT_TAIL(&env->sockets, new_sock, entry); } } } static struct socket * sockets_conf_new_socket(struct gotwebd *env, int id, struct address *a) { struct socket *sock; struct address *acp; if ((sock = calloc(1, sizeof(*sock))) == NULL) fatalx("%s: calloc", __func__); sock->conf.id = id; sock->fd = -1; sock->conf.af_type = a->ss.ss_family; if (a->ss.ss_family == AF_UNIX) { struct sockaddr_un *sun; sun = (struct sockaddr_un *)&a->ss; if (strlcpy(sock->conf.unix_socket_name, sun->sun_path, sizeof(sock->conf.unix_socket_name)) >= sizeof(sock->conf.unix_socket_name)) fatalx("unix socket path too long: %s", sun->sun_path); } sock->conf.fcgi_socket_port = a->port; acp = &sock->conf.addr; memcpy(&acp->ss, &a->ss, sizeof(acp->ss)); acp->slen = a->slen; acp->ai_family = a->ai_family; acp->ai_socktype = a->ai_socktype; acp->ai_protocol = a->ai_protocol; acp->port = a->port; if (*a->ifname != '\0') { if (strlcpy(acp->ifname, a->ifname, sizeof(acp->ifname)) >= sizeof(acp->ifname)) { fatalx("%s: interface name truncated", __func__); } } return (sock); } static void sockets_launch(void) { struct socket *sock; struct server *srv; const struct got_error *error; TAILQ_FOREACH(sock, &gotwebd_env->sockets, entry) { log_debug("%s: configuring socket %d (%d)", __func__, sock->conf.id, sock->fd); event_set(&sock->ev, sock->fd, EV_READ | EV_PERSIST, sockets_socket_accept, sock); if (event_add(&sock->ev, NULL)) fatalx("event add sock"); evtimer_set(&sock->pause, sockets_accept_paused, sock); log_debug("%s: running socket listener %d", __func__, sock->conf.id); } TAILQ_FOREACH(srv, &gotwebd_env->servers, entry) { if (unveil(srv->repos_path, "r") == -1) fatal("unveil %s", srv->repos_path); } error = got_privsep_unveil_exec_helpers(); if (error) fatal("%s", error->msg); if (unveil(NULL, NULL) == -1) fatal("unveil"); } static void sockets_purge(struct gotwebd *env) { struct socket *sock, *tsock; /* shutdown and remove sockets */ TAILQ_FOREACH_SAFE(sock, &env->sockets, entry, tsock) { if (event_initialized(&sock->ev)) event_del(&sock->ev); if (evtimer_initialized(&sock->evt)) evtimer_del(&sock->evt); if (evtimer_initialized(&sock->pause)) evtimer_del(&sock->pause); if (sock->fd != -1) close(sock->fd); TAILQ_REMOVE(&env->sockets, sock, entry); } } static void sockets_dispatch_main(int fd, short event, void *arg) { struct imsgev *iev = arg; struct imsgbuf *ibuf; struct imsg imsg; struct gotwebd *env = gotwebd_env; ssize_t n; int shut = 0; ibuf = &iev->ibuf; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) /* Connection closed */ shut = 1; } if (event & EV_WRITE) { if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) fatal("msgbuf_write"); if (n == 0) /* Connection closed */ shut = 1; } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("imsg_get"); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case IMSG_CFG_SRV: config_getserver(env, &imsg); break; case IMSG_CFG_SOCK: config_getsock(env, &imsg); break; case IMSG_CFG_FD: config_getfd(env, &imsg); break; case IMSG_CFG_DONE: config_getcfg(env, &imsg); break; case IMSG_CTL_START: sockets_launch(); break; default: fatalx("%s: unknown imsg type %d", __func__, imsg.hdr.type); } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } static void sockets_sighdlr(int sig, short event, void *arg) { switch (sig) { case SIGHUP: log_info("%s: ignoring SIGHUP", __func__); break; case SIGPIPE: log_info("%s: ignoring SIGPIPE", __func__); break; case SIGUSR1: log_info("%s: ignoring SIGUSR1", __func__); break; case SIGCHLD: break; case SIGINT: case SIGTERM: sockets_shutdown(); break; default: log_info("SIGNAL: %d", sig); fatalx("unexpected signal"); } } static void sockets_shutdown(void) { struct server *srv, *tsrv; struct socket *sock, *tsock; sockets_purge(gotwebd_env); /* clean sockets */ TAILQ_FOREACH_SAFE(sock, &gotwebd_env->sockets, entry, tsock) { TAILQ_REMOVE(&gotwebd_env->sockets, sock, entry); close(sock->fd); free(sock); } /* clean servers */ TAILQ_FOREACH_SAFE(srv, &gotwebd_env->servers, entry, tsrv) free(srv); free(gotwebd_env); exit(0); } int sockets_privinit(struct gotwebd *env, struct socket *sock) { if (sock->conf.af_type == AF_UNIX) { log_debug("%s: initializing unix socket %s", __func__, sock->conf.unix_socket_name); sock->fd = sockets_unix_socket_listen(env, sock); if (sock->fd == -1) { log_warnx("%s: create unix socket failed", __func__); return -1; } } if (sock->conf.af_type == AF_INET || sock->conf.af_type == AF_INET6) { log_debug("%s: initializing %s FCGI socket on port %d", __func__, sock->conf.af_type == AF_INET ? "inet" : "inet6", sock->conf.fcgi_socket_port); sock->fd = sockets_create_socket(&sock->conf.addr); if (sock->fd == -1) { log_warnx("%s: create FCGI socket failed", __func__); return -1; } } return 0; } static int sockets_unix_socket_listen(struct gotwebd *env, struct socket *sock) { int u_fd = -1; mode_t old_umask, mode; int flags = SOCK_STREAM | SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC flags |= SOCK_CLOEXEC; #endif u_fd = socket(AF_UNIX, flags, 0); if (u_fd == -1) { log_warn("%s: socket", __func__); return -1; } if (unlink(sock->conf.unix_socket_name) == -1) { if (errno != ENOENT) { log_warn("%s: unlink %s", __func__, sock->conf.unix_socket_name); close(u_fd); return -1; } } old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP; if (bind(u_fd, (struct sockaddr *)&sock->conf.addr.ss, sock->conf.addr.slen) == -1) { log_warn("%s: bind: %s", __func__, sock->conf.unix_socket_name); close(u_fd); (void)umask(old_umask); return -1; } (void)umask(old_umask); if (chmod(sock->conf.unix_socket_name, mode) == -1) { log_warn("%s: chmod", __func__); close(u_fd); (void)unlink(sock->conf.unix_socket_name); return -1; } if (chown(sock->conf.unix_socket_name, env->pw->pw_uid, env->pw->pw_gid) == -1) { log_warn("%s: chown", __func__); close(u_fd); (void)unlink(sock->conf.unix_socket_name); return -1; } if (listen(u_fd, SOCKS_BACKLOG) == -1) { log_warn("%s: listen", __func__); return -1; } return u_fd; } static int sockets_create_socket(struct address *a) { int fd = -1, o_val = 1, flags; fd = socket(a->ai_family, a->ai_socktype, a->ai_protocol); if (fd == -1) return -1; log_debug("%s: opened socket (%d) for %s", __func__, fd, a->ifname); if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &o_val, sizeof(int)) == -1) { log_warn("%s: setsockopt error", __func__); close(fd); return -1; } /* non-blocking */ flags = fcntl(fd, F_GETFL); flags |= O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) == -1) { log_info("%s: could not enable non-blocking I/O", __func__); close(fd); return -1; } if (bind(fd, (struct sockaddr *)&a->ss, a->slen) == -1) { close(fd); log_info("%s: can't bind to port %d", __func__, a->port); return -1; } if (listen(fd, SOMAXCONN) == -1) { log_warn("%s, unable to listen on socket", __func__); close(fd); return -1; } return (fd); } static int sockets_accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int reserve, volatile int *counter) { int ret; if (getdtablecount() + reserve + ((*counter + 1) * FD_NEEDED) >= getdtablesize()) { log_debug("inflight fds exceeded"); errno = EMFILE; return -1; } /* TA: This needs fixing upstream. */ #ifdef __APPLE__ ret = accept(sockfd, addr, addrlen); #else ret = accept4(sockfd, addr, addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); #endif if (ret > -1) { (*counter)++; log_debug("inflight incremented, now %d", *counter); } return ret; } static void sockets_accept_paused(int fd, short events, void *arg) { struct socket *sock = (struct socket *)arg; event_add(&sock->ev, NULL); } void sockets_socket_accept(int fd, short event, void *arg) { struct socket *sock = (struct socket *)arg; struct sockaddr_storage ss; struct timeval backoff; struct request *c = NULL; socklen_t len; int s; backoff.tv_sec = 1; backoff.tv_usec = 0; event_add(&sock->ev, NULL); if (event & EV_TIMEOUT) return; len = sizeof(ss); s = sockets_accept_reserve(fd, (struct sockaddr *)&ss, &len, FD_RESERVE, &cgi_inflight); if (s == -1) { switch (errno) { case EINTR: case EWOULDBLOCK: case ECONNABORTED: return; case EMFILE: case ENFILE: event_del(&sock->ev); evtimer_add(&sock->pause, &backoff); return; default: log_warn("%s: accept", __func__); } } if (client_cnt > GOTWEBD_MAXCLIENTS) goto err; c = calloc(1, sizeof(struct request)); if (c == NULL) { log_warn("%s", __func__); close(s); cgi_inflight--; return; } c->tp = template(c, &fcgi_write, c->outbuf, sizeof(c->outbuf)); if (c->tp == NULL) { log_warn("%s", __func__); close(s); cgi_inflight--; free(c); return; } c->fd = s; c->sock = sock; memcpy(c->priv_fd, gotwebd_env->priv_fd, sizeof(c->priv_fd)); c->buf_pos = 0; c->buf_len = 0; c->request_started = 0; c->sock->client_status = CLIENT_CONNECT; event_set(&c->ev, s, EV_READ|EV_PERSIST, fcgi_request, c); event_add(&c->ev, NULL); evtimer_set(&c->tmo, fcgi_timeout, c); evtimer_add(&c->tmo, &timeout); client_cnt++; return; err: cgi_inflight--; close(s); if (c != NULL) free(c); } static void sockets_rlimit(int maxfd) { struct rlimit rl; if (getrlimit(RLIMIT_NOFILE, &rl) == -1) fatal("%s: failed to get resource limit", __func__); log_debug("%s: max open files %llu", __func__, (unsigned long long)rl.rlim_max); /* * Allow the maximum number of open file descriptors for this * login class (which should be the class "daemon" by default). */ if (maxfd == -1) rl.rlim_cur = rl.rlim_max; else rl.rlim_cur = MAXIMUM(rl.rlim_max, (rlim_t)maxfd); if (setrlimit(RLIMIT_NOFILE, &rl) == -1) fatal("%s: failed to set resource limit", __func__); } got-portable-0.101/gotwebd/gotwebd.h0000664000175100017510000003056114644143163013051 /* * Copyright (c) 2016, 2019, 2020-2022 Tracey Emery * Copyright (c) 2015 Mike Larkin * Copyright (c) 2013 David Gwynne * Copyright (c) 2013 Florian Obser * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif /* GOTWEBD DEFAULTS */ #define GOTWEBD_CONF "/etc/gotwebd.conf" #ifndef GOTWEBD_DEFAULT_USER #define GOTWEBD_DEFAULT_USER "www" #endif #define GOTWEBD_MAXDESCRSZ 1024 #define GOTWEBD_MAXCLONEURLSZ 1024 #define GOTWEBD_CACHESIZE 1024 #define GOTWEBD_MAXCLIENTS 1024 #define GOTWEBD_MAXTEXT 511 #define GOTWEBD_MAXNAME 64 #define GOTWEBD_MAXPORT 6 #define GOTWEBD_NUMPROC 3 #define GOTWEBD_SOCK_FILENO 3 #define PROC_MAX_INSTANCES 32 /* GOTWEB DEFAULTS */ #define MAX_QUERYSTRING 2048 #define MAX_DOCUMENT_URI 255 #define MAX_SERVER_NAME 255 #define GOTWEB_GIT_DIR ".git" #define D_HTTPD_CHROOT "/var/www" #define D_UNIX_SOCKET "/run/gotweb.sock" #define D_FCGI_PORT "9000" #define D_GOTPATH "/got/public" #define D_SITENAME "Gotweb" #define D_SITEOWNER "Got Owner" #define D_SITELINK "Repos" #define D_GOTLOGO "got.png" #define D_GOTURL "https://gameoftrees.org" #define D_GOTWEBCSS "gotweb.css" #define D_SHOWROWNER 1 #define D_SHOWSOWNER 1 #define D_SHOWAGE 1 #define D_SHOWDESC 1 #define D_SHOWURL 1 #define D_RESPECTEXPORTOK 0 #define D_MAXREPODISP 25 #define D_MAXSLCOMMDISP 10 #define D_MAXCOMMITDISP 25 #define D_MAXSLTAGDISP 3 #define BUF 8192 #define TIMEOUT_DEFAULT 120 #define FCGI_CONTENT_SIZE 65535 #define FCGI_PADDING_SIZE 255 #define FCGI_RECORD_SIZE \ (sizeof(struct fcgi_record_header) + FCGI_CONTENT_SIZE + FCGI_PADDING_SIZE) #define FCGI_ALIGNMENT 8 #define FCGI_ALIGN(n) \ (((n) + (FCGI_ALIGNMENT - 1)) & ~(FCGI_ALIGNMENT - 1)) #define FD_RESERVE 5 #define FD_NEEDED 6 #define FCGI_BEGIN_REQUEST 1 #define FCGI_ABORT_REQUEST 2 #define FCGI_END_REQUEST 3 #define FCGI_PARAMS 4 #define FCGI_STDIN 5 #define FCGI_STDOUT 6 #define FCGI_STDERR 7 #define FCGI_DATA 8 #define FCGI_GET_VALUES 9 #define FCGI_GET_VALUES_RESULT 10 #define FCGI_UNKNOWN_TYPE 11 #define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE) #define FCGI_REQUEST_COMPLETE 0 #define FCGI_CANT_MPX_CONN 1 #define FCGI_OVERLOADED 2 #define FCGI_UNKNOWN_ROLE 3 #define GOTWEB_PACK_NUM_TEMPFILES (32 * 2) /* Forward declaration */ struct got_blob_object; struct got_tree_entry; struct got_reflist_head; enum imsg_type { IMSG_CFG_SRV, IMSG_CFG_SOCK, IMSG_CFG_FD, IMSG_CFG_DONE, IMSG_CTL_START, }; struct imsgev { struct imsgbuf ibuf; void (*handler)(int, short, void *); struct event ev; void *data; short events; }; #define IMSG_DATA_SIZE(imsg) ((imsg)->hdr.len - IMSG_HEADER_SIZE) struct env_val { SLIST_ENTRY(env_val) entry; char *val; }; SLIST_HEAD(env_head, env_val); struct fcgi_record_header { uint8_t version; uint8_t type; uint16_t id; uint16_t content_len; uint8_t padding_len; uint8_t reserved; }__attribute__((__packed__)); struct blame_line { int annotated; char *id_str; char *committer; char datebuf[11]; /* YYYY-MM-DD + NUL */ }; struct repo_dir { char *name; char *owner; char *description; char *url; time_t age; char *path; }; struct repo_tag { TAILQ_ENTRY(repo_tag) entry; char *commit_id; char *tag_name; char *tag_commit; char *commit_msg; char *tagger; time_t tagger_time; }; struct repo_commit { TAILQ_ENTRY(repo_commit) entry; char *path; char *refs_str; char *commit_id; /* id_str1 */ char *parent_id; /* id_str2 */ char *tree_id; char *author; char *committer; char *commit_msg; time_t committer_time; }; struct got_repository; struct transport { TAILQ_HEAD(repo_commits_head, repo_commit) repo_commits; TAILQ_HEAD(repo_tags_head, repo_tag) repo_tags; struct got_reflist_head refs; struct got_repository *repo; struct repo_dir *repo_dir; struct querystring *qs; char *more_id; char *tags_more_id; unsigned int repos_total; unsigned int next_disp; unsigned int prev_disp; unsigned int tag_count; const struct got_error *error; struct got_blob_object *blob; int fd; FILE *fp; struct dirent **repos; int nrepos; }; enum socket_priv_fds { DIFF_FD_1, DIFF_FD_2, DIFF_FD_3, DIFF_FD_4, DIFF_FD_5, BLAME_FD_1, BLAME_FD_2, BLAME_FD_3, BLAME_FD_4, BLAME_FD_5, BLAME_FD_6, BLOB_FD_1, BLOB_FD_2, PRIV_FDS__MAX, }; struct template; struct request { struct socket *sock; struct server *srv; struct transport *t; struct template *tp; struct event ev; struct event tmo; uint16_t id; int fd; int priv_fd[PRIV_FDS__MAX]; uint8_t buf[FCGI_RECORD_SIZE]; size_t buf_pos; size_t buf_len; uint8_t outbuf[GOTWEBD_CACHESIZE]; char querystring[MAX_QUERYSTRING]; char document_uri[MAX_DOCUMENT_URI]; char server_name[MAX_SERVER_NAME]; int https; uint8_t request_started; }; struct fcgi_begin_request_body { uint16_t role; uint8_t flags; uint8_t reserved[5]; }__attribute__((__packed__)); struct fcgi_end_request_body { uint32_t app_status; uint8_t protocol_status; uint8_t reserved[3]; }__attribute__((__packed__)); struct address { TAILQ_ENTRY(address) entry; struct sockaddr_storage ss; socklen_t slen; int ai_family; int ai_socktype; int ai_protocol; in_port_t port; char ifname[IFNAMSIZ]; }; TAILQ_HEAD(addresslist, address); struct server { TAILQ_ENTRY(server) entry; char name[GOTWEBD_MAXTEXT]; char repos_path[PATH_MAX]; char site_name[GOTWEBD_MAXNAME]; char site_owner[GOTWEBD_MAXNAME]; char site_link[GOTWEBD_MAXTEXT]; char logo[GOTWEBD_MAXTEXT]; char logo_url[GOTWEBD_MAXTEXT]; char custom_css[PATH_MAX]; size_t max_repos_display; size_t max_commits_display; size_t summary_commits_display; size_t summary_tags_display; int show_site_owner; int show_repo_owner; int show_repo_age; int show_repo_description; int show_repo_cloneurl; int respect_exportok; }; TAILQ_HEAD(serverlist, server); enum client_action { CLIENT_CONNECT, CLIENT_DISCONNECT, }; struct socket_conf { struct address addr; int id; int af_type; char unix_socket_name[PATH_MAX]; in_port_t fcgi_socket_port; }; struct socket { TAILQ_ENTRY(socket) entry; struct socket_conf conf; int fd; struct event evt; struct event ev; struct event pause; int client_status; }; TAILQ_HEAD(socketlist, socket); struct passwd; struct gotwebd { struct serverlist servers; struct socketlist sockets; struct addresslist addresses; int pack_fds[GOTWEB_PACK_NUM_TEMPFILES]; int priv_fd[PRIV_FDS__MAX]; char *user; const char *gotwebd_conffile; int gotwebd_debug; int gotwebd_verbose; struct imsgev *iev_parent; struct imsgev *iev_server; size_t nserver; struct passwd *pw; uint16_t prefork_gotwebd; int gotwebd_reload; int server_cnt; char httpd_chroot[PATH_MAX]; }; /* * URL parameter for gotweb_render_url. NULL values and int set to -1 * are implicitly ignored, and string are properly escaped. */ struct gotweb_url { int action; int index_page; const char *commit; const char *file; const char *folder; const char *headref; const char *path; }; struct querystring { uint8_t action; char *commit; char *file; char *folder; char *headref; int index_page; char *path; }; struct querystring_keys { const char *name; int element; }; struct action_keys { const char *name; int action; }; enum querystring_elements { ACTION, COMMIT, RFILE, FOLDER, HEADREF, INDEX_PAGE, PATH, }; enum query_actions { BLAME, BLOB, BLOBRAW, BRIEFS, COMMITS, DIFF, ERR, INDEX, PATCH, SUMMARY, TAG, TAGS, TREE, RSS, }; extern struct gotwebd *gotwebd_env; typedef int (*got_render_blame_line_cb)(struct template *, const char *, struct blame_line *, int, int); /* gotwebd.c */ void imsg_event_add(struct imsgev *); int imsg_compose_event(struct imsgev *, uint16_t, uint32_t, pid_t, int, const void *, uint16_t); int main_compose_sockets(struct gotwebd *, uint32_t, int, const void *, uint16_t); int sockets_compose_main(struct gotwebd *, uint32_t, const void *, uint16_t); /* sockets.c */ void sockets(struct gotwebd *, int); void sockets_parse_sockets(struct gotwebd *); void sockets_socket_accept(int, short, void *); int sockets_privinit(struct gotwebd *, struct socket *); /* gotweb.c */ void gotweb_index_navs(struct request *, struct gotweb_url *, int *, struct gotweb_url *, int *); int gotweb_render_age(struct template *, time_t); const struct got_error *gotweb_init_transport(struct transport **); const char *gotweb_action_name(int); int gotweb_render_url(struct request *, struct gotweb_url *); int gotweb_render_absolute_url(struct request *, struct gotweb_url *); void gotweb_free_repo_commit(struct repo_commit *); void gotweb_free_repo_tag(struct repo_tag *); void gotweb_process_request(struct request *); void gotweb_free_transport(struct transport *); /* pages.tmpl */ int gotweb_render_page(struct template *, int (*)(struct template *)); int gotweb_render_error(struct template *); int gotweb_render_repo_table_hdr(struct template *); int gotweb_render_repo_fragment(struct template *, struct repo_dir *); int gotweb_render_briefs(struct template *); int gotweb_render_navs(struct template *); int gotweb_render_commits(struct template *); int gotweb_render_blob(struct template *); int gotweb_render_tree(struct template *); int gotweb_render_tags(struct template *); int gotweb_render_tag(struct template *); int gotweb_render_diff(struct template *); int gotweb_render_branches(struct template *, struct got_reflist_head *); int gotweb_render_summary(struct template *); int gotweb_render_blame(struct template *); int gotweb_render_patch(struct template *); int gotweb_render_rss(struct template *); /* parse.y */ int parse_config(const char *, struct gotwebd *); int cmdline_symset(char *); /* fcgi.c */ void fcgi_request(int, short, void *); void fcgi_timeout(int, short, void *); void fcgi_cleanup_request(struct request *); void fcgi_create_end_record(struct request *); void dump_fcgi_record(const char *, struct fcgi_record_header *); int fcgi_write(void *, const void *, size_t); /* got_operations.c */ const struct got_error *got_gotweb_closefile(FILE *); const struct got_error *got_get_repo_owner(char **, struct request *); const struct got_error *got_get_repo_age(time_t *, struct request *, const char *); const struct got_error *got_get_repo_commits(struct request *, size_t); const struct got_error *got_get_repo_tags(struct request *, size_t); const struct got_error *got_get_repo_heads(struct request *); const struct got_error *got_open_diff_for_output(FILE **, struct request *); int got_output_repo_tree(struct request *, char **, int (*)(struct template *, struct got_tree_entry *)); const struct got_error *got_open_blob_for_output(struct got_blob_object **, int *, int *, struct request *, const char *, const char *, const char *); int got_output_blob_by_lines(struct template *, struct got_blob_object *, int (*)(struct template *, const char *, size_t)); const struct got_error *got_output_file_blame(struct request *, got_render_blame_line_cb); /* config.c */ int config_setserver(struct gotwebd *, struct server *); int config_getserver(struct gotwebd *, struct imsg *); int config_setsock(struct gotwebd *, struct socket *); int config_getsock(struct gotwebd *, struct imsg *); int config_setfd(struct gotwebd *); int config_getfd(struct gotwebd *, struct imsg *); int config_getcfg(struct gotwebd *, struct imsg *); int config_init(struct gotwebd *); got-portable-0.101/gotwebd/parse.c0000644000175100017510000022365614644145562012537 /* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. 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 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 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output, and Bison version. */ #define YYBISON 30802 /* Bison version string. */ #define YYBISON_VERSION "3.8.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* First part of user prologue. */ #line 23 "parse.y" #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_reference.h" #include "gotwebd.h" #include "log.h" TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); static struct file { TAILQ_ENTRY(file) entry; FILE *stream; char *name; int lineno; int errors; } *file; struct file *newfile(const char *, int); static void closefile(struct file *); int check_file_secrecy(int, const char *); int yyparse(void); int yylex(void); int yyerror(const char *, ...) __attribute__((__format__ (printf, 1, 2))) __attribute__((__nonnull__ (1))); int kw_cmp(const void *, const void *); int lookup(char *); int lgetc(int); int lungetc(int); int findeol(void); TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); struct sym { TAILQ_ENTRY(sym) entry; int used; int persist; char *nam; char *val; }; int symset(const char *, const char *, int); char *symget(const char *); static int errors; static struct gotwebd *gotwebd; static struct server *new_srv; static struct server *conf_new_server(const char *); int getservice(const char *); int n; int get_addrs(const char *, const char *); int get_unix_addr(const char *); int addr_dup_check(struct addresslist *, struct address *); int add_addr(struct address *); typedef struct { union { long long number; char *string; } v; int lineno; } YYSTYPE; #line 162 "parse.c" # ifndef YY_CAST # ifdef __cplusplus # define YY_CAST(Type, Val) static_cast (Val) # define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) # else # define YY_CAST(Type, Val) ((Type) (Val)) # define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) # endif # endif # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # else # define YY_NULLPTR ((void*)0) # endif # endif /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yydebug; #endif /* Token kinds. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { YYEMPTY = -2, YYEOF = 0, /* "end of file" */ YYerror = 256, /* error */ YYUNDEF = 257, /* "invalid token" */ LISTEN = 258, /* LISTEN */ WWW_PATH = 259, /* WWW_PATH */ SITE_NAME = 260, /* SITE_NAME */ SITE_OWNER = 261, /* SITE_OWNER */ SITE_LINK = 262, /* SITE_LINK */ LOGO = 263, /* LOGO */ LOGO_URL = 264, /* LOGO_URL */ SHOW_REPO_OWNER = 265, /* SHOW_REPO_OWNER */ SHOW_REPO_AGE = 266, /* SHOW_REPO_AGE */ SHOW_REPO_DESCRIPTION = 267, /* SHOW_REPO_DESCRIPTION */ MAX_REPOS_DISPLAY = 268, /* MAX_REPOS_DISPLAY */ REPOS_PATH = 269, /* REPOS_PATH */ MAX_COMMITS_DISPLAY = 270, /* MAX_COMMITS_DISPLAY */ ON = 271, /* ON */ ERROR = 272, /* ERROR */ SHOW_SITE_OWNER = 273, /* SHOW_SITE_OWNER */ SHOW_REPO_CLONEURL = 274, /* SHOW_REPO_CLONEURL */ PORT = 275, /* PORT */ PREFORK = 276, /* PREFORK */ RESPECT_EXPORTOK = 277, /* RESPECT_EXPORTOK */ SERVER = 278, /* SERVER */ CHROOT = 279, /* CHROOT */ CUSTOM_CSS = 280, /* CUSTOM_CSS */ SOCKET = 281, /* SOCKET */ SUMMARY_COMMITS_DISPLAY = 282, /* SUMMARY_COMMITS_DISPLAY */ SUMMARY_TAGS_DISPLAY = 283, /* SUMMARY_TAGS_DISPLAY */ USER = 284, /* USER */ STRING = 285, /* STRING */ NUMBER = 286 /* NUMBER */ }; typedef enum yytokentype yytoken_kind_t; #endif /* Token kinds. */ #define YYEMPTY -2 #define YYEOF 0 #define YYerror 256 #define YYUNDEF 257 #define LISTEN 258 #define WWW_PATH 259 #define SITE_NAME 260 #define SITE_OWNER 261 #define SITE_LINK 262 #define LOGO 263 #define LOGO_URL 264 #define SHOW_REPO_OWNER 265 #define SHOW_REPO_AGE 266 #define SHOW_REPO_DESCRIPTION 267 #define MAX_REPOS_DISPLAY 268 #define REPOS_PATH 269 #define MAX_COMMITS_DISPLAY 270 #define ON 271 #define ERROR 272 #define SHOW_SITE_OWNER 273 #define SHOW_REPO_CLONEURL 274 #define PORT 275 #define PREFORK 276 #define RESPECT_EXPORTOK 277 #define SERVER 278 #define CHROOT 279 #define CUSTOM_CSS 280 #define SOCKET 281 #define SUMMARY_COMMITS_DISPLAY 282 #define SUMMARY_TAGS_DISPLAY 283 #define USER 284 #define STRING 285 #define NUMBER 286 /* Value type. */ extern YYSTYPE yylval; int yyparse (void); /* Symbol kind. */ enum yysymbol_kind_t { YYSYMBOL_YYEMPTY = -2, YYSYMBOL_YYEOF = 0, /* "end of file" */ YYSYMBOL_YYerror = 1, /* error */ YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ YYSYMBOL_LISTEN = 3, /* LISTEN */ YYSYMBOL_WWW_PATH = 4, /* WWW_PATH */ YYSYMBOL_SITE_NAME = 5, /* SITE_NAME */ YYSYMBOL_SITE_OWNER = 6, /* SITE_OWNER */ YYSYMBOL_SITE_LINK = 7, /* SITE_LINK */ YYSYMBOL_LOGO = 8, /* LOGO */ YYSYMBOL_LOGO_URL = 9, /* LOGO_URL */ YYSYMBOL_SHOW_REPO_OWNER = 10, /* SHOW_REPO_OWNER */ YYSYMBOL_SHOW_REPO_AGE = 11, /* SHOW_REPO_AGE */ YYSYMBOL_SHOW_REPO_DESCRIPTION = 12, /* SHOW_REPO_DESCRIPTION */ YYSYMBOL_MAX_REPOS_DISPLAY = 13, /* MAX_REPOS_DISPLAY */ YYSYMBOL_REPOS_PATH = 14, /* REPOS_PATH */ YYSYMBOL_MAX_COMMITS_DISPLAY = 15, /* MAX_COMMITS_DISPLAY */ YYSYMBOL_ON = 16, /* ON */ YYSYMBOL_ERROR = 17, /* ERROR */ YYSYMBOL_SHOW_SITE_OWNER = 18, /* SHOW_SITE_OWNER */ YYSYMBOL_SHOW_REPO_CLONEURL = 19, /* SHOW_REPO_CLONEURL */ YYSYMBOL_PORT = 20, /* PORT */ YYSYMBOL_PREFORK = 21, /* PREFORK */ YYSYMBOL_RESPECT_EXPORTOK = 22, /* RESPECT_EXPORTOK */ YYSYMBOL_SERVER = 23, /* SERVER */ YYSYMBOL_CHROOT = 24, /* CHROOT */ YYSYMBOL_CUSTOM_CSS = 25, /* CUSTOM_CSS */ YYSYMBOL_SOCKET = 26, /* SOCKET */ YYSYMBOL_SUMMARY_COMMITS_DISPLAY = 27, /* SUMMARY_COMMITS_DISPLAY */ YYSYMBOL_SUMMARY_TAGS_DISPLAY = 28, /* SUMMARY_TAGS_DISPLAY */ YYSYMBOL_USER = 29, /* USER */ YYSYMBOL_STRING = 30, /* STRING */ YYSYMBOL_NUMBER = 31, /* NUMBER */ YYSYMBOL_32_n_ = 32, /* '\n' */ YYSYMBOL_33_ = 33, /* '=' */ YYSYMBOL_34_ = 34, /* '*' */ YYSYMBOL_35_ = 35, /* '{' */ YYSYMBOL_36_ = 36, /* '}' */ YYSYMBOL_YYACCEPT = 37, /* $accept */ YYSYMBOL_grammar = 38, /* grammar */ YYSYMBOL_varset = 39, /* varset */ YYSYMBOL_boolean = 40, /* boolean */ YYSYMBOL_listen_addr = 41, /* listen_addr */ YYSYMBOL_main = 42, /* main */ YYSYMBOL_server = 43, /* server */ YYSYMBOL_44_1 = 44, /* $@1 */ YYSYMBOL_serveropts1 = 45, /* serveropts1 */ YYSYMBOL_serveropts2 = 46, /* serveropts2 */ YYSYMBOL_nl = 47, /* nl */ YYSYMBOL_optnl = 48 /* optnl */ }; typedef enum yysymbol_kind_t yysymbol_kind_t; #ifdef short # undef short #endif /* On compilers that do not define __PTRDIFF_MAX__ etc., make sure and (if available) are included so that the code can choose integer types of a good width. */ #ifndef __PTRDIFF_MAX__ # include /* INFRINGES ON USER NAME SPACE */ # if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YY_STDINT_H # endif #endif /* Narrow types that promote to a signed type and that can represent a signed or unsigned integer of at least N bits. In tables they can save space and decrease cache pressure. Promoting to a signed type helps avoid bugs in integer arithmetic. */ #ifdef __INT_LEAST8_MAX__ typedef __INT_LEAST8_TYPE__ yytype_int8; #elif defined YY_STDINT_H typedef int_least8_t yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef __INT_LEAST16_MAX__ typedef __INT_LEAST16_TYPE__ yytype_int16; #elif defined YY_STDINT_H typedef int_least16_t yytype_int16; #else typedef short yytype_int16; #endif /* Work around bug in HP-UX 11.23, which defines these macros incorrectly for preprocessor constants. This workaround can likely be removed in 2023, as HPE has promised support for HP-UX 11.23 (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of . */ #ifdef __hpux # undef UINT_LEAST8_MAX # undef UINT_LEAST16_MAX # define UINT_LEAST8_MAX 255 # define UINT_LEAST16_MAX 65535 #endif #if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ typedef __UINT_LEAST8_TYPE__ yytype_uint8; #elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ && UINT_LEAST8_MAX <= INT_MAX) typedef uint_least8_t yytype_uint8; #elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX typedef unsigned char yytype_uint8; #else typedef short yytype_uint8; #endif #if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ typedef __UINT_LEAST16_TYPE__ yytype_uint16; #elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ && UINT_LEAST16_MAX <= INT_MAX) typedef uint_least16_t yytype_uint16; #elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX typedef unsigned short yytype_uint16; #else typedef int yytype_uint16; #endif #ifndef YYPTRDIFF_T # if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ # define YYPTRDIFF_T __PTRDIFF_TYPE__ # define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ # elif defined PTRDIFF_MAX # ifndef ptrdiff_t # include /* INFRINGES ON USER NAME SPACE */ # endif # define YYPTRDIFF_T ptrdiff_t # define YYPTRDIFF_MAXIMUM PTRDIFF_MAX # else # define YYPTRDIFF_T long # define YYPTRDIFF_MAXIMUM LONG_MAX # endif #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned # endif #endif #define YYSIZE_MAXIMUM \ YY_CAST (YYPTRDIFF_T, \ (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ ? YYPTRDIFF_MAXIMUM \ : YY_CAST (YYSIZE_T, -1))) #define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) /* Stored state numbers (used for stacks). */ typedef yytype_int8 yy_state_t; /* State numbers in computations. */ typedef int yy_state_fast_t; #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE_PURE # if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) # else # define YY_ATTRIBUTE_PURE # endif #endif #ifndef YY_ATTRIBUTE_UNUSED # if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) # else # define YY_ATTRIBUTE_UNUSED # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YY_USE(E) ((void) (E)) #else # define YY_USE(E) /* empty */ #endif /* Suppress an incorrect diagnostic about yylval being uninitialized. */ #if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ # if __GNUC__ * 100 + __GNUC_MINOR__ < 407 # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") # else # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # endif # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ # define YY_IGNORE_USELESS_CAST_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") # define YY_IGNORE_USELESS_CAST_END \ _Pragma ("GCC diagnostic pop") #endif #ifndef YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_END #endif #define YY_ASSERT(E) ((void) (0 && (E))) #if !defined yyoverflow /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* !defined yyoverflow */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yy_state_t yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYPTRDIFF_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / YYSIZEOF (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYPTRDIFF_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 97 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 37 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 12 /* YYNRULES -- Number of rules. */ #define YYNRULES 44 /* YYNSTATES -- Number of states. */ #define YYNSTATES 83 /* YYMAXUTOK -- Last valid token kind. */ #define YYMAXUTOK 286 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM as returned by yylex, with out-of-bounds checking. */ #define YYTRANSLATE(YYX) \ (0 <= (YYX) && (YYX) <= YYMAXUTOK \ ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ : YYSYMBOL_YYUNDEF) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex. */ static const yytype_int8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 34, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 35, 2, 36, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { 0, 128, 128, 129, 130, 131, 132, 133, 136, 154, 168, 169, 178, 179, 182, 190, 207, 215, 231, 239, 247, 262, 262, 280, 290, 300, 310, 320, 329, 339, 349, 352, 355, 358, 361, 364, 367, 375, 383, 391, 401, 402, 405, 408, 409 }; #endif /** Accessing symbol of state STATE. */ #define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) #if YYDEBUG || 0 /* The user-facing name of the symbol whose (internal) number is YYSYMBOL. No bounds checking. */ static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "\"end of file\"", "error", "\"invalid token\"", "LISTEN", "WWW_PATH", "SITE_NAME", "SITE_OWNER", "SITE_LINK", "LOGO", "LOGO_URL", "SHOW_REPO_OWNER", "SHOW_REPO_AGE", "SHOW_REPO_DESCRIPTION", "MAX_REPOS_DISPLAY", "REPOS_PATH", "MAX_COMMITS_DISPLAY", "ON", "ERROR", "SHOW_SITE_OWNER", "SHOW_REPO_CLONEURL", "PORT", "PREFORK", "RESPECT_EXPORTOK", "SERVER", "CHROOT", "CUSTOM_CSS", "SOCKET", "SUMMARY_COMMITS_DISPLAY", "SUMMARY_TAGS_DISPLAY", "USER", "STRING", "NUMBER", "'\\n'", "'='", "'*'", "'{'", "'}'", "$accept", "grammar", "varset", "boolean", "listen_addr", "main", "server", "$@1", "serveropts1", "serveropts2", "nl", "optnl", YY_NULLPTR }; static const char * yysymbol_name (yysymbol_kind_t yysymbol) { return yytname[yysymbol]; } #endif #define YYPACT_NINF (-36) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) #define YYTABLE_NINF (-22) #define yytable_value_is_error(Yyn) \ 0 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int8 yypact[] = { -36, 1, -36, -22, -8, -20, -18, -16, -15, -17, -36, -11, -9, -6, -36, -21, -36, -7, -36, -36, -3, -36, -36, -36, -1, -36, -36, 12, 11, -36, -36, -24, 17, -36, -36, 17, 61, -36, 20, 22, 23, 25, 28, -13, -13, -13, -12, 30, 31, -13, -13, -13, 33, 47, 50, 17, 29, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, 27, 17, -36, -36 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_int8 yydefact[] = { 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 7, 0, 14, 20, 15, 19, 0, 4, 5, 6, 0, 13, 12, 0, 0, 8, 18, 0, 44, 16, 17, 44, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 24, 25, 26, 27, 28, 10, 9, 11, 31, 32, 33, 36, 23, 37, 30, 34, 35, 29, 38, 39, 41, 22, 0, 44, 40, 42 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { -36, -36, -36, 46, -36, -36, -36, -36, 5, -36, -36, -35 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { 0, 1, 11, 65, 27, 12, 13, 28, 55, 56, 81, 36 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int8 yytable[] = { 37, 2, 3, 62, 4, 24, 33, 34, 15, 25, 14, 16, 17, 26, 18, 19, 20, 63, 64, 68, 77, 21, 5, 22, 6, 7, 23, 29, -21, 30, 8, 9, 31, 10, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 82, 32, 49, 50, 35, 57, 51, 58, 59, 52, 60, 53, 54, 61, 80, 69, 79, 70, 74, 0, 78, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 0, 75, 49, 50, 76, 0, 51, 0, 0, 52, 0, 53, 54, 66, 67, 0, 0, 0, 71, 72, 73 }; static const yytype_int8 yycheck[] = { 35, 0, 1, 16, 3, 26, 30, 31, 16, 30, 32, 31, 30, 34, 30, 30, 33, 30, 31, 31, 55, 32, 21, 32, 23, 24, 32, 30, 35, 30, 29, 30, 20, 32, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 80, 35, 18, 19, 32, 30, 22, 30, 30, 25, 30, 27, 28, 30, 32, 30, 56, 31, 30, -1, 36, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -1, 31, 18, 19, 31, -1, 22, -1, -1, 25, -1, 27, 28, 44, 45, -1, -1, -1, 49, 50, 51 }; /* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of state STATE-NUM. */ static const yytype_int8 yystos[] = { 0, 38, 0, 1, 3, 21, 23, 24, 29, 30, 32, 39, 42, 43, 32, 16, 31, 30, 30, 30, 33, 32, 32, 32, 26, 30, 34, 41, 44, 30, 30, 20, 35, 30, 31, 32, 48, 48, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19, 22, 25, 27, 28, 45, 46, 30, 30, 30, 30, 30, 16, 30, 31, 40, 40, 40, 31, 30, 31, 40, 40, 40, 30, 31, 31, 48, 36, 45, 32, 47, 48 }; /* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ static const yytype_int8 yyr1[] = { 0, 37, 38, 38, 38, 38, 38, 38, 39, 40, 40, 40, 41, 41, 42, 42, 42, 42, 42, 42, 43, 44, 43, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 46, 46, 47, 48, 48 }; /* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ static const yytype_int8 yyr2[] = { 0, 2, 0, 2, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 2, 2, 5, 5, 4, 2, 2, 0, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 0 }; enum { YYENOMEM = -2 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYNOMEM goto yyexhaustedlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Backward compatibility with an undocumented macro. Use YYerror or YYUNDEF. */ #define YYERRCODE YYUNDEF /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Kind, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*-----------------------------------. | Print this symbol's value on YYO. | `-----------------------------------*/ static void yy_symbol_value_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) { FILE *yyoutput = yyo; YY_USE (yyoutput); if (!yyvaluep) return; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /*---------------------------. | Print this symbol on YYO. | `---------------------------*/ static void yy_symbol_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) { YYFPRINTF (yyo, "%s %s (", yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); yy_symbol_value_print (yyo, yykind, yyvaluep); YYFPRINTF (yyo, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, int yyrule) { int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), &yyvsp[(yyi + 1) - (yynrhs)]); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, Rule); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) ((void) 0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, yysymbol_kind_t yykind, YYSTYPE *yyvaluep) { YY_USE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /* Lookahead token kind. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*----------. | yyparse. | `----------*/ int yyparse (void) { yy_state_fast_t yystate = 0; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus = 0; /* Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* Their size. */ YYPTRDIFF_T yystacksize = YYINITDEPTH; /* The state stack: array, bottom, top. */ yy_state_t yyssa[YYINITDEPTH]; yy_state_t *yyss = yyssa; yy_state_t *yyssp = yyss; /* The semantic value stack: array, bottom, top. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; YYSTYPE *yyvsp = yyvs; int yyn; /* The return value of yyparse. */ int yyresult; /* Lookahead symbol kind. */ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; YYDPRINTF ((stderr, "Starting parse\n")); yychar = YYEMPTY; /* Cause a token to be read. */ goto yysetstate; /*------------------------------------------------------------. | yynewstate -- push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; /*--------------------------------------------------------------------. | yysetstate -- set current state (the top of the stack) to yystate. | `--------------------------------------------------------------------*/ yysetstate: YYDPRINTF ((stderr, "Entering state %d\n", yystate)); YY_ASSERT (0 <= yystate && yystate < YYNSTATES); YY_IGNORE_USELESS_CAST_BEGIN *yyssp = YY_CAST (yy_state_t, yystate); YY_IGNORE_USELESS_CAST_END YY_STACK_PRINT (yyss, yyssp); if (yyss + yystacksize - 1 <= yyssp) #if !defined yyoverflow && !defined YYSTACK_RELOCATE YYNOMEM; #else { /* Get the current used size of the three stacks, in elements. */ YYPTRDIFF_T yysize = yyssp - yyss + 1; # if defined yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ yy_state_t *yyss1 = yyss; YYSTYPE *yyvs1 = yyvs; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * YYSIZEOF (*yyssp), &yyvs1, yysize * YYSIZEOF (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } # else /* defined YYSTACK_RELOCATE */ /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) YYNOMEM; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yy_state_t *yyss1 = yyss; union yyalloc *yyptr = YY_CAST (union yyalloc *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); if (! yyptr) YYNOMEM; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YY_IGNORE_USELESS_CAST_BEGIN YYDPRINTF ((stderr, "Stack size increased to %ld\n", YY_CAST (long, yystacksize))); YY_IGNORE_USELESS_CAST_END if (yyss + yystacksize - 1 <= yyssp) YYABORT; } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token\n")); yychar = yylex (); } if (yychar <= YYEOF) { yychar = YYEOF; yytoken = YYSYMBOL_YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else if (yychar == YYerror) { /* The scanner already issued an error message, process directly to error recovery. But do not keep the error token as lookahead, it is too special and may lead us to an endless loop in error recovery. */ yychar = YYUNDEF; yytoken = YYSYMBOL_YYerror; goto yyerrlab1; } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Discard the shifted token. */ yychar = YYEMPTY; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 7: /* grammar: grammar error '\n' */ #line 133 "parse.y" { file->errors++; } #line 1344 "parse.c" break; case 8: /* varset: STRING '=' STRING */ #line 136 "parse.y" { char *s = (yyvsp[-2].v.string); while (*s++) { if (isspace((unsigned char)*s)) { yyerror("macro name cannot contain " "whitespace"); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } if (symset((yyvsp[-2].v.string), (yyvsp[0].v.string), 0) == -1) fatal("cannot store variable"); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1365 "parse.c" break; case 9: /* boolean: STRING */ #line 154 "parse.y" { if (strcasecmp((yyvsp[0].v.string), "1") == 0 || strcasecmp((yyvsp[0].v.string), "on") == 0) (yyval.v.number) = 1; else if (strcasecmp((yyvsp[0].v.string), "0") == 0 || strcasecmp((yyvsp[0].v.string), "off") == 0) (yyval.v.number) = 0; else { yyerror("invalid boolean value '%s'", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1384 "parse.c" break; case 10: /* boolean: ON */ #line 168 "parse.y" { (yyval.v.number) = 1; } #line 1390 "parse.c" break; case 11: /* boolean: NUMBER */ #line 169 "parse.y" { if ((yyvsp[0].v.number) != 0 && (yyvsp[0].v.number) != 1) { yyerror("invalid boolean value '%lld'", (yyvsp[0].v.number)); YYERROR; } (yyval.v.number) = (yyvsp[0].v.number); } #line 1402 "parse.c" break; case 12: /* listen_addr: '*' */ #line 178 "parse.y" { (yyval.v.string) = NULL; } #line 1408 "parse.c" break; case 14: /* main: PREFORK NUMBER */ #line 182 "parse.y" { if ((yyvsp[0].v.number) <= 0 || (yyvsp[0].v.number) > PROC_MAX_INSTANCES) { yyerror("prefork is %s: %lld", (yyvsp[0].v.number) <= 0 ? "too small" : "too large", (yyvsp[0].v.number)); YYERROR; } gotwebd->prefork_gotwebd = (yyvsp[0].v.number); } #line 1421 "parse.c" break; case 15: /* main: CHROOT STRING */ #line 190 "parse.y" { if (*(yyvsp[0].v.string) == '\0') { yyerror("chroot path can't be an empty" " string"); free((yyvsp[0].v.string)); YYERROR; } n = strlcpy(gotwebd->httpd_chroot, (yyvsp[0].v.string), sizeof(gotwebd->httpd_chroot)); if (n >= sizeof(gotwebd->httpd_chroot)) { yyerror("%s: httpd_chroot truncated", __func__); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1443 "parse.c" break; case 16: /* main: LISTEN ON listen_addr PORT STRING */ #line 207 "parse.y" { if (get_addrs((yyvsp[-2].v.string), (yyvsp[0].v.string)) == -1) { yyerror("could not get addrs"); YYERROR; } free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1456 "parse.c" break; case 17: /* main: LISTEN ON listen_addr PORT NUMBER */ #line 215 "parse.y" { char portno[32]; int n; n = snprintf(portno, sizeof(portno), "%lld", (long long)(yyvsp[0].v.number)); if (n < 0 || (size_t)n >= sizeof(portno)) fatalx("port number too long: %lld", (long long)(yyvsp[0].v.number)); if (get_addrs((yyvsp[-2].v.string), portno) == -1) { yyerror("could not get addrs"); YYERROR; } free((yyvsp[-2].v.string)); } #line 1477 "parse.c" break; case 18: /* main: LISTEN ON SOCKET STRING */ #line 231 "parse.y" { if (get_unix_addr((yyvsp[0].v.string)) == -1) { yyerror("can't listen on %s", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1490 "parse.c" break; case 19: /* main: USER STRING */ #line 239 "parse.y" { if (gotwebd->user != NULL) yyerror("user already specified"); free(gotwebd->user); gotwebd->user = (yyvsp[0].v.string); } #line 1501 "parse.c" break; case 20: /* server: SERVER STRING */ #line 247 "parse.y" { struct server *srv; TAILQ_FOREACH(srv, &gotwebd->servers, entry) { if (strcmp(srv->name, (yyvsp[0].v.string)) == 0) { yyerror("server name exists '%s'", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } } new_srv = conf_new_server((yyvsp[0].v.string)); log_debug("adding server %s", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); } #line 1521 "parse.c" break; case 21: /* $@1: %empty */ #line 262 "parse.y" { struct server *srv; TAILQ_FOREACH(srv, &gotwebd->servers, entry) { if (strcmp(srv->name, (yyvsp[0].v.string)) == 0) { yyerror("server name exists '%s'", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } } new_srv = conf_new_server((yyvsp[0].v.string)); log_debug("adding server %s", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); } #line 1541 "parse.c" break; case 22: /* server: SERVER STRING $@1 '{' optnl serveropts2 '}' */ #line 276 "parse.y" { } #line 1548 "parse.c" break; case 23: /* serveropts1: REPOS_PATH STRING */ #line 280 "parse.y" { n = strlcpy(new_srv->repos_path, (yyvsp[0].v.string), sizeof(new_srv->repos_path)); if (n >= sizeof(new_srv->repos_path)) { yyerror("%s: repos_path truncated", __func__); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1563 "parse.c" break; case 24: /* serveropts1: SITE_NAME STRING */ #line 290 "parse.y" { n = strlcpy(new_srv->site_name, (yyvsp[0].v.string), sizeof(new_srv->site_name)); if (n >= sizeof(new_srv->site_name)) { yyerror("%s: site_name truncated", __func__); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1578 "parse.c" break; case 25: /* serveropts1: SITE_OWNER STRING */ #line 300 "parse.y" { n = strlcpy(new_srv->site_owner, (yyvsp[0].v.string), sizeof(new_srv->site_owner)); if (n >= sizeof(new_srv->site_owner)) { yyerror("%s: site_owner truncated", __func__); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1593 "parse.c" break; case 26: /* serveropts1: SITE_LINK STRING */ #line 310 "parse.y" { n = strlcpy(new_srv->site_link, (yyvsp[0].v.string), sizeof(new_srv->site_link)); if (n >= sizeof(new_srv->site_link)) { yyerror("%s: site_link truncated", __func__); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1608 "parse.c" break; case 27: /* serveropts1: LOGO STRING */ #line 320 "parse.y" { n = strlcpy(new_srv->logo, (yyvsp[0].v.string), sizeof(new_srv->logo)); if (n >= sizeof(new_srv->logo)) { yyerror("%s: logo truncated", __func__); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1622 "parse.c" break; case 28: /* serveropts1: LOGO_URL STRING */ #line 329 "parse.y" { n = strlcpy(new_srv->logo_url, (yyvsp[0].v.string), sizeof(new_srv->logo_url)); if (n >= sizeof(new_srv->logo_url)) { yyerror("%s: logo_url truncated", __func__); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1637 "parse.c" break; case 29: /* serveropts1: CUSTOM_CSS STRING */ #line 339 "parse.y" { n = strlcpy(new_srv->custom_css, (yyvsp[0].v.string), sizeof(new_srv->custom_css)); if (n >= sizeof(new_srv->custom_css)) { yyerror("%s: custom_css truncated", __func__); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1652 "parse.c" break; case 30: /* serveropts1: SHOW_SITE_OWNER boolean */ #line 349 "parse.y" { new_srv->show_site_owner = (yyvsp[0].v.number); } #line 1660 "parse.c" break; case 31: /* serveropts1: SHOW_REPO_OWNER boolean */ #line 352 "parse.y" { new_srv->show_repo_owner = (yyvsp[0].v.number); } #line 1668 "parse.c" break; case 32: /* serveropts1: SHOW_REPO_AGE boolean */ #line 355 "parse.y" { new_srv->show_repo_age = (yyvsp[0].v.number); } #line 1676 "parse.c" break; case 33: /* serveropts1: SHOW_REPO_DESCRIPTION boolean */ #line 358 "parse.y" { new_srv->show_repo_description = (yyvsp[0].v.number); } #line 1684 "parse.c" break; case 34: /* serveropts1: SHOW_REPO_CLONEURL boolean */ #line 361 "parse.y" { new_srv->show_repo_cloneurl = (yyvsp[0].v.number); } #line 1692 "parse.c" break; case 35: /* serveropts1: RESPECT_EXPORTOK boolean */ #line 364 "parse.y" { new_srv->respect_exportok = (yyvsp[0].v.number); } #line 1700 "parse.c" break; case 36: /* serveropts1: MAX_REPOS_DISPLAY NUMBER */ #line 367 "parse.y" { if ((yyvsp[0].v.number) < 0) { yyerror("max_repos_display is too small: %lld", (yyvsp[0].v.number)); YYERROR; } new_srv->max_repos_display = (yyvsp[0].v.number); } #line 1713 "parse.c" break; case 37: /* serveropts1: MAX_COMMITS_DISPLAY NUMBER */ #line 375 "parse.y" { if ((yyvsp[0].v.number) <= 1) { yyerror("max_commits_display is too small:" " %lld", (yyvsp[0].v.number)); YYERROR; } new_srv->max_commits_display = (yyvsp[0].v.number); } #line 1726 "parse.c" break; case 38: /* serveropts1: SUMMARY_COMMITS_DISPLAY NUMBER */ #line 383 "parse.y" { if ((yyvsp[0].v.number) < 1) { yyerror("summary_commits_display is too small:" " %lld", (yyvsp[0].v.number)); YYERROR; } new_srv->summary_commits_display = (yyvsp[0].v.number); } #line 1739 "parse.c" break; case 39: /* serveropts1: SUMMARY_TAGS_DISPLAY NUMBER */ #line 391 "parse.y" { if ((yyvsp[0].v.number) < 1) { yyerror("summary_tags_display is too small:" " %lld", (yyvsp[0].v.number)); YYERROR; } new_srv->summary_tags_display = (yyvsp[0].v.number); } #line 1752 "parse.c" break; #line 1756 "parse.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; *++yyvsp = yyval; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ { const int yylhs = yyr1[yyn] - YYNTOKENS; const int yyi = yypgoto[yylhs] + *yyssp; yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp ? yytable[yyi] : yydefgoto[yylhs]); } goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; yyerror (YY_("syntax error")); } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (0) YYERROR; ++yynerrs; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ /* Pop stack until we find a state that shifts the error token. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYSYMBOL_YYerror; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", YY_ACCESSING_SYMBOL (yystate), yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturnlab; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturnlab; /*-----------------------------------------------------------. | yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | `-----------------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; goto yyreturnlab; /*----------------------------------------------------------. | yyreturnlab -- parsing is finished, clean up and return. | `----------------------------------------------------------*/ yyreturnlab: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", YY_ACCESSING_SYMBOL (+*yyssp), yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif return yyresult; } #line 412 "parse.y" struct keywords { const char *k_name; int k_val; }; int yyerror(const char *fmt, ...) { va_list ap; char *msg; file->errors++; va_start(ap, fmt); if (vasprintf(&msg, fmt, ap) == -1) fatalx("yyerror vasprintf"); va_end(ap); logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); free(msg); return (0); } int kw_cmp(const void *k, const void *e) { return (strcmp(k, ((const struct keywords *)e)->k_name)); } int lookup(char *s) { /* This has to be sorted always. */ static const struct keywords keywords[] = { { "chroot", CHROOT }, { "custom_css", CUSTOM_CSS }, { "listen", LISTEN }, { "logo", LOGO }, { "logo_url", LOGO_URL }, { "max_commits_display", MAX_COMMITS_DISPLAY }, { "max_repos_display", MAX_REPOS_DISPLAY }, { "on", ON }, { "port", PORT }, { "prefork", PREFORK }, { "repos_path", REPOS_PATH }, { "respect_exportok", RESPECT_EXPORTOK }, { "server", SERVER }, { "show_repo_age", SHOW_REPO_AGE }, { "show_repo_cloneurl", SHOW_REPO_CLONEURL }, { "show_repo_description", SHOW_REPO_DESCRIPTION }, { "show_repo_owner", SHOW_REPO_OWNER }, { "show_site_owner", SHOW_SITE_OWNER }, { "site_link", SITE_LINK }, { "site_name", SITE_NAME }, { "site_owner", SITE_OWNER }, { "socket", SOCKET }, { "summary_commits_display", SUMMARY_COMMITS_DISPLAY }, { "summary_tags_display", SUMMARY_TAGS_DISPLAY }, { "user", USER }, }; const struct keywords *p; p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), sizeof(keywords[0]), kw_cmp); if (p) return (p->k_val); else return (STRING); } #define MAXPUSHBACK 128 unsigned char *parsebuf; int parseindex; unsigned char pushback_buffer[MAXPUSHBACK]; int pushback_index = 0; int lgetc(int quotec) { int c, next; if (parsebuf) { /* Read character from the parsebuffer instead of input. */ if (parseindex >= 0) { c = parsebuf[parseindex++]; if (c != '\0') return (c); parsebuf = NULL; } else parseindex++; } if (pushback_index) return (pushback_buffer[--pushback_index]); if (quotec) { c = getc(file->stream); if (c == EOF) yyerror("reached end of file while parsing " "quoted string"); return (c); } c = getc(file->stream); while (c == '\\') { next = getc(file->stream); if (next != '\n') { c = next; break; } yylval.lineno = file->lineno; file->lineno++; c = getc(file->stream); } return (c); } int lungetc(int c) { if (c == EOF) return (EOF); if (parsebuf) { parseindex--; if (parseindex >= 0) return (c); } if (pushback_index < MAXPUSHBACK-1) return (pushback_buffer[pushback_index++] = c); else return (EOF); } int findeol(void) { int c; parsebuf = NULL; /* Skip to either EOF or the first real EOL. */ while (1) { if (pushback_index) c = pushback_buffer[--pushback_index]; else c = lgetc(0); if (c == '\n') { file->lineno++; break; } if (c == EOF) break; } return (ERROR); } int yylex(void) { unsigned char buf[8096]; unsigned char *p, *val; int quotec, next, c; int token; top: p = buf; c = lgetc(0); while (c == ' ' || c == '\t') c = lgetc(0); /* nothing */ yylval.lineno = file->lineno; if (c == '#') { c = lgetc(0); while (c != '\n' && c != EOF) c = lgetc(0); /* nothing */ } if (c == '$' && parsebuf == NULL) { while (1) { c = lgetc(0); if (c == EOF) return (0); if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } if (isalnum(c) || c == '_') { *p++ = c; continue; } *p = '\0'; lungetc(c); break; } val = symget(buf); if (val == NULL) { yyerror("macro '%s' not defined", buf); return (findeol()); } parsebuf = val; parseindex = 0; goto top; } switch (c) { case '\'': case '"': quotec = c; while (1) { c = lgetc(quotec); if (c == EOF) return (0); if (c == '\n') { file->lineno++; continue; } else if (c == '\\') { next = lgetc(quotec); if (next == EOF) return (0); if (next == quotec || c == ' ' || c == '\t') c = next; else if (next == '\n') { file->lineno++; continue; } else lungetc(next); } else if (c == quotec) { *p = '\0'; break; } else if (c == '\0') { yyerror("syntax error"); return (findeol()); } if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } *p++ = c; } yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "yylex: strdup"); return (STRING); } #define allowed_to_end_number(x) \ (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') if (c == '-' || isdigit(c)) { do { *p++ = c; if ((unsigned)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && isdigit(c)); lungetc(c); if (p == buf + 1 && buf[0] == '-') goto nodigits; if (c == EOF || allowed_to_end_number(c)) { const char *errstr = NULL; *p = '\0'; yylval.v.number = strtonum(buf, LLONG_MIN, LLONG_MAX, &errstr); if (errstr) { yyerror("\"%s\" invalid number: %s", buf, errstr); return (findeol()); } return (NUMBER); } else { nodigits: while (p > buf + 1) lungetc(*--p); c = *--p; if (c == '-') return (c); } } #define allowed_in_string(x) \ (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ x != '{' && x != '}' && \ x != '!' && x != '=' && x != '#' && \ x != ',')) if (isalnum(c) || c == ':' || c == '_') { do { *p++ = c; if ((unsigned)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && (allowed_in_string(c))); lungetc(c); *p = '\0'; token = lookup(buf); if (token == STRING) { yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "yylex: strdup"); } return (token); } if (c == '\n') { yylval.lineno = file->lineno; file->lineno++; } if (c == EOF) return (0); return (c); } int check_file_secrecy(int fd, const char *fname) { struct stat st; if (fstat(fd, &st)) { log_warn("cannot stat %s", fname); return (-1); } if (st.st_uid != 0 && st.st_uid != getuid()) { log_warnx("%s: owner not root or current user", fname); return (-1); } if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { log_warnx("%s: group writable or world read/writable", fname); return (-1); } return (0); } struct file * newfile(const char *name, int secret) { struct file *nfile; nfile = calloc(1, sizeof(struct file)); if (nfile == NULL) { log_warn("calloc"); return (NULL); } nfile->name = strdup(name); if (nfile->name == NULL) { log_warn("strdup"); free(nfile); return (NULL); } nfile->stream = fopen(nfile->name, "r"); if (nfile->stream == NULL) { /* no warning, we don't require a conf file */ free(nfile->name); free(nfile); return (NULL); } else if (secret && check_file_secrecy(fileno(nfile->stream), nfile->name)) { fclose(nfile->stream); free(nfile->name); free(nfile); return (NULL); } nfile->lineno = 1; return (nfile); } static void closefile(struct file *xfile) { fclose(xfile->stream); free(xfile->name); free(xfile); } static void add_default_server(void) { new_srv = conf_new_server(D_SITENAME); log_debug("%s: adding default server %s", __func__, D_SITENAME); } int parse_config(const char *filename, struct gotwebd *env) { struct sym *sym, *next; if (config_init(env) == -1) fatalx("failed to initialize configuration"); gotwebd = env; file = newfile(filename, 0); if (file != NULL) { /* we don't require a config file */ yyparse(); errors = file->errors; closefile(file); } /* Free macros and check which have not been used. */ TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { if ((gotwebd->gotwebd_verbose > 1) && !sym->used) fprintf(stderr, "warning: macro '%s' not used\n", sym->nam); if (!sym->persist) { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } /* just add default server if no config specified */ if (gotwebd->server_cnt == 0) add_default_server(); /* add the implicit listen on socket */ if (TAILQ_EMPTY(&gotwebd->addresses)) { const char *path = D_HTTPD_CHROOT D_UNIX_SOCKET; if (get_unix_addr(path) == -1) yyerror("can't listen on %s", path); } if (errors) return (-1); /* setup our listening sockets */ sockets_parse_sockets(env); return (0); } struct server * conf_new_server(const char *name) { struct server *srv = NULL; srv = calloc(1, sizeof(*srv)); if (srv == NULL) fatalx("%s: calloc", __func__); n = strlcpy(srv->name, name, sizeof(srv->name)); if (n >= sizeof(srv->name)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->repos_path, D_GOTPATH, sizeof(srv->repos_path)); if (n >= sizeof(srv->repos_path)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->site_name, D_SITENAME, sizeof(srv->site_name)); if (n >= sizeof(srv->site_name)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->site_owner, D_SITEOWNER, sizeof(srv->site_owner)); if (n >= sizeof(srv->site_owner)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->site_link, D_SITELINK, sizeof(srv->site_link)); if (n >= sizeof(srv->site_link)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->logo, D_GOTLOGO, sizeof(srv->logo)); if (n >= sizeof(srv->logo)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->logo_url, D_GOTURL, sizeof(srv->logo_url)); if (n >= sizeof(srv->logo_url)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->custom_css, D_GOTWEBCSS, sizeof(srv->custom_css)); if (n >= sizeof(srv->custom_css)) fatalx("%s: strlcpy", __func__); srv->show_site_owner = D_SHOWSOWNER; srv->show_repo_owner = D_SHOWROWNER; srv->show_repo_age = D_SHOWAGE; srv->show_repo_description = D_SHOWDESC; srv->show_repo_cloneurl = D_SHOWURL; srv->respect_exportok = D_RESPECTEXPORTOK; srv->max_repos_display = D_MAXREPODISP; srv->max_commits_display = D_MAXCOMMITDISP; srv->summary_commits_display = D_MAXSLCOMMDISP; srv->summary_tags_display = D_MAXSLTAGDISP; TAILQ_INSERT_TAIL(&gotwebd->servers, srv, entry); gotwebd->server_cnt++; return srv; }; int symset(const char *nam, const char *val, int persist) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) break; } if (sym != NULL) { if (sym->persist == 1) return (0); else { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } sym = calloc(1, sizeof(*sym)); if (sym == NULL) return (-1); sym->nam = strdup(nam); if (sym->nam == NULL) { free(sym); return (-1); } sym->val = strdup(val); if (sym->val == NULL) { free(sym->nam); free(sym); return (-1); } sym->used = 0; sym->persist = persist; TAILQ_INSERT_TAIL(&symhead, sym, entry); return (0); } int cmdline_symset(char *s) { char *sym, *val; int ret; val = strrchr(s, '='); if (val == NULL) return (-1); sym = strndup(s, val - s); if (sym == NULL) fatal("%s: strndup", __func__); ret = symset(sym, val + 1, 1); free(sym); return (ret); } char * symget(const char *nam) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) { sym->used = 1; return (sym->val); } } return (NULL); } int get_addrs(const char *hostname, const char *servname) { struct addrinfo hints, *res0, *res; int error; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; struct address *h; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; error = getaddrinfo(hostname, servname, &hints, &res0); if (error) { log_warnx("%s: could not parse \"%s:%s\": %s", __func__, hostname, servname, gai_strerror(error)); return (-1); } for (res = res0; res; res = res->ai_next) { if ((h = calloc(1, sizeof(*h))) == NULL) fatal(__func__); if (hostname == NULL) { strlcpy(h->ifname, "*", sizeof(h->ifname)); } else { if (strlcpy(h->ifname, hostname, sizeof(h->ifname)) >= sizeof(h->ifname)) { log_warnx("%s: address truncated: %s", __func__, hostname); freeaddrinfo(res0); free(h); return (-1); } } h->ai_family = res->ai_family; h->ai_socktype = res->ai_socktype; h->ai_protocol = res->ai_protocol; memcpy(&h->ss, res->ai_addr, res->ai_addrlen); h->slen = res->ai_addrlen; switch (res->ai_family) { case AF_INET: sin = (struct sockaddr_in *)res->ai_addr; h->port = ntohs(sin->sin_port); break; case AF_INET6: sin6 = (struct sockaddr_in6 *)res->ai_addr; h->port = ntohs(sin6->sin6_port); break; default: fatalx("unknown address family %d", res->ai_family); } if (add_addr(h) == -1) { freeaddrinfo(res0); return -1; } } freeaddrinfo(res0); return (0); } int get_unix_addr(const char *path) { struct address *h; struct sockaddr_un *sun; if ((h = calloc(1, sizeof(*h))) == NULL) fatal("%s: calloc", __func__); h->ai_family = AF_UNIX; h->ai_socktype = SOCK_STREAM; h->ai_protocol = PF_UNSPEC; h->slen = sizeof(*sun); sun = (struct sockaddr_un *)&h->ss; sun->sun_family = AF_UNIX; if (strlcpy(sun->sun_path, path, sizeof(sun->sun_path)) >= sizeof(sun->sun_path)) { log_warnx("socket path too long: %s", sun->sun_path); return (-1); } return add_addr(h); } int addr_dup_check(struct addresslist *al, struct address *h) { struct address *a; TAILQ_FOREACH(a, al, entry) { if (a->ai_family != h->ai_family || a->ai_socktype != h->ai_socktype || a->ai_protocol != h->ai_protocol || a->slen != h->slen || memcmp(&a->ss, &h->ss, a->slen) != 0) continue; return -1; } return 0; } int add_addr(struct address *h) { if (addr_dup_check(&gotwebd->addresses, h) == 0) { TAILQ_INSERT_TAIL(&gotwebd->addresses, h, entry); return (0); } free(h); return (0); } got-portable-0.101/gotwebd/config.c0000664000175100017510000001230414644144735012657 /* * Copyright (c) 2020-2021 Tracey Emery * Copyright (c) 2015 Reyk Floeter * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_opentemp.h" #include "got_reference.h" #include "gotwebd.h" #include "log.h" int config_init(struct gotwebd *env) { int i; strlcpy(env->httpd_chroot, D_HTTPD_CHROOT, sizeof(env->httpd_chroot)); env->prefork_gotwebd = GOTWEBD_NUMPROC; env->server_cnt = 0; TAILQ_INIT(&env->servers); TAILQ_INIT(&env->sockets); TAILQ_INIT(&env->addresses); for (i = 0; i < PRIV_FDS__MAX; i++) env->priv_fd[i] = -1; for (i = 0; i < GOTWEB_PACK_NUM_TEMPFILES; i++) env->pack_fds[i] = -1; return 0; } int config_getcfg(struct gotwebd *env, struct imsg *imsg) { /* nothing to do but tell gotwebd configuration is done */ if (sockets_compose_main(env, IMSG_CFG_DONE, NULL, 0) == -1) fatal("sockets_compose_main IMSG_CFG_DONE"); return 0; } int config_setserver(struct gotwebd *env, struct server *srv) { if (main_compose_sockets(env, IMSG_CFG_SRV, -1, srv, sizeof(*srv)) == -1) fatal("main_compose_sockets IMSG_CFG_SRV"); return 0; } int config_getserver(struct gotwebd *env, struct imsg *imsg) { struct server *srv; uint8_t *p = imsg->data; srv = calloc(1, sizeof(*srv)); if (srv == NULL) fatalx("%s: calloc", __func__); if (IMSG_DATA_SIZE(imsg) != sizeof(*srv)) fatalx("%s: wrong size", __func__); memcpy(srv, p, sizeof(*srv)); /* log server info */ log_debug("%s: server=%s", __func__, srv->name); TAILQ_INSERT_TAIL(&env->servers, srv, entry); return 0; } int config_setsock(struct gotwebd *env, struct socket *sock) { /* open listening sockets */ if (sockets_privinit(env, sock) == -1) return -1; if (main_compose_sockets(env, IMSG_CFG_SOCK, sock->fd, &sock->conf, sizeof(sock->conf)) == -1) fatal("main_compose_sockets IMSG_CFG_SOCK"); sock->fd = -1; return 0; } int config_getsock(struct gotwebd *env, struct imsg *imsg) { struct socket *sock = NULL; struct socket_conf sock_conf; uint8_t *p = imsg->data; if (IMSG_DATA_SIZE(imsg) != sizeof(sock_conf)) fatalx("%s: wrong size", __func__); memcpy(&sock_conf, p, sizeof(sock_conf)); if (IMSG_DATA_SIZE(imsg) != sizeof(sock_conf)) { log_debug("%s: imsg size error", __func__); return 1; } /* create a new socket */ if ((sock = calloc(1, sizeof(*sock))) == NULL) { return 1; } memcpy(&sock->conf, &sock_conf, sizeof(sock->conf)); sock->fd = imsg_get_fd(imsg); TAILQ_INSERT_TAIL(&env->sockets, sock, entry); /* log new socket info */ log_debug("%s: id=%d af_type=%s socket_path=%s", __func__, sock->conf.id, sock->conf.af_type == AF_UNIX ? "unix" : (sock->conf.af_type == AF_INET ? "inet" : (sock->conf.af_type == AF_INET6 ? "inet6" : "unknown")), *sock->conf.unix_socket_name != '\0' ? sock->conf.unix_socket_name : "none"); return 0; } int config_setfd(struct gotwebd *env) { int i, j, ret, fd; log_debug("%s: Allocating %d file descriptors", __func__, PRIV_FDS__MAX + GOTWEB_PACK_NUM_TEMPFILES); for (i = 0; i < PRIV_FDS__MAX + GOTWEB_PACK_NUM_TEMPFILES; i++) { for (j = 0; j < env->nserver; ++j) { fd = got_opentempfd(); if (fd == -1) fatal("got_opentemp"); if (imsg_compose_event(&env->iev_server[j], IMSG_CFG_FD, 0, -1, fd, NULL, 0) == -1) fatal("imsg_compose_event IMSG_CFG_FD"); do { ret = imsg_flush(&env->iev_server[j].ibuf); } while (ret == -1 && errno == EAGAIN); if (ret == -1) fatal("imsg_flush"); imsg_event_add(&env->iev_server[j]); } } return 0; } int config_getfd(struct gotwebd *env, struct imsg *imsg) { int match = 0, i, j; const int nfds = GOTWEB_PACK_NUM_TEMPFILES + PRIV_FDS__MAX; if (imsg_get_len(imsg) != 0) fatalx("%s: wrong size", __func__); for (i = 0; i < nfds; i++) { if (i < PRIV_FDS__MAX && env->priv_fd[i] == -1) { env->priv_fd[i] = imsg_get_fd(imsg); log_debug("%s: assigning priv_fd %d", __func__, env->priv_fd[i]); match = 1; break; } j = i - PRIV_FDS__MAX; if (env->pack_fds[j] == -1) { env->pack_fds[j] = imsg_get_fd(imsg); log_debug("%s: assigning pack_fd %d", __func__, env->pack_fds[j]); match = 1; break; } } if (match) return 0; else return 1; } got-portable-0.101/gotwebd/gotwebd.conf.50000664000175100017510000001454714644143163013720 .\" .\" Copyright (c) 2020 Tracey Emery .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt GOTWEBD.CONF 5 .Os .Sh NAME .Nm gotwebd.conf .Nd gotwebd configuration file .Sh DESCRIPTION .Nm is the run-time configuration file for .Xr gotwebd 8 . .Pp The file format is line-based, with one configuration directive per line. Any lines beginning with a .Sq # are treated as comments and ignored. .Pp Macros can be defined that are later expanded in context. Macro names must start with a letter, digit, or underscore, and may contain any of those characters, but may not be reserved words. Macros are not expanded inside quotes. For example: .Bd -literal -offset indent lan_addr = "192.168.0.1" listen on $lan_addr port 9090 .Ed .Pp Paths mentioned in .Nm must be relative to .Pa /var/www , the .Xr chroot 2 environment of .Xr httpd 8 . .Sh GLOBAL CONFIGURATION The available global configuration directives are as follows: .Bl -tag -width Ds .It Ic chroot Ar path Set the path to the .Xr chroot 2 environment of .Xr httpd 8 . If not specified, it defaults to .Pa /var/www , the home directory of the www user. .It Ic listen on Ar address Ic port Ar number Configure an address and port for incoming FastCGI connections. Valid .Ar address arguments are hostnames, IPv4 and IPv6 addresses. The .Ar port argument may be number or a service name defined in .Xr services 5 . May be specified multiple times to build up a list of listening sockets. .It Ic listen on socket Ar path Configure a .Ux Ns -domain socket for incoming FastCGI connections. May be specified multiple times to build up a list of listening sockets. .It Ic prefork Ar number Run the specified number of server processes. .Xr gotwebd 8 runs 3 server processes by default. .It Ic user Ar user Set the .Ar user which will run .Xr gotwebd 8 . If not specified, the user www will be used. .El .Pp If no .Ic listen directive is used, .Xr gotwebd 8 will listen on the .Ux Ns -domain socket at .Pa /var/www/run/gotweb.sock . .Sh SERVER CONFIGURATION At least one server context must exist for .Xr gotwebd 8 to function. In case no server context is defined in the configuration file, a default server context will be used which uses default parameters for all applicable settings. .Pp A server context is declared with a unique .Ar name , followed by server-specific configuration directives inside curly braces: .Pp .Ic server Ar name Brq ... .Pp The first server defined is used if the requested hostname is not matched by any server block. .Pp The available server configuration directives are as follows: .Bl -tag -width Ds .It Ic custom_css Ar path Set the path to a custom Cascading Style Sheet (CSS) to be used. If this option is not specified then the default style sheet .Sq gotweb.css will be used. .It Ic logo Ar path Set the path to an image file containing a logo to be displayed. Defaults to .Sq got.png . .It Ic logo_url Ar url Set a hyperlink for the logo. Defaults to .Lk https://gameoftrees.org . .It Ic max_commits_display Ar number Set the maximum amount of commits and tags displayed per page. Defaults to 25. .It Ic max_repos_display Ar number Set the maximum amount of repositories displayed on the index screen. Defaults to 25. Set to zero to show all the repositories without pagination. .It Ic repos_path Ar path Set the path to the directory which contains Git repositories that the server should publish. Defaults to .Pa /got/public under the chroot. .It Ic respect_exportok Ar on | off Set whether to display the repository only if it contains the magic .Pa git-daemon-export-ok file. Disabled by default. .It Ic show_repo_age Ar on | off Toggle display of last repository modification date. Enabled by default. .It Ic show_repo_cloneurl Ar on | off Toggle display of clone URLs for a repository. This requires the creation of a .Pa cloneurl file inside the repository which contains one URL per line. Enabled by default. .It Ic show_repo_description Ar on | off Toggle display of the repository description. Enabled by default. The .Pa description file in the repository should be updated with an appropriate description. .It Ic show_repo_owner Ar on | off Set whether to display the repository owner. Enabled by default. Displaying the owner requires owner information to be added to the .Pa config file in the repository. .Xr gotwebd 8 will parse owner information from either a [gotweb] or a [gitweb] section. For example: .Bd -literal -offset indent [gotweb] owner = "Your Name" .Ed .It Ic site_link Ar string Set the displayed site link name for the index page. Defaults to .Sq Repos . .It Ic site_name Ar string Set the displayed site name title. Defaults to .Sq Gotweb . .It Ic site_owner Ar string Set the displayed site owner. Defaults to .Sq Got Owner . .It Ic show_site_owner Ar on | off Toggle display of the site owner. Enabled by default. .It Ic summary_commits_display Ar number The maximum number of commits to show in the summary page. Defaults to 10. .It Ic summary_tags_display Ar number The maximum number of tags to show in the summary page. Defaults to 3. .El .Sh FILES .Bl -tag -width Ds -compact .It Pa /etc/gotwebd.conf Default location of the .Nm configuration file. .It Pa /var/www/run/gotweb.sock Default location for the .Xr gotwebd 8 listening socket. .El .Sh EXAMPLES A sample configuration: .Bd -literal -offset indent server "localhost" { site_name "my public repos" site_owner "Flan Hacker" site_link "Flan' Projects" } .Ed .Pp Another example, this time listening on a local port instead of the implicit .Ux socket. .Bd -literal -offset indent listen on 127.0.0.1 port 9000 listen on ::1 port 9000 server "localhost" { site_name "my public repos" } .Ed .Sh SEE ALSO .Xr got 1 , .Xr httpd.conf 5 , .Xr services 5 , .Xr gotwebd 8 , .Xr httpd 8 got-portable-0.101/gotwebd/Makefile.in0000664000175100017510000014740414644145543013323 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ sbin_PROGRAMS = gotwebd$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = gotwebd ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" \ "$(DESTDIR)$(man8dir)" PROGRAMS = $(sbin_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_gotwebd_OBJECTS = config.$(OBJEXT) \ $(top_builddir)/lib/blame.$(OBJEXT) \ $(top_builddir)/lib/bloom.$(OBJEXT) \ $(top_builddir)/lib/buf.$(OBJEXT) \ $(top_builddir)/lib/commit_graph.$(OBJEXT) \ $(top_builddir)/lib/date.$(OBJEXT) \ $(top_builddir)/lib/deflate.$(OBJEXT) \ $(top_builddir)/lib/delta.$(OBJEXT) \ $(top_builddir)/lib/delta_cache.$(OBJEXT) \ $(top_builddir)/lib/diff.$(OBJEXT) \ $(top_builddir)/lib/diff3.$(OBJEXT) \ $(top_builddir)/lib/diff_atomize_text.$(OBJEXT) \ $(top_builddir)/lib/diff_main.$(OBJEXT) \ $(top_builddir)/lib/diff_myers.$(OBJEXT) \ $(top_builddir)/lib/diff_output.$(OBJEXT) \ $(top_builddir)/lib/diff_output_edscript.$(OBJEXT) \ $(top_builddir)/lib/diff_output_plain.$(OBJEXT) \ $(top_builddir)/lib/diff_output_unidiff.$(OBJEXT) \ $(top_builddir)/lib/diff_patience.$(OBJEXT) \ $(top_builddir)/lib/diffreg.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/fileindex.$(OBJEXT) \ $(top_builddir)/lib/gotconfig.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/lockfile.$(OBJEXT) \ $(top_builddir)/lib/log.$(OBJEXT) \ $(top_builddir)/lib/murmurhash2.$(OBJEXT) \ $(top_builddir)/lib/object.$(OBJEXT) \ $(top_builddir)/lib/object_cache.$(OBJEXT) \ $(top_builddir)/lib/object_create.$(OBJEXT) \ $(top_builddir)/lib/object_idset.$(OBJEXT) \ $(top_builddir)/lib/object_open_privsep.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/opentemp.$(OBJEXT) \ $(top_builddir)/lib/pack.$(OBJEXT) \ $(top_builddir)/lib/patch.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) \ $(top_builddir)/lib/rcsutil.$(OBJEXT) \ $(top_builddir)/lib/read_gitconfig_privsep.$(OBJEXT) \ $(top_builddir)/lib/read_gotconfig_privsep.$(OBJEXT) \ $(top_builddir)/lib/reference.$(OBJEXT) \ $(top_builddir)/lib/reference_parse.$(OBJEXT) \ $(top_builddir)/lib/repository.$(OBJEXT) \ $(top_builddir)/lib/sigs.$(OBJEXT) \ $(top_builddir)/lib/utf8.$(OBJEXT) \ $(top_builddir)/lib/worktree.$(OBJEXT) \ $(top_builddir)/lib/worktree_open.$(OBJEXT) \ $(top_builddir)/template/tmpl.$(OBJEXT) fcgi.$(OBJEXT) \ got_operations.$(OBJEXT) gotweb.$(OBJEXT) gotwebd.$(OBJEXT) \ pages.$(OBJEXT) parse.$(OBJEXT) sockets.$(OBJEXT) gotwebd_OBJECTS = $(am_gotwebd_OBJECTS) gotwebd_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/blame.Po \ $(top_builddir)/lib/$(DEPDIR)/bloom.Po \ $(top_builddir)/lib/$(DEPDIR)/buf.Po \ $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po \ $(top_builddir)/lib/$(DEPDIR)/date.Po \ $(top_builddir)/lib/$(DEPDIR)/deflate.Po \ $(top_builddir)/lib/$(DEPDIR)/delta.Po \ $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/diff.Po \ $(top_builddir)/lib/$(DEPDIR)/diff3.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_main.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po \ $(top_builddir)/lib/$(DEPDIR)/diffreg.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/fileindex.Po \ $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/lockfile.Po \ $(top_builddir)/lib/$(DEPDIR)/log.Po \ $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po \ $(top_builddir)/lib/$(DEPDIR)/object.Po \ $(top_builddir)/lib/$(DEPDIR)/object_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/object_create.Po \ $(top_builddir)/lib/$(DEPDIR)/object_idset.Po \ $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/opentemp.Po \ $(top_builddir)/lib/$(DEPDIR)/pack.Po \ $(top_builddir)/lib/$(DEPDIR)/patch.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po \ $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/reference.Po \ $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/repository.Po \ $(top_builddir)/lib/$(DEPDIR)/sigs.Po \ $(top_builddir)/lib/$(DEPDIR)/utf8.Po \ $(top_builddir)/lib/$(DEPDIR)/worktree.Po \ $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po \ $(top_builddir)/template/$(DEPDIR)/tmpl.Po \ ./$(DEPDIR)/config.Po ./$(DEPDIR)/fcgi.Po \ ./$(DEPDIR)/got_operations.Po ./$(DEPDIR)/gotweb.Po \ ./$(DEPDIR)/gotwebd.Po ./$(DEPDIR)/pages.Po \ ./$(DEPDIR)/parse.Po ./$(DEPDIR)/sockets.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \ -e s/c++$$/h++/ -e s/c$$/h/ YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS) AM_V_YACC = $(am__v_YACC_@AM_V@) am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@) am__v_YACC_0 = @echo " YACC " $@; am__v_YACC_1 = YLWRAP = $(top_srcdir)/etc/ylwrap SOURCES = $(gotwebd_SOURCES) DIST_SOURCES = $(gotwebd_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } man5dir = $(mandir)/man5 man8dir = $(mandir)/man8 NROFF = nroff MANS = $(man5_MANS) $(man8_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp \ $(top_srcdir)/etc/ylwrap parse.c DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(libbsd_CFLAGS) $(libevent_CFLAGS) \ $(zlib_CFLAGS) $(libuuid_CFLAGS) $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ # /home/n6tadam/projects/got/gotwebd/../template/template -o pages.c pages.tmpl BUILT_SOURCES = pages.c CLEANFILES = pages.c parse.c gotwebd_SOURCES = config.c \ $(top_srcdir)/lib/blame.c \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/commit_graph.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/diff.c \ $(top_srcdir)/lib/diff3.c \ $(top_srcdir)/lib/diff_atomize_text.c \ $(top_srcdir)/lib/diff_main.c \ $(top_srcdir)/lib/diff_myers.c \ $(top_srcdir)/lib/diff_output.c \ $(top_srcdir)/lib/diff_output_edscript.c \ $(top_srcdir)/lib/diff_output_plain.c \ $(top_srcdir)/lib/diff_output_unidiff.c \ $(top_srcdir)/lib/diff_patience.c \ $(top_srcdir)/lib/diffreg.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fileindex.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/log.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/patch.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/rcsutil.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/lib/utf8.c \ $(top_srcdir)/lib/worktree.c \ $(top_srcdir)/lib/worktree_open.c \ $(top_srcdir)/template/tmpl.c \ fcgi.c \ got_operations.c \ gotweb.c \ gotwebd.c \ pages.c \ parse.y \ sockets.c gotwebd_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = $(top_srcdir)/gotwebd/*.h \ $(top_srcdir)/gotwebd/*.tmpl \ $(top_srcdir)/template/tmpl.h \ gotwebd.8 gotwebd.conf.5 man5_MANS = gotwebd.conf.5 man8_MANS = gotwebd.8 LDADD = -L$(top_builddir)/compat -L$(top_builddir)/template \ -lopenbsd-compat -lm $(libbsd_LIBS) $(libevent_LIBS) \ $(zlib_LIBS) $(libuuid_LIBS) $(libutil_LIBS) $(libmd_LIBS) \ $(am__append_1) all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .o .obj .y $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gotwebd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign gotwebd/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: > $(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: > $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/blame.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/bloom.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/buf.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/commit_graph.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/date.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/deflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff3.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_atomize_text.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_main.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_myers.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_edscript.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_plain.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_unidiff.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_patience.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diffreg.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/fileindex.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gotconfig.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/lockfile.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/log.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/murmurhash2.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_create.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_idset.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_open_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/opentemp.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/patch.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/rcsutil.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/read_gitconfig_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/read_gotconfig_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/repository.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/sigs.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/utf8.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/worktree.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/worktree_open.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/template/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/template @: > $(top_builddir)/template/$(am__dirstamp) $(top_builddir)/template/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/template/$(DEPDIR) @: > $(top_builddir)/template/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/template/tmpl.$(OBJEXT): \ $(top_builddir)/template/$(am__dirstamp) \ $(top_builddir)/template/$(DEPDIR)/$(am__dirstamp) gotwebd$(EXEEXT): $(gotwebd_OBJECTS) $(gotwebd_DEPENDENCIES) $(EXTRA_gotwebd_DEPENDENCIES) @rm -f gotwebd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gotwebd_OBJECTS) $(gotwebd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) -rm -f $(top_builddir)/template/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/blame.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/bloom.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/buf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/commit_graph.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/date.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/deflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff3.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_myers.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_patience.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diffreg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/fileindex.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gotconfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/lockfile.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/log.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_create.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_idset.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/opentemp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/patch.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/rcsutil.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/repository.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/sigs.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/utf8.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/worktree.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/worktree_open.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/template/$(DEPDIR)/tmpl.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fcgi.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got_operations.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gotweb.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gotwebd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pages.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sockets.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .y.c: $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE) install-man5: $(man5_MANS) @$(NORMAL_INSTALL) @list1='$(man5_MANS)'; \ list2=''; \ test -n "$(man5dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man5dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man5dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.5[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \ done; } uninstall-man5: @$(NORMAL_UNINSTALL) @list='$(man5_MANS)'; test -n "$(man5dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man5dir)'; $(am__uninstall_files_from_dir) install-man8: $(man8_MANS) @$(NORMAL_INSTALL) @list1='$(man8_MANS)'; \ list2=''; \ test -n "$(man8dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.8[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ done; } uninstall-man8: @$(NORMAL_UNINSTALL) @list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(PROGRAMS) $(MANS) installdirs: for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(am__dirstamp) -test -z "$(top_builddir)/template/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/template/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/template/$(am__dirstamp)" || rm -f $(top_builddir)/template/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -rm -f parse.c -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/blame.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/bloom.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/buf.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/date.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff3.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_main.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diffreg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fileindex.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/lockfile.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/log.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/patch.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/sigs.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/utf8.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po -rm -f $(top_builddir)/template/$(DEPDIR)/tmpl.Po -rm -f ./$(DEPDIR)/config.Po -rm -f ./$(DEPDIR)/fcgi.Po -rm -f ./$(DEPDIR)/got_operations.Po -rm -f ./$(DEPDIR)/gotweb.Po -rm -f ./$(DEPDIR)/gotwebd.Po -rm -f ./$(DEPDIR)/pages.Po -rm -f ./$(DEPDIR)/parse.Po -rm -f ./$(DEPDIR)/sockets.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man5 install-man8 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/blame.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/bloom.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/buf.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/date.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff3.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_main.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diffreg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fileindex.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/lockfile.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/log.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/patch.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/sigs.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/utf8.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po -rm -f $(top_builddir)/template/$(DEPDIR)/tmpl.Po -rm -f ./$(DEPDIR)/config.Po -rm -f ./$(DEPDIR)/fcgi.Po -rm -f ./$(DEPDIR)/got_operations.Po -rm -f ./$(DEPDIR)/gotweb.Po -rm -f ./$(DEPDIR)/gotwebd.Po -rm -f ./$(DEPDIR)/pages.Po -rm -f ./$(DEPDIR)/parse.Po -rm -f ./$(DEPDIR)/sockets.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-man uninstall-sbinPROGRAMS uninstall-man: uninstall-man5 uninstall-man8 .MAKE: all check install install-am install-exec install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-sbinPROGRAMS cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-man5 install-man8 install-pdf install-pdf-am \ install-ps install-ps-am install-sbinPROGRAMS install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-man uninstall-man5 uninstall-man8 \ uninstall-sbinPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common pages.c: $(top_srcdir)/gotwebd/pages.tmpl ${MAKE} -C $(top_builddir)/template $(top_builddir)/template/template -o pages.c $(top_srcdir)/gotwebd/pages.tmpl #realinstall: # if [ ! -d ${DESTDIR}${PUB_REPOS_DIR}/. ]; then \ # ${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${PUB_REPOS_DIR}; \ # fi # ${INSTALL} -c -o root -g daemon -m 0755 ${PROG} ${BINDIR}/${PROG} # if [ ! -d ${DESTDIR}${HTTPD_DIR}/. ]; then \ # ${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${HTTPD_DIR}; \ # fi # if [ ! -d ${DESTDIR}${PROG_DIR}/. ]; then \ # ${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${PROG_DIR}; \ # fi # ${INSTALL} -c -o ${WWWUSR} -g ${WWWGRP} -m 0755 \ # ${.CURDIR}/files/htdocs/${PROG}/* ${DESTDIR}${PROG_DIR} # #.include # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/gotwebd/gotwebd.80000664000175100017510000001046614644143163012773 .\" .\" Copyright (c) 2020 Stefan Sperling .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt GOTWEBD 8 .Os .Sh NAME .Nm gotwebd .Nd Game of Trees FastCGI server for web browsers .Sh SYNOPSIS .Nm .Op Fl dnv .Op Fl D Ar macro Ns = Ns Ar value .Op Fl f Ar file .Sh DESCRIPTION .Nm is a FastCGI server program which can display the contents of Git repositories via a web browser. The program has been designed to work out of the box with the .Xr httpd 8 web server. .Pp .Nm provides the following options: .Bl -tag -width tenletters .It Fl D Ar macro Ns = Ns Ar value Define .Ar macro to be set to .Ar value . Overrides the definition of .Ar macro in the configuration file. .It Fl d Do not daemonize. Send log output to stderr. .It Fl f Ar file Set the path to the configuration file. If not specified, the file .Pa /etc/gotwebd.conf will be used. .It Fl n Parse the configuration file, report errors if any, and exit. .It Fl v Verbose mode. Verbosity increases if this option is used multiple times. .El .Pp Enabling .Nm requires the following steps: .Bl -enum .It The .Xr httpd.conf 5 configuration file must be adjusted to run .Nm as a FastCGI helper program. The .Sx EXAMPLES section below contains an appropriate configuration file sample. .It httpd(8) must be enabled and started: .Bd -literal -offset indent # rcctl enable httpd # rcctl start httpd .Ed .It Optionally, the run-time behaviour of .Nm can be configured via the .Xr gotwebd.conf 5 configuration file. .It Git repositories must be created at a suitable location inside the web server's .Xr chroot 2 environment. These repositories should .Em not be writable by the user ID shared between .Nm and .Xr httpd 8 . The default location for repositories published by .Nm is .Pa /var/www/got/public . .It Git repositories served by .Nm should be kept up-to-date with a mechanism such as .Cm got fetch , .Xr git-fetch 1 , or .Xr rsync 1 , scheduled by .Xr cron 8 . .El .Sh FILES .Bl -tag -width /var/www/got/public/ -compact .It Pa /etc/gotwebd.conf Default location of the .Xr gotwebd.conf 5 configuration file. .It Pa /var/www/got/public/ Default location for Git repositories served by .Nm . This location can be adjusted in the .Xr gotwebd.conf 5 configuration file. .It Pa /var/www/bin/gotwebd/ Directory containing statically linked .Xr got 1 helper programs which are run by .Nm to read Git repositories. .It Pa /var/www/htdocs/gotwebd/ Directory containing HTML, CSS, and image files used by .Nm . .It Pa /var/www/run/gotweb.sock Default location for the .Nm listening socket. .It Pa /tmp/ Directory for temporary files created by .Nm . .El .Sh EXAMPLES Example configuration for .Xr httpd.conf 5 : .Bd -literal -offset indent types { include "/usr/share/misc/mime.types" } server "example.com" { listen on * port 80 root "/htdocs/gotwebd" location "/" { fastcgi socket "/run/gotweb.sock" } } .Ed .Pp Hosting multiple .Nm gotwebd instances on the same HTTP server under different path prefixes, with the first reached via the default .Ux Ns -domain socket, the second configured to listen on localhost port 9000: .Bd -literal -offset indent server "example.com" { listen on * port 80 location "/gotwebd-unix/" { fastcgi socket "/run/gotweb.sock" } location "/gotwebd-unix/*" { root "/htdocs/gotwebd" request strip 1 } location "/gotwebd-tcp/" { fastcgi socket tcp localhost 9000 } location "/gotwebd-tcp/*" { root "/htdocs/gotwebd" request strip 1 } } .Ed .Sh SEE ALSO .Xr got 1 , .Xr git-repository 5 , .Xr gotwebd.conf 5 , .Xr httpd.conf 5 , .Xr httpd 8 .Sh AUTHORS .An Omar Polo Aq Mt op@openbsd.org .An Stefan Sperling Aq Mt stsp@openbsd.org .An Tracey Emery Aq Mt tracey@traceyemery.net got-portable-0.101/gotwebd/pages.tmpl0000664000175100017510000010136614644144735013252 {! /* * Copyright (c) 2022 Omar Polo * Copyright (c) 2016, 2019, 2020-2022 Tracey Emery * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_reference.h" #include "gotwebd.h" #include "log.h" #include "tmpl.h" enum gotweb_ref_tm { TM_DIFF, TM_LONG, }; static int breadcumbs(struct template *); static int datetime(struct template *, time_t, int); static int gotweb_render_blob_line(struct template *, const char *, size_t); static int gotweb_render_tree_item(struct template *, struct got_tree_entry *); static int blame_line(struct template *, const char *, struct blame_line *, int, int); static inline int gotweb_render_more(struct template *, int); static inline int tree_listing(struct template *); static inline int diff_line(struct template *, char *); static inline int tag_item(struct template *, struct repo_tag *); static inline int branch(struct template *, struct got_reflist_entry *); static inline int rss_tag_item(struct template *, struct repo_tag *); static inline int rss_author(struct template *, char *); static inline char * nextsep(char *s, char **t) { char *q; while (*s == '/') s++; *t = s; if (*s == '\0') return NULL; q = strchr(s, '/'); if (q == NULL) q = strchr(s, '\0'); return q; } !} {{ define datetime(struct template *tp, time_t t, int fmt) }} {! struct tm tm; char rfc3339[64]; char datebuf[64]; if (gmtime_r(&t, &tm) == NULL) return -1; if (strftime(rfc3339, sizeof(rfc3339), "%FT%TZ", &tm) == 0) return -1; if (fmt != TM_DIFF && asctime_r(&tm, datebuf) == NULL) return -1; !} {{ end }} {{ define breadcumbs(struct template *tp) }} {! struct request *c = tp->tp_arg; struct querystring *qs = c->t->qs; struct gotweb_url url; const char *folder = qs->folder; const char *action = "tree"; char *t, *s = NULL, *dir = NULL; char ch; memset(&url, 0, sizeof(url)); url.index_page = -1; url.action = TREE; url.path = qs->path; url.commit = qs->commit; if (qs->action != TREE && qs->action != BLOB) { action = gotweb_action_name(qs->action); url.action = qs->action; } if (folder && *folder != '\0') { while (*folder == '/') folder++; dir = strdup(folder); if (dir == NULL) return (-1); s = dir; } !} {{ " / " }} {{ action }} {{ " / " }} {{ if dir }} {{ while (s = nextsep(s, &t)) != NULL }} {! ch = *s; *s = '\0'; url.folder = dir; !} {{ t }} {{ " / " }} {! *s = ch; !} {{ end }} {{ end }} {{ if qs->file }} {{ qs->file }} {{ end}} {{ finally }} {! free(dir); !} {{ end }} {{ define gotweb_render_page(struct template *tp, int (*body)(struct template *)) }} {! struct request *c = tp->tp_arg; struct server *srv = c->srv; struct querystring *qs = c->t->qs; struct gotweb_url u_path; const char *prfx = c->document_uri; const char *css = srv->custom_css; memset(&u_path, 0, sizeof(u_path)); u_path.index_page = -1; u_path.action = SUMMARY; !} {{ srv->site_name }}
{{ render body(tp) }}

{{ if srv->show_site_owner }} {{ srv->site_owner }} {{ end }}

{{ end }} {{ define gotweb_render_error(struct template *tp) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; !}
{{ if t->error }} {{ t->error->msg }} {{ else }} See daemon logs for details {{ end }}
{{ end }} {{ define gotweb_render_repo_table_hdr(struct template *tp) }} {! struct request *c = tp->tp_arg; struct server *srv = c->srv; !}
Project
{{ if srv->show_repo_description }}
Description
{{ end }} {{ if srv->show_repo_owner }}
Owner
{{ end }} {{ if srv->show_repo_age }}
Last Change
{{ end }}
{{ end }} {{ define gotweb_render_repo_fragment(struct template *tp, struct repo_dir *repo_dir) }} {! struct request *c = tp->tp_arg; struct server *srv = c->srv; struct gotweb_url summary = { .action = SUMMARY, .index_page = -1, .path = repo_dir->name, }, briefs = { .action = BRIEFS, .index_page = -1, .path = repo_dir->name, }, commits = { .action = COMMITS, .index_page = -1, .path = repo_dir->name, }, tags = { .action = TAGS, .index_page = -1, .path = repo_dir->name, }, tree = { .action = TREE, .index_page = -1, .path = repo_dir->name, }, rss = { .action = RSS, .index_page = -1, .path = repo_dir->name, }; !}
{{ if srv->show_repo_description }}
{{ repo_dir->description }}
{{ end }} {{ if srv->show_repo_owner }}
{{ repo_dir->owner }}
{{ end }} {{ if srv->show_repo_age }}
{{ render datetime(tp, repo_dir->age, TM_DIFF) }}
{{ end }}
{{ end }} {{ define gotweb_render_briefs(struct template *tp) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct querystring *qs = c->t->qs; struct repo_commit *rc; struct repo_dir *repo_dir = t->repo_dir; struct gotweb_url diff_url, patch_url, tree_url; char *tmp, *body; diff_url = (struct gotweb_url){ .action = DIFF, .index_page = -1, .path = repo_dir->name, .headref = qs->headref, }; patch_url = (struct gotweb_url){ .action = PATCH, .index_page = -1, .path = repo_dir->name, .headref = qs->headref, }; tree_url = (struct gotweb_url){ .action = TREE, .index_page = -1, .path = repo_dir->name, .headref = qs->headref, }; !}

Commit Briefs

{{ tailq-foreach rc &t->repo_commits entry }} {! diff_url.commit = rc->commit_id; patch_url.commit = rc->commit_id; tree_url.commit = rc->commit_id; tmp = strchr(rc->committer, '<'); if (tmp) *tmp = '\0'; body = strchr(rc->commit_msg, '\n'); if (body) { *body++ = '\0'; while (*body == '\n') body++; } !}

{{ render datetime(tp, rc->committer_time, TM_DIFF) }} {{" "}} {{ rc->committer }}

{{ if body && *body != '\0' }}
{{ rc->commit_msg }} {{ if rc->refs_str }} {{ " " }} ({{ rc->refs_str }}) {{ end }} {{ " " }} {{ "\n" }}

{{ body }}

{{ else }}

{{ rc->commit_msg }} {{ if rc->refs_str }} {{ " " }} ({{ rc->refs_str }}) {{ end }}

{{ end }}

{{ end }} {{ render gotweb_render_more(tp, BRIEFS) }}
{{ end }} {{ define gotweb_render_more(struct template *tp, int action) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct querystring *qs = t->qs; struct gotweb_url more = { .action = action, .index_page = -1, .path = qs->path, .commit = t->more_id, .headref = qs->headref, .file = qs->file, }; if (action == TAGS) more.commit = t->tags_more_id; !} {{ if more.commit }} {{ end }} {{ end }} {{ define gotweb_render_navs(struct template *tp) }} {! struct request *c = tp->tp_arg; struct gotweb_url prev, next; int have_prev, have_next; gotweb_index_navs(c, &prev, &have_prev, &next, &have_next); !}
{{ end }} {{ define gotweb_render_commits(struct template *tp) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_dir *repo_dir = t->repo_dir; struct repo_commit *rc; struct gotweb_url diff, patch, tree; diff = (struct gotweb_url){ .action = DIFF, .index_page = -1, .path = repo_dir->name, }; patch = (struct gotweb_url){ .action = PATCH, .index_page = -1, .path = repo_dir->name, }; tree = (struct gotweb_url){ .action = TREE, .index_page = -1, .path = repo_dir->name, }; !}

Commits

{{ tailq-foreach rc &t->repo_commits entry }} {! diff.commit = rc->commit_id; patch.commit = rc->commit_id; tree.commit = rc->commit_id; !}
{{ "\n" }} {{ rc->commit_msg }}

{{ end }} {{ render gotweb_render_more(tp, COMMITS) }}
{{ end }} {{ define gotweb_render_blob(struct template *tp) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct querystring *qs = t->qs; struct got_blob_object *blob = t->blob; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); struct gotweb_url briefs_url, blame_url, raw_url; memset(&briefs_url, 0, sizeof(briefs_url)); briefs_url.index_page = -1, briefs_url.action = BRIEFS, briefs_url.path = qs->path, briefs_url.commit = qs->commit, briefs_url.folder = qs->folder, briefs_url.file = qs->file, memcpy(&blame_url, &briefs_url, sizeof(blame_url)); blame_url.action = BLAME; memcpy(&raw_url, &briefs_url, sizeof(raw_url)); raw_url.action = BLOBRAW; !}

Blob


      {{ render got_output_blob_by_lines(tp, blob, gotweb_render_blob_line) }}
    
{{ end }} {{ define gotweb_render_blob_line(struct template *tp, const char *line, size_t no) }} {! char lineno[16]; int r; r = snprintf(lineno, sizeof(lineno), "%zu", no); if (r < 0 || (size_t)r >= sizeof(lineno)) return -1; !}
{{ lineno }}{{" "}} {{ line }}
{{ end }} {{ define tree_listing(struct template *tp) }} {! const struct got_error *error; struct request *c = tp->tp_arg; struct transport *t = c->t; struct querystring *qs = c->t->qs; struct gotweb_url url; char *readme = NULL; int binary; const uint8_t *buf; size_t len; !} {{ render got_output_repo_tree(c, &readme, gotweb_render_tree_item) }}
{{ if readme }} {! error = got_open_blob_for_output(&t->blob, &t->fd, &binary, c, qs->folder, readme, qs->commit); if (error) { free(readme); return (-1); } memset(&url, 0, sizeof(url)); url.index_page = -1; url.action = BLOB; url.path = t->qs->path; url.file = readme; url.folder = t->qs->folder; url.commit = t->qs->commit; !} {{ if !binary }}

{{ readme }}

        {!
		for (;;) {
			error = got_object_blob_read_block(&len, t->blob);
			if (error) {
				free(readme);
				return (-1);
			}
			if (len == 0)
				break;
			buf = got_object_blob_get_read_buf(t->blob);
			if (tp_write_htmlescape(tp, buf, len) == -1) {
				free(readme);
				return (-1);
			}
		}
        !}
      
{{ end }} {{ end }} {{ finally }} {! free(readme); !} {{ end }} {{ define gotweb_render_tree(struct template *tp) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); !}

Tree


{{ render tree_listing(tp) }}
{{ end }} {{ define gotweb_render_tree_item(struct template *tp, struct got_tree_entry *te) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct querystring *qs = t->qs; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); const char *modestr = ""; const char *name; const char *folder; char *dir = NULL; mode_t mode; struct gotweb_url url = { .index_page = -1, .commit = rc->commit_id, .path = qs->path, }; name = got_tree_entry_get_name(te); mode = got_tree_entry_get_mode(te); folder = qs->folder ? qs->folder : ""; if (S_ISDIR(mode)) { if (asprintf(&dir, "%s/%s", folder, name) == -1) return (-1); url.action = TREE; url.folder = dir; } else { url.action = BLOB; url.folder = folder; url.file = name; } if (got_object_tree_entry_is_submodule(te)) modestr = "$"; else if (S_ISLNK(mode)) modestr = "@"; else if (S_ISDIR(mode)) modestr = "/"; else if (mode & S_IXUSR) modestr = "*"; !} {{ if S_ISDIR(mode) }} {{ name }}{{ modestr }} {{ else }} {{ name }}{{ modestr }} {! url.action = COMMITS; !} commits {{ " | " }} {! url.action = BLAME; !} blame {{ end }} {{ finally }} {! free(dir); !} {{ end }} {{ define gotweb_render_tags(struct template *tp) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct querystring *qs = t->qs; struct repo_tag *rt; int commit_found; commit_found = qs->commit == NULL; !}

Tags

{{ if t->tag_count == 0 }}
This repository contains no tags
{{ else }} {{ tailq-foreach rt &t->repo_tags entry }} {{ if commit_found || !strcmp(qs->commit, rt->commit_id) }} {! commit_found = 1; !} {{ render tag_item(tp, rt) }} {{ end }} {{ end }} {{ render gotweb_render_more(tp, TAGS) }} {{ end }}
{{ end }} {{ define tag_item(struct template *tp, struct repo_tag *rt) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_dir *repo_dir = t->repo_dir; char *tag_name = rt->tag_name; char *msg = rt->tag_commit; char *nl; struct gotweb_url url = { .action = TAG, .index_page = -1, .path = repo_dir->name, .commit = rt->commit_id, }; if (strncmp(tag_name, "refs/tags/", 10) == 0) tag_name += 10; if (msg) { nl = strchr(msg, '\n'); if (nl) *nl = '\0'; } !}
{{ render datetime(tp, rt->tagger_time, TM_DIFF) }}
{{ tag_name }}

{{ end }} {{ define gotweb_render_tag(struct template *tp) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_tag *rt; const char *tag_name; rt = TAILQ_LAST(&t->repo_tags, repo_tags_head); tag_name = rt->tag_name; if (strncmp(tag_name, "refs/", 5) == 0) tag_name += 5; !}

Tag

{{ end }} {{ define gotweb_render_diff(struct template *tp) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct querystring *qs = t->qs; FILE *fp = t->fp; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); char *line = NULL; size_t linesize = 0; ssize_t linelen; struct gotweb_url patch_url, tree_url = { .action = TREE, .index_page = -1, .path = qs->path, .commit = rc->commit_id, }; memcpy(&patch_url, &tree_url, sizeof(patch_url)); patch_url.action = PATCH; !}

Commit Diff


    {{ while (linelen = getline(&line, &linesize, fp)) != -1 }}
      {{ render diff_line(tp, line) }}
    {{ end }}
  
{{ finally }} {! free(line); !} {{ end }} {{ define diff_line(struct template *tp, char *line )}} {! const char *color = NULL; char *nl; if (!strncmp(line, "-", 1)) color = "diff_minus"; else if (!strncmp(line, "+", 1)) color = "diff_plus"; else if (!strncmp(line, "@@", 2)) color = "diff_chunk_header"; else if (!strncmp(line, "commit +", 8) || !strncmp(line, "commit -", 8) || !strncmp(line, "blob +", 6) || !strncmp(line, "blob -", 6) || !strncmp(line, "file +", 6) || !strncmp(line, "file -", 6)) color = "diff_meta"; else if (!strncmp(line, "from:", 5) || !strncmp(line, "via:", 4)) color = "diff_author"; else if (!strncmp(line, "date:", 5)) color = "diff_date"; nl = strchr(line, '\n'); if (nl) *nl = '\0'; !} {{ line }}{{"\n"}} {{ end }} {{ define gotweb_render_branches(struct template *tp, struct got_reflist_head *refs) }} {! struct got_reflist_entry *re; !}

Branches

{{ tailq-foreach re refs entry }} {{ if !got_ref_is_symbolic(re->ref) }} {{ render branch(tp, re) }} {{ end }} {{ end }}
{{ end }} {{ define branch(struct template *tp, struct got_reflist_entry *re) }} {! const struct got_error *err; struct request *c = tp->tp_arg; struct querystring *qs = c->t->qs; const char *refname; time_t age; struct gotweb_url url = { .action = SUMMARY, .index_page = -1, .path = qs->path, }; refname = got_ref_get_name(re->ref); err = got_get_repo_age(&age, c, refname); if (err) { log_warnx("%s: %s", __func__, err->msg); return -1; } if (strncmp(refname, "refs/heads/", 11) == 0) refname += 11; url.headref = refname; !}
{{ render datetime(tp, age, TM_DIFF) }}

{{ end }} {{ define gotweb_render_summary(struct template *tp) }} {! struct request *c = tp->tp_arg; struct server *srv = c->srv; struct transport *t = c->t; struct got_reflist_head *refs = &t->refs; !} {{ render gotweb_render_briefs(tp) }} {{ render gotweb_render_branches(tp, refs) }} {{ render gotweb_render_tags(tp) }}

Tree

{{ render tree_listing(tp) }}
{{ end }} {{ define gotweb_render_blame(struct template *tp) }} {! const struct got_error *err; struct request *c = tp->tp_arg; struct transport *t = c->t; struct querystring *qs = t->qs; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); struct gotweb_url briefs_url, blob_url, raw_url; memset(&briefs_url, 0, sizeof(briefs_url)); briefs_url.index_page = -1, briefs_url.action = BRIEFS, briefs_url.path = qs->path, briefs_url.commit = qs->commit, briefs_url.folder = qs->folder, briefs_url.file = qs->file, memcpy(&blob_url, &briefs_url, sizeof(blob_url)); blob_url.action = BLOB; memcpy(&raw_url, &briefs_url, sizeof(raw_url)); raw_url.action = BLOBRAW; !}

Blame


    {!
	err = got_output_file_blame(c, &blame_line);
	if (err && err->code != GOT_ERR_CANCELLED)
		log_warnx("%s: got_output_file_blame: %s", __func__,
		    err->msg);
	if (err)
		return (-1);
    !}
  
{{ end }} {{ define blame_line(struct template *tp, const char *line, struct blame_line *bline, int lprec, int lcur) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_dir *repo_dir = t->repo_dir; char *committer, *s; struct gotweb_url url = { .action = DIFF, .index_page = -1, .path = repo_dir->name, .commit = bline->id_str, }; s = strchr(bline->committer, '<'); committer = s ? s + 1 : bline->committer; s = strchr(committer, '@'); if (s) *s = '\0'; !}
{{ printf "%*d ", lprec, lcur }} {{ printf "%.8s", bline->id_str }} {{" "}} {{ bline->datebuf }} {{" "}} {{ printf "%.9s", committer }} {{" "}} {{ line }}
{{ end }} {{ define gotweb_render_patch(struct template *tp) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); struct tm tm; char buf[BUFSIZ], datebuf[64]; size_t r; if (gmtime_r(&rc->committer_time, &tm) == NULL || strftime(datebuf, sizeof(datebuf), "%a %b %d %T %Y UTC", &tm) == 0) return (-1); !} commit {{ rc->commit_id }} {{ "\n" }} from: {{ rc->author | unsafe }} {{ "\n" }} {{ if strcmp(rc->committer, rc->author) != 0 }} via: {{ rc->committer | unsafe }} {{ "\n" }} {{ end }} date: {{ datebuf }} {{ "\n" }} {{ "\n" }} {{ rc->commit_msg | unsafe }} {{ "\n" }} {! if (template_flush(tp) == -1) return (-1); for (;;) { r = fread(buf, 1, sizeof(buf), t->fp); if (fcgi_write(c, buf, r) == -1 || r != sizeof(buf)) break; } !} {{ end }} {{ define gotweb_render_rss(struct template *tp) }} {! struct request *c = tp->tp_arg; struct server *srv = c->srv; struct transport *t = c->t; struct repo_dir *repo_dir = t->repo_dir; struct repo_tag *rt; struct gotweb_url summary = { .action = SUMMARY, .index_page = -1, .path = repo_dir->name, }; !} Tags of {{ repo_dir->name }} {{ if srv->show_repo_description }} {{ repo_dir->description }} {{ end }} {{ tailq-foreach rt &t->repo_tags entry }} {{ render rss_tag_item(tp, rt) }} {{ end }} {{ end }} {{ define rss_tag_item(struct template *tp, struct repo_tag *rt) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_dir *repo_dir = t->repo_dir; struct tm tm; char rfc822[128]; int r; char *tag_name = rt->tag_name; struct gotweb_url tag = { .action = TAG, .index_page = -1, .path = repo_dir->name, .commit = rt->commit_id, }; if (strncmp(tag_name, "refs/tags/", 10) == 0) tag_name += 10; if (gmtime_r(&rt->tagger_time, &tm) == NULL) return -1; r = strftime(rfc822, sizeof(rfc822), "%a, %d %b %Y %H:%M:%S GMT", &tm); if (r == 0) return 0; !} {{ repo_dir->name }} {{" "}} {{ tag_name }} {{ rt->tag_commit }}]]> {{ render rss_author(tp, rt->tagger) }} {{ rt->commit_id }} {{ rfc822 }} {{ end }} {{ define rss_author(struct template *tp, char *author) }} {! char *t, *mail; /* what to do if the author name contains a paren? */ if (strchr(author, '(') != NULL || strchr(author, ')') != NULL) return 0; t = strchr(author, '<'); if (t == NULL) return 0; *t = '\0'; mail = t+1; while (isspace((unsigned char)*--t)) *t = '\0'; t = strchr(mail, '>'); if (t == NULL) return 0; *t = '\0'; !} {{ mail }} {{" "}} ({{ author }}) {{ end }} got-portable-0.101/gotwebd/fcgi.c0000664000175100017510000002400514644144735012323 /* * Copyright (c) 2020-2022 Tracey Emery * Copyright (c) 2013 David Gwynne * Copyright (c) 2013 Florian Obser * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_reference.h" #include "gotwebd.h" #include "log.h" #include "tmpl.h" size_t fcgi_parse_record(uint8_t *, size_t, struct request *); void fcgi_parse_begin_request(uint8_t *, uint16_t, struct request *, uint16_t); void fcgi_parse_params(uint8_t *, uint16_t, struct request *, uint16_t); int fcgi_send_response(struct request *, int, const void *, size_t); void dump_fcgi_record_header(const char *, struct fcgi_record_header *); void dump_fcgi_begin_request_body(const char *, struct fcgi_begin_request_body *); void dump_fcgi_end_request_body(const char *, struct fcgi_end_request_body *); extern int cgi_inflight; extern volatile int client_cnt; void fcgi_request(int fd, short events, void *arg) { struct request *c = arg; ssize_t n; size_t parsed = 0; n = read(fd, c->buf + c->buf_pos + c->buf_len, FCGI_RECORD_SIZE - c->buf_pos-c->buf_len); switch (n) { case -1: switch (errno) { case EINTR: case EAGAIN: return; default: goto fail; } break; case 0: log_debug("closed connection"); goto fail; default: break; } c->buf_len += n; /* * Parse the records as they are received. Per the FastCGI * specification, the server need only receive the FastCGI * parameter records in full; it is free to begin execution * at that point, which is what happens here. */ do { parsed = fcgi_parse_record(c->buf + c->buf_pos, c->buf_len, c); if (parsed != 0) { c->buf_pos += parsed; c->buf_len -= parsed; } /* drop the parsed record */ if (parsed != 0 && c->buf_len > 0) { bcopy(c->buf + c->buf_pos, c->buf, c->buf_len); c->buf_pos = 0; } } while (parsed > 0 && c->buf_len > 0); return; fail: fcgi_cleanup_request(c); } size_t fcgi_parse_record(uint8_t *buf, size_t n, struct request *c) { struct fcgi_record_header *h; if (n < sizeof(struct fcgi_record_header)) return 0; h = (struct fcgi_record_header*) buf; dump_fcgi_record("", h); if (n < sizeof(struct fcgi_record_header) + ntohs(h->content_len) + h->padding_len) return 0; if (h->version != 1) log_warn("wrong version"); switch (h->type) { case FCGI_BEGIN_REQUEST: fcgi_parse_begin_request(buf + sizeof(struct fcgi_record_header), ntohs(h->content_len), c, ntohs(h->id)); break; case FCGI_PARAMS: fcgi_parse_params(buf + sizeof(struct fcgi_record_header), ntohs(h->content_len), c, ntohs(h->id)); break; case FCGI_STDIN: case FCGI_ABORT_REQUEST: fcgi_create_end_record(c); fcgi_cleanup_request(c); return 0; default: log_warn("unimplemented type %d", h->type); break; } return (sizeof(struct fcgi_record_header) + ntohs(h->content_len) + h->padding_len); } void fcgi_parse_begin_request(uint8_t *buf, uint16_t n, struct request *c, uint16_t id) { /* XXX -- FCGI_CANT_MPX_CONN */ if (c->request_started) { log_warn("unexpected FCGI_BEGIN_REQUEST, ignoring"); return; } if (n != sizeof(struct fcgi_begin_request_body)) { log_warn("wrong size %d != %lu", n, sizeof(struct fcgi_begin_request_body)); return; } c->request_started = 1; c->id = id; } void fcgi_parse_params(uint8_t *buf, uint16_t n, struct request *c, uint16_t id) { uint32_t name_len, val_len; uint8_t *val; if (!c->request_started) { log_warn("FCGI_PARAMS without FCGI_BEGIN_REQUEST, ignoring"); return; } if (c->id != id) { log_warn("unexpected id, ignoring"); return; } if (n == 0) { gotweb_process_request(c); template_flush(c->tp); return; } while (n > 0) { if (buf[0] >> 7 == 0) { name_len = buf[0]; n--; buf++; } else { if (n > 3) { name_len = ((buf[0] & 0x7f) << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]; n -= 4; buf += 4; } else return; } if (n == 0) return; if (buf[0] >> 7 == 0) { val_len = buf[0]; n--; buf++; } else { if (n > 3) { val_len = ((buf[0] & 0x7f) << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]; n -= 4; buf += 4; } else return; } if (n < name_len + val_len) return; val = buf + name_len; if (val_len < MAX_QUERYSTRING && name_len == 12 && strncmp(buf, "QUERY_STRING", 12) == 0) { memcpy(c->querystring, val, val_len); c->querystring[val_len] = '\0'; } if (val_len < MAX_DOCUMENT_URI && name_len == 12 && strncmp(buf, "DOCUMENT_URI", 12) == 0) { memcpy(c->document_uri, val, val_len); c->document_uri[val_len] = '\0'; } if (val_len < MAX_SERVER_NAME && name_len == 11 && strncmp(buf, "SERVER_NAME", 11) == 0) { memcpy(c->server_name, val, val_len); c->server_name[val_len] = '\0'; } if (name_len == 5 && strncmp(buf, "HTTPS", 5) == 0) c->https = 1; buf += name_len + val_len; n -= name_len - val_len; } } void fcgi_timeout(int fd, short events, void *arg) { fcgi_cleanup_request((struct request*) arg); } static int send_response(struct request *c, int type, const uint8_t *data, size_t len) { static const uint8_t padding[FCGI_PADDING_SIZE]; struct fcgi_record_header header; struct iovec iov[3]; struct timespec ts; ssize_t nw; size_t padded_len, tot; int i, err = 0, th = 2000; ts.tv_sec = 0; ts.tv_nsec = 50; memset(&header, 0, sizeof(header)); header.version = 1; header.type = type; header.id = htons(c->id); header.content_len = htons(len); /* The FastCGI spec suggests to align the output buffer */ tot = sizeof(header) + len; padded_len = FCGI_ALIGN(tot); if (padded_len > tot) { header.padding_len = padded_len - tot; tot += header.padding_len; } iov[0].iov_base = &header; iov[0].iov_len = sizeof(header); iov[1].iov_base = (void *)data; iov[1].iov_len = len; iov[2].iov_base = (void *)padding; iov[2].iov_len = header.padding_len; dump_fcgi_record("resp ", &header); /* * XXX: add some simple write heuristics here * On slower VMs, spotty connections, etc., we don't want to go right to * disconnect. Let's at least try to write the data a few times before * giving up. */ while (tot > 0) { nw = writev(c->fd, iov, nitems(iov)); if (nw == 0) { c->sock->client_status = CLIENT_DISCONNECT; break; } if (nw == -1) { err++; if (errno == EAGAIN && err < th) { nanosleep(&ts, NULL); continue; } log_debug("%s: write failure: %s", __func__, strerror(errno)); c->sock->client_status = CLIENT_DISCONNECT; return -1; } if (nw != tot) log_debug("%s: partial write: %zu vs %zu", __func__, nw, tot); tot -= nw; for (i = 0; i < nitems(iov); ++i) { if (nw < iov[i].iov_len) { iov[i].iov_base += nw; iov[i].iov_len -= nw; break; } nw -= iov[i].iov_len; iov[i].iov_len = 0; } } return 0; } int fcgi_send_response(struct request *c, int type, const void *data, size_t len) { if (c->sock->client_status == CLIENT_DISCONNECT) return -1; while (len > FCGI_CONTENT_SIZE) { if (send_response(c, type, data, len) == -1) return -1; data += FCGI_CONTENT_SIZE; len -= FCGI_CONTENT_SIZE; } if (len == 0) return 0; return send_response(c, type, data, len); } int fcgi_write(void *arg, const void *buf, size_t len) { struct request *c = arg; return fcgi_send_response(c, FCGI_STDOUT, buf, len); } void fcgi_create_end_record(struct request *c) { struct fcgi_end_request_body end_request; memset(&end_request, 0, sizeof(end_request)); end_request.app_status = htonl(0); /* script status */ end_request.protocol_status = FCGI_REQUEST_COMPLETE; fcgi_send_response(c, FCGI_END_REQUEST, &end_request, sizeof(end_request)); } void fcgi_cleanup_request(struct request *c) { cgi_inflight--; client_cnt--; evtimer_del(&c->tmo); if (event_initialized(&c->ev)) event_del(&c->ev); close(c->fd); template_free(c->tp); if (c->t != NULL) gotweb_free_transport(c->t); free(c); } void dump_fcgi_record(const char *p, struct fcgi_record_header *h) { dump_fcgi_record_header(p, h); if (h->type == FCGI_BEGIN_REQUEST) dump_fcgi_begin_request_body(p, (struct fcgi_begin_request_body *)(h + 1)); else if (h->type == FCGI_END_REQUEST) dump_fcgi_end_request_body(p, (struct fcgi_end_request_body *)(h + 1)); } void dump_fcgi_record_header(const char* p, struct fcgi_record_header *h) { log_debug("%sversion: %d", p, h->version); log_debug("%stype: %d", p, h->type); log_debug("%srequestId: %d", p, ntohs(h->id)); log_debug("%scontentLength: %d", p, ntohs(h->content_len)); log_debug("%spaddingLength: %d", p, h->padding_len); log_debug("%sreserved: %d", p, h->reserved); } void dump_fcgi_begin_request_body(const char *p, struct fcgi_begin_request_body *b) { log_debug("%srole %d", p, ntohs(b->role)); log_debug("%sflags %d", p, b->flags); } void dump_fcgi_end_request_body(const char *p, struct fcgi_end_request_body *b) { log_debug("%sappStatus: %d", p, ntohl(b->app_status)); log_debug("%sprotocolStatus: %d", p, b->protocol_status); } got-portable-0.101/gotwebd/gotwebd.c0000664000175100017510000002544614644144735013060 /* * Copyright (c) 2016, 2019, 2020-2021 Tracey Emery * Copyright (c) 2015 Reyk Floeter * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_opentemp.h" #include "got_reference.h" #include "gotwebd.h" #include "log.h" __dead void usage(void); int main(int, char **); int gotwebd_configure(struct gotwebd *); void gotwebd_configure_done(struct gotwebd *); void gotwebd_sighdlr(int sig, short event, void *arg); void gotwebd_shutdown(void); void gotwebd_dispatch_sockets(int, short, void *); struct gotwebd *gotwebd_env; void imsg_event_add(struct imsgev *iev) { if (iev->handler == NULL) { imsg_flush(&iev->ibuf); return; } iev->events = EV_READ; if (iev->ibuf.w.queued) iev->events |= EV_WRITE; event_del(&iev->ev); event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data); event_add(&iev->ev, NULL); } int imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, pid_t pid, int fd, const void *data, uint16_t datalen) { int ret; ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, datalen); if (ret == -1) return (ret); imsg_event_add(iev); return (ret); } int main_compose_sockets(struct gotwebd *env, uint32_t type, int fd, const void *data, uint16_t len) { size_t i; int ret, d; for (i = 0; i < env->nserver; ++i) { d = -1; if (fd != -1 && (d = dup(fd)) == -1) goto err; ret = imsg_compose_event(&env->iev_server[i], type, 0, -1, d, data, len); if (ret == -1) goto err; /* prevent fd exhaustion */ if (d != -1) { do { ret = imsg_flush(&env->iev_server[i].ibuf); } while (ret == -1 && errno == EAGAIN); if (ret == -1) goto err; imsg_event_add(&env->iev_server[i]); } } if (fd != -1) close(fd); return 0; err: if (fd != -1) close(fd); return -1; } int sockets_compose_main(struct gotwebd *env, uint32_t type, const void *d, uint16_t len) { return (imsg_compose_event(env->iev_parent, type, 0, -1, -1, d, len)); } void gotwebd_dispatch_sockets(int fd, short event, void *arg) { struct imsgev *iev = arg; struct imsgbuf *ibuf; struct imsg imsg; struct gotwebd *env = gotwebd_env; ssize_t n; int shut = 0; ibuf = &iev->ibuf; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) /* Connection closed */ shut = 1; } if (event & EV_WRITE) { if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) fatal("msgbuf_write"); if (n == 0) /* Connection closed */ shut = 1; } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("imsg_get"); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case IMSG_CFG_DONE: gotwebd_configure_done(env); break; default: fatalx("%s: unknown imsg type %d", __func__, imsg.hdr.type); } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void gotwebd_sighdlr(int sig, short event, void *arg) { /* struct privsep *ps = arg; */ switch (sig) { case SIGHUP: log_info("%s: ignoring SIGHUP", __func__); break; case SIGPIPE: log_info("%s: ignoring SIGPIPE", __func__); break; case SIGUSR1: log_info("%s: ignoring SIGUSR1", __func__); break; case SIGTERM: case SIGINT: gotwebd_shutdown(); break; default: fatalx("unexpected signal"); } } static int spawn_socket_process(struct gotwebd *env, const char *argv0, int n) { const char *argv[6]; int argc = 0; int p[2]; pid_t pid; if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, p) == -1) fatal("socketpair"); switch (pid = fork()) { case -1: fatal("fork"); case 0: /* child */ break; default: /* parent */ close(p[0]); imsg_init(&env->iev_server[n].ibuf, p[1]); env->iev_server[n].handler = gotwebd_dispatch_sockets; env->iev_server[n].data = &env->iev_server[n]; event_set(&env->iev_server[n].ev, p[1], EV_READ, gotwebd_dispatch_sockets, &env->iev_server[n]); event_add(&env->iev_server[n].ev, NULL); return 0; } close(p[1]); argv[argc++] = argv0; argv[argc++] = "-S"; if (env->gotwebd_debug) argv[argc++] = "-d"; if (env->gotwebd_verbose > 0) argv[argc++] = "-v"; if (env->gotwebd_verbose > 1) argv[argc++] = "-v"; argv[argc] = NULL; if (p[0] != GOTWEBD_SOCK_FILENO) { if (dup2(p[0], GOTWEBD_SOCK_FILENO) == -1) fatal("dup2"); } else if (fcntl(p[0], F_SETFD, 0) == -1) fatal("fcntl"); /* obnoxious cast */ execvp(argv0, (char * const *)argv); fatal("execvp %s", argv0); } __dead void usage(void) { fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n", getprogname()); exit(1); } int main(int argc, char **argv) { struct event sigint, sigterm, sighup, sigpipe, sigusr1; struct gotwebd *env; struct passwd *pw; int ch, i; int no_action = 0; int server_proc = 0; const char *conffile = GOTWEBD_CONF; const char *username = GOTWEBD_DEFAULT_USER; const char *argv0; if ((argv0 = argv[0]) == NULL) argv0 = "gotwebd"; /* log to stderr until daemonized */ log_init(1, LOG_DAEMON); env = calloc(1, sizeof(*env)); if (env == NULL) fatal("%s: calloc", __func__); config_init(env); while ((ch = getopt(argc, argv, "D:df:nSv")) != -1) { switch (ch) { case 'D': if (cmdline_symset(optarg) < 0) log_warnx("could not parse macro definition %s", optarg); break; case 'd': env->gotwebd_debug = 1; break; case 'f': conffile = optarg; break; case 'n': no_action = 1; break; case 'S': server_proc = 1; break; case 'v': if (env->gotwebd_verbose < 3) env->gotwebd_verbose++; break; default: usage(); } } argc -= optind; if (argc > 0) usage(); gotwebd_env = env; env->gotwebd_conffile = conffile; if (parse_config(env->gotwebd_conffile, env) == -1) exit(1); if (no_action) { fprintf(stderr, "configuration OK\n"); exit(0); } /* check for root privileges */ if (geteuid()) fatalx("need root privileges"); if (env->user) username = env->user; pw = getpwnam(username); if (pw == NULL) fatalx("unknown user %s", username); env->pw = pw; log_init(env->gotwebd_debug, LOG_DAEMON); log_setverbose(env->gotwebd_verbose); if (server_proc) { setproctitle("sockets"); log_procinit("sockets"); if (chroot(env->httpd_chroot) == -1) fatal("chroot %s", env->httpd_chroot); if (chdir("/") == -1) fatal("chdir /"); if (setgroups(1, &pw->pw_gid) == -1 || setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 || setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) fatal("failed to drop privileges"); sockets(env, GOTWEBD_SOCK_FILENO); return 1; } if (!env->gotwebd_debug && daemon(1, 0) == -1) fatal("daemon"); event_init(); env->nserver = env->prefork_gotwebd; env->iev_server = calloc(env->nserver, sizeof(*env->iev_server)); if (env->iev_server == NULL) fatal("calloc"); for (i = 0; i < env->nserver; ++i) { if (spawn_socket_process(env, argv0, i) == -1) fatal("spawn_socket_process"); } if (chdir("/") == -1) fatal("chdir /"); log_procinit("gotwebd"); log_info("%s startup", getprogname()); signal_set(&sigint, SIGINT, gotwebd_sighdlr, env); signal_set(&sigterm, SIGTERM, gotwebd_sighdlr, env); signal_set(&sighup, SIGHUP, gotwebd_sighdlr, env); signal_set(&sigpipe, SIGPIPE, gotwebd_sighdlr, env); signal_set(&sigusr1, SIGUSR1, gotwebd_sighdlr, env); signal_add(&sigint, NULL); signal_add(&sigterm, NULL); signal_add(&sighup, NULL); signal_add(&sigpipe, NULL); signal_add(&sigusr1, NULL); if (gotwebd_configure(env) == -1) fatalx("configuration failed"); #ifdef PROFILE if (unveil("gmon.out", "rwc") != 0) err(1, "gmon.out"); #endif if (unveil(env->httpd_chroot, "r") == -1) err(1, "unveil"); if (unveil(GOTWEBD_CONF, "r") == -1) err(1, "unveil"); if (unveil(NULL, NULL) != 0) err(1, "unveil"); #ifndef PROFILE if (pledge("stdio", NULL) == -1) err(1, "pledge"); #endif event_dispatch(); log_debug("%s gotwebd exiting", getprogname()); return (0); } int gotwebd_configure(struct gotwebd *env) { struct server *srv; struct socket *sock; /* gotweb need to reload its config. */ env->gotwebd_reload = env->prefork_gotwebd; /* send our gotweb servers */ TAILQ_FOREACH(srv, &env->servers, entry) { if (config_setserver(env, srv) == -1) fatalx("%s: send server error", __func__); } /* send our sockets */ TAILQ_FOREACH(sock, &env->sockets, entry) { if (config_setsock(env, sock) == -1) fatalx("%s: send socket error", __func__); } /* send the temp files */ if (config_setfd(env) == -1) fatalx("%s: send priv_fd error", __func__); if (main_compose_sockets(env, IMSG_CFG_DONE, -1, NULL, 0) == -1) fatal("main_compose_sockets IMSG_CFG_DONE"); return (0); } void gotwebd_configure_done(struct gotwebd *env) { if (env->gotwebd_reload == 0) { log_warnx("%s: configuration already finished", __func__); return; } env->gotwebd_reload--; if (env->gotwebd_reload == 0 && main_compose_sockets(env, IMSG_CTL_START, -1, NULL, 0) == -1) fatal("main_compose_sockets IMSG_CTL_START"); } void gotwebd_shutdown(void) { struct gotwebd *env = gotwebd_env; pid_t pid; int i, status; for (i = 0; i < env->nserver; ++i) { event_del(&env->iev_server[i].ev); imsg_clear(&env->iev_server[i].ibuf); close(env->iev_server[i].ibuf.fd); env->iev_server[i].ibuf.fd = -1; } do { pid = waitpid(WAIT_ANY, &status, 0); if (pid <= 0) continue; if (WIFSIGNALED(status)) log_warnx("lost child: pid %u terminated; signal %d", pid, WTERMSIG(status)); else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) log_warnx("lost child: pid %u exited abnormally", pid); } while (pid != -1 || (pid == -1 && errno == EINTR)); free(gotwebd_env); log_warnx("gotwebd terminating"); exit(0); } got-portable-0.101/gotwebd/pages.c0000644000175100017510000020321314644145561012506 #line 2 "../gotwebd/pages.tmpl" /* * Copyright (c) 2022 Omar Polo * Copyright (c) 2016, 2019, 2020-2022 Tracey Emery * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #line 19 "../gotwebd/pages.tmpl" #include "got_compat.h" #line 21 "../gotwebd/pages.tmpl" #include #include #include #line 25 "../gotwebd/pages.tmpl" #include #include #include #include #include #include #include #line 33 "../gotwebd/pages.tmpl" #include "got_error.h" #include "got_object.h" #include "got_reference.h" #line 37 "../gotwebd/pages.tmpl" #include "gotwebd.h" #include "log.h" #include "tmpl.h" #line 41 "../gotwebd/pages.tmpl" enum gotweb_ref_tm { TM_DIFF, TM_LONG, }; #line 46 "../gotwebd/pages.tmpl" static int breadcumbs(struct template *); static int datetime(struct template *, time_t, int); static int gotweb_render_blob_line(struct template *, const char *, size_t); static int gotweb_render_tree_item(struct template *, struct got_tree_entry *); static int blame_line(struct template *, const char *, struct blame_line *, int, int); #line 53 "../gotwebd/pages.tmpl" static inline int gotweb_render_more(struct template *, int); #line 55 "../gotwebd/pages.tmpl" static inline int tree_listing(struct template *); static inline int diff_line(struct template *, char *); static inline int tag_item(struct template *, struct repo_tag *); static inline int branch(struct template *, struct got_reflist_entry *); static inline int rss_tag_item(struct template *, struct repo_tag *); static inline int rss_author(struct template *, char *); #line 62 "../gotwebd/pages.tmpl" static inline char * nextsep(char *s, char **t) { char *q; #line 67 "../gotwebd/pages.tmpl" while (*s == '/') s++; *t = s; if (*s == '\0') return NULL; #line 73 "../gotwebd/pages.tmpl" q = strchr(s, '/'); if (q == NULL) q = strchr(s, '\0'); return q; } #line 81 "../gotwebd/pages.tmpl" int datetime(struct template *tp, time_t t, int fmt) { int tp_ret = 0; #line 83 "../gotwebd/pages.tmpl" struct tm tm; char rfc3339[64]; char datebuf[64]; #line 87 "../gotwebd/pages.tmpl" if (gmtime_r(&t, &tm) == NULL) return -1; #line 90 "../gotwebd/pages.tmpl" if (strftime(rfc3339, sizeof(rfc3339), "%FT%TZ", &tm) == 0) return -1; #line 93 "../gotwebd/pages.tmpl" if (fmt != TM_DIFF && asctime_r(&tm, datebuf) == NULL) return -1; #line 96 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 7)) == -1) goto err; err: return tp_ret; } #line 105 "../gotwebd/pages.tmpl" int breadcumbs(struct template *tp) { int tp_ret = 0; #line 107 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct querystring *qs = c->t->qs; struct gotweb_url url; const char *folder = qs->folder; const char *action = "tree"; char *t, *s = NULL, *dir = NULL; char ch; #line 115 "../gotwebd/pages.tmpl" memset(&url, 0, sizeof(url)); url.index_page = -1; url.action = TREE; url.path = qs->path; url.commit = qs->commit; #line 121 "../gotwebd/pages.tmpl" if (qs->action != TREE && qs->action != BLOB) { action = gotweb_action_name(qs->action); url.action = qs->action; } #line 126 "../gotwebd/pages.tmpl" if (folder && *folder != '\0') { while (*folder == '/') folder++; dir = strdup(folder); if (dir == NULL) return (-1); s = dir; } #line 135 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " / ")) == -1) goto err; if ((tp_ret = tp_write(tp, "", 2)) == -1) goto err; #line 136 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, action)) == -1) goto err; if ((tp_ret = tp_write(tp, "", 4)) == -1) goto err; #line 137 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " / ")) == -1) goto err; if (dir) { while ((s = nextsep(s, &t)) != NULL) { #line 141 "../gotwebd/pages.tmpl" ch = *s; *s = '\0'; url.folder = dir; #line 146 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 2)) == -1) goto err; #line 147 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, t)) == -1) goto err; #line 149 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 4)) == -1) goto err; #line 149 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " / ")) == -1) goto err; #line 151 "../gotwebd/pages.tmpl" *s = ch; } } #line 155 "../gotwebd/pages.tmpl" if (qs->file) { if ((tp_ret = tp_htmlescape(tp, qs->file)) == -1) goto err; } #line 159 "../gotwebd/pages.tmpl" err: free(dir); return tp_ret; } #line 164 "../gotwebd/pages.tmpl" int gotweb_render_page(struct template *tp, int (*body)(struct template *)) { int tp_ret = 0; #line 166 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct server *srv = c->srv; struct querystring *qs = c->t->qs; struct gotweb_url u_path; const char *prfx = c->document_uri; const char *css = srv->custom_css; #line 173 "../gotwebd/pages.tmpl" memset(&u_path, 0, sizeof(u_path)); u_path.index_page = -1; u_path.action = SUMMARY; #line 181 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 58)) == -1) goto err; #line 181 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, srv->site_name)) == -1) goto err; #line 185 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 18)) == -1) goto err; #line 221 "../gotwebd/pages.tmpl" if ((tp_ret = body(tp)) == -1) goto err; #line 225 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 58)) == -1) goto err; #line 225 "../gotwebd/pages.tmpl" if (srv->show_site_owner) { if ((tp_ret = tp_htmlescape(tp, srv->site_owner)) == -1) goto err; } #line 232 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 27)) == -1) goto err; err: return tp_ret; } #line 234 "../gotwebd/pages.tmpl" int gotweb_render_error(struct template *tp) { int tp_ret = 0; #line 236 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; #line 240 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 22)) == -1) goto err; #line 240 "../gotwebd/pages.tmpl" if (t->error) { if ((tp_ret = tp_htmlescape(tp, t->error->msg)) == -1) goto err; } else { #line 244 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "See daemon logs for details", 27)) == -1) goto err; } #line 246 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; err: return tp_ret; } #line 248 "../gotwebd/pages.tmpl" int gotweb_render_repo_table_hdr(struct template *tp) { int tp_ret = 0; #line 250 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct server *srv = c->srv; #line 257 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Project
", 63)) == -1) goto err; #line 257 "../gotwebd/pages.tmpl" if (srv->show_repo_description) { #line 261 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Description
", 56)) == -1) goto err; } if (srv->show_repo_owner) { #line 266 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Owner
", 44)) == -1) goto err; } if (srv->show_repo_age) { #line 271 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Last Change
", 48)) == -1) goto err; } #line 273 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; err: return tp_ret; } #line 275 "../gotwebd/pages.tmpl" int gotweb_render_repo_fragment(struct template *tp, struct repo_dir *repo_dir) { int tp_ret = 0; #line 277 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct server *srv = c->srv; struct gotweb_url summary = { .action = SUMMARY, .index_page = -1, .path = repo_dir->name, }, briefs = { .action = BRIEFS, .index_page = -1, .path = repo_dir->name, }, commits = { .action = COMMITS, .index_page = -1, .path = repo_dir->name, }, tags = { .action = TAGS, .index_page = -1, .path = repo_dir->name, }, tree = { .action = TREE, .index_page = -1, .path = repo_dir->name, }, rss = { .action = RSS, .index_page = -1, .path = repo_dir->name, }; #line 307 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 10)) == -1) goto err; #line 309 "../gotwebd/pages.tmpl" if (srv->show_repo_description) { #line 311 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 39)) == -1) goto err; #line 311 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, repo_dir->description)) == -1) goto err; #line 313 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; } if (srv->show_repo_owner) { #line 316 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 33)) == -1) goto err; #line 316 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, repo_dir->owner)) == -1) goto err; #line 318 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; } if (srv->show_repo_age) { #line 321 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 31)) == -1) goto err; #line 321 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, repo_dir->age, TM_DIFF)) == -1) goto err; #line 323 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; } #line 326 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
tp_arg, &summary)) == -1) goto err; if ((tp_ret = tp_write(tp, "\">summary", 13)) == -1) goto err; #line 327 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "tp_arg, &briefs)) == -1) goto err; if ((tp_ret = tp_write(tp, "\">briefs", 12)) == -1) goto err; #line 329 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "tp_arg, &commits)) == -1) goto err; if ((tp_ret = tp_write(tp, "\">commits", 13)) == -1) goto err; #line 331 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "tp_arg, &tags)) == -1) goto err; if ((tp_ret = tp_write(tp, "\">tags", 10)) == -1) goto err; #line 333 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "tp_arg, &tree)) == -1) goto err; if ((tp_ret = tp_write(tp, "\">tree", 10)) == -1) goto err; #line 335 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "tp_arg, &rss)) == -1) goto err; #line 341 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "\">rss

", 33)) == -1) goto err; err: return tp_ret; } #line 343 "../gotwebd/pages.tmpl" int gotweb_render_briefs(struct template *tp) { int tp_ret = 0; #line 345 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct querystring *qs = c->t->qs; struct repo_commit *rc; struct repo_dir *repo_dir = t->repo_dir; struct gotweb_url diff_url, patch_url, tree_url; char *tmp, *body; #line 353 "../gotwebd/pages.tmpl" diff_url = (struct gotweb_url){ .action = DIFF, .index_page = -1, .path = repo_dir->name, .headref = qs->headref, }; patch_url = (struct gotweb_url){ .action = PATCH, .index_page = -1, .path = repo_dir->name, .headref = qs->headref, }; tree_url = (struct gotweb_url){ .action = TREE, .index_page = -1, .path = repo_dir->name, .headref = qs->headref, }; #line 376 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Commit Briefs

", 81)) == -1) goto err; TAILQ_FOREACH(rc, &t->repo_commits, entry) { #line 378 "../gotwebd/pages.tmpl" diff_url.commit = rc->commit_id; patch_url.commit = rc->commit_id; tree_url.commit = rc->commit_id; #line 382 "../gotwebd/pages.tmpl" tmp = strchr(rc->committer, '<'); if (tmp) *tmp = '\0'; #line 386 "../gotwebd/pages.tmpl" body = strchr(rc->commit_msg, '\n'); if (body) { *body++ = '\0'; while (*body == '\n') body++; } #line 396 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 66)) == -1) goto err; #line 396 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, rc->committer_time, TM_DIFF)) == -1) goto err; #line 398 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 7)) == -1) goto err; #line 398 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; #line 400 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 28)) == -1) goto err; #line 400 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->committer)) == -1) goto err; #line 403 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 11)) == -1) goto err; #line 403 "../gotwebd/pages.tmpl" if (body && *body != '\0') { #line 406 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
tp_arg, &diff_url)) == -1) goto err; if ((tp_ret = tp_write(tp, "\">", 2)) == -1) goto err; #line 407 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->commit_msg)) == -1) goto err; #line 409 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 4)) == -1) goto err; #line 409 "../gotwebd/pages.tmpl" if (rc->refs_str) { if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; #line 410 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "(", 24)) == -1) goto err; #line 410 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->refs_str)) == -1) goto err; if ((tp_ret = tp_write(tp, ")", 8)) == -1) goto err; } if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; #line 414 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 47)) == -1) goto err; #line 414 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " ⋅⋅⋅ ")) == -1) goto err; #line 417 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 17)) == -1) goto err; #line 417 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, "\n")) == -1) goto err; if ((tp_ret = tp_write(tp, "

", 3)) == -1) goto err; #line 418 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, body)) == -1) goto err; #line 420 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 14)) == -1) goto err; #line 420 "../gotwebd/pages.tmpl" } else { #line 422 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

tp_arg, &diff_url)) == -1) goto err; if ((tp_ret = tp_write(tp, "\">", 2)) == -1) goto err; #line 423 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->commit_msg)) == -1) goto err; #line 425 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 4)) == -1) goto err; #line 425 "../gotwebd/pages.tmpl" if (rc->refs_str) { if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; #line 426 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "(", 24)) == -1) goto err; #line 426 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->refs_str)) == -1) goto err; if ((tp_ret = tp_write(tp, ")", 8)) == -1) goto err; } #line 429 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 4)) == -1) goto err; } #line 433 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
tp_arg, &diff_url)) == -1) goto err; if ((tp_ret = tp_write(tp, "\">diff", 10)) == -1) goto err; #line 434 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "tp_arg, &patch_url)) == -1) goto err; if ((tp_ret = tp_write(tp, "\">patch", 11)) == -1) goto err; #line 436 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "tp_arg, &tree_url)) == -1) goto err; #line 441 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "\">tree

", 28)) == -1) goto err; } if ((tp_ret = gotweb_render_more(tp, BRIEFS)) == -1) goto err; #line 444 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; err: return tp_ret; } #line 446 "../gotwebd/pages.tmpl" int gotweb_render_more(struct template *tp, int action) { int tp_ret = 0; #line 448 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct querystring *qs = t->qs; struct gotweb_url more = { .action = action, .index_page = -1, .path = qs->path, .commit = t->more_id, .headref = qs->headref, .file = qs->file, }; #line 460 "../gotwebd/pages.tmpl" if (action == TAGS) more.commit = t->tags_more_id; #line 463 "../gotwebd/pages.tmpl" if (more.commit) { #line 466 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 34)) == -1) goto err; } err: return tp_ret; } #line 474 "../gotwebd/pages.tmpl" int gotweb_render_navs(struct template *tp) { int tp_ret = 0; #line 476 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct gotweb_url prev, next; int have_prev, have_next; #line 480 "../gotwebd/pages.tmpl" gotweb_index_navs(c, &prev, &have_prev, &next, &have_next); #line 484 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 40)) == -1) goto err; #line 484 "../gotwebd/pages.tmpl" if (have_prev) { if ((tp_ret = tp_write(tp, "Previous", 14)) == -1) goto err; } #line 491 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 25)) == -1) goto err; #line 491 "../gotwebd/pages.tmpl" if (have_next) { if ((tp_ret = tp_write(tp, "Next", 10)) == -1) goto err; } #line 498 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 12)) == -1) goto err; err: return tp_ret; } #line 500 "../gotwebd/pages.tmpl" int gotweb_render_commits(struct template *tp) { int tp_ret = 0; #line 502 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_dir *repo_dir = t->repo_dir; struct repo_commit *rc; struct gotweb_url diff, patch, tree; #line 508 "../gotwebd/pages.tmpl" diff = (struct gotweb_url){ .action = DIFF, .index_page = -1, .path = repo_dir->name, }; patch = (struct gotweb_url){ .action = PATCH, .index_page = -1, .path = repo_dir->name, }; tree = (struct gotweb_url){ .action = TREE, .index_page = -1, .path = repo_dir->name, }; #line 528 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Commits

", 79)) == -1) goto err; TAILQ_FOREACH(rc, &t->repo_commits, entry) { #line 530 "../gotwebd/pages.tmpl" diff.commit = rc->commit_id; patch.commit = rc->commit_id; tree.commit = rc->commit_id; #line 537 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Commit:
", 81)) == -1) goto err; #line 537 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->commit_id)) == -1) goto err; #line 539 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
From:
", 30)) == -1) goto err; #line 539 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->author)) == -1) goto err; if ((tp_ret = tp_write(tp, "
", 5)) == -1) goto err; #line 540 "../gotwebd/pages.tmpl" if (strcmp(rc->committer, rc->author) != 0) { #line 542 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Via:
", 17)) == -1) goto err; #line 542 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->committer)) == -1) goto err; if ((tp_ret = tp_write(tp, "
", 5)) == -1) goto err; } #line 546 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Date:
", 18)) == -1) goto err; #line 546 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, rc->committer_time, TM_LONG)) == -1) goto err; #line 552 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 42)) == -1) goto err; #line 552 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, "\n")) == -1) goto err; if ((tp_ret = tp_htmlescape(tp, rc->commit_msg)) == -1) goto err; #line 557 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
diff", 10)) == -1) goto err; #line 558 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "patch", 11)) == -1) goto err; #line 560 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "tree

", 28)) == -1) goto err; } if ((tp_ret = gotweb_render_more(tp, COMMITS)) == -1) goto err; #line 568 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; err: return tp_ret; } #line 570 "../gotwebd/pages.tmpl" int gotweb_render_blob(struct template *tp) { int tp_ret = 0; #line 572 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct querystring *qs = t->qs; struct got_blob_object *blob = t->blob; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); struct gotweb_url briefs_url, blame_url, raw_url; #line 579 "../gotwebd/pages.tmpl" memset(&briefs_url, 0, sizeof(briefs_url)); briefs_url.index_page = -1, briefs_url.action = BRIEFS, briefs_url.path = qs->path, briefs_url.commit = qs->commit, briefs_url.folder = qs->folder, briefs_url.file = qs->file, #line 587 "../gotwebd/pages.tmpl" memcpy(&blame_url, &briefs_url, sizeof(blame_url)); blame_url.action = BLAME; #line 590 "../gotwebd/pages.tmpl" memcpy(&raw_url, &briefs_url, sizeof(raw_url)); raw_url.action = BLOBRAW; #line 601 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Blob

Date:
", 125)) == -1) goto err; #line 601 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, rc->committer_time, TM_LONG)) == -1) goto err; #line 604 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Message:
", 45)) == -1) goto err; #line 604 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->commit_msg)) == -1) goto err; #line 607 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Actions:
History", 13)) == -1) goto err; #line 610 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "Blame", 11)) == -1) goto err; #line 614 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "Raw File

", 56)) == -1) goto err;
#line 624 "../gotwebd/pages.tmpl"
if ((tp_ret = got_output_blob_by_lines(tp, blob, gotweb_render_blob_line)) == -1) goto err;
#line 628 "../gotwebd/pages.tmpl"
if ((tp_ret = tp_write(tp, "
", 18)) == -1) goto err; err: return tp_ret; } #line 631 "../gotwebd/pages.tmpl" int gotweb_render_blob_line(struct template *tp, const char *line, size_t no) { int tp_ret = 0; #line 633 "../gotwebd/pages.tmpl" char lineno[16]; int r; #line 636 "../gotwebd/pages.tmpl" r = snprintf(lineno, sizeof(lineno), "%zu", no); if (r < 0 || (size_t)r >= sizeof(lineno)) return -1; #line 640 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 2)) == -1) goto err; #line 641 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, lineno)) == -1) goto err; #line 641 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; if ((tp_ret = tp_write(tp, "", 28)) == -1) goto err; #line 642 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, line)) == -1) goto err; #line 644 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 13)) == -1) goto err; err: return tp_ret; } #line 646 "../gotwebd/pages.tmpl" int tree_listing(struct template *tp) { int tp_ret = 0; #line 648 "../gotwebd/pages.tmpl" const struct got_error *error; struct request *c = tp->tp_arg; struct transport *t = c->t; struct querystring *qs = c->t->qs; struct gotweb_url url; char *readme = NULL; int binary; const uint8_t *buf; size_t len; #line 659 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 17)) == -1) goto err; #line 659 "../gotwebd/pages.tmpl" if ((tp_ret = got_output_repo_tree(c, &readme, gotweb_render_tree_item)) == -1) goto err; #line 661 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 8)) == -1) goto err; #line 661 "../gotwebd/pages.tmpl" if (readme) { #line 663 "../gotwebd/pages.tmpl" error = got_open_blob_for_output(&t->blob, &t->fd, &binary, c, qs->folder, readme, qs->commit); if (error) { free(readme); return (-1); } #line 670 "../gotwebd/pages.tmpl" memset(&url, 0, sizeof(url)); url.index_page = -1; url.action = BLOB; url.path = t->qs->path; url.file = readme; url.folder = t->qs->folder; url.commit = t->qs->commit; #line 678 "../gotwebd/pages.tmpl" if (!binary) { #line 680 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 2)) == -1) goto err; #line 681 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, readme)) == -1) goto err; #line 685 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 14)) == -1) goto err;
for (;;) {
error = got_object_blob_read_block(&len, t->blob);
if (error) {
free(readme);
return (-1);
}
if (len == 0)
break;
buf = got_object_blob_get_read_buf(t->blob);
if (tp_write_htmlescape(tp, buf, len) == -1) {
free(readme);
return (-1);
}
}
#line 702 "../gotwebd/pages.tmpl"
if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; } } #line 704 "../gotwebd/pages.tmpl" err: free(readme); return tp_ret; } #line 708 "../gotwebd/pages.tmpl" int gotweb_render_tree(struct template *tp) { int tp_ret = 0; #line 710 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); #line 721 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Tree

Tree:
", 149)) == -1) goto err; #line 721 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->tree_id)) == -1) goto err; #line 724 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Date:
", 30)) == -1) goto err; #line 724 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, rc->committer_time, TM_LONG)) == -1) goto err; #line 727 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Message:
", 45)) == -1) goto err; #line 727 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->commit_msg)) == -1) goto err; #line 731 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 22)) == -1) goto err; #line 731 "../gotwebd/pages.tmpl" if ((tp_ret = tree_listing(tp)) == -1) goto err; #line 733 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; err: return tp_ret; } #line 736 "../gotwebd/pages.tmpl" int gotweb_render_tree_item(struct template *tp, struct got_tree_entry *te) { int tp_ret = 0; #line 738 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct querystring *qs = t->qs; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); const char *modestr = ""; const char *name; const char *folder; char *dir = NULL; mode_t mode; struct gotweb_url url = { .index_page = -1, .commit = rc->commit_id, .path = qs->path, }; #line 753 "../gotwebd/pages.tmpl" name = got_tree_entry_get_name(te); mode = got_tree_entry_get_mode(te); #line 756 "../gotwebd/pages.tmpl" folder = qs->folder ? qs->folder : ""; if (S_ISDIR(mode)) { if (asprintf(&dir, "%s/%s", folder, name) == -1) return (-1); #line 761 "../gotwebd/pages.tmpl" url.action = TREE; url.folder = dir; } else { url.action = BLOB; url.folder = folder; url.file = name; } #line 769 "../gotwebd/pages.tmpl" if (got_object_tree_entry_is_submodule(te)) modestr = "$"; else if (S_ISLNK(mode)) modestr = "@"; else if (S_ISDIR(mode)) modestr = "/"; else if (mode & S_IXUSR) modestr = "*"; #line 779 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 25)) == -1) goto err; #line 779 "../gotwebd/pages.tmpl" if (S_ISDIR(mode)) { #line 781 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 2)) == -1) goto err; #line 782 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, name)) == -1) goto err; #line 782 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, modestr)) == -1) goto err; #line 785 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 9)) == -1) goto err; #line 785 "../gotwebd/pages.tmpl" } else { #line 787 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 2)) == -1) goto err; #line 788 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, name)) == -1) goto err; #line 788 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, modestr)) == -1) goto err; #line 792 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 37)) == -1) goto err; #line 792 "../gotwebd/pages.tmpl" url.action = COMMITS; if ((tp_ret = tp_write(tp, "commits", 13)) == -1) goto err; #line 796 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; url.action = BLAME; if ((tp_ret = tp_write(tp, "blame", 16)) == -1) goto err; } #line 804 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 5)) == -1) goto err; #line 804 "../gotwebd/pages.tmpl" err: #line 806 "../gotwebd/pages.tmpl" free(dir); return tp_ret; } #line 810 "../gotwebd/pages.tmpl" int gotweb_render_tags(struct template *tp) { int tp_ret = 0; #line 812 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct querystring *qs = t->qs; struct repo_tag *rt; int commit_found; #line 818 "../gotwebd/pages.tmpl" commit_found = qs->commit == NULL; #line 824 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Tags

", 70)) == -1) goto err; #line 824 "../gotwebd/pages.tmpl" if (t->tag_count == 0) { #line 828 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
This repository contains no tags
", 60)) == -1) goto err; #line 828 "../gotwebd/pages.tmpl" } else { TAILQ_FOREACH(rt, &t->repo_tags, entry) { #line 830 "../gotwebd/pages.tmpl" if (commit_found ||!strcmp(qs->commit, rt->commit_id)) { commit_found = 1; if ((tp_ret = tag_item(tp, rt)) == -1) goto err; } } #line 835 "../gotwebd/pages.tmpl" if ((tp_ret = gotweb_render_more(tp, TAGS)) == -1) goto err; } #line 838 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; err: return tp_ret; } #line 840 "../gotwebd/pages.tmpl" int tag_item(struct template *tp, struct repo_tag *rt) { int tp_ret = 0; #line 842 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_dir *repo_dir = t->repo_dir; char *tag_name = rt->tag_name; char *msg = rt->tag_commit; char *nl; struct gotweb_url url = { .action = TAG, .index_page = -1, .path = repo_dir->name, .commit = rt->commit_id, }; #line 855 "../gotwebd/pages.tmpl" if (strncmp(tag_name, "refs/tags/", 10) == 0) tag_name += 10; #line 858 "../gotwebd/pages.tmpl" if (msg) { nl = strchr(msg, '\n'); if (nl) *nl = '\0'; } #line 865 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 21)) == -1) goto err; #line 865 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, rt->tagger_time, TM_DIFF)) == -1) goto err; #line 867 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 28)) == -1) goto err; #line 867 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, tag_name)) == -1) goto err; #line 869 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
tag", 9)) == -1) goto err; #line 876 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; url.action = BRIEFS; if ((tp_ret = tp_write(tp, "commit briefs", 19)) == -1) goto err; #line 879 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; url.action = COMMITS; if ((tp_ret = tp_write(tp, "commits

", 31)) == -1) goto err; err: return tp_ret; } #line 887 "../gotwebd/pages.tmpl" int gotweb_render_tag(struct template *tp) { int tp_ret = 0; #line 889 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_tag *rt; const char *tag_name; #line 894 "../gotwebd/pages.tmpl" rt = TAILQ_LAST(&t->repo_tags, repo_tags_head); tag_name = rt->tag_name; #line 897 "../gotwebd/pages.tmpl" if (strncmp(tag_name, "refs/", 5) == 0) tag_name += 5; #line 908 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Tag

Commit:
", 150)) == -1) goto err; #line 908 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rt->commit_id)) == -1) goto err; if ((tp_ret = tp_write(tp, "", 7)) == -1) goto err; #line 909 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; if ((tp_ret = tp_write(tp, "(", 24)) == -1) goto err; #line 910 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, tag_name)) == -1) goto err; #line 913 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, ")
Tagger:
", 33)) == -1) goto err; #line 913 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rt->tagger)) == -1) goto err; #line 916 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Date:
", 23)) == -1) goto err; #line 916 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, rt->tagger_time, TM_LONG)) == -1) goto err; #line 919 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Message:
", 45)) == -1) goto err; #line 919 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rt->commit_msg)) == -1) goto err; #line 923 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 37)) == -1) goto err;
#line 923 "../gotwebd/pages.tmpl"
if ((tp_ret = tp_htmlescape(tp, rt->tag_commit)) == -1)
goto err;
#line 927 "../gotwebd/pages.tmpl"
if ((tp_ret = tp_write(tp, "
", 18)) == -1) goto err; err: return tp_ret; } #line 929 "../gotwebd/pages.tmpl" int gotweb_render_diff(struct template *tp) { int tp_ret = 0; #line 931 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct querystring *qs = t->qs; FILE *fp = t->fp; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); char *line = NULL; size_t linesize = 0; ssize_t linelen; struct gotweb_url patch_url, tree_url = { .action = TREE, .index_page = -1, .path = qs->path, .commit = rc->commit_id, }; #line 946 "../gotwebd/pages.tmpl" memcpy(&patch_url, &tree_url, sizeof(patch_url)); patch_url.action = PATCH; #line 956 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Commit Diff

Commit:
", 158)) == -1) goto err; #line 956 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->commit_id)) == -1) goto err; #line 958 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
From:
", 30)) == -1) goto err; #line 958 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->author)) == -1) goto err; if ((tp_ret = tp_write(tp, "
", 5)) == -1) goto err; #line 959 "../gotwebd/pages.tmpl" if (strcmp(rc->committer, rc->author) != 0) { #line 961 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Via:
", 17)) == -1) goto err; #line 961 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->committer)) == -1) goto err; if ((tp_ret = tp_write(tp, "
", 5)) == -1) goto err; } #line 965 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Date:
", 18)) == -1) goto err; #line 965 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, rc->committer_time, TM_LONG)) == -1) goto err; #line 968 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Message:
", 45)) == -1) goto err; #line 968 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->commit_msg)) == -1) goto err; #line 971 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Actions:
Patch", 11)) == -1) goto err; #line 974 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "Tree

", 47)) == -1) goto err;
while ((linelen = getline(&line, &linesize, fp)) != -1) {
if ((tp_ret = diff_line(tp, line)) == -1) goto err;
}
#line 988 "../gotwebd/pages.tmpl"
if ((tp_ret = tp_write(tp, "
", 12)) == -1) goto err; #line 988 "../gotwebd/pages.tmpl" err: free(line); return tp_ret; } #line 992 "../gotwebd/pages.tmpl" int diff_line(struct template *tp, char *line ) { int tp_ret = 0; #line 994 "../gotwebd/pages.tmpl" const char *color = NULL; char *nl; #line 997 "../gotwebd/pages.tmpl" if (!strncmp(line, "-", 1)) color = "diff_minus"; else if (!strncmp(line, "+", 1)) color = "diff_plus"; else if (!strncmp(line, "@@", 2)) color = "diff_chunk_header"; else if (!strncmp(line, "commit +", 8) || !strncmp(line, "commit -", 8) || !strncmp(line, "blob +", 6) || !strncmp(line, "blob -", 6) || !strncmp(line, "file +", 6) || !strncmp(line, "file -", 6)) color = "diff_meta"; else if (!strncmp(line, "from:", 5) || !strncmp(line, "via:", 4)) color = "diff_author"; else if (!strncmp(line, "date:", 5)) color = "diff_date"; #line 1015 "../gotwebd/pages.tmpl" nl = strchr(line, '\n'); if (nl) *nl = '\0'; #line 1019 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 2)) == -1) goto err; #line 1019 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, line)) == -1) goto err; #line 1019 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 7)) == -1) goto err; #line 1019 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, "\n")) == -1) goto err; err: return tp_ret; } #line 1023 "../gotwebd/pages.tmpl" int gotweb_render_branches(struct template *tp, struct got_reflist_head *refs) { int tp_ret = 0; #line 1025 "../gotwebd/pages.tmpl" struct got_reflist_entry *re; #line 1031 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Branches

", 78)) == -1) goto err; TAILQ_FOREACH(re, refs, entry) { if (!got_ref_is_symbolic(re->ref)) { if ((tp_ret = branch(tp, re)) == -1) goto err; } } #line 1037 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; err: return tp_ret; } #line 1039 "../gotwebd/pages.tmpl" int branch(struct template *tp, struct got_reflist_entry *re) { int tp_ret = 0; #line 1041 "../gotwebd/pages.tmpl" const struct got_error *err; struct request *c = tp->tp_arg; struct querystring *qs = c->t->qs; const char *refname; time_t age; struct gotweb_url url = { .action = SUMMARY, .index_page = -1, .path = qs->path, }; #line 1052 "../gotwebd/pages.tmpl" refname = got_ref_get_name(re->ref); #line 1054 "../gotwebd/pages.tmpl" err = got_get_repo_age(&age, c, refname); if (err) { log_warnx("%s: %s", __func__, err->msg); return -1; } #line 1060 "../gotwebd/pages.tmpl" if (strncmp(refname, "refs/heads/", 11) == 0) refname += 11; #line 1063 "../gotwebd/pages.tmpl" url.headref = refname; #line 1067 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 60)) == -1) goto err; #line 1067 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, age, TM_DIFF)) == -1) goto err; #line 1070 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
summary", 13)) == -1) goto err; #line 1075 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; url.action = BRIEFS; if ((tp_ret = tp_write(tp, "commit briefs", 19)) == -1) goto err; #line 1078 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; url.action = COMMITS; if ((tp_ret = tp_write(tp, "commits

", 41)) == -1) goto err; err: return tp_ret; } #line 1087 "../gotwebd/pages.tmpl" int gotweb_render_summary(struct template *tp) { int tp_ret = 0; #line 1089 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct server *srv = c->srv; struct transport *t = c->t; struct got_reflist_head *refs = &t->refs; #line 1095 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 53)) == -1) goto err; #line 1095 "../gotwebd/pages.tmpl" if (srv->show_repo_description) { #line 1097 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Description:
", 25)) == -1) goto err; #line 1097 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, t->repo_dir->description)) == -1) goto err; if ((tp_ret = tp_write(tp, "
", 5)) == -1) goto err; } if (srv->show_repo_owner) { #line 1101 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Owner:
", 19)) == -1) goto err; #line 1101 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, t->repo_dir->owner)) == -1) goto err; if ((tp_ret = tp_write(tp, "
", 5)) == -1) goto err; } if (srv->show_repo_age) { #line 1106 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Last Change:
", 25)) == -1) goto err; #line 1106 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, t->repo_dir->age, TM_DIFF)) == -1) goto err; #line 1108 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 5)) == -1) goto err; } if (srv->show_repo_cloneurl) { #line 1111 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Clone URL:
", 46)) == -1) goto err;
#line 1111 "../gotwebd/pages.tmpl"
if ((tp_ret = tp_htmlescape(tp, t->repo_dir->url)) == -1)
goto err;
if ((tp_ret = tp_write(tp, "
", 11)) == -1) goto err; } #line 1114 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 5)) == -1) goto err; #line 1114 "../gotwebd/pages.tmpl" if ((tp_ret = gotweb_render_briefs(tp)) == -1) goto err; if ((tp_ret = gotweb_render_branches(tp, refs)) == -1) goto err; if ((tp_ret = gotweb_render_tags(tp)) == -1) goto err; #line 1121 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Tree

", 70)) == -1) goto err; #line 1121 "../gotwebd/pages.tmpl" if ((tp_ret = tree_listing(tp)) == -1) goto err; #line 1123 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; err: return tp_ret; } #line 1125 "../gotwebd/pages.tmpl" int gotweb_render_blame(struct template *tp) { int tp_ret = 0; #line 1127 "../gotwebd/pages.tmpl" const struct got_error *err; struct request *c = tp->tp_arg; struct transport *t = c->t; struct querystring *qs = t->qs; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); struct gotweb_url briefs_url, blob_url, raw_url; #line 1134 "../gotwebd/pages.tmpl" memset(&briefs_url, 0, sizeof(briefs_url)); briefs_url.index_page = -1, briefs_url.action = BRIEFS, briefs_url.path = qs->path, briefs_url.commit = qs->commit, briefs_url.folder = qs->folder, briefs_url.file = qs->file, #line 1142 "../gotwebd/pages.tmpl" memcpy(&blob_url, &briefs_url, sizeof(blob_url)); blob_url.action = BLOB; #line 1145 "../gotwebd/pages.tmpl" memcpy(&raw_url, &briefs_url, sizeof(raw_url)); raw_url.action = BLOBRAW; #line 1156 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Blame

Date:
", 127)) == -1) goto err; #line 1156 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, rc->committer_time, TM_LONG)) == -1) goto err; #line 1159 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Message:
", 45)) == -1) goto err; #line 1159 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->commit_msg)) == -1) goto err; #line 1162 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Actions:
History", 13)) == -1) goto err; #line 1165 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "Blob", 10)) == -1) goto err; #line 1169 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "Raw File

", 52)) == -1) goto err;
err = got_output_file_blame(c, &blame_line);
if (err && err->code != GOT_ERR_CANCELLED)
log_warnx("%s: got_output_file_blame: %s", __func__,
err->msg);
if (err)
return (-1);
#line 1188 "../gotwebd/pages.tmpl"
if ((tp_ret = tp_write(tp, "
", 12)) == -1) goto err; err: return tp_ret; } #line 1191 "../gotwebd/pages.tmpl" int blame_line(struct template *tp, const char *line, struct blame_line *bline, int lprec, int lcur) { int tp_ret = 0; #line 1193 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_dir *repo_dir = t->repo_dir; char *committer, *s; struct gotweb_url url = { .action = DIFF, .index_page = -1, .path = repo_dir->name, .commit = bline->id_str, }; #line 1204 "../gotwebd/pages.tmpl" s = strchr(bline->committer, '<'); committer = s ? s + 1 : bline->committer; #line 1207 "../gotwebd/pages.tmpl" s = strchr(committer, '@'); if (s) *s = '\0'; #line 1212 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 51)) == -1) goto err; #line 1212 "../gotwebd/pages.tmpl" if (asprintf(&tp->tp_tmp, "%*d ", lprec, lcur) == -1) goto err; if ((tp_ret = tp_htmlescape(tp, tp->tp_tmp)) == -1) goto err; free(tp->tp_tmp); tp->tp_tmp = NULL; #line 1214 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 2)) == -1) goto err; #line 1215 "../gotwebd/pages.tmpl" if (asprintf(&tp->tp_tmp, "%.8s", bline->id_str) == -1) goto err; if ((tp_ret = tp_htmlescape(tp, tp->tp_tmp)) == -1) goto err; free(tp->tp_tmp); tp->tp_tmp = NULL; #line 1218 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 11)) == -1) goto err; #line 1218 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; if ((tp_ret = tp_write(tp, "", 25)) == -1) goto err; #line 1219 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, bline->datebuf)) == -1) goto err; if ((tp_ret = tp_write(tp, "", 7)) == -1) goto err; #line 1220 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; if ((tp_ret = tp_write(tp, "", 27)) == -1) goto err; #line 1221 "../gotwebd/pages.tmpl" if (asprintf(&tp->tp_tmp, "%.9s", committer) == -1) goto err; if ((tp_ret = tp_htmlescape(tp, tp->tp_tmp)) == -1) goto err; free(tp->tp_tmp); tp->tp_tmp = NULL; if ((tp_ret = tp_write(tp, "", 7)) == -1) goto err; #line 1222 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; if ((tp_ret = tp_write(tp, "", 25)) == -1) goto err; #line 1223 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, line)) == -1) goto err; #line 1225 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 13)) == -1) goto err; err: return tp_ret; } #line 1227 "../gotwebd/pages.tmpl" int gotweb_render_patch(struct template *tp) { int tp_ret = 0; #line 1229 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); struct tm tm; char buf[BUFSIZ], datebuf[64]; size_t r; #line 1236 "../gotwebd/pages.tmpl" if (gmtime_r(&rc->committer_time, &tm) == NULL || strftime(datebuf, sizeof(datebuf), "%a %b %d %T %Y UTC", &tm) == 0) return (-1); #line 1240 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "commit ", 7)) == -1) goto err; #line 1240 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->commit_id)) == -1) goto err; #line 1240 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, "\n")) == -1) goto err; if ((tp_ret = tp_write(tp, "from: ", 6)) == -1) goto err; #line 1241 "../gotwebd/pages.tmpl" if ((tp_ret = tp_writes(tp, rc->author)) == -1) goto err; #line 1241 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, "\n")) == -1) goto err; if (strcmp(rc->committer, rc->author) != 0) { if ((tp_ret = tp_write(tp, "via: ", 5)) == -1) goto err; #line 1243 "../gotwebd/pages.tmpl" if ((tp_ret = tp_writes(tp, rc->committer)) == -1) goto err; #line 1243 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, "\n")) == -1) goto err; } #line 1245 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "date: ", 6)) == -1) goto err; #line 1245 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, datebuf)) == -1) goto err; #line 1245 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, "\n")) == -1) goto err; if ((tp_ret = tp_htmlescape(tp, "\n")) == -1) goto err; if ((tp_ret = tp_writes(tp, rc->commit_msg)) == -1) goto err; #line 1247 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, "\n")) == -1) goto err; #line 1249 "../gotwebd/pages.tmpl" if (template_flush(tp) == -1) return (-1); for (;;) { r = fread(buf, 1, sizeof(buf), t->fp); if (fcgi_write(c, buf, r) == -1 || r != sizeof(buf)) break; } err: return tp_ret; } #line 1260 "../gotwebd/pages.tmpl" int gotweb_render_rss(struct template *tp) { int tp_ret = 0; #line 1262 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct server *srv = c->srv; struct transport *t = c->t; struct repo_dir *repo_dir = t->repo_dir; struct repo_tag *rt; struct gotweb_url summary = { .action = SUMMARY, .index_page = -1, .path = repo_dir->name, }; #line 1276 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "Tags of ", 138)) == -1) goto err; #line 1276 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, repo_dir->name)) == -1) goto err; #line 1279 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 10)) == -1) goto err; #line 1282 "../gotwebd/pages.tmpl" if (srv->show_repo_description) { if ((tp_ret = tp_write(tp, "", 13)) == -1) goto err; #line 1283 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, repo_dir->description)) == -1) goto err; if ((tp_ret = tp_write(tp, "", 14)) == -1) goto err; } TAILQ_FOREACH(rt, &t->repo_tags, entry) { #line 1286 "../gotwebd/pages.tmpl" if ((tp_ret = rss_tag_item(tp, rt)) == -1) goto err; } #line 1290 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 16)) == -1) goto err; err: return tp_ret; } #line 1292 "../gotwebd/pages.tmpl" int rss_tag_item(struct template *tp, struct repo_tag *rt) { int tp_ret = 0; #line 1294 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_dir *repo_dir = t->repo_dir; struct tm tm; char rfc822[128]; int r; char *tag_name = rt->tag_name; struct gotweb_url tag = { .action = TAG, .index_page = -1, .path = repo_dir->name, .commit = rt->commit_id, }; #line 1308 "../gotwebd/pages.tmpl" if (strncmp(tag_name, "refs/tags/", 10) == 0) tag_name += 10; #line 1311 "../gotwebd/pages.tmpl" if (gmtime_r(&rt->tagger_time, &tm) == NULL) return -1; r = strftime(rfc822, sizeof(rfc822), "%a, %d %b %Y %H:%M:%S GMT", &tm); if (r == 0) return 0; #line 1318 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 13)) == -1) goto err; #line 1318 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, repo_dir->name)) == -1) goto err; #line 1318 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; #line 1318 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, tag_name)) == -1) goto err; #line 1321 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 37)) == -1) goto err; #line 1325 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rt->tag_commit)) == -1) goto err; #line 1327 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "]]>", 23)) == -1) goto err; #line 1327 "../gotwebd/pages.tmpl" if ((tp_ret = rss_author(tp, rt->tagger)) == -1) goto err; if ((tp_ret = tp_write(tp, "", 26)) == -1) goto err; #line 1328 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rt->commit_id)) == -1) goto err; #line 1330 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 16)) == -1) goto err; #line 1330 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rfc822)) == -1) goto err; #line 1333 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 17)) == -1) goto err; err: return tp_ret; } #line 1335 "../gotwebd/pages.tmpl" int rss_author(struct template *tp, char *author) { int tp_ret = 0; #line 1337 "../gotwebd/pages.tmpl" char *t, *mail; #line 1339 "../gotwebd/pages.tmpl" /* what to do if the author name contains a paren? */ if (strchr(author, '(') != NULL || strchr(author, ')') != NULL) return 0; #line 1343 "../gotwebd/pages.tmpl" t = strchr(author, '<'); if (t == NULL) return 0; *t = '\0'; mail = t+1; #line 1349 "../gotwebd/pages.tmpl" while (isspace((unsigned char)*--t)) *t = '\0'; #line 1352 "../gotwebd/pages.tmpl" t = strchr(mail, '>'); if (t == NULL) return 0; *t = '\0'; #line 1358 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 8)) == -1) goto err; #line 1358 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, mail)) == -1) goto err; #line 1358 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; #line 1358 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "(", 1)) == -1) goto err; #line 1358 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, author)) == -1) goto err; #line 1360 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, ")", 10)) == -1) goto err; err: return tp_ret; } got-portable-0.101/gotwebd/parse.y0000664000175100017510000005601714644144735012563 /* * Copyright (c) 2016-2019, 2020-2021 Tracey Emery * Copyright (c) 2004, 2005 Esben Norby * Copyright (c) 2004 Ryan McBride * Copyright (c) 2002, 2003, 2004 Henning Brauer * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. * Copyright (c) 2001 Theo de Raadt. All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ %{ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_reference.h" #include "gotwebd.h" #include "log.h" TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); static struct file { TAILQ_ENTRY(file) entry; FILE *stream; char *name; int lineno; int errors; } *file; struct file *newfile(const char *, int); static void closefile(struct file *); int check_file_secrecy(int, const char *); int yyparse(void); int yylex(void); int yyerror(const char *, ...) __attribute__((__format__ (printf, 1, 2))) __attribute__((__nonnull__ (1))); int kw_cmp(const void *, const void *); int lookup(char *); int lgetc(int); int lungetc(int); int findeol(void); TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); struct sym { TAILQ_ENTRY(sym) entry; int used; int persist; char *nam; char *val; }; int symset(const char *, const char *, int); char *symget(const char *); static int errors; static struct gotwebd *gotwebd; static struct server *new_srv; static struct server *conf_new_server(const char *); int getservice(const char *); int n; int get_addrs(const char *, const char *); int get_unix_addr(const char *); int addr_dup_check(struct addresslist *, struct address *); int add_addr(struct address *); typedef struct { union { long long number; char *string; } v; int lineno; } YYSTYPE; %} %token LISTEN WWW_PATH SITE_NAME SITE_OWNER SITE_LINK LOGO %token LOGO_URL SHOW_REPO_OWNER SHOW_REPO_AGE SHOW_REPO_DESCRIPTION %token MAX_REPOS_DISPLAY REPOS_PATH MAX_COMMITS_DISPLAY ON ERROR %token SHOW_SITE_OWNER SHOW_REPO_CLONEURL PORT PREFORK RESPECT_EXPORTOK %token SERVER CHROOT CUSTOM_CSS SOCKET %token SUMMARY_COMMITS_DISPLAY SUMMARY_TAGS_DISPLAY USER %token STRING %token NUMBER %type boolean %type listen_addr %% grammar : /* empty */ | grammar '\n' | grammar varset '\n' | grammar main '\n' | grammar server '\n' | grammar error '\n' { file->errors++; } ; varset : STRING '=' STRING { char *s = $1; while (*s++) { if (isspace((unsigned char)*s)) { yyerror("macro name cannot contain " "whitespace"); free($1); free($3); YYERROR; } } if (symset($1, $3, 0) == -1) fatal("cannot store variable"); free($1); free($3); } ; boolean : STRING { if (strcasecmp($1, "1") == 0 || strcasecmp($1, "on") == 0) $$ = 1; else if (strcasecmp($1, "0") == 0 || strcasecmp($1, "off") == 0) $$ = 0; else { yyerror("invalid boolean value '%s'", $1); free($1); YYERROR; } free($1); } | ON { $$ = 1; } | NUMBER { if ($1 != 0 && $1 != 1) { yyerror("invalid boolean value '%lld'", $1); YYERROR; } $$ = $1; } ; listen_addr : '*' { $$ = NULL; } | STRING ; main : PREFORK NUMBER { if ($2 <= 0 || $2 > PROC_MAX_INSTANCES) { yyerror("prefork is %s: %lld", $2 <= 0 ? "too small" : "too large", $2); YYERROR; } gotwebd->prefork_gotwebd = $2; } | CHROOT STRING { if (*$2 == '\0') { yyerror("chroot path can't be an empty" " string"); free($2); YYERROR; } n = strlcpy(gotwebd->httpd_chroot, $2, sizeof(gotwebd->httpd_chroot)); if (n >= sizeof(gotwebd->httpd_chroot)) { yyerror("%s: httpd_chroot truncated", __func__); free($2); YYERROR; } free($2); } | LISTEN ON listen_addr PORT STRING { if (get_addrs($3, $5) == -1) { yyerror("could not get addrs"); YYERROR; } free($3); free($5); } | LISTEN ON listen_addr PORT NUMBER { char portno[32]; int n; n = snprintf(portno, sizeof(portno), "%lld", (long long)$5); if (n < 0 || (size_t)n >= sizeof(portno)) fatalx("port number too long: %lld", (long long)$5); if (get_addrs($3, portno) == -1) { yyerror("could not get addrs"); YYERROR; } free($3); } | LISTEN ON SOCKET STRING { if (get_unix_addr($4) == -1) { yyerror("can't listen on %s", $4); free($4); YYERROR; } free($4); } | USER STRING { if (gotwebd->user != NULL) yyerror("user already specified"); free(gotwebd->user); gotwebd->user = $2; } ; server : SERVER STRING { struct server *srv; TAILQ_FOREACH(srv, &gotwebd->servers, entry) { if (strcmp(srv->name, $2) == 0) { yyerror("server name exists '%s'", $2); free($2); YYERROR; } } new_srv = conf_new_server($2); log_debug("adding server %s", $2); free($2); } | SERVER STRING { struct server *srv; TAILQ_FOREACH(srv, &gotwebd->servers, entry) { if (strcmp(srv->name, $2) == 0) { yyerror("server name exists '%s'", $2); free($2); YYERROR; } } new_srv = conf_new_server($2); log_debug("adding server %s", $2); free($2); } '{' optnl serveropts2 '}' { } ; serveropts1 : REPOS_PATH STRING { n = strlcpy(new_srv->repos_path, $2, sizeof(new_srv->repos_path)); if (n >= sizeof(new_srv->repos_path)) { yyerror("%s: repos_path truncated", __func__); free($2); YYERROR; } free($2); } | SITE_NAME STRING { n = strlcpy(new_srv->site_name, $2, sizeof(new_srv->site_name)); if (n >= sizeof(new_srv->site_name)) { yyerror("%s: site_name truncated", __func__); free($2); YYERROR; } free($2); } | SITE_OWNER STRING { n = strlcpy(new_srv->site_owner, $2, sizeof(new_srv->site_owner)); if (n >= sizeof(new_srv->site_owner)) { yyerror("%s: site_owner truncated", __func__); free($2); YYERROR; } free($2); } | SITE_LINK STRING { n = strlcpy(new_srv->site_link, $2, sizeof(new_srv->site_link)); if (n >= sizeof(new_srv->site_link)) { yyerror("%s: site_link truncated", __func__); free($2); YYERROR; } free($2); } | LOGO STRING { n = strlcpy(new_srv->logo, $2, sizeof(new_srv->logo)); if (n >= sizeof(new_srv->logo)) { yyerror("%s: logo truncated", __func__); free($2); YYERROR; } free($2); } | LOGO_URL STRING { n = strlcpy(new_srv->logo_url, $2, sizeof(new_srv->logo_url)); if (n >= sizeof(new_srv->logo_url)) { yyerror("%s: logo_url truncated", __func__); free($2); YYERROR; } free($2); } | CUSTOM_CSS STRING { n = strlcpy(new_srv->custom_css, $2, sizeof(new_srv->custom_css)); if (n >= sizeof(new_srv->custom_css)) { yyerror("%s: custom_css truncated", __func__); free($2); YYERROR; } free($2); } | SHOW_SITE_OWNER boolean { new_srv->show_site_owner = $2; } | SHOW_REPO_OWNER boolean { new_srv->show_repo_owner = $2; } | SHOW_REPO_AGE boolean { new_srv->show_repo_age = $2; } | SHOW_REPO_DESCRIPTION boolean { new_srv->show_repo_description = $2; } | SHOW_REPO_CLONEURL boolean { new_srv->show_repo_cloneurl = $2; } | RESPECT_EXPORTOK boolean { new_srv->respect_exportok = $2; } | MAX_REPOS_DISPLAY NUMBER { if ($2 < 0) { yyerror("max_repos_display is too small: %lld", $2); YYERROR; } new_srv->max_repos_display = $2; } | MAX_COMMITS_DISPLAY NUMBER { if ($2 <= 1) { yyerror("max_commits_display is too small:" " %lld", $2); YYERROR; } new_srv->max_commits_display = $2; } | SUMMARY_COMMITS_DISPLAY NUMBER { if ($2 < 1) { yyerror("summary_commits_display is too small:" " %lld", $2); YYERROR; } new_srv->summary_commits_display = $2; } | SUMMARY_TAGS_DISPLAY NUMBER { if ($2 < 1) { yyerror("summary_tags_display is too small:" " %lld", $2); YYERROR; } new_srv->summary_tags_display = $2; } ; serveropts2 : serveropts2 serveropts1 nl | serveropts1 optnl ; nl : '\n' optnl ; optnl : '\n' optnl /* zero or more newlines */ | /* empty */ ; %% struct keywords { const char *k_name; int k_val; }; int yyerror(const char *fmt, ...) { va_list ap; char *msg; file->errors++; va_start(ap, fmt); if (vasprintf(&msg, fmt, ap) == -1) fatalx("yyerror vasprintf"); va_end(ap); logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); free(msg); return (0); } int kw_cmp(const void *k, const void *e) { return (strcmp(k, ((const struct keywords *)e)->k_name)); } int lookup(char *s) { /* This has to be sorted always. */ static const struct keywords keywords[] = { { "chroot", CHROOT }, { "custom_css", CUSTOM_CSS }, { "listen", LISTEN }, { "logo", LOGO }, { "logo_url", LOGO_URL }, { "max_commits_display", MAX_COMMITS_DISPLAY }, { "max_repos_display", MAX_REPOS_DISPLAY }, { "on", ON }, { "port", PORT }, { "prefork", PREFORK }, { "repos_path", REPOS_PATH }, { "respect_exportok", RESPECT_EXPORTOK }, { "server", SERVER }, { "show_repo_age", SHOW_REPO_AGE }, { "show_repo_cloneurl", SHOW_REPO_CLONEURL }, { "show_repo_description", SHOW_REPO_DESCRIPTION }, { "show_repo_owner", SHOW_REPO_OWNER }, { "show_site_owner", SHOW_SITE_OWNER }, { "site_link", SITE_LINK }, { "site_name", SITE_NAME }, { "site_owner", SITE_OWNER }, { "socket", SOCKET }, { "summary_commits_display", SUMMARY_COMMITS_DISPLAY }, { "summary_tags_display", SUMMARY_TAGS_DISPLAY }, { "user", USER }, }; const struct keywords *p; p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), sizeof(keywords[0]), kw_cmp); if (p) return (p->k_val); else return (STRING); } #define MAXPUSHBACK 128 unsigned char *parsebuf; int parseindex; unsigned char pushback_buffer[MAXPUSHBACK]; int pushback_index = 0; int lgetc(int quotec) { int c, next; if (parsebuf) { /* Read character from the parsebuffer instead of input. */ if (parseindex >= 0) { c = parsebuf[parseindex++]; if (c != '\0') return (c); parsebuf = NULL; } else parseindex++; } if (pushback_index) return (pushback_buffer[--pushback_index]); if (quotec) { c = getc(file->stream); if (c == EOF) yyerror("reached end of file while parsing " "quoted string"); return (c); } c = getc(file->stream); while (c == '\\') { next = getc(file->stream); if (next != '\n') { c = next; break; } yylval.lineno = file->lineno; file->lineno++; c = getc(file->stream); } return (c); } int lungetc(int c) { if (c == EOF) return (EOF); if (parsebuf) { parseindex--; if (parseindex >= 0) return (c); } if (pushback_index < MAXPUSHBACK-1) return (pushback_buffer[pushback_index++] = c); else return (EOF); } int findeol(void) { int c; parsebuf = NULL; /* Skip to either EOF or the first real EOL. */ while (1) { if (pushback_index) c = pushback_buffer[--pushback_index]; else c = lgetc(0); if (c == '\n') { file->lineno++; break; } if (c == EOF) break; } return (ERROR); } int yylex(void) { unsigned char buf[8096]; unsigned char *p, *val; int quotec, next, c; int token; top: p = buf; c = lgetc(0); while (c == ' ' || c == '\t') c = lgetc(0); /* nothing */ yylval.lineno = file->lineno; if (c == '#') { c = lgetc(0); while (c != '\n' && c != EOF) c = lgetc(0); /* nothing */ } if (c == '$' && parsebuf == NULL) { while (1) { c = lgetc(0); if (c == EOF) return (0); if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } if (isalnum(c) || c == '_') { *p++ = c; continue; } *p = '\0'; lungetc(c); break; } val = symget(buf); if (val == NULL) { yyerror("macro '%s' not defined", buf); return (findeol()); } parsebuf = val; parseindex = 0; goto top; } switch (c) { case '\'': case '"': quotec = c; while (1) { c = lgetc(quotec); if (c == EOF) return (0); if (c == '\n') { file->lineno++; continue; } else if (c == '\\') { next = lgetc(quotec); if (next == EOF) return (0); if (next == quotec || c == ' ' || c == '\t') c = next; else if (next == '\n') { file->lineno++; continue; } else lungetc(next); } else if (c == quotec) { *p = '\0'; break; } else if (c == '\0') { yyerror("syntax error"); return (findeol()); } if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } *p++ = c; } yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "yylex: strdup"); return (STRING); } #define allowed_to_end_number(x) \ (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') if (c == '-' || isdigit(c)) { do { *p++ = c; if ((unsigned)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && isdigit(c)); lungetc(c); if (p == buf + 1 && buf[0] == '-') goto nodigits; if (c == EOF || allowed_to_end_number(c)) { const char *errstr = NULL; *p = '\0'; yylval.v.number = strtonum(buf, LLONG_MIN, LLONG_MAX, &errstr); if (errstr) { yyerror("\"%s\" invalid number: %s", buf, errstr); return (findeol()); } return (NUMBER); } else { nodigits: while (p > buf + 1) lungetc(*--p); c = *--p; if (c == '-') return (c); } } #define allowed_in_string(x) \ (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ x != '{' && x != '}' && \ x != '!' && x != '=' && x != '#' && \ x != ',')) if (isalnum(c) || c == ':' || c == '_') { do { *p++ = c; if ((unsigned)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && (allowed_in_string(c))); lungetc(c); *p = '\0'; token = lookup(buf); if (token == STRING) { yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "yylex: strdup"); } return (token); } if (c == '\n') { yylval.lineno = file->lineno; file->lineno++; } if (c == EOF) return (0); return (c); } int check_file_secrecy(int fd, const char *fname) { struct stat st; if (fstat(fd, &st)) { log_warn("cannot stat %s", fname); return (-1); } if (st.st_uid != 0 && st.st_uid != getuid()) { log_warnx("%s: owner not root or current user", fname); return (-1); } if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { log_warnx("%s: group writable or world read/writable", fname); return (-1); } return (0); } struct file * newfile(const char *name, int secret) { struct file *nfile; nfile = calloc(1, sizeof(struct file)); if (nfile == NULL) { log_warn("calloc"); return (NULL); } nfile->name = strdup(name); if (nfile->name == NULL) { log_warn("strdup"); free(nfile); return (NULL); } nfile->stream = fopen(nfile->name, "r"); if (nfile->stream == NULL) { /* no warning, we don't require a conf file */ free(nfile->name); free(nfile); return (NULL); } else if (secret && check_file_secrecy(fileno(nfile->stream), nfile->name)) { fclose(nfile->stream); free(nfile->name); free(nfile); return (NULL); } nfile->lineno = 1; return (nfile); } static void closefile(struct file *xfile) { fclose(xfile->stream); free(xfile->name); free(xfile); } static void add_default_server(void) { new_srv = conf_new_server(D_SITENAME); log_debug("%s: adding default server %s", __func__, D_SITENAME); } int parse_config(const char *filename, struct gotwebd *env) { struct sym *sym, *next; if (config_init(env) == -1) fatalx("failed to initialize configuration"); gotwebd = env; file = newfile(filename, 0); if (file != NULL) { /* we don't require a config file */ yyparse(); errors = file->errors; closefile(file); } /* Free macros and check which have not been used. */ TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { if ((gotwebd->gotwebd_verbose > 1) && !sym->used) fprintf(stderr, "warning: macro '%s' not used\n", sym->nam); if (!sym->persist) { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } /* just add default server if no config specified */ if (gotwebd->server_cnt == 0) add_default_server(); /* add the implicit listen on socket */ if (TAILQ_EMPTY(&gotwebd->addresses)) { const char *path = D_HTTPD_CHROOT D_UNIX_SOCKET; if (get_unix_addr(path) == -1) yyerror("can't listen on %s", path); } if (errors) return (-1); /* setup our listening sockets */ sockets_parse_sockets(env); return (0); } struct server * conf_new_server(const char *name) { struct server *srv = NULL; srv = calloc(1, sizeof(*srv)); if (srv == NULL) fatalx("%s: calloc", __func__); n = strlcpy(srv->name, name, sizeof(srv->name)); if (n >= sizeof(srv->name)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->repos_path, D_GOTPATH, sizeof(srv->repos_path)); if (n >= sizeof(srv->repos_path)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->site_name, D_SITENAME, sizeof(srv->site_name)); if (n >= sizeof(srv->site_name)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->site_owner, D_SITEOWNER, sizeof(srv->site_owner)); if (n >= sizeof(srv->site_owner)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->site_link, D_SITELINK, sizeof(srv->site_link)); if (n >= sizeof(srv->site_link)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->logo, D_GOTLOGO, sizeof(srv->logo)); if (n >= sizeof(srv->logo)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->logo_url, D_GOTURL, sizeof(srv->logo_url)); if (n >= sizeof(srv->logo_url)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->custom_css, D_GOTWEBCSS, sizeof(srv->custom_css)); if (n >= sizeof(srv->custom_css)) fatalx("%s: strlcpy", __func__); srv->show_site_owner = D_SHOWSOWNER; srv->show_repo_owner = D_SHOWROWNER; srv->show_repo_age = D_SHOWAGE; srv->show_repo_description = D_SHOWDESC; srv->show_repo_cloneurl = D_SHOWURL; srv->respect_exportok = D_RESPECTEXPORTOK; srv->max_repos_display = D_MAXREPODISP; srv->max_commits_display = D_MAXCOMMITDISP; srv->summary_commits_display = D_MAXSLCOMMDISP; srv->summary_tags_display = D_MAXSLTAGDISP; TAILQ_INSERT_TAIL(&gotwebd->servers, srv, entry); gotwebd->server_cnt++; return srv; }; int symset(const char *nam, const char *val, int persist) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) break; } if (sym != NULL) { if (sym->persist == 1) return (0); else { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } sym = calloc(1, sizeof(*sym)); if (sym == NULL) return (-1); sym->nam = strdup(nam); if (sym->nam == NULL) { free(sym); return (-1); } sym->val = strdup(val); if (sym->val == NULL) { free(sym->nam); free(sym); return (-1); } sym->used = 0; sym->persist = persist; TAILQ_INSERT_TAIL(&symhead, sym, entry); return (0); } int cmdline_symset(char *s) { char *sym, *val; int ret; val = strrchr(s, '='); if (val == NULL) return (-1); sym = strndup(s, val - s); if (sym == NULL) fatal("%s: strndup", __func__); ret = symset(sym, val + 1, 1); free(sym); return (ret); } char * symget(const char *nam) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) { sym->used = 1; return (sym->val); } } return (NULL); } int get_addrs(const char *hostname, const char *servname) { struct addrinfo hints, *res0, *res; int error; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; struct address *h; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; error = getaddrinfo(hostname, servname, &hints, &res0); if (error) { log_warnx("%s: could not parse \"%s:%s\": %s", __func__, hostname, servname, gai_strerror(error)); return (-1); } for (res = res0; res; res = res->ai_next) { if ((h = calloc(1, sizeof(*h))) == NULL) fatal(__func__); if (hostname == NULL) { strlcpy(h->ifname, "*", sizeof(h->ifname)); } else { if (strlcpy(h->ifname, hostname, sizeof(h->ifname)) >= sizeof(h->ifname)) { log_warnx("%s: address truncated: %s", __func__, hostname); freeaddrinfo(res0); free(h); return (-1); } } h->ai_family = res->ai_family; h->ai_socktype = res->ai_socktype; h->ai_protocol = res->ai_protocol; memcpy(&h->ss, res->ai_addr, res->ai_addrlen); h->slen = res->ai_addrlen; switch (res->ai_family) { case AF_INET: sin = (struct sockaddr_in *)res->ai_addr; h->port = ntohs(sin->sin_port); break; case AF_INET6: sin6 = (struct sockaddr_in6 *)res->ai_addr; h->port = ntohs(sin6->sin6_port); break; default: fatalx("unknown address family %d", res->ai_family); } if (add_addr(h) == -1) { freeaddrinfo(res0); return -1; } } freeaddrinfo(res0); return (0); } int get_unix_addr(const char *path) { struct address *h; struct sockaddr_un *sun; if ((h = calloc(1, sizeof(*h))) == NULL) fatal("%s: calloc", __func__); h->ai_family = AF_UNIX; h->ai_socktype = SOCK_STREAM; h->ai_protocol = PF_UNSPEC; h->slen = sizeof(*sun); sun = (struct sockaddr_un *)&h->ss; sun->sun_family = AF_UNIX; if (strlcpy(sun->sun_path, path, sizeof(sun->sun_path)) >= sizeof(sun->sun_path)) { log_warnx("socket path too long: %s", sun->sun_path); return (-1); } return add_addr(h); } int addr_dup_check(struct addresslist *al, struct address *h) { struct address *a; TAILQ_FOREACH(a, al, entry) { if (a->ai_family != h->ai_family || a->ai_socktype != h->ai_socktype || a->ai_protocol != h->ai_protocol || a->slen != h->slen || memcmp(&a->ss, &h->ss, a->slen) != 0) continue; return -1; } return 0; } int add_addr(struct address *h) { if (addr_dup_check(&gotwebd->addresses, h) == 0) { TAILQ_INSERT_TAIL(&gotwebd->addresses, h, entry); return (0); } free(h); return (0); } got-portable-0.101/gotwebd/gotweb.c0000664000175100017510000006754614644144735012723 /* * Copyright (c) 2016, 2019, 2020-2022 Tracey Emery * Copyright (c) 2015 Mike Larkin * Copyright (c) 2014 Reyk Floeter * Copyright (c) 2013 David Gwynne * Copyright (c) 2013 Florian Obser * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_reference.h" #include "got_repository.h" #include "got_path.h" #include "got_cancel.h" #include "got_worktree.h" #include "got_diff.h" #include "got_commit_graph.h" #include "got_blame.h" #include "got_privsep.h" #include "gotwebd.h" #include "log.h" #include "tmpl.h" static const struct querystring_keys querystring_keys[] = { { "action", ACTION }, { "commit", COMMIT }, { "file", RFILE }, { "folder", FOLDER }, { "headref", HEADREF }, { "index_page", INDEX_PAGE }, { "path", PATH }, }; static const struct action_keys action_keys[] = { { "blame", BLAME }, { "blob", BLOB }, { "blobraw", BLOBRAW }, { "briefs", BRIEFS }, { "commits", COMMITS }, { "diff", DIFF }, { "error", ERR }, { "index", INDEX }, { "patch", PATCH }, { "summary", SUMMARY }, { "tag", TAG }, { "tags", TAGS }, { "tree", TREE }, { "rss", RSS }, }; static const struct got_error *gotweb_init_querystring(struct querystring **); static const struct got_error *gotweb_parse_querystring(struct querystring *, char *); static const struct got_error *gotweb_assign_querystring(struct querystring *, char *, char *); static int gotweb_render_index(struct template *); static const struct got_error *gotweb_load_got_path(struct repo_dir **, const char *, struct request *); static const struct got_error *gotweb_get_repo_description(char **, struct server *, const char *, int); static const struct got_error *gotweb_get_clone_url(char **, struct server *, const char *, int); static void gotweb_free_querystring(struct querystring *); static void gotweb_free_repo_dir(struct repo_dir *); struct server *gotweb_get_server(const char *); static int gotweb_reply(struct request *c, int status, const char *ctype, struct gotweb_url *location) { const char *csp; if (status != 200 && tp_writef(c->tp, "Status: %d\r\n", status) == -1) return -1; if (location) { if (tp_writes(c->tp, "Location: ") == -1 || gotweb_render_url(c, location) == -1 || tp_writes(c->tp, "\r\n") == -1) return -1; } csp = "Content-Security-Policy: default-src 'self'; " "script-src 'none'; object-src 'none';\r\n"; if (tp_writes(c->tp, csp) == -1) return -1; if (ctype && tp_writef(c->tp, "Content-Type: %s\r\n", ctype) == -1) return -1; return tp_writes(c->tp, "\r\n"); } static int gotweb_reply_file(struct request *c, const char *ctype, const char *file, const char *suffix) { int r; r = tp_writef(c->tp, "Content-Disposition: attachment; " "filename=%s%s\r\n", file, suffix ? suffix : ""); if (r == -1) return -1; return gotweb_reply(c, 200, ctype, NULL); } void gotweb_process_request(struct request *c) { const struct got_error *error = NULL; struct server *srv = NULL; struct querystring *qs = NULL; struct repo_dir *repo_dir = NULL; const char *rss_ctype = "application/rss+xml;charset=utf-8"; const uint8_t *buf; size_t len; int r, binary = 0; /* init the transport */ error = gotweb_init_transport(&c->t); if (error) { log_warnx("%s: %s", __func__, error->msg); return; } /* get the gotwebd server */ srv = gotweb_get_server(c->server_name); if (srv == NULL) { log_warnx("%s: error server is NULL", __func__); goto err; } c->srv = srv; /* parse our querystring */ error = gotweb_init_querystring(&qs); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } c->t->qs = qs; error = gotweb_parse_querystring(qs, c->querystring); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } /* * certain actions require a commit id in the querystring. this stops * bad actors from exploiting this by manually manipulating the * querystring. */ if (qs->action == BLAME || qs->action == BLOB || qs->action == BLOBRAW || qs->action == DIFF || qs->action == PATCH) { if (qs->commit == NULL) { error = got_error(GOT_ERR_BAD_QUERYSTRING); goto err; } } if (qs->action != INDEX) { error = gotweb_load_got_path(&repo_dir, qs->path, c); c->t->repo_dir = repo_dir; if (error && error->code != GOT_ERR_LONELY_PACKIDX) goto err; } if (qs->action == BLOBRAW || qs->action == BLOB) { if (qs->folder == NULL || qs->file == NULL) { error = got_error(GOT_ERR_BAD_QUERYSTRING); goto err; } error = got_get_repo_commits(c, 1); if (error) goto err; error = got_open_blob_for_output(&c->t->blob, &c->t->fd, &binary, c, qs->folder, qs->file, qs->commit); if (error) goto err; } switch (qs->action) { case BLAME: if (qs->folder == NULL || qs->file == NULL) { error = got_error(GOT_ERR_BAD_QUERYSTRING); goto err; } error = got_get_repo_commits(c, 1); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } if (gotweb_reply(c, 200, "text/html", NULL) == -1) return; gotweb_render_page(c->tp, gotweb_render_blame); return; case BLOB: if (binary) { struct gotweb_url url = { .index_page = -1, .action = BLOBRAW, .path = qs->path, .commit = qs->commit, .folder = qs->folder, .file = qs->file, }; gotweb_reply(c, 302, NULL, &url); return; } if (gotweb_reply(c, 200, "text/html", NULL) == -1) return; gotweb_render_page(c->tp, gotweb_render_blob); return; case BLOBRAW: if (binary) r = gotweb_reply_file(c, "application/octet-stream", qs->file, NULL); else r = gotweb_reply(c, 200, "text/plain", NULL); if (r == -1) return; if (template_flush(c->tp) == -1) return; for (;;) { error = got_object_blob_read_block(&len, c->t->blob); if (error) break; if (len == 0) break; buf = got_object_blob_get_read_buf(c->t->blob); if (fcgi_write(c, buf, len) == -1) break; } return; case BRIEFS: error = got_get_repo_commits(c, srv->max_commits_display); if (error) goto err; if (gotweb_reply(c, 200, "text/html", NULL) == -1) return; gotweb_render_page(c->tp, gotweb_render_briefs); return; case COMMITS: error = got_get_repo_commits(c, srv->max_commits_display); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } if (gotweb_reply(c, 200, "text/html", NULL) == -1) return; gotweb_render_page(c->tp, gotweb_render_commits); return; case DIFF: error = got_get_repo_commits(c, 1); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } error = got_open_diff_for_output(&c->t->fp, c); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } if (gotweb_reply(c, 200, "text/html", NULL) == -1) return; gotweb_render_page(c->tp, gotweb_render_diff); return; case INDEX: c->t->nrepos = scandir(srv->repos_path, &c->t->repos, NULL, alphasort); if (c->t->nrepos == -1) { c->t->repos = NULL; error = got_error_from_errno2("scandir", srv->repos_path); goto err; } if (gotweb_reply(c, 200, "text/html", NULL) == -1) return; gotweb_render_page(c->tp, gotweb_render_index); return; case PATCH: error = got_get_repo_commits(c, 1); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } error = got_open_diff_for_output(&c->t->fp, c); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } if (gotweb_reply(c, 200, "text/plain", NULL) == -1) return; gotweb_render_patch(c->tp); return; case RSS: error = got_get_repo_tags(c, D_MAXSLCOMMDISP); if (error) goto err; if (gotweb_reply_file(c, rss_ctype, repo_dir->name, ".rss") == -1) return; gotweb_render_rss(c->tp); return; case SUMMARY: error = got_ref_list(&c->t->refs, c->t->repo, "refs/heads", got_ref_cmp_by_name, NULL); if (error) { log_warnx("%s: got_ref_list: %s", __func__, error->msg); goto err; } error = got_get_repo_commits(c, srv->summary_commits_display); if (error) goto err; qs->action = TAGS; error = got_get_repo_tags(c, srv->summary_tags_display); if (error) { log_warnx("%s: got_get_repo_tags: %s", __func__, error->msg); goto err; } qs->action = SUMMARY; if (gotweb_reply(c, 200, "text/html", NULL) == -1) return; gotweb_render_page(c->tp, gotweb_render_summary); return; case TAG: error = got_get_repo_tags(c, 1); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } if (c->t->tag_count == 0) { error = got_error_msg(GOT_ERR_BAD_OBJ_ID, "bad commit id"); goto err; } if (gotweb_reply(c, 200, "text/html", NULL) == -1) return; gotweb_render_page(c->tp, gotweb_render_tag); return; case TAGS: error = got_get_repo_tags(c, srv->max_commits_display); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } if (gotweb_reply(c, 200, "text/html", NULL) == -1) return; gotweb_render_page(c->tp, gotweb_render_tags); return; case TREE: error = got_get_repo_commits(c, 1); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } if (gotweb_reply(c, 200, "text/html", NULL) == -1) return; gotweb_render_page(c->tp, gotweb_render_tree); return; case ERR: default: error = got_error(GOT_ERR_BAD_QUERYSTRING); } err: c->t->error = error; if (gotweb_reply(c, 400, "text/html", NULL) == -1) return; gotweb_render_page(c->tp, gotweb_render_error); } struct server * gotweb_get_server(const char *server_name) { struct server *srv; /* check against the server name first */ if (*server_name != '\0') TAILQ_FOREACH(srv, &gotwebd_env->servers, entry) if (strcmp(srv->name, server_name) == 0) return srv; /* otherwise, use the first server */ return TAILQ_FIRST(&gotwebd_env->servers); }; const struct got_error * gotweb_init_transport(struct transport **t) { const struct got_error *error = NULL; *t = calloc(1, sizeof(**t)); if (*t == NULL) return got_error_from_errno2(__func__, "calloc"); TAILQ_INIT(&(*t)->repo_commits); TAILQ_INIT(&(*t)->repo_tags); TAILQ_INIT(&(*t)->refs); (*t)->fd = -1; return error; } static const struct got_error * gotweb_init_querystring(struct querystring **qs) { const struct got_error *error = NULL; *qs = calloc(1, sizeof(**qs)); if (*qs == NULL) return got_error_from_errno2(__func__, "calloc"); (*qs)->headref = strdup("HEAD"); if ((*qs)->headref == NULL) { free(*qs); *qs = NULL; return got_error_from_errno2(__func__, "strdup"); } (*qs)->action = INDEX; return error; } static const struct got_error * gotweb_parse_querystring(struct querystring *qs, char *qst) { const struct got_error *error = NULL; char *tok1 = NULL, *tok1_pair = NULL, *tok1_end = NULL; char *tok2 = NULL, *tok2_pair = NULL, *tok2_end = NULL; if (qst == NULL) return error; tok1 = strdup(qst); if (tok1 == NULL) return got_error_from_errno2(__func__, "strdup"); tok1_pair = tok1; tok1_end = tok1; while (tok1_pair != NULL) { strsep(&tok1_end, "&"); tok2 = strdup(tok1_pair); if (tok2 == NULL) { free(tok1); return got_error_from_errno2(__func__, "strdup"); } tok2_pair = tok2; tok2_end = tok2; while (tok2_pair != NULL) { strsep(&tok2_end, "="); if (tok2_end) { error = gotweb_assign_querystring(qs, tok2_pair, tok2_end); if (error) goto err; } tok2_pair = tok2_end; } free(tok2); tok1_pair = tok1_end; } free(tok1); return error; err: free(tok2); free(tok1); return error; } /* * Adapted from usr.sbin/httpd/httpd.c url_decode. */ static const struct got_error * gotweb_urldecode(char *url) { char *p, *q; char hex[3]; unsigned long x; hex[2] = '\0'; p = q = url; while (*p != '\0') { switch (*p) { case '%': /* Encoding character is followed by two hex chars */ if (!isxdigit((unsigned char)p[1]) || !isxdigit((unsigned char)p[2]) || (p[1] == '0' && p[2] == '0')) return got_error(GOT_ERR_BAD_QUERYSTRING); hex[0] = p[1]; hex[1] = p[2]; /* * We don't have to validate "hex" because it is * guaranteed to include two hex chars followed by nul. */ x = strtoul(hex, NULL, 16); *q = (char)x; p += 2; break; default: *q = *p; break; } p++; q++; } *q = '\0'; return NULL; } static const struct got_error * gotweb_assign_querystring(struct querystring *qs, char *key, char *value) { const struct got_error *error = NULL; const char *errstr; int a_cnt, el_cnt; error = gotweb_urldecode(value); if (error) return error; for (el_cnt = 0; el_cnt < nitems(querystring_keys); el_cnt++) { if (strcmp(key, querystring_keys[el_cnt].name) != 0) continue; switch (querystring_keys[el_cnt].element) { case ACTION: for (a_cnt = 0; a_cnt < nitems(action_keys); a_cnt++) { if (strcmp(value, action_keys[a_cnt].name) != 0) continue; qs->action = action_keys[a_cnt].action; goto qa_found; } qs->action = ERR; qa_found: break; case COMMIT: qs->commit = strdup(value); if (qs->commit == NULL) { error = got_error_from_errno2(__func__, "strdup"); goto done; } break; case RFILE: qs->file = strdup(value); if (qs->file == NULL) { error = got_error_from_errno2(__func__, "strdup"); goto done; } break; case FOLDER: qs->folder = strdup(value); if (qs->folder == NULL) { error = got_error_from_errno2(__func__, "strdup"); goto done; } break; case HEADREF: free(qs->headref); qs->headref = strdup(value); if (qs->headref == NULL) { error = got_error_from_errno2(__func__, "strdup"); goto done; } break; case INDEX_PAGE: if (*value == '\0') break; qs->index_page = strtonum(value, INT64_MIN, INT64_MAX, &errstr); if (errstr) { error = got_error_from_errno3(__func__, "strtonum", errstr); goto done; } if (qs->index_page < 0) qs->index_page = 0; break; case PATH: qs->path = strdup(value); if (qs->path == NULL) { error = got_error_from_errno2(__func__, "strdup"); goto done; } break; } /* entry found */ break; } done: return error; } void gotweb_free_repo_tag(struct repo_tag *rt) { if (rt != NULL) { free(rt->commit_id); free(rt->tag_name); free(rt->tag_commit); free(rt->commit_msg); free(rt->tagger); } free(rt); } void gotweb_free_repo_commit(struct repo_commit *rc) { if (rc != NULL) { free(rc->path); free(rc->refs_str); free(rc->commit_id); free(rc->parent_id); free(rc->tree_id); free(rc->author); free(rc->committer); free(rc->commit_msg); } free(rc); } static void gotweb_free_querystring(struct querystring *qs) { if (qs != NULL) { free(qs->commit); free(qs->file); free(qs->folder); free(qs->headref); free(qs->path); } free(qs); } static void gotweb_free_repo_dir(struct repo_dir *repo_dir) { if (repo_dir != NULL) { free(repo_dir->name); free(repo_dir->owner); free(repo_dir->description); free(repo_dir->url); free(repo_dir->path); } free(repo_dir); } void gotweb_free_transport(struct transport *t) { const struct got_error *err; struct repo_commit *rc = NULL, *trc = NULL; struct repo_tag *rt = NULL, *trt = NULL; int i; got_ref_list_free(&t->refs); TAILQ_FOREACH_SAFE(rc, &t->repo_commits, entry, trc) { TAILQ_REMOVE(&t->repo_commits, rc, entry); gotweb_free_repo_commit(rc); } TAILQ_FOREACH_SAFE(rt, &t->repo_tags, entry, trt) { TAILQ_REMOVE(&t->repo_tags, rt, entry); gotweb_free_repo_tag(rt); } gotweb_free_repo_dir(t->repo_dir); gotweb_free_querystring(t->qs); free(t->more_id); free(t->tags_more_id); if (t->blob) got_object_blob_close(t->blob); if (t->fp) { err = got_gotweb_closefile(t->fp); if (err) log_warnx("%s: got_gotweb_closefile failure: %s", __func__, err->msg); } if (t->fd != -1 && close(t->fd) == -1) log_warn("%s: close", __func__); if (t->repos) { for (i = 0; i < t->nrepos; ++i) free(t->repos[i]); free(t->repos); } if (t->repo) got_repo_close(t->repo); free(t); } void gotweb_index_navs(struct request *c, struct gotweb_url *prev, int *have_prev, struct gotweb_url *next, int *have_next) { struct transport *t = c->t; struct querystring *qs = t->qs; struct server *srv = c->srv; *have_prev = *have_next = 0; if (qs->index_page > 0) { *have_prev = 1; *prev = (struct gotweb_url){ .action = -1, .index_page = qs->index_page - 1, }; } if (t->next_disp == srv->max_repos_display && t->repos_total != (qs->index_page + 1) * srv->max_repos_display) { *have_next = 1; *next = (struct gotweb_url){ .action = -1, .index_page = qs->index_page + 1, }; } } static int gotweb_render_index(struct template *tp) { const struct got_error *error = NULL; struct request *c = tp->tp_arg; struct server *srv = c->srv; struct transport *t = c->t; struct querystring *qs = t->qs; struct repo_dir *repo_dir = NULL; struct dirent **sd_dent = t->repos; unsigned int d_i, d_disp = 0; unsigned int d_skipped = 0; int type, r; if (gotweb_render_repo_table_hdr(c->tp) == -1) return -1; for (d_i = 0; d_i < t->nrepos; d_i++) { if (strcmp(sd_dent[d_i]->d_name, ".") == 0 || strcmp(sd_dent[d_i]->d_name, "..") == 0) { d_skipped++; continue; } error = got_path_dirent_type(&type, srv->repos_path, sd_dent[d_i]); if (error) continue; if (type != DT_DIR) { d_skipped++; continue; } if (qs->index_page > 0 && (qs->index_page * srv->max_repos_display) > t->prev_disp) { t->prev_disp++; continue; } error = gotweb_load_got_path(&repo_dir, sd_dent[d_i]->d_name, c); if (error && error->code != GOT_ERR_LONELY_PACKIDX) { if (error->code != GOT_ERR_NOT_GIT_REPO) log_warnx("%s: %s: %s", __func__, sd_dent[d_i]->d_name, error->msg); gotweb_free_repo_dir(repo_dir); repo_dir = NULL; d_skipped++; continue; } d_disp++; t->prev_disp++; r = gotweb_render_repo_fragment(c->tp, repo_dir); gotweb_free_repo_dir(repo_dir); repo_dir = NULL; got_repo_close(t->repo); t->repo = NULL; if (r == -1) return -1; t->next_disp++; if (d_disp == srv->max_repos_display) break; } t->repos_total = t->nrepos - d_skipped; if (srv->max_repos_display == 0 || t->repos_total <= srv->max_repos_display) return 0; if (gotweb_render_navs(c->tp) == -1) return -1; return 0; } static inline int should_urlencode(int c) { if (c <= ' ' || c >= 127) return 1; switch (c) { /* gen-delim */ case ':': case '/': case '?': case '#': case '[': case ']': case '@': /* sub-delims */ case '!': case '$': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case ';': case '=': /* needed because the URLs are embedded into the HTML */ case '\"': return 1; default: return 0; } } static char * gotweb_urlencode(const char *str) { const char *s; char *escaped; size_t i, len; int a, b; len = 0; for (s = str; *s; ++s) { len++; if (should_urlencode(*s)) len += 2; } escaped = calloc(1, len + 1); if (escaped == NULL) return NULL; i = 0; for (s = str; *s; ++s) { if (should_urlencode(*s)) { a = (*s & 0xF0) >> 4; b = (*s & 0x0F); escaped[i++] = '%'; escaped[i++] = a <= 9 ? ('0' + a) : ('7' + a); escaped[i++] = b <= 9 ? ('0' + b) : ('7' + b); } else escaped[i++] = *s; } return escaped; } const char * gotweb_action_name(int action) { switch (action) { case BLAME: return "blame"; case BLOB: return "blob"; case BLOBRAW: return "blobraw"; case BRIEFS: return "briefs"; case COMMITS: return "commits"; case DIFF: return "diff"; case ERR: return "err"; case INDEX: return "index"; case PATCH: return "patch"; case SUMMARY: return "summary"; case TAG: return "tag"; case TAGS: return "tags"; case TREE: return "tree"; case RSS: return "rss"; default: return NULL; } } int gotweb_render_url(struct request *c, struct gotweb_url *url) { const char *sep = "?", *action; char *tmp; int r; action = gotweb_action_name(url->action); if (action != NULL) { if (tp_writef(c->tp, "?action=%s", action) == -1) return -1; sep = "&"; } if (url->commit) { if (tp_writef(c->tp, "%scommit=%s", sep, url->commit) == -1) return -1; sep = "&"; } if (url->file) { tmp = gotweb_urlencode(url->file); if (tmp == NULL) return -1; r = tp_writef(c->tp, "%sfile=%s", sep, tmp); free(tmp); if (r == -1) return -1; sep = "&"; } if (url->folder) { tmp = gotweb_urlencode(url->folder); if (tmp == NULL) return -1; r = tp_writef(c->tp, "%sfolder=%s", sep, tmp); free(tmp); if (r == -1) return -1; sep = "&"; } if (url->headref) { tmp = gotweb_urlencode(url->headref); if (tmp == NULL) return -1; r = tp_writef(c->tp, "%sheadref=%s", sep, url->headref); free(tmp); if (r == -1) return -1; sep = "&"; } if (url->index_page != -1) { if (tp_writef(c->tp, "%sindex_page=%d", sep, url->index_page) == -1) return -1; sep = "&"; } if (url->path) { tmp = gotweb_urlencode(url->path); if (tmp == NULL) return -1; r = tp_writef(c->tp, "%spath=%s", sep, tmp); free(tmp); if (r == -1) return -1; sep = "&"; } return 0; } int gotweb_render_absolute_url(struct request *c, struct gotweb_url *url) { struct template *tp = c->tp; const char *proto = c->https ? "https" : "http"; if (tp_writes(tp, proto) == -1 || tp_writes(tp, "://") == -1 || tp_htmlescape(tp, c->server_name) == -1 || tp_htmlescape(tp, c->document_uri) == -1) return -1; return gotweb_render_url(c, url); } static const struct got_error * gotweb_load_got_path(struct repo_dir **rp, const char *dir, struct request *c) { const struct got_error *error = NULL; struct server *srv = c->srv; struct transport *t = c->t; struct repo_dir *repo_dir; DIR *dt; char *dir_test; *rp = calloc(1, sizeof(**rp)); if (*rp == NULL) return got_error_from_errno("calloc"); repo_dir = *rp; if (asprintf(&dir_test, "%s/%s/%s", srv->repos_path, dir, GOTWEB_GIT_DIR) == -1) return got_error_from_errno("asprintf"); dt = opendir(dir_test); if (dt == NULL) { free(dir_test); if (asprintf(&dir_test, "%s/%s", srv->repos_path, dir) == -1) return got_error_from_errno("asprintf"); dt = opendir(dir_test); if (dt == NULL) { free(dir_test); if (asprintf(&dir_test, "%s/%s%s", srv->repos_path, dir, GOTWEB_GIT_DIR) == -1) return got_error_from_errno("asprintf"); dt = opendir(dir_test); if (dt == NULL) { free(dir_test); return got_error_path(dir, GOT_ERR_NOT_GIT_REPO); } } } repo_dir->path = dir_test; dir_test = NULL; repo_dir->name = strdup(repo_dir->path + strlen(srv->repos_path) + 1); if (repo_dir->name == NULL) { error = got_error_from_errno("strdup"); goto err; } if (srv->respect_exportok && faccessat(dirfd(dt), "git-daemon-export-ok", F_OK, 0) == -1) { error = got_error_path(repo_dir->name, GOT_ERR_NOT_GIT_REPO); goto err; } error = got_repo_open(&t->repo, repo_dir->path, NULL, gotwebd_env->pack_fds); if (error) goto err; error = gotweb_get_repo_description(&repo_dir->description, srv, repo_dir->path, dirfd(dt)); if (error) goto err; error = got_get_repo_owner(&repo_dir->owner, c); if (error) goto err; if (srv->show_repo_age) { error = got_get_repo_age(&repo_dir->age, c, NULL); if (error) goto err; } error = gotweb_get_clone_url(&repo_dir->url, srv, repo_dir->path, dirfd(dt)); err: free(dir_test); if (dt != NULL && closedir(dt) == EOF && error == NULL) error = got_error_from_errno("closedir"); if (error && t->repo) { got_repo_close(t->repo); t->repo = NULL; } return error; } static const struct got_error * gotweb_get_repo_description(char **description, struct server *srv, const char *dirpath, int dir) { const struct got_error *error = NULL; struct stat sb; int fd = -1; off_t len; *description = NULL; if (srv->show_repo_description == 0) return NULL; fd = openat(dir, "description", O_RDONLY); if (fd == -1) { if (errno != ENOENT && errno != EACCES) { error = got_error_from_errno_fmt("openat %s/%s", dirpath, "description"); } goto done; } if (fstat(fd, &sb) == -1) { error = got_error_from_errno_fmt("fstat %s/%s", dirpath, "description"); goto done; } len = sb.st_size; if (len > GOTWEBD_MAXDESCRSZ - 1) len = GOTWEBD_MAXDESCRSZ - 1; *description = calloc(len + 1, sizeof(**description)); if (*description == NULL) { error = got_error_from_errno("calloc"); goto done; } if (read(fd, *description, len) == -1) error = got_error_from_errno("read"); done: if (fd != -1 && close(fd) == -1 && error == NULL) error = got_error_from_errno("close"); return error; } static const struct got_error * gotweb_get_clone_url(char **url, struct server *srv, const char *dirpath, int dir) { const struct got_error *error = NULL; struct stat sb; int fd = -1; off_t len; *url = NULL; if (srv->show_repo_cloneurl == 0) return NULL; fd = openat(dir, "cloneurl", O_RDONLY); if (fd == -1) { if (errno != ENOENT && errno != EACCES) { error = got_error_from_errno_fmt("openat %s/%s", dirpath, "cloneurl"); } goto done; } if (fstat(fd, &sb) == -1) { error = got_error_from_errno_fmt("fstat %s/%s", dirpath, "cloneurl"); goto done; } len = sb.st_size; if (len > GOTWEBD_MAXCLONEURLSZ - 1) len = GOTWEBD_MAXCLONEURLSZ - 1; *url = calloc(len + 1, sizeof(**url)); if (*url == NULL) { error = got_error_from_errno("calloc"); goto done; } if (read(fd, *url, len) == -1) error = got_error_from_errno("read"); done: if (fd != -1 && close(fd) == -1 && error == NULL) error = got_error_from_errno("close"); return error; } int gotweb_render_age(struct template *tp, time_t committer_time) { struct request *c = tp->tp_arg; long long diff_time; const char *years = "years ago", *months = "months ago"; const char *weeks = "weeks ago", *days = "days ago"; const char *hours = "hours ago", *minutes = "minutes ago"; const char *seconds = "seconds ago", *now = "right now"; diff_time = time(NULL) - committer_time; if (diff_time > 60 * 60 * 24 * 365 * 2) { if (tp_writef(c->tp, "%lld %s", (diff_time / 60 / 60 / 24 / 365), years) == -1) return -1; } else if (diff_time > 60 * 60 * 24 * (365 / 12) * 2) { if (tp_writef(c->tp, "%lld %s", (diff_time / 60 / 60 / 24 / (365 / 12)), months) == -1) return -1; } else if (diff_time > 60 * 60 * 24 * 7 * 2) { if (tp_writef(c->tp, "%lld %s", (diff_time / 60 / 60 / 24 / 7), weeks) == -1) return -1; } else if (diff_time > 60 * 60 * 24 * 2) { if (tp_writef(c->tp, "%lld %s", (diff_time / 60 / 60 / 24), days) == -1) return -1; } else if (diff_time > 60 * 60 * 2) { if (tp_writef(c->tp, "%lld %s", (diff_time / 60 / 60), hours) == -1) return -1; } else if (diff_time > 60 * 2) { if (tp_writef(c->tp, "%lld %s", (diff_time / 60), minutes) == -1) return -1; } else if (diff_time > 2) { if (tp_writef(c->tp, "%lld %s", diff_time, seconds) == -1) return -1; } else { if (tp_writes(tp, now) == -1) return -1; } return 0; } got-portable-0.101/gotwebd/got_operations.c0000664000175100017510000007314614644144735014461 /* * Copyright (c) 2020-2022 Tracey Emery * Copyright (c) 2018, 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_reference.h" #include "got_repository.h" #include "got_path.h" #include "got_cancel.h" #include "got_diff.h" #include "got_commit_graph.h" #include "got_blame.h" #include "got_privsep.h" #include "gotwebd.h" #include "log.h" static const struct got_error *got_init_repo_commit(struct repo_commit **); static const struct got_error *got_init_repo_tag(struct repo_tag **); static const struct got_error *got_get_repo_commit(struct request *, struct repo_commit *, struct got_commit_object *, struct got_reflist_head *, struct got_object_id *); static const struct got_error *got_gotweb_dupfd(int *, int *); static const struct got_error *got_gotweb_openfile(FILE **, int *); static const struct got_error *got_gotweb_blame_cb(void *, int, int, struct got_commit_object *,struct got_object_id *); const struct got_error * got_gotweb_closefile(FILE *f) { const struct got_error *err = NULL; if (fseek(f, 0, SEEK_SET) == -1) err = got_error_from_errno("fseek"); if (ftruncate(fileno(f), 0) == -1 && err == NULL) err = got_error_from_errno("ftruncate"); if (fclose(f) == EOF && err == NULL) err = got_error_from_errno("fclose"); return err; } static const struct got_error * got_gotweb_openfile(FILE **f, int *priv_fd) { int fd; fd = dup(*priv_fd); if (fd == -1) return got_error_from_errno("dup"); *f = fdopen(fd, "w+"); if (*f == NULL) { close(fd); return got_error(GOT_ERR_PRIVSEP_NO_FD); } return NULL; } static const struct got_error * got_gotweb_dupfd(int *priv_fd, int *fd) { *fd = dup(*priv_fd); if (*fd == -1) return got_error_from_errno("dup"); return NULL; } const struct got_error * got_get_repo_owner(char **owner, struct request *c) { struct server *srv = c->srv; struct transport *t = c->t; struct got_repository *repo = t->repo; const char *gitconfig_owner; *owner = NULL; if (srv->show_repo_owner == 0) return NULL; gitconfig_owner = got_repo_get_gitconfig_owner(repo); if (gitconfig_owner) { *owner = strdup(gitconfig_owner); if (*owner == NULL) return got_error_from_errno("strdup"); } else { *owner = strdup(""); if (*owner == NULL) return got_error_from_errno("strdup"); } return NULL; } const struct got_error * got_get_repo_age(time_t *repo_age, struct request *c, const char *refname) { const struct got_error *error = NULL; struct transport *t = c->t; struct got_repository *repo = t->repo; struct got_commit_object *commit = NULL; struct got_reflist_head refs; struct got_reflist_entry *re; time_t committer_time = 0, cmp_time = 0; TAILQ_INIT(&refs); *repo_age = 0; error = got_ref_list(&refs, repo, "refs/heads", got_ref_cmp_by_name, NULL); if (error) goto done; /* * Find the youngest branch tip in the repository, or the age of * the a specific branch tip if a name was provided by the caller. */ TAILQ_FOREACH(re, &refs, entry) { struct got_object_id *id = NULL; if (refname && strcmp(got_ref_get_name(re->ref), refname) != 0) continue; error = got_ref_resolve(&id, repo, re->ref); if (error) goto done; error = got_object_open_as_commit(&commit, repo, id); free(id); if (error) goto done; committer_time = got_object_commit_get_committer_time(commit); got_object_commit_close(commit); if (cmp_time < committer_time) cmp_time = committer_time; if (refname) break; } if (cmp_time != 0) *repo_age = cmp_time; done: got_ref_list_free(&refs); return error; } static const struct got_error * got_get_repo_commit(struct request *c, struct repo_commit *repo_commit, struct got_commit_object *commit, struct got_reflist_head *refs, struct got_object_id *id) { const struct got_error *error = NULL; struct got_reflist_entry *re; struct got_object_id *id2 = NULL; struct got_object_qid *parent_id; struct transport *t = c->t; struct querystring *qs = c->t->qs; char *commit_msg = NULL, *commit_msg0; TAILQ_FOREACH(re, refs, entry) { char *s; const char *name; struct got_tag_object *tag = NULL; struct got_object_id *ref_id; int cmp; if (got_ref_is_symbolic(re->ref)) continue; name = got_ref_get_name(re->ref); if (strncmp(name, "refs/", 5) == 0) name += 5; if (strncmp(name, "got/", 4) == 0) continue; if (strncmp(name, "heads/", 6) == 0) name += 6; if (strncmp(name, "remotes/", 8) == 0) { name += 8; if (strstr(name, "/" GOT_REF_HEAD) != NULL) continue; } error = got_ref_resolve(&ref_id, t->repo, re->ref); if (error) return error; if (strncmp(name, "tags/", 5) == 0) { error = got_object_open_as_tag(&tag, t->repo, ref_id); if (error) { if (error->code != GOT_ERR_OBJ_TYPE) { free(ref_id); continue; } /* * Ref points at something other * than a tag. */ error = NULL; tag = NULL; } } cmp = got_object_id_cmp(tag ? got_object_tag_get_object_id(tag) : ref_id, id); free(ref_id); if (tag) got_object_tag_close(tag); if (cmp != 0) continue; s = repo_commit->refs_str; if (asprintf(&repo_commit->refs_str, "%s%s%s", s ? s : "", s ? ", " : "", name) == -1) { error = got_error_from_errno("asprintf"); free(s); repo_commit->refs_str = NULL; return error; } free(s); } error = got_object_id_str(&repo_commit->commit_id, id); if (error) return error; error = got_object_id_str(&repo_commit->tree_id, got_object_commit_get_tree_id(commit)); if (error) return error; if (qs->action == DIFF || qs->action == PATCH) { parent_id = STAILQ_FIRST( got_object_commit_get_parent_ids(commit)); if (parent_id != NULL) { id2 = got_object_id_dup(&parent_id->id); error = got_object_id_str(&repo_commit->parent_id, id2); if (error) return error; free(id2); } else { repo_commit->parent_id = strdup("/dev/null"); if (repo_commit->parent_id == NULL) { error = got_error_from_errno("strdup"); return error; } } } repo_commit->committer_time = got_object_commit_get_committer_time(commit); repo_commit->author = strdup(got_object_commit_get_author(commit)); if (repo_commit->author == NULL) { error = got_error_from_errno("strdup"); return error; } repo_commit->committer = strdup(got_object_commit_get_committer(commit)); if (repo_commit->committer == NULL) { error = got_error_from_errno("strdup"); return error; } error = got_object_commit_get_logmsg(&commit_msg0, commit); if (error) return error; commit_msg = commit_msg0; while (*commit_msg == '\n') commit_msg++; repo_commit->commit_msg = strdup(commit_msg); if (repo_commit->commit_msg == NULL) error = got_error_from_errno("strdup"); free(commit_msg0); return error; } const struct got_error * got_get_repo_commits(struct request *c, size_t limit) { const struct got_error *error = NULL; struct got_object_id *id = NULL; struct got_commit_graph *graph = NULL; struct got_commit_object *commit = NULL; struct got_reflist_head refs; struct got_reference *ref = NULL; struct repo_commit *repo_commit = NULL; struct server *srv = c->srv; struct transport *t = c->t; struct got_repository *repo = t->repo; struct querystring *qs = t->qs; struct repo_dir *repo_dir = t->repo_dir; char *in_repo_path = NULL, *repo_path = NULL, *file_path = NULL; int chk_next = 0; if (limit == 0) return got_error(GOT_ERR_RANGE); if (limit > 1) { /* * Traverse one commit more than requested to provide * the next button. */ limit++; chk_next = 1; } TAILQ_INIT(&refs); if (qs->file != NULL && *qs->file != '\0') if (asprintf(&file_path, "%s/%s", qs->folder ? qs->folder : "", qs->file) == -1) return got_error_from_errno("asprintf"); if (asprintf(&repo_path, "%s/%s", srv->repos_path, repo_dir->name) == -1) { error = got_error_from_errno("asprintf"); goto done; } if (qs->commit) { error = got_repo_match_object_id_prefix(&id, qs->commit, GOT_OBJ_TYPE_COMMIT, repo); if (error) goto done; } else { error = got_ref_open(&ref, repo, qs->headref, 0); if (error) goto done; error = got_ref_resolve(&id, repo, ref); if (error) goto done; } error = got_repo_map_path(&in_repo_path, repo, repo_path); if (error) goto done; error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; if (qs->file != NULL && *qs->file != '\0') { error = got_commit_graph_open(&graph, file_path, 0); if (error) goto done; } else { error = got_commit_graph_open(&graph, in_repo_path, 0); if (error) goto done; } error = got_commit_graph_bfsort(graph, id, repo, NULL, NULL); if (error) goto done; for (;;) { struct got_object_id next_id; error = got_commit_graph_iter_next(&next_id, graph, repo, NULL, NULL); if (error) { if (error->code == GOT_ERR_ITER_COMPLETED) error = NULL; goto done; } error = got_object_open_as_commit(&commit, repo, &next_id); if (error) goto done; error = got_init_repo_commit(&repo_commit); if (error) goto done; error = got_get_repo_commit(c, repo_commit, commit, &refs, &next_id); if (error) { gotweb_free_repo_commit(repo_commit); goto done; } if (--limit == 0 && chk_next) { t->more_id = strdup(repo_commit->commit_id); if (t->more_id == NULL) error = got_error_from_errno("strdup"); goto done; } TAILQ_INSERT_TAIL(&t->repo_commits, repo_commit, entry); if (limit == 0) goto done; if (commit) { got_object_commit_close(commit); commit = NULL; } } done: if (ref) got_ref_close(ref); if (commit) got_object_commit_close(commit); if (graph) got_commit_graph_close(graph); got_ref_list_free(&refs); free(in_repo_path); free(file_path); free(repo_path); free(id); return error; } const struct got_error * got_get_repo_tags(struct request *c, size_t limit) { const struct got_error *error = NULL; struct got_object_id *id = NULL; struct got_commit_object *commit = NULL; struct got_reflist_head refs; struct got_reference *ref; struct got_reflist_entry *re; struct server *srv = c->srv; struct transport *t = c->t; struct got_repository *repo = t->repo; struct querystring *qs = t->qs; struct repo_dir *repo_dir = t->repo_dir; struct got_tag_object *tag = NULL; char *in_repo_path = NULL, *repo_path = NULL, *id_str = NULL; char *tag_commit = NULL, *tag_commit0 = NULL; char *commit_msg = NULL, *commit_msg0 = NULL; int chk_next = 0, chk_multi = 1, commit_found = 0; TAILQ_INIT(&refs); if (limit == 0) return got_error(GOT_ERR_RANGE); if (asprintf(&repo_path, "%s/%s", srv->repos_path, repo_dir->name) == -1) return got_error_from_errno("asprintf"); if (qs->commit == NULL && (qs->action == TAGS || qs->action == RSS)) { error = got_ref_open(&ref, repo, qs->headref, 0); if (error) goto done; error = got_ref_resolve(&id, repo, ref); got_ref_close(ref); if (error) goto done; } else if (qs->commit == NULL && qs->action == TAG) { error = got_error_msg(GOT_ERR_EOF, "commit id missing"); goto done; } else { error = got_repo_match_object_id_prefix(&id, qs->commit, GOT_OBJ_TYPE_COMMIT, repo); if (error) goto done; } if (qs->action != SUMMARY && qs->action != TAGS) { error = got_object_open_as_commit(&commit, repo, id); if (error) goto done; error = got_object_commit_get_logmsg(&commit_msg0, commit); if (error) goto done; if (commit) { got_object_commit_close(commit); commit = NULL; } } error = got_repo_map_path(&in_repo_path, repo, repo_path); if (error) goto done; error = got_ref_list(&refs, repo, "refs/tags", got_ref_cmp_tags, repo); if (error) goto done; if (limit == 1) chk_multi = 0; /* * XXX: again, see previous message about caching */ TAILQ_FOREACH(re, &refs, entry) { struct repo_tag *new_repo_tag = NULL; error = got_init_repo_tag(&new_repo_tag); if (error) goto done; TAILQ_INSERT_TAIL(&t->repo_tags, new_repo_tag, entry); new_repo_tag->tag_name = strdup(got_ref_get_name(re->ref)); if (new_repo_tag->tag_name == NULL) { error = got_error_from_errno("strdup"); goto done; } free(id); id = NULL; free(id_str); id_str = NULL; error = got_ref_resolve(&id, repo, re->ref); if (error) goto done; if (tag) got_object_tag_close(tag); error = got_object_open_as_tag(&tag, repo, id); if (error) { if (error->code != GOT_ERR_OBJ_TYPE) goto done; /* "lightweight" tag */ error = got_object_open_as_commit(&commit, repo, id); if (error) goto done; new_repo_tag->tagger = strdup(got_object_commit_get_committer(commit)); if (new_repo_tag->tagger == NULL) { error = got_error_from_errno("strdup"); goto done; } new_repo_tag->tagger_time = got_object_commit_get_committer_time(commit); error = got_object_id_str(&id_str, id); if (error) goto done; } else { new_repo_tag->tagger = strdup(got_object_tag_get_tagger(tag)); if (new_repo_tag->tagger == NULL) { error = got_error_from_errno("strdup"); goto done; } new_repo_tag->tagger_time = got_object_tag_get_tagger_time(tag); error = got_object_id_str(&id_str, got_object_tag_get_object_id(tag)); if (error) goto done; } new_repo_tag->commit_id = strdup(id_str); if (new_repo_tag->commit_id == NULL) goto done; if (commit_found == 0 && qs->commit != NULL && strncmp(id_str, qs->commit, strlen(id_str)) != 0) continue; else commit_found = 1; t->tag_count++; /* * check for one more commit before breaking, * so we know whether to navigate through briefs * commits and summary */ if (chk_next) { t->tags_more_id = strdup(new_repo_tag->commit_id); if (t->tags_more_id == NULL) { error = got_error_from_errno("strdup"); goto done; } if (commit) { got_object_commit_close(commit); commit = NULL; } TAILQ_REMOVE(&t->repo_tags, new_repo_tag, entry); gotweb_free_repo_tag(new_repo_tag); goto done; } if (commit) { error = got_object_commit_get_logmsg(&tag_commit0, commit); if (error) goto done; got_object_commit_close(commit); commit = NULL; } else { tag_commit0 = strdup(got_object_tag_get_message(tag)); if (tag_commit0 == NULL) { error = got_error_from_errno("strdup"); goto done; } } tag_commit = tag_commit0; while (*tag_commit == '\n') tag_commit++; new_repo_tag->tag_commit = strdup(tag_commit); if (new_repo_tag->tag_commit == NULL) { error = got_error_from_errno("strdup"); free(tag_commit0); goto done; } free(tag_commit0); if (qs->action != SUMMARY && qs->action != TAGS) { commit_msg = commit_msg0; while (*commit_msg == '\n') commit_msg++; new_repo_tag->commit_msg = strdup(commit_msg); if (new_repo_tag->commit_msg == NULL) { error = got_error_from_errno("strdup"); goto done; } } if (limit && --limit == 0) { if (chk_multi == 0) break; chk_next = 1; } } done: if (commit) got_object_commit_close(commit); if (tag) got_object_tag_close(tag); got_ref_list_free(&refs); free(commit_msg0); free(in_repo_path); free(repo_path); free(id); free(id_str); return error; } int got_output_repo_tree(struct request *c, char **readme, int (*cb)(struct template *, struct got_tree_entry *)) { const struct got_error *error = NULL; struct transport *t = c->t; struct got_commit_object *commit = NULL; struct got_repository *repo = t->repo; struct querystring *qs = t->qs; struct repo_commit *rc = NULL; struct got_object_id *tree_id = NULL, *commit_id = NULL; struct got_reflist_head refs; struct got_tree_object *tree = NULL; struct got_tree_entry *te; struct repo_dir *repo_dir = t->repo_dir; const char *name; mode_t mode; char *escaped_name = NULL, *path = NULL; int nentries, i; TAILQ_INIT(&refs); *readme = NULL; rc = TAILQ_FIRST(&t->repo_commits); if (qs->folder != NULL) { path = strdup(qs->folder); if (path == NULL) { error = got_error_from_errno("strdup"); goto done; } } else { error = got_repo_map_path(&path, repo, repo_dir->path); if (error) goto done; } error = got_repo_match_object_id(&commit_id, NULL, rc->commit_id, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (error) goto done; error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; error = got_object_id_by_path(&tree_id, repo, commit, path); if (error) goto done; error = got_object_open_as_tree(&tree, repo, tree_id); if (error) goto done; nentries = got_object_tree_get_nentries(tree); for (i = 0; i < nentries; i++) { te = got_object_tree_get_entry(tree, i); name = got_tree_entry_get_name(te); mode = got_tree_entry_get_mode(te); if (!S_ISDIR(mode) && (!strcasecmp(name, "README") || !strcasecmp(name, "README.md") || !strcasecmp(name, "README.txt"))) { free(*readme); *readme = strdup(name); } if (cb(c->tp, te) == -1) { error = got_error(GOT_ERR_CANCELLED); break; } } done: free(escaped_name); free(path); got_ref_list_free(&refs); if (commit) got_object_commit_close(commit); if (tree) got_object_tree_close(tree); free(commit_id); free(tree_id); if (error) { free(*readme); *readme = NULL; if (error->code != GOT_ERR_CANCELLED) log_warnx("%s: %s", __func__, error->msg); return -1; } return 0; } const struct got_error * got_open_blob_for_output(struct got_blob_object **blob, int *fd, int *binary, struct request *c, const char *directory, const char *file, const char *commitstr) { const struct got_error *error = NULL; struct got_repository *repo = c->t->repo; struct got_commit_object *commit = NULL; struct got_object_id *commit_id = NULL; struct got_reflist_head refs; char *path = NULL, *in_repo_path = NULL; int obj_type; TAILQ_INIT(&refs); *blob = NULL; *fd = -1; *binary = 0; error = got_ref_list(&refs, repo, "refs/heads", got_ref_cmp_by_name, NULL); if (error) goto done; if (asprintf(&path, "%s%s%s", directory ? directory : "", directory ? "/" : "", file) == -1) { error = got_error_from_errno("asprintf"); goto done; } error = got_repo_map_path(&in_repo_path, repo, path); if (error) goto done; if (commitstr == NULL) commitstr = GOT_REF_HEAD; error = got_repo_match_object_id(&commit_id, NULL, commitstr, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (error) goto done; error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; error = got_object_id_by_path(&commit_id, repo, commit, in_repo_path); if (error) goto done; if (commit_id == NULL) { error = got_error(GOT_ERR_NO_OBJ); goto done; } error = got_object_get_type(&obj_type, repo, commit_id); if (error) goto done; if (obj_type != GOT_OBJ_TYPE_BLOB) { error = got_error(GOT_ERR_OBJ_TYPE); goto done; } error = got_gotweb_dupfd(&c->priv_fd[BLOB_FD_1], fd); if (error) goto done; error = got_object_open_as_blob(blob, repo, commit_id, BUF, *fd); if (error) goto done; error = got_object_blob_is_binary(binary, *blob); if (error) goto done; done: if (commit) got_object_commit_close(commit); if (error) { if (*fd != -1) close(*fd); if (*blob) got_object_blob_close(*blob); *fd = -1; *blob = NULL; } got_ref_list_free(&refs); free(in_repo_path); free(commit_id); free(path); return error; } int got_output_blob_by_lines(struct template *tp, struct got_blob_object *blob, int (*cb)(struct template *, const char *, size_t)) { const struct got_error *err; char *line = NULL; size_t linesize = 0; size_t lineno = 0; ssize_t linelen = 0; for (;;) { err = got_object_blob_getline(&line, &linelen, &linesize, blob); if (err || linelen == -1) break; lineno++; if (cb(tp, line, lineno) == -1) { err = got_error(GOT_ERR_CANCELLED); break; } } free(line); if (err) { if (err->code != GOT_ERR_CANCELLED) log_warnx("%s: got_object_blob_getline failed: %s", __func__, err->msg); return -1; } return 0; } struct blame_cb_args { struct blame_line *lines; int nlines; int nlines_prec; int lineno_cur; off_t *line_offsets; FILE *f; struct got_repository *repo; struct request *c; got_render_blame_line_cb cb; }; static const struct got_error * got_gotweb_blame_cb(void *arg, int nlines, int lineno, struct got_commit_object *commit, struct got_object_id *id) { const struct got_error *err = NULL; struct blame_cb_args *a = arg; struct blame_line *bline; struct request *c = a->c; char *line = NULL; size_t linesize = 0; off_t offset; struct tm tm; time_t committer_time; if (nlines != a->nlines || (lineno != -1 && lineno < 1) || lineno > a->nlines) return got_error(GOT_ERR_RANGE); if (lineno == -1) return NULL; /* no change in this commit */ /* Annotate this line. */ bline = &a->lines[lineno - 1]; if (bline->annotated) return NULL; err = got_object_id_str(&bline->id_str, id); if (err) return err; bline->committer = strdup(got_object_commit_get_committer(commit)); if (bline->committer == NULL) { err = got_error_from_errno("strdup"); goto done; } committer_time = got_object_commit_get_committer_time(commit); if (gmtime_r(&committer_time, &tm) == NULL) return got_error_from_errno("gmtime_r"); if (strftime(bline->datebuf, sizeof(bline->datebuf), "%F", &tm) == 0) { err = got_error(GOT_ERR_NO_SPACE); goto done; } bline->annotated = 1; /* Print lines annotated so far. */ bline = &a->lines[a->lineno_cur - 1]; if (!bline->annotated) goto done; offset = a->line_offsets[a->lineno_cur - 1]; if (fseeko(a->f, offset, SEEK_SET) == -1) { err = got_error_from_errno("fseeko"); goto done; } while (a->lineno_cur <= a->nlines && bline->annotated) { if (getline(&line, &linesize, a->f) == -1) { if (ferror(a->f)) err = got_error_from_errno("getline"); break; } if (a->cb(c->tp, line, bline, a->nlines_prec, a->lineno_cur) == -1) { err = got_error(GOT_ERR_CANCELLED); break; } a->lineno_cur++; bline = &a->lines[a->lineno_cur - 1]; } done: free(line); return err; } const struct got_error * got_output_file_blame(struct request *c, got_render_blame_line_cb cb) { const struct got_error *error = NULL; struct transport *t = c->t; struct got_repository *repo = t->repo; struct querystring *qs = c->t->qs; struct got_object_id *obj_id = NULL, *commit_id = NULL; struct got_commit_object *commit = NULL; struct got_reflist_head refs; struct got_blob_object *blob = NULL; char *path = NULL, *in_repo_path = NULL; struct blame_cb_args bca; int i, obj_type, blobfd = -1, fd1 = -1, fd2 = -1; off_t filesize; FILE *f1 = NULL, *f2 = NULL; TAILQ_INIT(&refs); bca.f = NULL; bca.lines = NULL; bca.cb = cb; if (asprintf(&path, "%s/%s", qs->folder, qs->file) == -1) { error = got_error_from_errno("asprintf"); goto done; } error = got_repo_map_path(&in_repo_path, repo, path); if (error) goto done; error = got_repo_match_object_id(&commit_id, NULL, qs->commit, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (error) goto done; error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; error = got_object_id_by_path(&obj_id, repo, commit, in_repo_path); if (error) goto done; error = got_object_get_type(&obj_type, repo, obj_id); if (error) goto done; if (obj_type != GOT_OBJ_TYPE_BLOB) { error = got_error(GOT_ERR_OBJ_TYPE); goto done; } error = got_gotweb_openfile(&bca.f, &c->priv_fd[BLAME_FD_1]); if (error) goto done; error = got_gotweb_dupfd(&c->priv_fd[BLAME_FD_2], &blobfd); if (error) goto done; error = got_object_open_as_blob(&blob, repo, obj_id, BUF, blobfd); if (error) goto done; error = got_object_blob_dump_to_file(&filesize, &bca.nlines, &bca.line_offsets, bca.f, blob); if (error || bca.nlines == 0) goto done; /* Don't include \n at EOF in the blame line count. */ if (bca.line_offsets[bca.nlines - 1] == filesize) bca.nlines--; bca.lines = calloc(bca.nlines, sizeof(*bca.lines)); if (bca.lines == NULL) { error = got_error_from_errno("calloc"); goto done; } bca.lineno_cur = 1; bca.nlines_prec = 0; i = bca.nlines; while (i > 0) { i /= 10; bca.nlines_prec++; } bca.repo = repo; bca.c = c; error = got_gotweb_dupfd(&c->priv_fd[BLAME_FD_3], &fd1); if (error) goto done; error = got_gotweb_dupfd(&c->priv_fd[BLAME_FD_4], &fd2); if (error) goto done; error = got_gotweb_openfile(&f1, &c->priv_fd[BLAME_FD_5]); if (error) goto done; error = got_gotweb_openfile(&f2, &c->priv_fd[BLAME_FD_6]); if (error) goto done; error = got_blame(in_repo_path, commit_id, repo, GOT_DIFF_ALGORITHM_MYERS, got_gotweb_blame_cb, &bca, NULL, NULL, fd1, fd2, f1, f2); done: if (bca.lines) { free(bca.line_offsets); for (i = 0; i < bca.nlines; i++) { struct blame_line *bline = &bca.lines[i]; free(bline->id_str); free(bline->committer); } } free(bca.lines); if (blobfd != -1 && close(blobfd) == -1 && error == NULL) error = got_error_from_errno("close"); if (fd1 != -1 && close(fd1) == -1 && error == NULL) error = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && error == NULL) error = got_error_from_errno("close"); if (bca.f) { const struct got_error *bca_err = got_gotweb_closefile(bca.f); if (error == NULL) error = bca_err; } if (f1) { const struct got_error *f1_err = got_gotweb_closefile(f1); if (error == NULL) error = f1_err; } if (f2) { const struct got_error *f2_err = got_gotweb_closefile(f2); if (error == NULL) error = f2_err; } if (commit) got_object_commit_close(commit); if (blob) got_object_blob_close(blob); free(in_repo_path); free(commit_id); free(obj_id); free(path); got_ref_list_free(&refs); return error; } const struct got_error * got_open_diff_for_output(FILE **fp, struct request *c) { const struct got_error *error = NULL; struct transport *t = c->t; struct got_repository *repo = t->repo; struct repo_commit *rc = NULL; struct got_object_id *id1 = NULL, *id2 = NULL; struct got_reflist_head refs; FILE *f1 = NULL, *f2 = NULL, *f3 = NULL; int obj_type, fd1 = -1, fd2 = -1; *fp = NULL; TAILQ_INIT(&refs); error = got_gotweb_openfile(&f1, &c->priv_fd[DIFF_FD_1]); if (error) goto done; error = got_gotweb_openfile(&f2, &c->priv_fd[DIFF_FD_2]); if (error) goto done; error = got_gotweb_openfile(&f3, &c->priv_fd[DIFF_FD_3]); if (error) goto done; rc = TAILQ_FIRST(&t->repo_commits); if (rc->parent_id != NULL && strncmp(rc->parent_id, "/dev/null", 9) != 0) { error = got_repo_match_object_id(&id1, NULL, rc->parent_id, GOT_OBJ_TYPE_ANY, &refs, repo); if (error) goto done; } error = got_repo_match_object_id(&id2, NULL, rc->commit_id, GOT_OBJ_TYPE_ANY, &refs, repo); if (error) goto done; error = got_object_get_type(&obj_type, repo, id2); if (error) goto done; error = got_gotweb_dupfd(&c->priv_fd[DIFF_FD_4], &fd1); if (error) goto done; error = got_gotweb_dupfd(&c->priv_fd[DIFF_FD_5], &fd2); if (error) goto done; switch (obj_type) { case GOT_OBJ_TYPE_BLOB: error = got_diff_objects_as_blobs(NULL, NULL, f1, f2, fd1, fd2, id1, id2, NULL, NULL, GOT_DIFF_ALGORITHM_MYERS, 3, 0, 0, NULL, repo, f3); break; case GOT_OBJ_TYPE_TREE: error = got_diff_objects_as_trees(NULL, NULL, f1, f2, fd1, fd2, id1, id2, NULL, "", "", GOT_DIFF_ALGORITHM_MYERS, 3, 0, 0, NULL, repo, f3); break; case GOT_OBJ_TYPE_COMMIT: error = got_diff_objects_as_commits(NULL, NULL, f1, f2, fd1, fd2, id1, id2, NULL, GOT_DIFF_ALGORITHM_MYERS, 3, 0, 0, NULL, repo, f3); break; default: error = got_error(GOT_ERR_OBJ_TYPE); } if (error) goto done; if (fseek(f3, 0, SEEK_SET) == -1) { error = got_ferror(f3, GOT_ERR_IO); goto done; } *fp = f3; done: if (fd1 != -1 && close(fd1) == -1 && error == NULL) error = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && error == NULL) error = got_error_from_errno("close"); if (f1) { const struct got_error *f1_err = got_gotweb_closefile(f1); if (error == NULL) error = f1_err; } if (f2) { const struct got_error *f2_err = got_gotweb_closefile(f2); if (error == NULL) error = f2_err; } if (error && f3) { got_gotweb_closefile(f3); *fp = NULL; } got_ref_list_free(&refs); free(id1); free(id2); return error; } static const struct got_error * got_init_repo_commit(struct repo_commit **rc) { *rc = calloc(1, sizeof(**rc)); if (*rc == NULL) return got_error_from_errno2(__func__, "calloc"); (*rc)->path = NULL; (*rc)->refs_str = NULL; (*rc)->commit_id = NULL; (*rc)->committer = NULL; (*rc)->author = NULL; (*rc)->parent_id = NULL; (*rc)->tree_id = NULL; (*rc)->commit_msg = NULL; return NULL; } static const struct got_error * got_init_repo_tag(struct repo_tag **rt) { *rt = calloc(1, sizeof(**rt)); if (*rt == NULL) return got_error_from_errno2(__func__, "calloc"); (*rt)->commit_id = NULL; (*rt)->tag_name = NULL; (*rt)->tag_commit = NULL; (*rt)->commit_msg = NULL; (*rt)->tagger = NULL; return NULL; } got-portable-0.101/configure.ac0000664000175100017510000005430514644144735012110 # Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) AC_INIT([got-portable], m4_esyscmd_s(util/got-portable-ver.sh), [thomas@xteddy.org]) AC_CONFIG_AUX_DIR(etc) AC_CONFIG_SRCDIR([lib/rcsutil.h]) AM_INIT_AUTOMAKE([foreign subdir-objects]) AC_CONFIG_HEADERS([include/got_compat.h]) AC_DEFINE_UNQUOTED(VERSION, $VERSION) AC_SUBST(VERSION) AC_SUBST(GOT_RELEASE) AC_DEFINE_UNQUOTED([GOT_VERSION], VERSION, [GoT version string]) AC_DEFINE_UNQUOTED([GOT_VERSION_NUMBER], VERSION, [Got version number]) AC_USE_SYSTEM_EXTENSIONS AC_CANONICAL_HOST AC_CONFIG_SUBDIRS([template]) AC_ARG_ENABLE([cvg], AS_HELP_STRING([--enable-cvg], [EXPERIMENTAL: cvg - cvs-like-git])) # Override gotd's empty_path location. AC_ARG_WITH([gotd-empty-path], [AS_HELP_STRING([--with-gotd-empty-path], [gotd empty path]) ], [GOTD_EMPTY_PATHC=$withval] []) AC_SUBST(GOTD_EMPTY_PATHC) # Override where git's libexec helpers are located for gitwrapper. AC_ARG_WITH([gitwrapper-git-libexec-path], [AS_HELP_STRING([--with-gitwrapper-git-libexec-path], [git libexec path for gitwrapper]) ], [GITWRAPPER_LIBEXEC_PATHC=$withval] []) AC_SUBST(GITWRAPPER_LIBEXEC_PATHC) # When CFLAGS isn't set at this stage and gcc is detected by the macro below, # autoconf will automatically use CFLAGS="-O2 -g". Prevent that by using an # empty default. : ${CFLAGS=""} # Save user CPPFLAGS, CFLAGS and LDFLAGS. We need to change them because # AC_CHECK_HEADER doesn't give us any other way to update the include # paths. But for Makefile.am we want to use AM_CPPFLAGS and friends. SAVED_CFLAGS="$CFLAGS" SAVED_CPPFLAGS="$CPPFLAGS" SAVED_LDFLAGS="$LDFLAGS" # YACC override YACC_OVERRIDE="yes" # Checks for programs. AC_PROG_CC AC_PROG_CPP AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET if test -z "$YACC"; then YACC_OVERRIDE="no" AC_PROG_YACC fi AM_PROG_AR AC_PROG_RANLIB PKG_PROG_PKG_CONFIG if test "$YACC_OVERRIDE" = "yes"; then AC_MSG_NOTICE("Using YACC set from environment: $YACC") fi # Checks for header files. AC_CHECK_HEADERS([ \ fcntl.h \ getopt.h \ langinfo.h \ libutil.h \ limits.h \ linux/landlock.h \ locale.h \ netdb.h \ netinet/in.h \ paths.h \ poll.h \ sha.h \ sha1.h \ sha2.h \ sha256.h \ stddef.h \ stdint.h \ stdlib.h \ string.h \ sys/ioctl.h \ sys/param.h \ sys/poll.h \ sys/queue.h \ sys/select.h \ sys/socket.h \ sys/time.h \ sys/tree.h \ tls.h \ util.h \ unistd.h \ wchar.h \ ]) AC_HEADER_DIRENT AC_CHECK_DECL([F_CLOSEM], HAVE_FCNTL_CLOSEM AC_DEFINE([HAVE_FCNTL_CLOSEM], [1], [Use F_CLOSEM fcntl for closefrom]), [], [#include #include ] ) AC_MSG_CHECKING([for /proc/pid/fd directory]) if test -d "/proc/$$/fd" ; then AC_DEFINE([HAVE_PROC_PID], [1], [Define if you have /proc/$pid/fd]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi AC_MSG_CHECKING([whether program_invocation_short_name is defined]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], [[ program_invocation_short_name = "test"; ]])], [ AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_PROGRAM_INVOCATION_SHORT_NAME], [1], [Define if program_invocation_short_name is defined]) ], [ AC_MSG_RESULT([no]) ]) # Look for prctl(PR_SET_NAME). AC_CHECK_DECL( [PR_SET_NAME], [AC_DEFINE([HAVE_PR_SET_NAME], [1], [Define if PR_SET_NAME is defined])], [], [#include ] ) AM_CONDITIONAL([HAVE_SHA2], [test "x$ac_cv_header_sha2_h" = xyes || \ test "x$ac_cv_header_sha256_h" = xyes]) AC_CACHE_CHECK([whether getopt has optreset support], ac_cv_have_getopt_optreset, [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include ]], [[ extern int optreset; optreset = 0; ]])], [ ac_cv_have_getopt_optreset="yes" ], [ ac_cv_have_getopt_optreset="no" ]) ]) AM_CONDITIONAL([HAVE_GETOPT], [test "x$ac_cv_have_getopt_optreset" = "xyes"]) if test "x$ac_cv_have_getopt_optreset" = "xyes" ; then AC_DEFINE([HAVE_GETOPT_OPTRESET], [1], [Define if your getopt(3) defines and uses optreset]) fi AC_CHECK_MEMBERS([struct pollfd.fd], [], [], [[ #include #ifdef HAVE_POLL_H #include #endif #ifdef HAVE_SYS_POLL_H #include #endif ]]) # Checks for typ edefs, structures, and compiler characteristics. AC_CHECK_HEADER_STDBOOL AC_C_INLINE AC_TYPE_INT64_T AC_TYPE_MODE_T AC_TYPE_OFF_T AC_TYPE_PID_T AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_TYPE_UINT8_T # Check for ifgroupreq which is only available on BSD. AC_CHECK_TYPES([struct ifgroupreq]) # Check for sockaddr_storage. On some systems, ss_len is filled out, although # this is not mandated by POSIX, and hence systems such as linux, don't have # it. AC_CHECK_TYPES([struct sockaddr_storage], [], [], [ #include #include ]) # Same thing as sockaddr_storage above, only now check if the member exists in # the struct as well. AC_CHECK_MEMBERS([struct sockaddr_storage.ss_len], , , [ #include #include #include ] ) AC_CHECK_MEMBERS([struct sockaddr.sa_len], , , [ #include #include #include ] ) # Both checks above will result in: # # HAVE_STRUCT_SOCKADDR_AS_LEN # SS_LEN # # Either being defined or not. # Look for library needed for flock. AC_SEARCH_LIBS(flock, bsd) # Checks for library functions. AC_FUNC_FORK AC_FUNC_FSEEKO AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK AC_FUNC_MALLOC AC_FUNC_MMAP AC_FUNC_REALLOC AC_FUNC_STRERROR_R AC_FUNC_STRNLEN AC_CHECK_FUNCS([ \ dup2 \ flock \ getcwd \ localtime_r \ memchr \ memmove \ memset \ mergesort \ mkdir \ munmap \ nl_langinfo \ realpath \ regcomp \ rmdir \ setlocale \ socket \ setresgid \ setresuid \ setproctitle \ strcasecmp \ strchr \ strcspn \ strdup \ strerror \ strncasecmp \ strndup \ strrchr \ strspn \ strstr \ strtol \ strtoul \ sysconf \ wcwidth \ ]) AM_CONDITIONAL([HAVE_SETPROCTITLE], [test "x$ac_cv_func_setproctitle" = xyes]) if test "x$ac_cv_func_sysconf" = xyes; then AC_DEFINE([HAVE_SYSCONF], [1], [Define to 1 if sysconf() present]) fi # Siphash support. AC_CHECK_FUNCS([SipHash]) AM_CONDITIONAL([HAVE_SIPHASH], [test "x$ac_cv_func_SipHash" = xyes]) # Check for functions with a compatibility implementation. AC_REPLACE_FUNCS([ \ asprintf \ closefrom \ explicit_bzero \ fmt_scaled \ freezero \ getdtablecount \ getline \ getprogname \ recallocarray \ reallocarray \ strlcat \ strlcpy \ strndup \ strnlen \ strsep \ strtonum \ ]) AM_CONDITIONAL([HAVE_CLOSEFROM], [test "x$ac_cv_func_closefrom" = xyes]) # Always use our getopt because 1) glibc's doesn't enforce argument order 2) # musl does not set optarg to NULL for flags without arguments (although it is # not required to, but it is helpful) 3) there are probably other weird # implementations. AC_LIBOBJ(getopt) # Check for b64_ntop. If we have b64_ntop, we assume b64_pton as well. AC_MSG_CHECKING(for b64_ntop) AC_LINK_IFELSE([AC_LANG_PROGRAM( [ #include #include #include ], [ b64_ntop(NULL, 0, NULL, 0); ])], found_b64_ntop=yes, found_b64_ntop=no ) AC_MSG_RESULT($found_b64_ntop) libresolv_LIBS="" if test "x$found_b64_ntop" = xno; then AC_MSG_CHECKING(for b64_ntop with -lresolv) LIBS="-lresolv" AC_LINK_IFELSE([AC_LANG_PROGRAM( [ #include #include #include ], [ b64_ntop(NULL, 0, NULL, 0); ])], found_b64_ntop=yes, found_b64_ntop=no ) AC_MSG_RESULT($found_b64_ntop) libresolv_LIBS="$LIBS" fi if test "x$found_b64_ntop" = xno; then AC_MSG_CHECKING(for b64_ntop with -lnetwork) LIBS="-lresolv -lnetwork" AC_LINK_IFELSE([AC_LANG_PROGRAM( [ #include #include #include ], [ b64_ntop(NULL, 0, NULL, 0); ])], found_b64_ntop=yes, found_b64_ntop=no ) AC_MSG_RESULT($found_b64_ntop) libresolv_LIBS="$LIBS" fi AM_CONDITIONAL([HAVE_B64], [test "x$found_b64_ntop" = xyes]) if test "x$found_b64_ntop" = xyes; then AC_DEFINE([HAVE_B64_NTOP], [1], [define if b64_ntop is present]) AC_SUBST(libresolv_LIBS) else AC_LIBOBJ(base64) fi # Check the platform we're compiling on. AC_MSG_CHECKING(platform) case "$host_os" in *linux*) AC_MSG_RESULT(linux) PLATFORM=linux ;; *freebsd*) AC_MSG_RESULT(freebsd) PLATFORM=freebsd ;; *darwin*) AC_MSG_RESULT(darwin) PLATFORM=darwin ;; *netbsd*) AC_MSG_RESULT(netbsd) PLATFORM=netbsd ;; *openbsd*) AC_MSG_RESULT(openbsd) PLATFORM=openbsd ;; *dragonfly*) AC_MSG_RESULT(dragonfly) PLATFORM=dragonflybsd ;; *) AC_MSG_RESULT(unknown) PLATFORM=unknown ;; esac AC_SUBST(PLATFORM) AM_CONDITIONAL([HOST_FREEBSD], [test "$PLATFORM" = "freebsd"]) AM_CONDITIONAL([HOST_LINUX], [test "$PLATFORM" = "linux"]) AM_CONDITIONAL([HOST_DARWIN], [test "$PLATFORM" = "darwin"]) AM_CONDITIONAL([HOST_NETBSD], [test "$PLATFORM" = "netbsd"]) AM_CONDITIONAL([HOST_OPENBSD], [test "$PLATFORM" = "openbsd"]) AM_CONDITIONAL([HOST_DRAGONFLYBSD], [test "$PLATFORM" = "dragonflybsd"]) # On OpenBSD, these functions are already defined, yet looking for them in # this way on OpenBSD breaks inclusion. # FIXME: this needs addressing. if test "x$PLATFORM" != "xopenbsd"; then AC_CHECK_FUNCS([SHA256Update]) fi # Look for yacc. if test "YACC_OVERRIDE" = "yes" && test -n "$YACC" \ && ! command -v "$YACC" >/dev/null 2>&1; then AC_MSG_ERROR("yacc not found: $YACC") fi if test x"$PLATFORM" = "xdarwin"; then # Check for and/or set HOMEBREW_PREFIX. brew is a common way of # installing applications. The other is MacPorts. # # Before Apple Silicon existed (M1 onward), the paths for applications # installed via homebrew was typically /usr/local. However, with M1 # onward, this changed to a different path. # # Rather than hardcode this, check for HOMEBREW_PREFIX in the # environment if it's already set, and use it. Otherwise, check for # brew(1) and use that. If that fails, default to /usr/local # # This also means that MacPorts should continue to work. # # But with MacPorts, we should also check --prefix, and use that if it # has been supplied. # # In both cases, the variable HOMEBREW_PREFIX is used for both. HB_PREFIX="" FOUND_BISON="no" GNUBISON="" if test -z "$HOMEBREW_PREFIX" -o "$HOMEBREW_PREFIX" = "NONE"; then # HOMEBREW_PREFIX not set, check for brew(1) if command -v brew >/dev/null 2>&1; then AC_MSG_NOTICE("HOMEBREW_PREFIX set via 'brew --prefix'") export HOMEBREW_PREFIX="$(brew --prefix)" fi if test -z "$HOMEBREW_PREFIX" -o "$HOMEBREW_PREFIX" = "NONE" then # Default. if test -z "${prefix}" -o "${prefix}" = "NONE"; then export HOMEBREW_PREFIX="/usr/local" HB_PREFIX="/usr/local" AC_MSG_NOTICE("HOMEBREW_PREFIX defaulting to $HB_PREFIX") else HB_PREFIX="$(eval echo ${prefix})" if test "$HB_PREFIX" = "NONE"; then HB_PREFIX="/opt/local" else AC_MSG_NOTICE("HOMEBREW_PREFIX using --prefix") fi export HOMEBREW_PREFIX="$HB_PREFIX" fi fi fi AC_MSG_NOTICE("HOMEBREW_PREFIX determined as: $HOMEBREW_PREFIX") if test "$YACC_OVERRIDE" = "no" && \ ! test -x "${HOMEBREW_PREFIX}/opt/bison/bin/bison"; then AC_MSG_WARN([ "*********************************************************** GNU Bison not found: ${HOMEBREW_PREFIX}/opt/bison/bin/bison *********************************************************** Falling back to checking either /usr/local or \${prefix}" ]) FOUND_BISON="no" AC_MSG_WARN("Trying ${HB_PREFIX}/opt/bison/bin/bison") if test -x "${HB_PREFIX}/opt/bison/bin/bison"; then export HOMEBREW_PREFIX="/usr/local" FOUND_BISON="yes" GNUBISON="${HB_PREFIX}/opt/bison/bin/bison" fi if test "$FOUND_BISON" = "no"; then HB_PREFIX="/opt/local" AC_MSG_WARN("Trying ${HB_PREFIX}/bin/bison") if test -x "${HB_PREFIX}/bin/bison"; then export HOMEBREW_PREFIX="${HB_PREFIX}" GNUBISON="${HB_PREFIX}/bin/bison" FOUND_BISON="yes" fi fi else FOUND_BISON="yes" GNUBISON="${HOMEBREW_PREFIX}/opt/bison/bin/bison" fi if test "$FOUND_BISON" = "no" && test "$YACC_OVERRIDE" = "no"; then AC_MSG_ERROR("*** Couldn't find GNU BISON ***") fi # Override YACC here to point to the GNU version of bison. if test "$YACC_OVERRIDE" = "yes"; then export YACC="$YACC -y" else AC_MSG_NOTICE("Found GNU Bison as: $GNUBISON") export YACC="${GNUBISON} -y" fi export LDFLAGS="-L${HOMEBREW_PREFIX}/opt/ncurses/lib -L${HOMEBREW_PREFIX}/opt/openssl@3/lib $LDFLAGS" export CPPFLAGS="-I${HOMEBREW_PREFIX}/opt/ncurses/include -I${HOMEBREW_PREFIX}/opt/openssl@3/include $CPPFLAGS" export PKG_CONFIG_PATH="${HOMEBREW_PREFIX}/opt/ncurses/lib/pkgconfig" export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:${HOMEBREW_PREFIX}/opt/openssl@3/lib/pkgconfig" fi # Landlock detection. AC_MSG_CHECKING([for landlock]) AM_CONDITIONAL([HAVE_LINUX_LANDLOCK], [test "x$ac_cv_header_linux_landlock_h" = "xyes"]) if test "x$ac_cv_header_linux_landlock_h" = "xyes"; then AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi # Clang sanitizers wrap reallocarray even if it isn't available on the target # system. When compiled it always returns NULL and crashes the program. To # detect this we need a more complicated test. AC_MSG_CHECKING([for working reallocarray]) AC_RUN_IFELSE([AC_LANG_PROGRAM( [#include ], [return (reallocarray(NULL, 1, 1) == NULL);] )], AC_MSG_RESULT(yes), [AC_LIBOBJ(reallocarray) AC_MSG_RESULT([no])], [AC_LIBOBJ(reallocarray) AC_MSG_RESULT([no])] ) AC_MSG_CHECKING([for working recallocarray]) AC_RUN_IFELSE([AC_LANG_PROGRAM( [#include ], [return (recallocarray(NULL, 1, 1, 1) == NULL);] )], AC_MSG_RESULT(yes), [AC_LIBOBJ(recallocarray) AC_MSG_RESULT([no])], [AC_LIBOBJ(recallocarray) AC_MSG_RESULT([no])] ) # Look for imsg_init in libutil. AC_SEARCH_LIBS(imsg_init, util, found_imsg_init=yes, found_imsg_init=no) AM_CONDITIONAL([HAVE_IMSG], [test "x$found_imsg_init" = "xyes"]) if test "x$found_imsg_init" = "xyes"; then AC_DEFINE([HAVE_IMSG], [1], [Define to 1 if imsg is declared in libutil]) libutil_LIBS="$ac_cv_search_imsg_init" AC_SUBST(libutil_LIBS) fi # libevent (for gotwebd). Lifted from tmux. # Look for libevent. Try libevent_core or libevent with pkg-config first then # look for the library. found_libevent=no PKG_CHECK_MODULES( LIBEVENT_CORE, [libevent_core >= 2], [ libevent_CFLAGS="$LIBEVENT_CORE_CFLAGS" libevent_LIBS="$LIBEVENT_CORE_LIBS" AC_SUBST(libevent_CFLAGS) AC_SUBST(libevent_LIBS) found_libevent=yes ], found_libevent=no ) if test x$found_libevent = xno; then PKG_CHECK_MODULES( LIBEVENT, [libevent >= 2], [ libevent_CFLAGS="$LIBEVENT_CFLAGS" libevent_LIBS="$LIBEVENT_LIBS" AC_SUBST(libevent_CFLAGS) AC_SUBST(libevent_LIBS) found_libevent=yes ], found_libevent=no ) fi if test x$found_libevent = xno; then AC_SEARCH_LIBS( event_init, [event_core event event-1.4], found_libevent=yes, found_libevent=no ) if test "x$found_libevent" = "xyes"; then libevent_LIBS="$ac_cv_search_event_init" AC_SUBST(libevent_LIBS) fi fi if test x$found_libevent = xno; then AC_CHECK_HEADER( event2/event.h, AC_DEFINE([HAVE_EVENT2_EVENT_H], [1], [libevent2 has event.h]), [ AC_CHECK_HEADER( event.h, AC_DEFINE([HAVE_EVENT_H], [0], [libevent]), found_libevent=no ) ] ) fi if test "x$found_libevent" = xno; then AC_MSG_ERROR("libevent not found") fi AC_CHECK_FUNC([uuid_create], [found_uuid=yes], [found_uuid=no]) # Don't define HAVE_BSD_UUID on darwin (Apple) as this breaks the BSD API. # Instead, use the UUID implementation wrapper that's in compat/ plus uuid # ossp if test "x$found_uuid" = "xyes" -a "x$PLATFORM" != "darwin"; then AC_DEFINE([HAVE_BSD_UUID], [1], [BSD UUID]) else PKG_CHECK_MODULES( LIBUUID, uuid, [ libuuid_CFLAGS="$LIBUUID_CFLAGS" libuuid_LIBS="$LIBUUID_LIBS" AC_SUBST(libuuid_CFLAGS) AC_SUBST(libuuid_LIBS) found_libuuid=yes ], [ found_libuuid=no ] ) if test "x$found_libuuid" = "xno"; then AC_CHECK_HEADER( uuid.h, found_libuuid=yes, found_libuuid=no) fi fi if test "x$found_libuuid" = "xno"; then AC_MSG_ERROR("*** couldn't find uuid ***") fi PKG_CHECK_MODULES( ZLIB, zlib, [ zlib_CFLAGS="$ZLIB_CFLAGS" zlib_LIBS="$ZLIB_LIBS" AC_SUBST(zlib_CFLAGS) AC_SUBST(zlib_LIBS) found_zlib=yes ], [ found_zlib=no ] ) if test "x$found_zlib" = "xno"; then AC_CHECK_HEADER( zlib.h, , found_zlib=no) fi if test "x$found_zlib" = "xno"; then AC_MSG_ERROR("*** couldn't find zlib ***") fi if test "$PLATFORM" = "linux"; then PKG_CHECK_MODULES( LIBBSD, libbsd-overlay, [ libbsd_CFLAGS="$LIBBSD_CFLAGS" libbsd_LIBS="$LIBBSD_LIBS" AC_SUBST(libbsd_CFLAGS) AC_SUBST(libbsd_LIBS) AC_DEFINE([HAVE_LIBBSD], [1], [BSD UUID]) ], [ AC_MSG_ERROR("*** couldn't find libbsd-overlay via pkg-config") ] ) # Add LIBBSD_{CFLAGS,LIBS} to the environment here, as libbsd puts its # header files in a non-standard location, which means the overlay for # and won't be found. CFLAGS="$CFLAGS $LIBBSD_CFLAGS" LIBS="$LIBS $LIBBSD_LIBS" PKG_CHECK_MODULES( LIBMD, libmd, [ libmd_CFLAGS="$LIBMD_CFLAGS" libmd_LIBS="$LIBMD_LIBS" AC_SUBST(libmd_CFLAGS) AC_SUBST(libmd_LIBS) ], [] ) CFLAGS="$CFLAGS $LIBMD_CFLAGS" LIBS="$LIBS $LIBMD_LIBS" fi # Look for a suitable queue.h. We hope libbsd is enough, but that is missing # some declarations. AC_CHECK_DECL( TAILQ_CONCAT, found_queue_h=yes, found_queue_h=no, [#include ] ) AC_CHECK_DECL( TAILQ_PREV, , found_queue_h=no, [#include ] ) AC_CHECK_DECL( TAILQ_FOREACH_SAFE, , found_queue_h=no, [#include ] ) if test "x$found_queue_h" = xyes; then AC_DEFINE([HAVE_QUEUE_H], [1], [sys/queue.h]) else AC_MSG_ERROR("*** sys/queue.h missing key defines ***) fi AC_CHECK_DECL( RB_GENERATE_STATIC, found_sys_tree_h=yes, found_sys_tree_h=no, [#include ] ) if test "x$PLATFORM" != "xopenbsd"; then PKG_CHECK_MODULES( LIBTLS, [libtls], [ libtls_CFLAGS="$LIBTLS_CFLAGS" libtls_LIBS="$LIBTLS_LIBS" AC_SUBST(libtls_CFLAGS) AC_SUBST(libtls_LIBS) ], AC_MSG_ERROR(["*** Couldn't find libtls ***"]) ) fi # Look for __progname. AC_MSG_CHECKING(for __progname) AC_LINK_IFELSE([AC_LANG_SOURCE( [ #include #include extern char *__progname; int main(void) { const char *cp = __progname; printf("%s\n", cp); exit(0); } ])], [AC_DEFINE([HAVE___PROGNAME], [1], [___progname]) AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)] ) PKG_CHECK_MODULES( LIBPANELW, panelw, LIBPANELW_LIBS="$LIBPANELW_LIBS" found_panel=yes, found_panel=no ) if test "x$found_panel" = "xno"; then PKG_CHECK_MODULES( LIBPANELW, gnupanelw, [ LIBPANELW_LIBS="$LIBPANELW_LIBS" found_panel=yes ], found_panel=no ) fi if test "x$found_panel" = "xno"; then PKG_CHECK_MODULES( LIBPANELW, panel, [ LIBPANELW_LIBS="$LIBPANELW_LIBS" found_panel=yes ], found_panel=no ) fi if test "x$found_panel" = "xno"; then AC_CHECK_LIB(panelw, update_panels, [], AC_MSG_ERROR([ "*** panelw not found for ncurses. ***"]), [-lncurses] ) fi PKG_CHECK_MODULES( LIBNCURSES, ncursesw, found_ncurses=yes, found_ncurses=no ) if test "x$found_ncurses" = xyes; then libncurses_CFLAGS="$LIBNCURSES_CFLAGS $LIBTINFO_CFLAGS $LIBPANELW_CFLAGS" libncurses_LIBS="$LIBNCURSES_LIBS $LIBTINFO_LIBS $LIBPANELW_LIBS" AC_SUBST(libncurses_CFLAGS) AC_SUBST(libncurses_LIBS) else AC_SEARCH_LIBS( setupterm, found_ncurses=yes, found_ncurses=no ) if test "x$found_ncurses" = xyes; then AC_CHECK_HEADER( ncurses.h, libncurses_CFLAGS="$LIBPANELW_CFLAGS $LIBPANEL_CFLAGS" libncurses_LIBS="$LIBPANELW_LIBS -lncursesw" AC_SUBST(libncurses_CFLAGS) AC_SUBST(libncurses_LIBS) ) fi fi if test "x$found_ncurses" = xyes; then AC_DEFINE([HAVE_NCURSES_H], [1], [NCurses]) else # No ncurses, try curses. AC_CHECK_FUNC( setupterm, found_curses=yes, found_curses=no ) AC_CHECK_HEADER( curses.h, found_curses=yes, found_curses=no) if test "x$found_curses" = xyes; then libncurses_CFLAGS="$LIBPANELW_CFLAGS $LIBPANEL_CFLAGS" libncurses_LIBS="$LIBPANELW_LIBS -lncursesw -lpanelw" AC_SUBST(libncurses_CFLAGS) AC_SUBST(libncurses_LIBS) AC_DEFINE([HAVE_CURSES_H], [1], [Curses_h]) else AC_MSG_ERROR("curses not found") fi fi # Save our CFLAGS/CPPFLAGS/LDFLAGS for the Makefile and restore the old user # variables. AC_SUBST(AM_CPPFLAGS) CPPFLAGS="$SAVED_CPPFLAGS" AC_SUBST(AM_CFLAGS) CFLAGS="$SAVED_CFLAGS" AC_SUBST(AM_LDFLAGS) LDFLAGS="$SAVED_LDFLAGS" # LIBS is designed to accumulate library dependencies as checks for them are # peformed, so that this can be included directly to ld(1). # # However, this hinders the splitting up of the library dependencies so that # they're targetted just where they're needed. Flatting LIBS here ensures # that this happens appropriately. LIBS="" AH_BOTTOM([#include "got_compat2.h"]) AM_CONDITIONAL([CVG_ENABLED], [test "x$enable_cvg" = xyes]) AC_CONFIG_FILES([Makefile compat/Makefile gitwrapper/Makefile got/Makefile gotadmin/Makefile gotctl/Makefile gotd/Makefile gotd/libexec/Makefile gotd/libexec/got-notify-email/Makefile gotd/libexec/got-notify-http/Makefile gotsh/Makefile gotwebd/Makefile libexec/Makefile libexec/got-fetch-http/Makefile libexec/got-fetch-pack/Makefile libexec/got-index-pack/Makefile libexec/got-read-blob/Makefile libexec/got-read-commit/Makefile libexec/got-read-gitconfig/Makefile libexec/got-read-gotconfig/Makefile libexec/got-read-object/Makefile libexec/got-read-pack/Makefile libexec/got-read-patch/Makefile libexec/got-read-tag/Makefile libexec/got-read-tree/Makefile libexec/got-send-pack/Makefile tog/Makefile Makefile.common:Makefile.common.in]) if test "x$enable_cvg" = "xyes"; then AC_CONFIG_FILES([cvg/Makefile]) fi AC_OUTPUT executables="$(eval echo ${exec_prefix}/bin)" helpers="$(eval echo ${libexecdir})" manpages="$(eval echo ${mandir})" gotdep="$GOTD_EMPTY_PATHC" gotgwlep="$GITWRAPPER_LIBEXEC_PATHC" if test -z "$enable_cvg"; then enable_cvg="no" fi if test -z "$gotdep"; then gotdep="N/A" fi if test -z "$gotgwlep"; then gotgwlep="N/A" fi echo " Configured got-portable with: Version: $VERSION Prefix: ${prefix} Executables: ${executables} Bison: $YACC CFlags: $CFLAGS cvg: ${enable_cvg} Gotd: Empty Path: ${gotdep} Gitwrapper: ${gotgwlep} Helpers: ${helpers} Man pages: ${manpages} " got-portable-0.101/gotd/0000775000175100017510000000000014644145570010626 5got-portable-0.101/gotd/repo_imsg.c0000664000175100017510000000464114644144735012705 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_lib_hash.h" #include "gotd.h" #include "log.h" void gotd_imsg_send_ack(struct got_object_id *id, struct imsgbuf *ibuf, uint32_t peerid, pid_t pid) { const struct got_error *err = NULL; struct gotd_imsg_ack iack; char hex[SHA1_DIGEST_STRING_LENGTH]; if (log_getverbose() > 0 && got_object_id_hex(id, hex, sizeof(hex))) log_debug("sending ACK for %s", hex); memset(&iack, 0, sizeof(iack)); memcpy(iack.object_id, id->sha1, SHA1_DIGEST_LENGTH); if (imsg_compose(ibuf, GOTD_IMSG_ACK, peerid, pid, -1, &iack, sizeof(iack)) == -1) { err = got_error_from_errno("imsg_compose ACK"); goto done; } err = gotd_imsg_flush(ibuf); done: if (err) log_warnx("sending ACK: %s", err->msg); } void gotd_imsg_send_nak(struct got_object_id *id, struct imsgbuf *ibuf, uint32_t peerid, pid_t pid) { const struct got_error *err = NULL; struct gotd_imsg_nak inak; char hex[SHA1_DIGEST_STRING_LENGTH]; if (log_getverbose() > 0 && got_object_id_hex(id, hex, sizeof(hex))) log_debug("sending NAK for %s", hex); memset(&inak, 0, sizeof(inak)); memcpy(inak.object_id, id->sha1, SHA1_DIGEST_LENGTH); if (imsg_compose(ibuf, GOTD_IMSG_NAK, peerid, pid, -1, &inak, sizeof(inak)) == -1) { err = got_error_from_errno("imsg_compose NAK"); goto done; } err = gotd_imsg_flush(ibuf); done: if (err) log_warnx("sending NAK: %s", err->msg); } got-portable-0.101/gotd/repo_write.h0000664000175100017510000000176414644143163013102 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void repo_write_main(const char *, const char *, int *, int *, FILE *, FILE *, int, int, struct got_pathlist_head *, struct got_pathlist_head *, struct got_pathlist_head *); void repo_write_shutdown(void); got-portable-0.101/gotd/Makefile.am0000664000175100017510000000454114644144735012610 sbin_PROGRAMS = gotd SUBDIRS=libexec include $(top_builddir)/Makefile.common AM_CPPFLAGS += -DGOTD_EMPTY_PATH='"@GOTD_EMPTY_PATHC@"' gotd_SOURCES = gotd.c \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/commit_graph.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/diff.c \ $(top_srcdir)/lib/diff_atomize_text.c \ $(top_srcdir)/lib/diff_main.c \ $(top_srcdir)/lib/diff_myers.c \ $(top_srcdir)/lib/diff_output.c \ $(top_srcdir)/lib/diff_output_plain.c \ $(top_srcdir)/lib/diff_output_unidiff.c \ $(top_srcdir)/lib/diff_patience.c \ $(top_srcdir)/lib/diffreg.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gitconfig.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/log.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_io.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_io.c \ $(top_srcdir)/lib/pack_index.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig.c \ $(top_srcdir)/lib/read_gotconfig.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ auth.c \ imsg.c \ listen.c \ notify.c \ parse.y \ privsep_stub.c \ repo_imsg.c \ repo_read.c \ repo_write.c \ session_read.c \ session_write.c if !HOST_OPENBSD gotd_SOURCES += chroot-notobsd.c else gotd_SOURCES += chroot-openbsd.c endif gotd_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = gotd.8 gotd.conf.5 *.h man5_MANS = gotd.conf.5 man8_MANS = gotd.8 LDADD = -L$(top_builddir)/compat -lopenbsd-compat -lm LDADD += $(libuuid_LIBS) \ $(zlib_LIBS) \ $(libbsd_LIBS) \ $(libevent_LIBS) \ $(libutil_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(libuuid_CFLAGS) \ $(zlib_CFLAGS) \ $(libbsd_CFLAGS) \ $(libevent_CFLAGS) got-portable-0.101/gotd/session_read.h0000664000175100017510000000161414644143163013373 /* * Copyright (c) 2022, 2023 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void session_read_main(const char *, const char *, int *, int *, struct timeval *, struct gotd_repo *); got-portable-0.101/gotd/notify.c0000664000175100017510000003041514644144735012227 /* * Copyright (c) 2024 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "gotd.h" #include "log.h" #include "notify.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif static struct gotd_notify { pid_t pid; const char *title; struct gotd_imsgev parent_iev; struct gotd_repolist *repos; const char *default_sender; } gotd_notify; struct gotd_notify_session { STAILQ_ENTRY(gotd_notify_session) entry; uint32_t id; struct gotd_imsgev iev; }; STAILQ_HEAD(gotd_notify_sessions, gotd_notify_session); static struct gotd_notify_sessions gotd_notify_sessions[GOTD_CLIENT_TABLE_SIZE]; static SIPHASH_KEY sessions_hash_key; static void gotd_notify_shutdown(void); static uint64_t session_hash(uint32_t session_id) { return SipHash24(&sessions_hash_key, &session_id, sizeof(session_id)); } static void add_session(struct gotd_notify_session *session) { uint64_t slot; slot = session_hash(session->id) % nitems(gotd_notify_sessions); STAILQ_INSERT_HEAD(&gotd_notify_sessions[slot], session, entry); } static struct gotd_notify_session * find_session(uint32_t session_id) { uint64_t slot; struct gotd_notify_session *s; slot = session_hash(session_id) % nitems(gotd_notify_sessions); STAILQ_FOREACH(s, &gotd_notify_sessions[slot], entry) { if (s->id == session_id) return s; } return NULL; } static struct gotd_notify_session * find_session_by_fd(int fd) { uint64_t slot; struct gotd_notify_session *s; for (slot = 0; slot < nitems(gotd_notify_sessions); slot++) { STAILQ_FOREACH(s, &gotd_notify_sessions[slot], entry) { if (s->iev.ibuf.fd == fd) return s; } } return NULL; } static void remove_session(struct gotd_notify_session *session) { uint64_t slot; slot = session_hash(session->id) % nitems(gotd_notify_sessions); STAILQ_REMOVE(&gotd_notify_sessions[slot], session, gotd_notify_session, entry); close(session->iev.ibuf.fd); free(session); } static uint32_t get_session_id(void) { int duplicate = 0; uint32_t id; do { id = arc4random(); duplicate = (find_session(id) != NULL); } while (duplicate || id == 0); return id; } static void gotd_notify_sighdlr(int sig, short event, void *arg) { /* * Normal signal handler rules don't apply because libevent * decouples for us. */ switch (sig) { case SIGHUP: log_info("%s: ignoring SIGHUP", __func__); break; case SIGUSR1: log_info("%s: ignoring SIGUSR1", __func__); break; case SIGTERM: case SIGINT: gotd_notify_shutdown(); /* NOTREACHED */ break; default: fatalx("unexpected signal"); } } static void run_notification_helper(const char *prog, const char **argv, int fd, const char *user, const char *pass) { const struct got_error *err = NULL; pid_t pid; int child_status; pid = fork(); if (pid == -1) { err = got_error_from_errno("fork"); log_warn("%s", err->msg); return; } else if (pid == 0) { signal(SIGQUIT, SIG_DFL); signal(SIGINT, SIG_DFL); signal(SIGCHLD, SIG_DFL); if (dup2(fd, STDIN_FILENO) == -1) { fprintf(stderr, "%s: dup2: %s\n", getprogname(), strerror(errno)); _exit(1); } closefrom(STDERR_FILENO + 1); if (user != NULL && pass != NULL) { setenv("GOT_NOTIFY_HTTP_USER", user, 1); setenv("GOT_NOTIFY_HTTP_PASS", pass, 1); } if (execv(prog, (char *const *)argv) == -1) { fprintf(stderr, "%s: exec %s: %s\n", getprogname(), prog, strerror(errno)); _exit(1); } /* not reached */ } if (waitpid(pid, &child_status, 0) == -1) { err = got_error_from_errno("waitpid"); goto done; } if (!WIFEXITED(child_status)) { err = got_error(GOT_ERR_PRIVSEP_DIED); goto done; } if (WEXITSTATUS(child_status) != 0) err = got_error(GOT_ERR_PRIVSEP_EXIT); done: if (err) log_warnx("%s: child %s pid %d: %s", gotd_notify.title, prog, pid, err->msg); } static void notify_email(struct gotd_notification_target *target, const char *subject_line, int fd) { const char *argv[13]; int i = 0; argv[i++] = GOTD_PATH_PROG_NOTIFY_EMAIL; argv[i++] = "-f"; if (target->conf.email.sender) argv[i++] = target->conf.email.sender; else argv[i++] = gotd_notify.default_sender; if (target->conf.email.responder) { argv[i++] = "-r"; argv[i++] = target->conf.email.responder; } if (target->conf.email.hostname) { argv[i++] = "-h"; argv[i++] = target->conf.email.hostname; } if (target->conf.email.port) { argv[i++] = "-p"; argv[i++] = target->conf.email.port; } argv[i++] = "-s"; argv[i++] = subject_line; argv[i++] = target->conf.email.recipient; argv[i] = NULL; run_notification_helper(GOTD_PATH_PROG_NOTIFY_EMAIL, argv, fd, NULL, NULL); } static void notify_http(struct gotd_notification_target *target, const char *repo, const char *username, int fd) { const char *argv[12]; int argc = 0; argv[argc++] = GOTD_PATH_PROG_NOTIFY_HTTP; if (target->conf.http.tls) argv[argc++] = "-c"; argv[argc++] = "-r"; argv[argc++] = repo; argv[argc++] = "-h"; argv[argc++] = target->conf.http.hostname; argv[argc++] = "-p"; argv[argc++] = target->conf.http.port; argv[argc++] = "-u"; argv[argc++] = username; argv[argc++] = target->conf.http.path; argv[argc] = NULL; run_notification_helper(GOTD_PATH_PROG_NOTIFY_HTTP, argv, fd, target->conf.http.user, target->conf.http.password); } static const struct got_error * send_notification(struct imsg *imsg, struct gotd_imsgev *iev) { const struct got_error *err = NULL; struct gotd_imsg_notify inotify; size_t datalen; struct gotd_repo *repo; struct gotd_notification_target *target; int fd; char *username = NULL; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(inotify)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&inotify, imsg->data, sizeof(inotify)); if (datalen != sizeof(inotify) + inotify.username_len) return got_error(GOT_ERR_PRIVSEP_LEN); repo = gotd_find_repo_by_name(inotify.repo_name, gotd_notify.repos); if (repo == NULL) return got_error(GOT_ERR_PRIVSEP_MSG); fd = imsg_get_fd(imsg); if (fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); username = strndup(imsg->data + sizeof(inotify), inotify.username_len); if (username == NULL) return got_error_from_errno("strndup"); STAILQ_FOREACH(target, &repo->notification_targets, entry) { if (lseek(fd, 0, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } switch (target->type) { case GOTD_NOTIFICATION_VIA_EMAIL: notify_email(target, inotify.subject_line, fd); break; case GOTD_NOTIFICATION_VIA_HTTP: notify_http(target, repo->name, username, fd); break; } } if (gotd_imsg_compose_event(iev, GOTD_IMSG_NOTIFICATION_SENT, PROC_NOTIFY, -1, NULL, 0) == -1) { err = got_error_from_errno("imsg compose NOTIFY"); goto done; } done: close(fd); free(username); return err; } static void notify_dispatch_session(int fd, short event, void *arg) { struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; ssize_t n; int shut = 0; struct imsg imsg; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno != EAGAIN && errno != EPIPE) fatal("msgbuf_write"); if (n == 0 || (n == -1 && errno == EPIPE)) { /* Connection closed. */ shut = 1; goto done; } } for (;;) { const struct got_error *err = NULL; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_NOTIFY: err = send_notification(&imsg, iev); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); if (err) log_warnx("%s: %s", __func__, err->msg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { struct gotd_notify_session *session; /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); imsg_clear(&iev->ibuf); session = find_session_by_fd(fd); if (session) remove_session(session); } } static const struct got_error * recv_session(struct imsg *imsg) { struct gotd_notify_session *session; size_t datalen; int fd; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); fd = imsg_get_fd(imsg); if (fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); session = calloc(1, sizeof(*session)); if (session == NULL) return got_error_from_errno("calloc"); session->id = get_session_id(); imsg_init(&session->iev.ibuf, fd); session->iev.handler = notify_dispatch_session; session->iev.events = EV_READ; session->iev.handler_arg = NULL; event_set(&session->iev.ev, session->iev.ibuf.fd, EV_READ, notify_dispatch_session, &session->iev); gotd_imsg_event_add(&session->iev); add_session(session); return NULL; } static void notify_dispatch(int fd, short event, void *arg) { struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; ssize_t n; int shut = 0; struct imsg imsg; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno != EAGAIN) fatal("msgbuf_write"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } for (;;) { const struct got_error *err = NULL; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_CONNECT_SESSION: err = recv_session(&imsg); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); if (err) log_warnx("%s: %s", __func__, err->msg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void notify_main(const char *title, struct gotd_repolist *repos, const char *default_sender) { const struct got_error *err = NULL; struct event evsigint, evsigterm, evsighup, evsigusr1; arc4random_buf(&sessions_hash_key, sizeof(sessions_hash_key)); gotd_notify.title = title; gotd_notify.repos = repos; gotd_notify.default_sender = default_sender; gotd_notify.pid = getpid(); signal_set(&evsigint, SIGINT, gotd_notify_sighdlr, NULL); signal_set(&evsigterm, SIGTERM, gotd_notify_sighdlr, NULL); signal_set(&evsighup, SIGHUP, gotd_notify_sighdlr, NULL); signal_set(&evsigusr1, SIGUSR1, gotd_notify_sighdlr, NULL); signal(SIGPIPE, SIG_IGN); signal_add(&evsigint, NULL); signal_add(&evsigterm, NULL); signal_add(&evsighup, NULL); signal_add(&evsigusr1, NULL); imsg_init(&gotd_notify.parent_iev.ibuf, GOTD_FILENO_MSG_PIPE); gotd_notify.parent_iev.handler = notify_dispatch; gotd_notify.parent_iev.events = EV_READ; gotd_notify.parent_iev.handler_arg = NULL; event_set(&gotd_notify.parent_iev.ev, gotd_notify.parent_iev.ibuf.fd, EV_READ, notify_dispatch, &gotd_notify.parent_iev); gotd_imsg_event_add(&gotd_notify.parent_iev); event_dispatch(); if (err) log_warnx("%s: %s", title, err->msg); gotd_notify_shutdown(); } void gotd_notify_shutdown(void) { log_debug("%s: shutting down", gotd_notify.title); exit(0); } got-portable-0.101/gotd/listen.h0000644000175100017510000000165014644143163012211 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void listen_main(const char *title, int gotd_socket, struct gotd_uid_connection_limit *connection_limits, size_t nconnection_limits); got-portable-0.101/gotd/chroot-notobsd.c0000664000175100017510000000206014644144735013656 /* * Copyright (c) 2023 Thomas Adam * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include "log.h" int enter_chroot(const char *path) { log_info("chroot into %s", path); if (chroot(path) == -1) fatal("chroot"); if (chdir("/") == -1) fatal("chdir(\"/\")"); return 1; } got-portable-0.101/gotd/auth.h0000644000175100017510000000156514644143163011661 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void auth_main(const char *title, struct gotd_repolist *repos, const char *repo_path); got-portable-0.101/gotd/chroot-openbsd.c0000664000175100017510000000155714644144735013652 /* * Copyright (c) 2023 Thomas Adam * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" int enter_chroot(const char *path) { (void)path; return 0; } got-portable-0.101/gotd/gotd.conf.50000664000175100017510000003403414644143163012515 .\" .\" Copyright (c) 2022 Stefan Sperling .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt GOTD.CONF 5 .Os .Sh NAME .Nm gotd.conf .Nd gotd configuration file .Sh DESCRIPTION .Nm is the run-time configuration file for .Xr gotd 8 . .Pp The file format is line-based, with one configuration directive per line. Any lines beginning with a .Sq # are treated as comments and ignored. .Sh GLOBAL CONFIGURATION The available global configuration directives are as follows: .Bl -tag -width Ds .It Ic connection Ar option Set the specified options and limits for connections to the .Xr gotd 8 unix socket. .Pp The .Ic connection directive may be specified multiple times, and multiple .Ar option arguments may be specified within curly braces: .Pp .Ic connection Brq Ar ... .Pp Each option should only be specified once. If a given option is listed multiple times, the last line which sets this option wins. .Pp Valid connection options are: .Bl -tag -width Ds .It Ic request timeout Ar seconds Specify the inactivity timeout for operations between client and server. If this timeout is exceeded while a Git protocol request is being processed, the request will be aborted and the connection will be terminated. .Pp The timeout value may also have a suffix indicating its unit of measure. Supported suffixes are: .Pp .Bl -tag -compact -width tenletters .It Ar s No or Ar S seconds .It Ar m No or Ar M minutes .It Ar h No or Ar H hours .El .Pp The default timeout is 1h (3600 seconds, one hour). This should only be changed if legitimate requests are exceeding the default timeout for some reason, such as the server spending an extraordinary amount of time generating a pack file. .It Ic limit Ic user Ar identity Ar number Limit the maximum amount of concurrent connections by the user with the username .Ar identity to .Ar number . Numeric user IDs are also accepted. .Pp The default per-user limit is 4. This should only be changed if concurrent connections from a given user are expected to exceed the default limit, for example if an anonymous user is granted read access and many concurrent connections will share this anonymous user identity. .El .It Ic listen on Ar path Set the path to the unix socket which .Xr gotd 8 should listen on. If not specified, the path .Pa /var/run/gotd.sock will be used. .It Ic user Ar user Set the .Ar user which will run .Xr gotd 8 . Initially, .Xr gotd 8 requires root privileges in order to create its unix socket. Afterwards, .Xr gotd 8 drops privileges to the specified .Ar user . If not specified, the user _gotd will be used. .El .Sh REPOSITORY CONFIGURATION At least one repository context must exist for .Xr gotd 8 to function. For each repository, access rules must be configured using the .Ic permit and .Ic deny configuration directives. Multiple access rules can be specified, and the last matching rule determines the action taken. If no rule matches, access to the repository is denied. .Pp A repository context is declared with a unique .Ar name , followed by repository-specific configuration directives inside curly braces: .Pp .Ic repository Ar name Brq ... .Pp .Xr got 1 and .Xr git 1 clients can connect to a repository by including the repository's unique .Ar name in the request URL. Clients appending the string .Dq .git to the .Ar name will also be accepted. .Pp If desired, the .Ar name may contain path-separators, .Dq / , to expose repositories as part of a virtual client-visible directory hierarchy. .Pp The available repository configuration directives are as follows: .Bl -tag -width Ds .It Ic deny Ar identity Deny repository access to users with the username .Ar identity . Group names may be matched by prepending a colon .Pq Sq \&: to .Ar identity . Numeric IDs are also accepted. .It Ic path Ar path Set the path to the Git repository. Must be specified. .It Ic permit Ar mode Ar identity Permit repository access to users with the username .Ar identity . The .Ar mode argument must be set to either .Ic ro for read-only access, or .Ic rw for read-write access. Group names may be matched by prepending a colon .Pq Sq \&: to .Ar identity . Numeric IDs are also accepted. .It Ic protect Brq Ar ... The .Cm protect directive may be used to protect branches and tags in a repository from being overwritten by potentially destructive client-side commands, such as when .Cm got send -f and .Cm git push -f are used to change the history of a branch. .Pp To build a set of protected branches and tags, multiple .Ic protect directives may be specified per repository and multiple .Ic protect directive parameters may be specified within curly braces. .Pp The available .Cm protect parameters are as follows: .Bl -tag -width Ds .It Ic branch Ar name Protect the named branch. The branch may be created if it does not exist yet. Attempts to delete the branch or change its history will be denied. .Pp If the .Ar name does not already begin with .Dq refs/heads/ it will be looked up in the .Dq refs/heads/ reference namespace. .It Ic branch Ic namespace Ar namespace Protect the given reference namespace, assuming that references in this namespace represent branches. New branches may be created in the namespace. Attempts to change the history of branches or delete them will be denied. .Pp The .Ar namespace argument must be absolute, starting with .Dq refs/ . .It Ic tag Ic namespace Ar namespace Protect the given reference namespace, assuming that references in this namespace represent tags. New tags may be created in the namespace. Attempts to change or delete existing tags will be denied. .Pp The .Ar namespace argument must be absolute, starting with .Dq refs/ . .El .Pp The special reference namespaces .Dq refs/got/ and .Dq refs/remotes/ do not need to be listed in .Nm . These namespaces are always protected and even attempts to create new references in these namespaces will always be denied. .It Ic notify Brq Ar ... The .Ic notify directive enables notifications about new commits or tags added to the repository. .Pp Notifications via email require an SMTP daemon which accepts mail for forwarding without requiring client authentication or encryption. On .Ox the .Xr smtpd 8 daemon can be used for this purpose. The default content of email notifications looks similar to the output of the .Cm got log -d command. .Pp Notifications via HTTP require a HTTP or HTTPS server which is accepting POST requests with or without HTTP Basic authentication. Depending on the use case a custom server-side CGI script may be required for the processing of notifications. HTTP notifications can achieve functionality similar to Git's server-side post-receive hook script with .Xr gotd 8 by triggering arbitrary post-commit actions via the HTTP server. .Pp The .Ic notify directive expects parameters which must be enclosed in curly braces. The available parameters are as follows: .Bl -tag -width Ds .It Ic branch Ar name Send notifications about commits to the named branch. The .Ar name will be looked up in the .Dq refs/heads/ reference namespace. This directive may be specified multiple times to build a list of branches to send notifications for. If neither a .Ic branch nor a .Ic reference namespace are specified then changes to any reference will trigger notifications. .It Ic reference Ic namespace Ar namespace Send notifications about commits or tags within a reference namespace. This directive may be specified multiple times to build a list of namespaces to send notifications for. If neither a .Ic branch nor a .Ic reference namespace are specified then changes to any reference will trigger notifications. .It Ic email Oo Ic from Ar sender Oc Ic to Ar recipient Oo Ic reply to Ar responder Oc Oo Ic relay Ar hostname Oo Ic port Ar port Oc Oc Send notifications via email to the specified .Ar recipient . This directive may be specified multiple times to build a list of recipients to send notifications to. .Pp The .Ar recipient must be an email addresses that accepts mail. The .Ar sender will be used as the From address. If not specified, the sender defaults to an email address composed of the user account running .Xr gotd 8 and the local hostname. .Pp If a .Ar responder is specified via the .Ic reply to directive, the .Ar responder will be used as the Reply-to address. Setting the Reply-to header can be useful if replies should go to a mailing list instead of the .Ar sender , for example. .Pp By default, mail will be sent to the SMTP server listening on the loopback address 127.0.0.1 on port 25. The .Ic relay and .Ic port directives can be used to specify a different SMTP server address and port. .It Ic url Ar URL Oo Ic user Ar user Ic password Ar password Oo Ic insecure Oc Oc Send notifications via HTTP. This directive may be specified multiple times to build a list of HTTP servers to send notifications to. .Pp The notification will be sent as a POST request to the given .Ar URL , which must be a valid HTTP URL and begin with either .Dq http:// or .Dq https:// . If HTTPS is used, sending of notifications will only succeed if no TLS errors occur. .Pp The optional .Ic user and .Ic password directives enable HTTP Basic authentication. If used, both a .Ar user and a .Ar password must be specified. The .Ar password must not be an empty string. Unless the .Ic insecure option is specified the notification target .Ar URL must be a .Dq https:// URL to avoid leaking of authentication credentials. .Pp The request body contains a JSON object with a .Dq notifications property containing an array of notification objects. The following notification object properties are always present: .Bl -tag -width authenticated_user .It Dv repo The repository name as a string. .It Dv authenticated_user The committer's user account as authenticated by .Xr gotd 8 as a string. .It Dv type The notification object type as a string. .El .Pp Each notification object carries additional type-specific properties. The types and their type-specific properties are: .Bl -tag -width Ds .It Dv commit The commit notification object has the following fields. Except where noted, all are optional. .Bl -tag -width Ds .It Dv short Boolean, indicates whether the object has all the fields set. When several commits are batched in a single send operation, not all of the fields are available for each commit object. .It Dv id The commit ID as string, may be abbreviated. .It Dv committer An object with the committer information with the following fields: .Pp .Bl -tag -compact -width Ds .It Dv full Committer's full name. .It Dv name Committer's name. .It Dv mail Committer's mail address. .It Dv user Committer's username. This is the only field guaranteed to be set. .El .It Dv author An object with the author information. Has the same fields as the .Sq committer but may be unset. .It Dv date Number, representing the number of seconds since the Epoch in UTC. .It Dv short_message The first line of the commit message. This field is always set. .It Dv message The complete commit message, may be unset. .It Dv diffstat An object with the summarized changes, may be unset. Contains a .Sq files field with an array of objects describing the changes per-file and a .Sq total field with the cumulative changes. The changes per-file contains the following fields: .Pp .Bl -tag -compact -width removed .It Dv action A string describing the action, can be .Dq added , .Dq deleted , .Dq modified , .Dq mode changed , or .Dq unknown . .It Dv file The file path. .It Dv added The number of lines added. .It Dv removed The number of lines removed. .El .Pp The .Sq total object contains two fields: .Sq added and .Sq removed which are the number of added and removed lines respectively. .El .It Dv branch-deleted The branch deleted notifications has the following fields, all guaranteed to be set: .Bl -tag -width Ds .It Dv ref The removed branch reference. .It Dv id The hash of the commit pointed by the deleted branch. .El .It Dv tag The tag notification has the following fields, all guaranteed to be set: .Bl -tag -width Ds .It tag The tag reference. .It tagger The user information, with the same format of the .Sq committer field for the .Sq commit notification but with all the field guaranteed to be set. .It Dv date Number, representing the number of seconds since the Epoch in UTC. .It Dv object The object being tagged. It contains the fields .Sq type with the object type and .Sq id with the object id being tagged. .It Dv message The tag message. .El .El .El .El .Sh FILES .Bl -tag -width Ds -compact .It Pa /etc/gotd.conf Location of the .Nm configuration file. .El .Sh EXAMPLES .Bd -literal -offset indent # Run as the default user: user _gotd # Listen on the default socket: listen on "/var/run/gotd.sock" # This repository can be accessed via ssh://user@example.com/src repository "src" { path "/var/git/src.git" permit rw flan_hacker permit rw :developers permit ro anonymous protect branch "main" protect tag namespace "refs/tags/" } # This repository can be accessed via # ssh://user@example.com/openbsd/ports repository "openbsd/ports" { path "/var/git/ports.git" permit rw :porters permit ro anonymous deny flan_hacker protect { branch "main" tag namespace "refs/tags/" } notify { branch "main" reference namespace "refs/tags/" email to openbsd-ports-changes@example.com .\" url https://example.com/notify/ user "flan_announcer" password "secret" } } # Use a larger request timeout value: connection request timeout 2h # Some users are granted a higher concurrent connection limit: connection { limit user flan_hacker 16 limit user anonymous 32 } .Ed .Sh SEE ALSO .Xr got 1 , .Xr gotsh 1 , .Xr gotd 8 got-portable-0.101/gotd/notify.h0000664000175100017510000000154014644143163012223 /* * Copyright (c) 2024 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void notify_main(const char *, struct gotd_repolist *, const char *); got-portable-0.101/gotd/privsep_stub.c0000664000175100017510000000372514644144735013450 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_object_cache.h" #include "got_lib_pack.h" #include "got_lib_repository.h" #include "got_lib_privsep.h" const struct got_error * got_privsep_send_stop(int fd) { return got_error(GOT_ERR_NOT_IMPL); } const struct got_error * got_privsep_wait_for_child(pid_t pid) { return got_error(GOT_ERR_NOT_IMPL); } void got_privsep_exec_child(int imsg_fds[2], const char *path, const char *repo_path) { fprintf(stderr, "%s: cannot run libexec helpers\n", getprogname()); exit(1); } const struct got_error * got_privsep_init_pack_child(struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx) { return got_error(GOT_ERR_NOT_IMPL); } const struct got_error * got_traverse_packed_commits(struct got_object_id_queue *traversed_commits, struct got_object_id *commit_id, const char *path, struct got_repository *repo) { return NULL; } got-portable-0.101/gotd/auth.c0000664000175100017510000001731614644144735011665 /* * Copyright (c) 2022 Stefan Sperling * Copyright (c) 2015 Ted Unangst * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "gotd.h" #include "log.h" #include "auth.h" static struct gotd_auth { pid_t pid; const char *title; struct gotd_repo *repo; } gotd_auth; static void auth_shutdown(void); static void auth_sighdlr(int sig, short event, void *arg) { /* * Normal signal handler rules don't apply because libevent * decouples for us. */ switch (sig) { case SIGHUP: break; case SIGUSR1: break; case SIGTERM: case SIGINT: auth_shutdown(); /* NOTREACHED */ break; default: fatalx("unexpected signal"); } } static int uidcheck(const char *s, uid_t desired) { uid_t uid; if (gotd_parseuid(s, &uid) != 0) return -1; if (uid != desired) return -1; return 0; } static int parsegid(const char *s, gid_t *gid) { struct group *gr; const char *errstr; if ((gr = getgrnam(s)) != NULL) { *gid = gr->gr_gid; if (*gid == GID_MAX) return -1; return 0; } *gid = strtonum(s, 0, GID_MAX - 1, &errstr); if (errstr) return -1; return 0; } static int match_identifier(const char *identifier, gid_t *groups, int ngroups, uid_t euid, gid_t egid) { int i; if (identifier[0] == ':') { gid_t rgid; if (parsegid(identifier + 1, &rgid) == -1) return 0; if (rgid == egid) return 1; for (i = 0; i < ngroups; i++) { if (rgid == groups[i]) break; } if (i == ngroups) return 0; } else if (uidcheck(identifier, euid) != 0) return 0; return 1; } static const struct got_error * auth_check(char **username, struct gotd_access_rule_list *rules, const char *repo_name, uid_t euid, gid_t egid, int required_auth) { struct gotd_access_rule *rule; enum gotd_access access = GOTD_ACCESS_DENIED; struct passwd *pw; gid_t groups[NGROUPS_MAX]; int ngroups = NGROUPS_MAX; int matched_user = 0; *username = NULL; pw = getpwuid(euid); if (pw == NULL) { if (errno) return got_error_from_errno("getpwuid"); else return got_error_set_errno(EACCES, repo_name); } *username = strdup(pw->pw_name); if (*username == NULL) return got_error_from_errno("strdup"); if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups) == -1) log_warnx("group membership list truncated"); STAILQ_FOREACH(rule, rules, entry) { if (!match_identifier(rule->identifier, groups, ngroups, euid, egid)) continue; matched_user = 1; access = rule->access; if (rule->access == GOTD_ACCESS_PERMITTED && (rule->authorization & required_auth) != required_auth) access = GOTD_ACCESS_DENIED; } if (access == GOTD_ACCESS_DENIED) { /* * If a user has no explicit read or write access then * do not leak the existence of a repository to them. */ if (!matched_user) return got_error(GOT_ERR_NOT_GIT_REPO); else return got_error_set_errno(EACCES, repo_name); } if (access == GOTD_ACCESS_PERMITTED) return NULL; /* should not happen, this would be a bug */ return got_error_msg(GOT_ERR_NOT_IMPL, "bad access rule"); } static const struct got_error * recv_authreq(struct imsg *imsg, struct gotd_imsgev *iev) { const struct got_error *err; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_imsg_auth iauth; size_t datalen; uid_t euid; gid_t egid; char *username = NULL; size_t len; const size_t maxlen = MAX_IMSGSIZE - IMSG_HEADER_SIZE; int fd = -1; log_debug("authentication request received"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(iauth)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iauth, imsg->data, datalen); fd = imsg_get_fd(imsg); if (fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); if (getpeereid(fd, &euid, &egid) == -1) return got_error_from_errno("getpeerid"); if (iauth.euid != euid) return got_error(GOT_ERR_UID); if (iauth.egid != egid) return got_error(GOT_ERR_GID); log_debug("authenticating uid %d gid %d", euid, egid); err = auth_check(&username, &gotd_auth.repo->rules, gotd_auth.repo->name, iauth.euid, iauth.egid, iauth.required_auth); if (err) { gotd_imsg_send_error(ibuf, PROC_AUTH, iauth.client_id, err); goto done; } len = strlen(username); if (len > maxlen) len = maxlen; if (gotd_imsg_compose_event(iev, GOTD_IMSG_ACCESS_GRANTED, PROC_AUTH, -1, username, len) == -1) err = got_error_from_errno("imsg compose ACCESS_GRANTED"); done: free(username); return err; } static void auth_dispatch(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; ssize_t n; int shut = 0; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) /* Connection closed. */ shut = 1; } if (event & EV_WRITE) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno != EAGAIN) fatal("msgbuf_write"); if (n == 0) /* Connection closed. */ shut = 1; } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_AUTHENTICATE: err = recv_authreq(&imsg, iev); if (err) log_warnx("%s", err->msg); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void auth_main(const char *title, struct gotd_repolist *repos, const char *repo_path) { struct gotd_repo *repo = NULL; struct gotd_imsgev iev; struct event evsigint, evsigterm, evsighup, evsigusr1; gotd_auth.title = title; gotd_auth.pid = getpid(); TAILQ_FOREACH(repo, repos, entry) { if (got_path_cmp(repo->path, repo_path, strlen(repo->path), strlen(repo_path)) == 0) break; } if (repo == NULL) fatalx("repository %s not found in config", repo_path); gotd_auth.repo = repo; signal_set(&evsigint, SIGINT, auth_sighdlr, NULL); signal_set(&evsigterm, SIGTERM, auth_sighdlr, NULL); signal_set(&evsighup, SIGHUP, auth_sighdlr, NULL); signal_set(&evsigusr1, SIGUSR1, auth_sighdlr, NULL); signal(SIGPIPE, SIG_IGN); signal_add(&evsigint, NULL); signal_add(&evsigterm, NULL); signal_add(&evsighup, NULL); signal_add(&evsigusr1, NULL); imsg_init(&iev.ibuf, GOTD_FILENO_MSG_PIPE); iev.handler = auth_dispatch; iev.events = EV_READ; iev.handler_arg = NULL; event_set(&iev.ev, iev.ibuf.fd, EV_READ, auth_dispatch, &iev); if (event_add(&iev.ev, NULL) == -1) fatalx("event add"); event_dispatch(); auth_shutdown(); } static void auth_shutdown(void) { log_debug("%s: shutting down", gotd_auth.title); exit(0); } got-portable-0.101/gotd/session_read.c0000664000175100017510000005607614644144735013410 /* * Copyright (c) 2022, 2023 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_repository.h" #include "got_object.h" #include "got_path.h" #include "got_reference.h" #include "got_opentemp.h" #include "got_lib_hash.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_object_cache.h" #include "got_lib_pack.h" #include "got_lib_repository.h" #include "got_lib_gitproto.h" #include "gotd.h" #include "log.h" #include "session_read.h" enum gotd_session_read_state { GOTD_STATE_EXPECT_LIST_REFS, GOTD_STATE_EXPECT_CAPABILITIES, GOTD_STATE_EXPECT_WANT, GOTD_STATE_EXPECT_HAVE_OR_DONE, GOTD_STATE_DONE, }; static struct gotd_session_read { pid_t pid; const char *title; struct got_repository *repo; struct gotd_repo *repo_cfg; int *pack_fds; int *temp_fds; struct gotd_imsgev parent_iev; struct gotd_imsgev notifier_iev; struct timeval request_timeout; enum gotd_session_read_state state; struct gotd_imsgev repo_child_iev; } gotd_session; static struct gotd_session_client { struct gotd_client_capability *capabilities; size_t ncapa_alloc; size_t ncapabilities; uint32_t id; int fd; int delta_cache_fd; struct gotd_imsgev iev; struct event tmo; uid_t euid; gid_t egid; char *username; char *packfile_path; char *packidx_path; int nref_updates; int accept_flush_pkt; int flush_disconnect; } gotd_session_client; static void session_read_shutdown(void); static void disconnect(struct gotd_session_client *client) { log_debug("uid %d: disconnecting", client->euid); if (gotd_imsg_compose_event(&gotd_session.parent_iev, GOTD_IMSG_DISCONNECT, PROC_SESSION_READ, -1, NULL, 0) == -1) log_warn("imsg compose DISCONNECT"); imsg_clear(&gotd_session.repo_child_iev.ibuf); event_del(&gotd_session.repo_child_iev.ev); evtimer_del(&client->tmo); close(client->fd); if (client->delta_cache_fd != -1) close(client->delta_cache_fd); if (client->packfile_path) { if (unlink(client->packfile_path) == -1 && errno != ENOENT) log_warn("unlink %s: ", client->packfile_path); free(client->packfile_path); } if (client->packidx_path) { if (unlink(client->packidx_path) == -1 && errno != ENOENT) log_warn("unlink %s: ", client->packidx_path); free(client->packidx_path); } free(client->capabilities); session_read_shutdown(); } static void disconnect_on_error(struct gotd_session_client *client, const struct got_error *err) { struct imsgbuf ibuf; if (err->code != GOT_ERR_EOF) { log_warnx("uid %d: %s", client->euid, err->msg); imsg_init(&ibuf, client->fd); gotd_imsg_send_error(&ibuf, 0, PROC_SESSION_READ, err); imsg_clear(&ibuf); } disconnect(client); } static void gotd_request_timeout(int fd, short events, void *arg) { struct gotd_session_client *client = arg; log_warnx("disconnecting uid %d due to timeout", client->euid); disconnect(client); } static void session_read_sighdlr(int sig, short event, void *arg) { /* * Normal signal handler rules don't apply because libevent * decouples for us. */ switch (sig) { case SIGHUP: log_info("%s: ignoring SIGHUP", __func__); break; case SIGUSR1: log_info("%s: ignoring SIGUSR1", __func__); break; case SIGTERM: case SIGINT: session_read_shutdown(); /* NOTREACHED */ break; default: fatalx("unexpected signal"); } } static const struct got_error * recv_packfile_done(struct imsg *imsg) { size_t datalen; log_debug("packfile-done received"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); return NULL; } static void session_dispatch_repo_child(int fd, short event, void *arg) { struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_session_client *client = &gotd_session_client; ssize_t n; int shut = 0; struct imsg imsg; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno != EAGAIN) fatal("msgbuf_write"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } for (;;) { const struct got_error *err = NULL; uint32_t client_id = 0; int do_disconnect = 0; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: do_disconnect = 1; err = gotd_imsg_recv_error(&client_id, &imsg); break; case GOTD_IMSG_PACKFILE_DONE: do_disconnect = 1; err = recv_packfile_done(&imsg); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } if (do_disconnect) { if (err) disconnect_on_error(client, err); else disconnect(client); } else { if (err) log_warnx("uid %d: %s", client->euid, err->msg); } imsg_free(&imsg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } static const struct got_error * recv_capabilities(struct gotd_session_client *client, struct imsg *imsg) { struct gotd_imsg_capabilities icapas; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(icapas)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&icapas, imsg->data, sizeof(icapas)); client->ncapa_alloc = icapas.ncapabilities; client->capabilities = calloc(client->ncapa_alloc, sizeof(*client->capabilities)); if (client->capabilities == NULL) { client->ncapa_alloc = 0; return got_error_from_errno("calloc"); } log_debug("expecting %zu capabilities from uid %d", client->ncapa_alloc, client->euid); return NULL; } static const struct got_error * recv_capability(struct gotd_session_client *client, struct imsg *imsg) { struct gotd_imsg_capability icapa; struct gotd_client_capability *capa; size_t datalen; char *key, *value = NULL; if (client->capabilities == NULL || client->ncapabilities >= client->ncapa_alloc) { return got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected capability received"); } memset(&icapa, 0, sizeof(icapa)); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(icapa)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&icapa, imsg->data, sizeof(icapa)); if (datalen != sizeof(icapa) + icapa.key_len + icapa.value_len) return got_error(GOT_ERR_PRIVSEP_LEN); key = strndup(imsg->data + sizeof(icapa), icapa.key_len); if (key == NULL) return got_error_from_errno("strndup"); if (icapa.value_len > 0) { value = strndup(imsg->data + sizeof(icapa) + icapa.key_len, icapa.value_len); if (value == NULL) { free(key); return got_error_from_errno("strndup"); } } capa = &client->capabilities[client->ncapabilities++]; capa->key = key; capa->value = value; if (value) log_debug("uid %d: capability %s=%s", client->euid, key, value); else log_debug("uid %d: capability %s", client->euid, key); return NULL; } static const struct got_error * forward_want(struct gotd_session_client *client, struct imsg *imsg) { struct gotd_imsg_want ireq; struct gotd_imsg_want iwant; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ireq)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ireq, imsg->data, datalen); memset(&iwant, 0, sizeof(iwant)); memcpy(iwant.object_id, ireq.object_id, SHA1_DIGEST_LENGTH); if (gotd_imsg_compose_event(&gotd_session.repo_child_iev, GOTD_IMSG_WANT, PROC_SESSION_READ, -1, &iwant, sizeof(iwant)) == -1) return got_error_from_errno("imsg compose WANT"); return NULL; } static const struct got_error * forward_have(struct gotd_session_client *client, struct imsg *imsg) { struct gotd_imsg_have ireq; struct gotd_imsg_have ihave; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ireq)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ireq, imsg->data, datalen); memset(&ihave, 0, sizeof(ihave)); memcpy(ihave.object_id, ireq.object_id, SHA1_DIGEST_LENGTH); if (gotd_imsg_compose_event(&gotd_session.repo_child_iev, GOTD_IMSG_HAVE, PROC_SESSION_READ, -1, &ihave, sizeof(ihave)) == -1) return got_error_from_errno("imsg compose HAVE"); return NULL; } static int client_has_capability(struct gotd_session_client *client, const char *capastr) { struct gotd_client_capability *capa; size_t i; if (client->ncapabilities == 0) return 0; for (i = 0; i < client->ncapabilities; i++) { capa = &client->capabilities[i]; if (strcmp(capa->key, capastr) == 0) return 1; } return 0; } static const struct got_error * send_packfile(struct gotd_session_client *client) { const struct got_error *err = NULL; struct gotd_imsg_send_packfile ipack; int pipe[2]; if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe) == -1) return got_error_from_errno("socketpair"); memset(&ipack, 0, sizeof(ipack)); if (client_has_capability(client, GOT_CAPA_SIDE_BAND_64K)) ipack.report_progress = 1; client->delta_cache_fd = got_opentempfd(); if (client->delta_cache_fd == -1) return got_error_from_errno("got_opentempfd"); if (gotd_imsg_compose_event(&gotd_session.repo_child_iev, GOTD_IMSG_SEND_PACKFILE, PROC_GOTD, client->delta_cache_fd, &ipack, sizeof(ipack)) == -1) { err = got_error_from_errno("imsg compose SEND_PACKFILE"); close(pipe[0]); close(pipe[1]); return err; } /* Send pack pipe end 0 to repo child process. */ if (gotd_imsg_compose_event(&gotd_session.repo_child_iev, GOTD_IMSG_PACKFILE_PIPE, PROC_GOTD, pipe[0], NULL, 0) == -1) { err = got_error_from_errno("imsg compose PACKFILE_PIPE"); close(pipe[1]); return err; } /* Send pack pipe end 1 to gotsh(1) (expects just an fd, no data). */ if (gotd_imsg_compose_event(&client->iev, GOTD_IMSG_PACKFILE_PIPE, PROC_GOTD, pipe[1], NULL, 0) == -1) err = got_error_from_errno("imsg compose PACKFILE_PIPE"); return err; } static void session_dispatch_client(int fd, short events, void *arg) { struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_session_client *client = &gotd_session_client; const struct got_error *err = NULL; struct imsg imsg; ssize_t n; if (events & EV_WRITE) { while (ibuf->w.queued) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno != EAGAIN) { err = got_error_from_errno("imsg_flush"); disconnect_on_error(client, err); return; } if (n == 0) { /* Connection closed. */ err = got_error(GOT_ERR_EOF); disconnect_on_error(client, err); return; } } if (client->flush_disconnect) { disconnect(client); return; } } if ((events & EV_READ) == 0) return; memset(&imsg, 0, sizeof(imsg)); while (err == NULL) { err = gotd_imsg_recv(&imsg, ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_READ) err = NULL; else if (err->code == GOT_ERR_EOF && gotd_session.state == GOTD_STATE_EXPECT_CAPABILITIES) { /* * The client has closed its socket before * sending its capability announcement. * This can happen when Git clients have * no ref-updates to send. */ disconnect_on_error(client, err); return; } break; } evtimer_del(&client->tmo); switch (imsg.hdr.type) { case GOTD_IMSG_CAPABILITIES: if (gotd_session.state != GOTD_STATE_EXPECT_CAPABILITIES) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected capabilities received"); break; } log_debug("receiving capabilities from uid %d", client->euid); err = recv_capabilities(client, &imsg); break; case GOTD_IMSG_CAPABILITY: if (gotd_session.state != GOTD_STATE_EXPECT_CAPABILITIES) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected capability received"); break; } err = recv_capability(client, &imsg); if (err || client->ncapabilities < client->ncapa_alloc) break; gotd_session.state = GOTD_STATE_EXPECT_WANT; client->accept_flush_pkt = 1; log_debug("uid %d: expecting want-lines", client->euid); break; case GOTD_IMSG_WANT: if (gotd_session.state != GOTD_STATE_EXPECT_WANT) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected want-line received"); break; } log_debug("received want-line from uid %d", client->euid); client->accept_flush_pkt = 1; err = forward_want(client, &imsg); break; case GOTD_IMSG_HAVE: if (gotd_session.state != GOTD_STATE_EXPECT_HAVE_OR_DONE) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected have-line received"); break; } log_debug("received have-line from uid %d", client->euid); err = forward_have(client, &imsg); if (err) break; client->accept_flush_pkt = 1; break; case GOTD_IMSG_FLUSH: if (gotd_session.state != GOTD_STATE_EXPECT_WANT && gotd_session.state != GOTD_STATE_EXPECT_HAVE_OR_DONE) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected flush-pkt received"); break; } if (!client->accept_flush_pkt) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected flush-pkt received"); break; } /* * Accept just one flush packet at a time. * Future client state transitions will set this flag * again if another flush packet is expected. */ client->accept_flush_pkt = 0; log_debug("received flush-pkt from uid %d", client->euid); if (gotd_session.state == GOTD_STATE_EXPECT_WANT) { gotd_session.state = GOTD_STATE_EXPECT_HAVE_OR_DONE; log_debug("uid %d: expecting have-lines " "or 'done'", client->euid); } else if (gotd_session.state == GOTD_STATE_EXPECT_HAVE_OR_DONE) { client->accept_flush_pkt = 1; log_debug("uid %d: expecting more have-lines " "or 'done'", client->euid); } else if (gotd_session.state != GOTD_STATE_EXPECT_HAVE_OR_DONE) { /* should not happen, see above */ err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected client state"); break; } break; case GOTD_IMSG_DONE: if (gotd_session.state != GOTD_STATE_EXPECT_HAVE_OR_DONE) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected flush-pkt received"); break; } log_debug("received 'done' from uid %d", client->euid); gotd_session.state = GOTD_STATE_DONE; client->accept_flush_pkt = 1; err = send_packfile(client); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); } if (err) { if (err->code != GOT_ERR_EOF) disconnect_on_error(client, err); } else { gotd_imsg_event_add(iev); evtimer_add(&client->tmo, &gotd_session.request_timeout); } } static const struct got_error * list_refs_request(void) { static const struct got_error *err; struct gotd_session_client *client = &gotd_session_client; struct gotd_imsgev *iev = &gotd_session.repo_child_iev; int fd; if (gotd_session.state != GOTD_STATE_EXPECT_LIST_REFS) return got_error(GOT_ERR_PRIVSEP_MSG); fd = dup(client->fd); if (fd == -1) return got_error_from_errno("dup"); if (gotd_imsg_compose_event(iev, GOTD_IMSG_LIST_REFS_INTERNAL, PROC_SESSION_READ, fd, NULL, 0) == -1) { err = got_error_from_errno("imsg compose LIST_REFS_INTERNAL"); close(fd); return err; } gotd_session.state = GOTD_STATE_EXPECT_CAPABILITIES; log_debug("uid %d: expecting capabilities", client->euid); return NULL; } static const struct got_error * recv_connect(struct imsg *imsg) { struct gotd_session_client *client = &gotd_session_client; struct gotd_imsg_connect iconnect; size_t datalen; if (gotd_session.state != GOTD_STATE_EXPECT_LIST_REFS) return got_error(GOT_ERR_PRIVSEP_MSG); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(iconnect)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iconnect, imsg->data, sizeof(iconnect)); if (iconnect.username_len == 0 || datalen != sizeof(iconnect) + iconnect.username_len) return got_error(GOT_ERR_PRIVSEP_LEN); client->euid = iconnect.euid; client->egid = iconnect.egid; client->fd = imsg_get_fd(imsg); if (client->fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); client->username = strndup(imsg->data + sizeof(iconnect), iconnect.username_len); if (client->username == NULL) return got_error_from_errno("strndup"); imsg_init(&client->iev.ibuf, client->fd); client->iev.handler = session_dispatch_client; client->iev.events = EV_READ; client->iev.handler_arg = NULL; event_set(&client->iev.ev, client->iev.ibuf.fd, EV_READ, session_dispatch_client, &client->iev); gotd_imsg_event_add(&client->iev); evtimer_set(&client->tmo, gotd_request_timeout, client); evtimer_add(&client->tmo, &gotd_session.request_timeout); return NULL; } static const struct got_error * recv_repo_child(struct imsg *imsg) { struct gotd_imsg_connect_repo_child ichild; struct gotd_session_client *client = &gotd_session_client; size_t datalen; int fd; if (gotd_session.state != GOTD_STATE_EXPECT_LIST_REFS) return got_error(GOT_ERR_PRIVSEP_MSG); /* We should already have received a pipe to the listener. */ if (client->fd == -1) return got_error(GOT_ERR_PRIVSEP_MSG); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ichild)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ichild, imsg->data, sizeof(ichild)); if (ichild.proc_id != PROC_REPO_READ) return got_error_msg(GOT_ERR_PRIVSEP_MSG, "bad child process type"); fd = imsg_get_fd(imsg); if (fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); imsg_init(&gotd_session.repo_child_iev.ibuf, fd); gotd_session.repo_child_iev.handler = session_dispatch_repo_child; gotd_session.repo_child_iev.events = EV_READ; gotd_session.repo_child_iev.handler_arg = NULL; event_set(&gotd_session.repo_child_iev.ev, gotd_session.repo_child_iev.ibuf.fd, EV_READ, session_dispatch_repo_child, &gotd_session.repo_child_iev); gotd_imsg_event_add(&gotd_session.repo_child_iev); /* The "recvfd" pledge promise is no longer needed. */ if (pledge("stdio rpath wpath cpath sendfd fattr flock", NULL) == -1) fatal("pledge"); return NULL; } static void session_dispatch(int fd, short event, void *arg) { struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_session_client *client = &gotd_session_client; ssize_t n; int shut = 0; struct imsg imsg; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno != EAGAIN) fatal("msgbuf_write"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } for (;;) { const struct got_error *err = NULL; uint32_t client_id = 0; int do_disconnect = 0, do_list_refs = 0; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: do_disconnect = 1; err = gotd_imsg_recv_error(&client_id, &imsg); break; case GOTD_IMSG_CONNECT: err = recv_connect(&imsg); break; case GOTD_IMSG_DISCONNECT: do_disconnect = 1; break; case GOTD_IMSG_CONNECT_REPO_CHILD: err = recv_repo_child(&imsg); if (err) break; do_list_refs = 1; break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); if (do_disconnect) { if (err) disconnect_on_error(client, err); else disconnect(client); } else if (do_list_refs) err = list_refs_request(); if (err) log_warnx("uid %d: %s", client->euid, err->msg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void session_read_main(const char *title, const char *repo_path, int *pack_fds, int *temp_fds, struct timeval *request_timeout, struct gotd_repo *repo_cfg) { const struct got_error *err = NULL; struct event evsigint, evsigterm, evsighup, evsigusr1; gotd_session.title = title; gotd_session.pid = getpid(); gotd_session.pack_fds = pack_fds; gotd_session.temp_fds = temp_fds; memcpy(&gotd_session.request_timeout, request_timeout, sizeof(gotd_session.request_timeout)); gotd_session.repo_cfg = repo_cfg; imsg_init(&gotd_session.notifier_iev.ibuf, -1); err = got_repo_open(&gotd_session.repo, repo_path, NULL, pack_fds); if (err) goto done; if (!got_repo_is_bare(gotd_session.repo)) { err = got_error_msg(GOT_ERR_NOT_GIT_REPO, "bare git repository required"); goto done; } got_repo_temp_fds_set(gotd_session.repo, temp_fds); signal_set(&evsigint, SIGINT, session_read_sighdlr, NULL); signal_set(&evsigterm, SIGTERM, session_read_sighdlr, NULL); signal_set(&evsighup, SIGHUP, session_read_sighdlr, NULL); signal_set(&evsigusr1, SIGUSR1, session_read_sighdlr, NULL); signal(SIGPIPE, SIG_IGN); signal_add(&evsigint, NULL); signal_add(&evsigterm, NULL); signal_add(&evsighup, NULL); signal_add(&evsigusr1, NULL); gotd_session.state = GOTD_STATE_EXPECT_LIST_REFS; gotd_session_client.fd = -1; gotd_session_client.nref_updates = -1; gotd_session_client.delta_cache_fd = -1; gotd_session_client.accept_flush_pkt = 1; imsg_init(&gotd_session.parent_iev.ibuf, GOTD_FILENO_MSG_PIPE); gotd_session.parent_iev.handler = session_dispatch; gotd_session.parent_iev.events = EV_READ; gotd_session.parent_iev.handler_arg = NULL; event_set(&gotd_session.parent_iev.ev, gotd_session.parent_iev.ibuf.fd, EV_READ, session_dispatch, &gotd_session.parent_iev); if (gotd_imsg_compose_event(&gotd_session.parent_iev, GOTD_IMSG_CLIENT_SESSION_READY, PROC_SESSION_READ, -1, NULL, 0) == -1) { err = got_error_from_errno("imsg compose CLIENT_SESSION_READY"); goto done; } event_dispatch(); done: if (err) log_warnx("%s: %s", title, err->msg); session_read_shutdown(); } static void session_read_shutdown(void) { log_debug("%s: shutting down", gotd_session.title); if (gotd_session.repo) got_repo_close(gotd_session.repo); got_repo_pack_fds_close(gotd_session.pack_fds); got_repo_temp_fds_close(gotd_session.temp_fds); free(gotd_session_client.username); exit(0); } got-portable-0.101/gotd/parse.c0000644000175100017510000030133014644145552012022 /* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. 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 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 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output, and Bison version. */ #define YYBISON 30802 /* Bison version string. */ #define YYBISON_VERSION "3.8.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* First part of user prologue. */ #line 24 "../gotd/parse.y" #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_reference.h" #include "log.h" #include "gotd.h" #include "auth.h" #include "listen.h" TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); static struct file { TAILQ_ENTRY(file) entry; FILE *stream; char *name; int lineno; int errors; } *file; struct file *newfile(const char *, int, int); static void closefile(struct file *); int check_file_secrecy(int, const char *); int yyparse(void); int yylex(void); int yyerror(const char *, ...) __attribute__((__format__ (printf, 1, 2))) __attribute__((__nonnull__ (1))); int kw_cmp(const void *, const void *); int lookup(char *); int lgetc(int); int lungetc(int); int findeol(void); static char *port_sprintf(int); TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); struct sym { TAILQ_ENTRY(sym) entry; int used; int persist; char *nam; char *val; }; int symset(const char *, const char *, int); char *symget(const char *); static int errors; static struct gotd *gotd; static struct gotd_repo *new_repo; static int conf_limit_user_connections(const char *, int); static struct gotd_repo *conf_new_repo(const char *); static void conf_new_access_rule(struct gotd_repo *, enum gotd_access, int, char *); static int conf_protect_ref_namespace(char **, struct got_pathlist_head *, char *); static int conf_protect_tag_namespace(struct gotd_repo *, char *); static int conf_protect_branch_namespace( struct gotd_repo *, char *); static int conf_protect_branch(struct gotd_repo *, char *); static int conf_notify_branch(struct gotd_repo *, char *); static int conf_notify_ref_namespace(struct gotd_repo *, char *); static int conf_notify_email(struct gotd_repo *, char *, char *, char *, char *, char *); static int conf_notify_http(struct gotd_repo *, char *, char *, char *, int); static enum gotd_procid gotd_proc_id; typedef struct { union { long long number; char *string; struct timeval tv; } v; int lineno; } YYSTYPE; #line 175 "../gotd/parse.c" # ifndef YY_CAST # ifdef __cplusplus # define YY_CAST(Type, Val) static_cast (Val) # define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) # else # define YY_CAST(Type, Val) ((Type) (Val)) # define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) # endif # endif # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # else # define YY_NULLPTR ((void*)0) # endif # endif /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yydebug; #endif /* Token kinds. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { YYEMPTY = -2, YYEOF = 0, /* "end of file" */ YYerror = 256, /* error */ YYUNDEF = 257, /* "invalid token" */ PATH = 258, /* PATH */ ERROR = 259, /* ERROR */ LISTEN = 260, /* LISTEN */ ON = 261, /* ON */ USER = 262, /* USER */ REPOSITORY = 263, /* REPOSITORY */ PERMIT = 264, /* PERMIT */ DENY = 265, /* DENY */ RO = 266, /* RO */ RW = 267, /* RW */ CONNECTION = 268, /* CONNECTION */ LIMIT = 269, /* LIMIT */ REQUEST = 270, /* REQUEST */ TIMEOUT = 271, /* TIMEOUT */ PROTECT = 272, /* PROTECT */ NAMESPACE = 273, /* NAMESPACE */ BRANCH = 274, /* BRANCH */ TAG = 275, /* TAG */ REFERENCE = 276, /* REFERENCE */ RELAY = 277, /* RELAY */ PORT = 278, /* PORT */ NOTIFY = 279, /* NOTIFY */ EMAIL = 280, /* EMAIL */ FROM = 281, /* FROM */ REPLY = 282, /* REPLY */ TO = 283, /* TO */ URL = 284, /* URL */ PASSWORD = 285, /* PASSWORD */ INSECURE = 286, /* INSECURE */ STRING = 287, /* STRING */ NUMBER = 288 /* NUMBER */ }; typedef enum yytokentype yytoken_kind_t; #endif /* Token kinds. */ #define YYEMPTY -2 #define YYEOF 0 #define YYerror 256 #define YYUNDEF 257 #define PATH 258 #define ERROR 259 #define LISTEN 260 #define ON 261 #define USER 262 #define REPOSITORY 263 #define PERMIT 264 #define DENY 265 #define RO 266 #define RW 267 #define CONNECTION 268 #define LIMIT 269 #define REQUEST 270 #define TIMEOUT 271 #define PROTECT 272 #define NAMESPACE 273 #define BRANCH 274 #define TAG 275 #define REFERENCE 276 #define RELAY 277 #define PORT 278 #define NOTIFY 279 #define EMAIL 280 #define FROM 281 #define REPLY 282 #define TO 283 #define URL 284 #define PASSWORD 285 #define INSECURE 286 #define STRING 287 #define NUMBER 288 /* Value type. */ extern YYSTYPE yylval; int yyparse (void); /* Symbol kind. */ enum yysymbol_kind_t { YYSYMBOL_YYEMPTY = -2, YYSYMBOL_YYEOF = 0, /* "end of file" */ YYSYMBOL_YYerror = 1, /* error */ YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ YYSYMBOL_PATH = 3, /* PATH */ YYSYMBOL_ERROR = 4, /* ERROR */ YYSYMBOL_LISTEN = 5, /* LISTEN */ YYSYMBOL_ON = 6, /* ON */ YYSYMBOL_USER = 7, /* USER */ YYSYMBOL_REPOSITORY = 8, /* REPOSITORY */ YYSYMBOL_PERMIT = 9, /* PERMIT */ YYSYMBOL_DENY = 10, /* DENY */ YYSYMBOL_RO = 11, /* RO */ YYSYMBOL_RW = 12, /* RW */ YYSYMBOL_CONNECTION = 13, /* CONNECTION */ YYSYMBOL_LIMIT = 14, /* LIMIT */ YYSYMBOL_REQUEST = 15, /* REQUEST */ YYSYMBOL_TIMEOUT = 16, /* TIMEOUT */ YYSYMBOL_PROTECT = 17, /* PROTECT */ YYSYMBOL_NAMESPACE = 18, /* NAMESPACE */ YYSYMBOL_BRANCH = 19, /* BRANCH */ YYSYMBOL_TAG = 20, /* TAG */ YYSYMBOL_REFERENCE = 21, /* REFERENCE */ YYSYMBOL_RELAY = 22, /* RELAY */ YYSYMBOL_PORT = 23, /* PORT */ YYSYMBOL_NOTIFY = 24, /* NOTIFY */ YYSYMBOL_EMAIL = 25, /* EMAIL */ YYSYMBOL_FROM = 26, /* FROM */ YYSYMBOL_REPLY = 27, /* REPLY */ YYSYMBOL_TO = 28, /* TO */ YYSYMBOL_URL = 29, /* URL */ YYSYMBOL_PASSWORD = 30, /* PASSWORD */ YYSYMBOL_INSECURE = 31, /* INSECURE */ YYSYMBOL_STRING = 32, /* STRING */ YYSYMBOL_NUMBER = 33, /* NUMBER */ YYSYMBOL_34_n_ = 34, /* '\n' */ YYSYMBOL_35_ = 35, /* '=' */ YYSYMBOL_36_ = 36, /* '{' */ YYSYMBOL_37_ = 37, /* '}' */ YYSYMBOL_YYACCEPT = 38, /* $accept */ YYSYMBOL_grammar = 39, /* grammar */ YYSYMBOL_varset = 40, /* varset */ YYSYMBOL_timeout = 41, /* timeout */ YYSYMBOL_main = 42, /* main */ YYSYMBOL_connection = 43, /* connection */ YYSYMBOL_conflags_l = 44, /* conflags_l */ YYSYMBOL_conflags = 45, /* conflags */ YYSYMBOL_protect = 46, /* protect */ YYSYMBOL_protectflags_l = 47, /* protectflags_l */ YYSYMBOL_protectflags = 48, /* protectflags */ YYSYMBOL_notify = 49, /* notify */ YYSYMBOL_notifyflags_l = 50, /* notifyflags_l */ YYSYMBOL_notifyflags = 51, /* notifyflags */ YYSYMBOL_repository = 52, /* repository */ YYSYMBOL_53_1 = 53, /* $@1 */ YYSYMBOL_repoopts1 = 54, /* repoopts1 */ YYSYMBOL_repoopts2 = 55, /* repoopts2 */ YYSYMBOL_nl = 56, /* nl */ YYSYMBOL_optnl = 57 /* optnl */ }; typedef enum yysymbol_kind_t yysymbol_kind_t; #ifdef short # undef short #endif /* On compilers that do not define __PTRDIFF_MAX__ etc., make sure and (if available) are included so that the code can choose integer types of a good width. */ #ifndef __PTRDIFF_MAX__ # include /* INFRINGES ON USER NAME SPACE */ # if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YY_STDINT_H # endif #endif /* Narrow types that promote to a signed type and that can represent a signed or unsigned integer of at least N bits. In tables they can save space and decrease cache pressure. Promoting to a signed type helps avoid bugs in integer arithmetic. */ #ifdef __INT_LEAST8_MAX__ typedef __INT_LEAST8_TYPE__ yytype_int8; #elif defined YY_STDINT_H typedef int_least8_t yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef __INT_LEAST16_MAX__ typedef __INT_LEAST16_TYPE__ yytype_int16; #elif defined YY_STDINT_H typedef int_least16_t yytype_int16; #else typedef short yytype_int16; #endif /* Work around bug in HP-UX 11.23, which defines these macros incorrectly for preprocessor constants. This workaround can likely be removed in 2023, as HPE has promised support for HP-UX 11.23 (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of . */ #ifdef __hpux # undef UINT_LEAST8_MAX # undef UINT_LEAST16_MAX # define UINT_LEAST8_MAX 255 # define UINT_LEAST16_MAX 65535 #endif #if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ typedef __UINT_LEAST8_TYPE__ yytype_uint8; #elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ && UINT_LEAST8_MAX <= INT_MAX) typedef uint_least8_t yytype_uint8; #elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX typedef unsigned char yytype_uint8; #else typedef short yytype_uint8; #endif #if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ typedef __UINT_LEAST16_TYPE__ yytype_uint16; #elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ && UINT_LEAST16_MAX <= INT_MAX) typedef uint_least16_t yytype_uint16; #elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX typedef unsigned short yytype_uint16; #else typedef int yytype_uint16; #endif #ifndef YYPTRDIFF_T # if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ # define YYPTRDIFF_T __PTRDIFF_TYPE__ # define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ # elif defined PTRDIFF_MAX # ifndef ptrdiff_t # include /* INFRINGES ON USER NAME SPACE */ # endif # define YYPTRDIFF_T ptrdiff_t # define YYPTRDIFF_MAXIMUM PTRDIFF_MAX # else # define YYPTRDIFF_T long # define YYPTRDIFF_MAXIMUM LONG_MAX # endif #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned # endif #endif #define YYSIZE_MAXIMUM \ YY_CAST (YYPTRDIFF_T, \ (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ ? YYPTRDIFF_MAXIMUM \ : YY_CAST (YYSIZE_T, -1))) #define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) /* Stored state numbers (used for stacks). */ typedef yytype_uint8 yy_state_t; /* State numbers in computations. */ typedef int yy_state_fast_t; #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE_PURE # if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) # else # define YY_ATTRIBUTE_PURE # endif #endif #ifndef YY_ATTRIBUTE_UNUSED # if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) # else # define YY_ATTRIBUTE_UNUSED # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YY_USE(E) ((void) (E)) #else # define YY_USE(E) /* empty */ #endif /* Suppress an incorrect diagnostic about yylval being uninitialized. */ #if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ # if __GNUC__ * 100 + __GNUC_MINOR__ < 407 # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") # else # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # endif # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ # define YY_IGNORE_USELESS_CAST_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") # define YY_IGNORE_USELESS_CAST_END \ _Pragma ("GCC diagnostic pop") #endif #ifndef YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_END #endif #define YY_ASSERT(E) ((void) (0 && (E))) #if !defined yyoverflow /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* !defined yyoverflow */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yy_state_t yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYPTRDIFF_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / YYSIZEOF (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYPTRDIFF_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 140 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 38 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 20 /* YYNRULES -- Number of rules. */ #define YYNRULES 63 /* YYNSTATES -- Number of states. */ #define YYNSTATES 133 /* YYMAXUTOK -- Last valid token kind. */ #define YYMAXUTOK 288 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM as returned by yylex, with out-of-bounds checking. */ #define YYTRANSLATE(YYX) \ (0 <= (YYX) && (YYX) <= YYMAXUTOK \ ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ : YYSYMBOL_YYUNDEF) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex. */ static const yytype_int8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 34, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 35, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 36, 2, 37, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { 0, 139, 139, 140, 141, 142, 143, 146, 164, 172, 218, 235, 245, 248, 249, 251, 252, 255, 264, 274, 275, 277, 278, 281, 291, 302, 314, 315, 317, 318, 321, 332, 343, 355, 369, 383, 399, 413, 429, 445, 463, 479, 497, 515, 535, 549, 565, 581, 599, 611, 626, 643, 643, 667, 710, 717, 725, 732, 733, 736, 737, 740, 743, 744 }; #endif /** Accessing symbol of state STATE. */ #define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) #if YYDEBUG || 0 /* The user-facing name of the symbol whose (internal) number is YYSYMBOL. No bounds checking. */ static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "\"end of file\"", "error", "\"invalid token\"", "PATH", "ERROR", "LISTEN", "ON", "USER", "REPOSITORY", "PERMIT", "DENY", "RO", "RW", "CONNECTION", "LIMIT", "REQUEST", "TIMEOUT", "PROTECT", "NAMESPACE", "BRANCH", "TAG", "REFERENCE", "RELAY", "PORT", "NOTIFY", "EMAIL", "FROM", "REPLY", "TO", "URL", "PASSWORD", "INSECURE", "STRING", "NUMBER", "'\\n'", "'='", "'{'", "'}'", "$accept", "grammar", "varset", "timeout", "main", "connection", "conflags_l", "conflags", "protect", "protectflags_l", "protectflags", "notify", "notifyflags_l", "notifyflags", "repository", "$@1", "repoopts1", "repoopts2", "nl", "optnl", YY_NULLPTR }; static const char * yysymbol_name (yysymbol_kind_t yysymbol) { return yytname[yysymbol]; } #endif #define YYPACT_NINF (-29) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) #define YYTABLE_NINF (-1) #define yytable_value_is_error(Yyn) \ 0 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int8 yypact[] = { -29, 1, -29, 7, -15, -3, 6, 9, -29, 16, 23, -29, 27, 44, -29, -29, 56, 48, 33, -29, 45, -29, -29, -29, -29, 43, 46, -9, 33, 13, -29, 33, 47, -29, -29, -29, -29, 49, 33, 31, -29, -29, 13, 50, 35, 51, -4, 24, -29, -29, 33, 2, -29, -29, 52, 53, -29, -14, 63, 33, -29, 55, 70, 10, 57, 33, -29, -29, -29, 58, -29, -29, 59, -29, 61, 32, -29, 62, 64, 65, 83, 37, 33, -29, -29, -29, 66, 33, -29, 67, -20, 68, 69, 33, -29, -29, 32, 72, 73, 71, 77, -29, 37, -29, 3, 75, 76, 78, -29, 79, 74, 36, 87, 81, 90, 82, -29, -29, 84, -29, 38, 93, 94, -29, -29, 86, 40, 96, -29, -29, 42, -29, -29 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_int8 yydefact[] = { 2, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 12, 0, 0, 11, 51, 0, 0, 63, 14, 0, 4, 5, 6, 10, 0, 0, 0, 63, 0, 7, 63, 0, 9, 8, 17, 62, 0, 63, 0, 18, 13, 16, 0, 0, 0, 0, 0, 57, 58, 63, 0, 15, 53, 0, 0, 56, 0, 0, 63, 20, 0, 0, 0, 0, 63, 27, 60, 52, 0, 54, 55, 0, 25, 0, 0, 30, 0, 0, 0, 48, 0, 63, 59, 24, 23, 0, 63, 31, 0, 32, 0, 0, 63, 61, 19, 22, 0, 0, 0, 0, 26, 29, 21, 33, 36, 0, 0, 28, 0, 0, 0, 34, 49, 37, 0, 40, 44, 0, 50, 0, 35, 38, 41, 45, 0, 0, 39, 42, 46, 0, 43, 47 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { -29, -29, -29, -29, -29, -29, 80, 95, -29, 25, 85, -29, 18, 88, -29, -29, 89, -29, -29, -28 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { 0, 1, 9, 35, 10, 11, 37, 38, 48, 86, 87, 49, 92, 93, 12, 25, 50, 51, 83, 29 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_uint8 yytable[] = { 36, 2, 98, 39, 72, 43, 3, 99, 4, 5, 42, 44, 45, 13, 6, 57, 58, 14, 73, 46, 16, 17, 67, 33, 34, 109, 47, 16, 17, 15, 110, 75, 59, 7, 43, 8, 78, 81, 79, 68, 44, 45, 18, 61, 20, 62, 54, 55, 46, 63, 21, 57, 58, 64, 94, 47, 61, 22, 62, 96, 65, 23, 63, 26, 27, 102, 64, 28, 116, 117, 123, 124, 128, 129, 131, 132, 24, 30, 32, 31, 40, 74, 53, 56, 70, 71, 41, 76, 77, 80, 91, 84, 82, 85, 88, 97, 89, 90, 111, 106, 100, 19, 115, 95, 104, 105, 101, 107, 112, 118, 113, 114, 119, 120, 121, 125, 122, 126, 127, 130, 108, 103, 52, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 66, 0, 0, 0, 0, 69 }; static const yytype_int8 yycheck[] = { 28, 0, 22, 31, 18, 3, 5, 27, 7, 8, 38, 9, 10, 6, 13, 19, 20, 32, 32, 17, 14, 15, 50, 32, 33, 22, 24, 14, 15, 32, 27, 59, 36, 32, 3, 34, 26, 65, 28, 37, 9, 10, 36, 19, 35, 21, 11, 12, 17, 25, 34, 19, 20, 29, 82, 24, 19, 34, 21, 87, 36, 34, 25, 7, 16, 93, 29, 34, 32, 33, 32, 33, 32, 33, 32, 33, 32, 32, 32, 36, 33, 18, 32, 32, 32, 32, 37, 32, 18, 32, 7, 32, 34, 32, 32, 28, 32, 32, 23, 28, 32, 6, 28, 37, 32, 32, 37, 30, 32, 22, 32, 32, 31, 23, 32, 22, 32, 23, 32, 23, 102, 96, 42, -1, -1, -1, -1, -1, -1, -1, -1, 46, -1, -1, -1, 47, -1, -1, -1, -1, 51 }; /* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of state STATE-NUM. */ static const yytype_int8 yystos[] = { 0, 39, 0, 5, 7, 8, 13, 32, 34, 40, 42, 43, 52, 6, 32, 32, 14, 15, 36, 45, 35, 34, 34, 34, 32, 53, 7, 16, 34, 57, 32, 36, 32, 32, 33, 41, 57, 44, 45, 57, 33, 37, 57, 3, 9, 10, 17, 24, 46, 49, 54, 55, 44, 32, 11, 12, 32, 19, 20, 36, 48, 19, 21, 25, 29, 36, 51, 57, 37, 54, 32, 32, 18, 32, 18, 57, 32, 18, 26, 28, 32, 57, 34, 56, 32, 32, 47, 48, 32, 32, 32, 7, 50, 51, 57, 37, 57, 28, 22, 27, 32, 37, 57, 47, 32, 32, 28, 30, 50, 22, 27, 23, 32, 32, 32, 28, 32, 33, 22, 31, 23, 32, 32, 32, 33, 22, 23, 32, 32, 33, 23, 32, 33 }; /* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ static const yytype_int8 yyr1[] = { 0, 38, 39, 39, 39, 39, 39, 40, 41, 41, 42, 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, 47, 48, 48, 48, 49, 49, 50, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 53, 52, 54, 54, 54, 54, 54, 54, 55, 55, 56, 57, 57 }; /* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ static const yytype_int8 yyr2[] = { 0, 2, 0, 2, 3, 3, 3, 3, 1, 1, 3, 2, 1, 5, 2, 3, 2, 3, 4, 5, 2, 3, 2, 3, 3, 2, 5, 2, 3, 2, 2, 3, 3, 5, 6, 8, 5, 7, 8, 10, 7, 9, 10, 12, 7, 9, 10, 12, 2, 6, 7, 0, 7, 2, 3, 3, 2, 1, 1, 3, 2, 2, 2, 0 }; enum { YYENOMEM = -2 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYNOMEM goto yyexhaustedlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Backward compatibility with an undocumented macro. Use YYerror or YYUNDEF. */ #define YYERRCODE YYUNDEF /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Kind, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*-----------------------------------. | Print this symbol's value on YYO. | `-----------------------------------*/ static void yy_symbol_value_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) { FILE *yyoutput = yyo; YY_USE (yyoutput); if (!yyvaluep) return; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /*---------------------------. | Print this symbol on YYO. | `---------------------------*/ static void yy_symbol_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) { YYFPRINTF (yyo, "%s %s (", yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); yy_symbol_value_print (yyo, yykind, yyvaluep); YYFPRINTF (yyo, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, int yyrule) { int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), &yyvsp[(yyi + 1) - (yynrhs)]); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, Rule); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) ((void) 0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, yysymbol_kind_t yykind, YYSTYPE *yyvaluep) { YY_USE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /* Lookahead token kind. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*----------. | yyparse. | `----------*/ int yyparse (void) { yy_state_fast_t yystate = 0; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus = 0; /* Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* Their size. */ YYPTRDIFF_T yystacksize = YYINITDEPTH; /* The state stack: array, bottom, top. */ yy_state_t yyssa[YYINITDEPTH]; yy_state_t *yyss = yyssa; yy_state_t *yyssp = yyss; /* The semantic value stack: array, bottom, top. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; YYSTYPE *yyvsp = yyvs; int yyn; /* The return value of yyparse. */ int yyresult; /* Lookahead symbol kind. */ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; YYDPRINTF ((stderr, "Starting parse\n")); yychar = YYEMPTY; /* Cause a token to be read. */ goto yysetstate; /*------------------------------------------------------------. | yynewstate -- push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; /*--------------------------------------------------------------------. | yysetstate -- set current state (the top of the stack) to yystate. | `--------------------------------------------------------------------*/ yysetstate: YYDPRINTF ((stderr, "Entering state %d\n", yystate)); YY_ASSERT (0 <= yystate && yystate < YYNSTATES); YY_IGNORE_USELESS_CAST_BEGIN *yyssp = YY_CAST (yy_state_t, yystate); YY_IGNORE_USELESS_CAST_END YY_STACK_PRINT (yyss, yyssp); if (yyss + yystacksize - 1 <= yyssp) #if !defined yyoverflow && !defined YYSTACK_RELOCATE YYNOMEM; #else { /* Get the current used size of the three stacks, in elements. */ YYPTRDIFF_T yysize = yyssp - yyss + 1; # if defined yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ yy_state_t *yyss1 = yyss; YYSTYPE *yyvs1 = yyvs; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * YYSIZEOF (*yyssp), &yyvs1, yysize * YYSIZEOF (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } # else /* defined YYSTACK_RELOCATE */ /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) YYNOMEM; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yy_state_t *yyss1 = yyss; union yyalloc *yyptr = YY_CAST (union yyalloc *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); if (! yyptr) YYNOMEM; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YY_IGNORE_USELESS_CAST_BEGIN YYDPRINTF ((stderr, "Stack size increased to %ld\n", YY_CAST (long, yystacksize))); YY_IGNORE_USELESS_CAST_END if (yyss + yystacksize - 1 <= yyssp) YYABORT; } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token\n")); yychar = yylex (); } if (yychar <= YYEOF) { yychar = YYEOF; yytoken = YYSYMBOL_YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else if (yychar == YYerror) { /* The scanner already issued an error message, process directly to error recovery. But do not keep the error token as lookahead, it is too special and may lead us to an endless loop in error recovery. */ yychar = YYUNDEF; yytoken = YYSYMBOL_YYerror; goto yyerrlab1; } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Discard the shifted token. */ yychar = YYEMPTY; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 7: /* varset: STRING '=' STRING */ #line 146 "../gotd/parse.y" { char *s = (yyvsp[-2].v.string); while (*s++) { if (isspace((unsigned char)*s)) { yyerror("macro name cannot contain " "whitespace"); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } if (symset((yyvsp[-2].v.string), (yyvsp[0].v.string), 0) == -1) fatal("cannot store variable"); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1416 "../gotd/parse.c" break; case 8: /* timeout: NUMBER */ #line 164 "../gotd/parse.y" { if ((yyvsp[0].v.number) < 0) { yyerror("invalid timeout: %lld", (yyvsp[0].v.number)); YYERROR; } (yyval.v.tv).tv_sec = (yyvsp[0].v.number); (yyval.v.tv).tv_usec = 0; } #line 1429 "../gotd/parse.c" break; case 9: /* timeout: STRING */ #line 172 "../gotd/parse.y" { const char *errstr; const char *type = "seconds"; size_t len; int mul = 1; if (*(yyvsp[0].v.string) == '\0') { yyerror("invalid number of seconds: %s", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } len = strlen((yyvsp[0].v.string)); switch ((yyvsp[0].v.string)[len - 1]) { case 'S': case 's': (yyvsp[0].v.string)[len - 1] = '\0'; break; case 'M': case 'm': type = "minutes"; mul = 60; (yyvsp[0].v.string)[len - 1] = '\0'; break; case 'H': case 'h': type = "hours"; mul = 60 * 60; (yyvsp[0].v.string)[len - 1] = '\0'; break; } (yyval.v.tv).tv_usec = 0; (yyval.v.tv).tv_sec = strtonum((yyvsp[0].v.string), 0, INT_MAX / mul, &errstr); if (errstr) { yyerror("number of %s is %s: %s", type, errstr, (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } (yyval.v.tv).tv_sec *= mul; free((yyvsp[0].v.string)); } #line 1478 "../gotd/parse.c" break; case 10: /* main: LISTEN ON STRING */ #line 218 "../gotd/parse.y" { if (!got_path_is_absolute((yyvsp[0].v.string))) yyerror("bad unix socket path \"%s\": " "must be an absolute path", (yyvsp[0].v.string)); if (gotd_proc_id == PROC_LISTEN) { if (strlcpy(gotd->unix_socket_path, (yyvsp[0].v.string), sizeof(gotd->unix_socket_path)) >= sizeof(gotd->unix_socket_path)) { yyerror("%s: unix socket path too long", __func__); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[0].v.string)); } #line 1500 "../gotd/parse.c" break; case 11: /* main: USER STRING */ #line 235 "../gotd/parse.y" { if (strlcpy(gotd->user_name, (yyvsp[0].v.string), sizeof(gotd->user_name)) >= sizeof(gotd->user_name)) { yyerror("%s: user name too long", __func__); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1515 "../gotd/parse.c" break; case 17: /* conflags: REQUEST TIMEOUT timeout */ #line 255 "../gotd/parse.y" { if ((yyvsp[0].v.tv).tv_sec <= 0) { yyerror("invalid timeout: %lld", (long long)(yyvsp[0].v.tv).tv_sec); YYERROR; } memcpy(&gotd->request_timeout, &(yyvsp[0].v.tv), sizeof(gotd->request_timeout)); } #line 1529 "../gotd/parse.c" break; case 18: /* conflags: LIMIT USER STRING NUMBER */ #line 264 "../gotd/parse.y" { if (gotd_proc_id == PROC_LISTEN && conf_limit_user_connections((yyvsp[-1].v.string), (yyvsp[0].v.number)) == -1) { free((yyvsp[-1].v.string)); YYERROR; } free((yyvsp[-1].v.string)); } #line 1542 "../gotd/parse.c" break; case 23: /* protectflags: TAG NAMESPACE STRING */ #line 281 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_REPO_WRITE) { if (conf_protect_tag_namespace(new_repo, (yyvsp[0].v.string))) { free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[0].v.string)); } #line 1557 "../gotd/parse.c" break; case 24: /* protectflags: BRANCH NAMESPACE STRING */ #line 291 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_REPO_WRITE) { if (conf_protect_branch_namespace(new_repo, (yyvsp[0].v.string))) { free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[0].v.string)); } #line 1573 "../gotd/parse.c" break; case 25: /* protectflags: BRANCH STRING */ #line 302 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_REPO_WRITE) { if (conf_protect_branch(new_repo, (yyvsp[0].v.string))) { free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[0].v.string)); } #line 1588 "../gotd/parse.c" break; case 30: /* notifyflags: BRANCH STRING */ #line 321 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_branch(new_repo, (yyvsp[0].v.string))) { free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[0].v.string)); } #line 1604 "../gotd/parse.c" break; case 31: /* notifyflags: REFERENCE NAMESPACE STRING */ #line 332 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_ref_namespace(new_repo, (yyvsp[0].v.string))) { free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[0].v.string)); } #line 1620 "../gotd/parse.c" break; case 32: /* notifyflags: EMAIL TO STRING */ #line 343 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, NULL, (yyvsp[0].v.string), NULL, NULL, NULL)) { free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[0].v.string)); } #line 1637 "../gotd/parse.c" break; case 33: /* notifyflags: EMAIL FROM STRING TO STRING */ #line 355 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, (yyvsp[-2].v.string), (yyvsp[0].v.string), NULL, NULL, NULL)) { free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1656 "../gotd/parse.c" break; case 34: /* notifyflags: EMAIL TO STRING REPLY TO STRING */ #line 369 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, NULL, (yyvsp[-3].v.string), (yyvsp[0].v.string), NULL, NULL)) { free((yyvsp[-3].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-3].v.string)); free((yyvsp[0].v.string)); } #line 1675 "../gotd/parse.c" break; case 35: /* notifyflags: EMAIL FROM STRING TO STRING REPLY TO STRING */ #line 383 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, (yyvsp[-5].v.string), (yyvsp[-3].v.string), (yyvsp[0].v.string), NULL, NULL)) { free((yyvsp[-5].v.string)); free((yyvsp[-3].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-5].v.string)); free((yyvsp[-3].v.string)); free((yyvsp[0].v.string)); } #line 1696 "../gotd/parse.c" break; case 36: /* notifyflags: EMAIL TO STRING RELAY STRING */ #line 399 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, NULL, (yyvsp[-2].v.string), NULL, (yyvsp[0].v.string), NULL)) { free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1715 "../gotd/parse.c" break; case 37: /* notifyflags: EMAIL FROM STRING TO STRING RELAY STRING */ #line 413 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, (yyvsp[-4].v.string), (yyvsp[-2].v.string), NULL, (yyvsp[0].v.string), NULL)) { free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1736 "../gotd/parse.c" break; case 38: /* notifyflags: EMAIL TO STRING REPLY TO STRING RELAY STRING */ #line 429 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, NULL, (yyvsp[-5].v.string), (yyvsp[-2].v.string), (yyvsp[0].v.string), NULL)) { free((yyvsp[-5].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-5].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1757 "../gotd/parse.c" break; case 39: /* notifyflags: EMAIL FROM STRING TO STRING REPLY TO STRING RELAY STRING */ #line 445 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, (yyvsp[-7].v.string), (yyvsp[-5].v.string), (yyvsp[-2].v.string), (yyvsp[0].v.string), NULL)) { free((yyvsp[-7].v.string)); free((yyvsp[-5].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-7].v.string)); free((yyvsp[-5].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1780 "../gotd/parse.c" break; case 40: /* notifyflags: EMAIL TO STRING RELAY STRING PORT STRING */ #line 463 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, NULL, (yyvsp[-4].v.string), NULL, (yyvsp[-2].v.string), (yyvsp[0].v.string))) { free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1801 "../gotd/parse.c" break; case 41: /* notifyflags: EMAIL FROM STRING TO STRING RELAY STRING PORT STRING */ #line 479 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, (yyvsp[-6].v.string), (yyvsp[-4].v.string), NULL, (yyvsp[-2].v.string), (yyvsp[0].v.string))) { free((yyvsp[-6].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-6].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1824 "../gotd/parse.c" break; case 42: /* notifyflags: EMAIL TO STRING REPLY TO STRING RELAY STRING PORT STRING */ #line 497 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, NULL, (yyvsp[-7].v.string), (yyvsp[-4].v.string), (yyvsp[-2].v.string), (yyvsp[0].v.string))) { free((yyvsp[-7].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-7].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1847 "../gotd/parse.c" break; case 43: /* notifyflags: EMAIL FROM STRING TO STRING REPLY TO STRING RELAY STRING PORT STRING */ #line 515 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, (yyvsp[-9].v.string), (yyvsp[-7].v.string), (yyvsp[-4].v.string), (yyvsp[-2].v.string), (yyvsp[0].v.string))) { free((yyvsp[-9].v.string)); free((yyvsp[-7].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-9].v.string)); free((yyvsp[-7].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1872 "../gotd/parse.c" break; case 44: /* notifyflags: EMAIL TO STRING RELAY STRING PORT NUMBER */ #line 535 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, NULL, (yyvsp[-4].v.string), NULL, (yyvsp[-2].v.string), port_sprintf((yyvsp[0].v.number)))) { free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); YYERROR; } } free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); } #line 1891 "../gotd/parse.c" break; case 45: /* notifyflags: EMAIL FROM STRING TO STRING RELAY STRING PORT NUMBER */ #line 549 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, (yyvsp[-6].v.string), (yyvsp[-4].v.string), NULL, (yyvsp[-2].v.string), port_sprintf((yyvsp[0].v.number)))) { free((yyvsp[-6].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); YYERROR; } } free((yyvsp[-6].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); } #line 1912 "../gotd/parse.c" break; case 46: /* notifyflags: EMAIL TO STRING REPLY TO STRING RELAY STRING PORT NUMBER */ #line 565 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, NULL, (yyvsp[-7].v.string), (yyvsp[-4].v.string), (yyvsp[-2].v.string), port_sprintf((yyvsp[0].v.number)))) { free((yyvsp[-7].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); YYERROR; } } free((yyvsp[-7].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); } #line 1933 "../gotd/parse.c" break; case 47: /* notifyflags: EMAIL FROM STRING TO STRING REPLY TO STRING RELAY STRING PORT NUMBER */ #line 581 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, (yyvsp[-9].v.string), (yyvsp[-7].v.string), (yyvsp[-4].v.string), (yyvsp[-2].v.string), port_sprintf((yyvsp[0].v.number)))) { free((yyvsp[-9].v.string)); free((yyvsp[-7].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); YYERROR; } } free((yyvsp[-9].v.string)); free((yyvsp[-7].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); } #line 1956 "../gotd/parse.c" break; case 48: /* notifyflags: URL STRING */ #line 599 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_http(new_repo, (yyvsp[0].v.string), NULL, NULL, 0)) { free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[0].v.string)); } #line 1973 "../gotd/parse.c" break; case 49: /* notifyflags: URL STRING USER STRING PASSWORD STRING */ #line 611 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_http(new_repo, (yyvsp[-4].v.string), (yyvsp[-2].v.string), (yyvsp[0].v.string), 0)) { free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1993 "../gotd/parse.c" break; case 50: /* notifyflags: URL STRING USER STRING PASSWORD STRING INSECURE */ #line 626 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_http(new_repo, (yyvsp[-5].v.string), (yyvsp[-3].v.string), (yyvsp[-1].v.string), 1)) { free((yyvsp[-5].v.string)); free((yyvsp[-3].v.string)); free((yyvsp[-1].v.string)); YYERROR; } } free((yyvsp[-5].v.string)); free((yyvsp[-3].v.string)); free((yyvsp[-1].v.string)); } #line 2013 "../gotd/parse.c" break; case 51: /* $@1: %empty */ #line 643 "../gotd/parse.y" { struct gotd_repo *repo; TAILQ_FOREACH(repo, &gotd->repos, entry) { if (strcmp(repo->name, (yyvsp[0].v.string)) == 0) { yyerror("duplicate repository '%s'", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } } if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_AUTH || gotd_proc_id == PROC_REPO_WRITE || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_GITWRAPPER | gotd_proc_id == PROC_NOTIFY) { new_repo = conf_new_repo((yyvsp[0].v.string)); } free((yyvsp[0].v.string)); } #line 2039 "../gotd/parse.c" break; case 52: /* repository: REPOSITORY STRING $@1 '{' optnl repoopts2 '}' */ #line 663 "../gotd/parse.y" { } #line 2046 "../gotd/parse.c" break; case 53: /* repoopts1: PATH STRING */ #line 667 "../gotd/parse.y" { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_AUTH || gotd_proc_id == PROC_REPO_WRITE || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_GITWRAPPER || gotd_proc_id == PROC_NOTIFY) { if (!got_path_is_absolute((yyvsp[0].v.string))) { yyerror("%s: path %s is not absolute", __func__, (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } if (realpath((yyvsp[0].v.string), new_repo->path) == NULL) { /* * To give admins a chance to create * missing repositories at run-time * we only warn about ENOENT here. * * And ignore 'permission denied' when * running in gitwrapper. Users may be * able to access this repository via * gotd regardless. */ if (errno == ENOENT) { yyerror("realpath %s: %s", (yyvsp[0].v.string), strerror(errno)); } else if (errno != EACCES || gotd_proc_id != PROC_GITWRAPPER) { yyerror("realpath %s: %s", (yyvsp[0].v.string), strerror(errno)); free((yyvsp[0].v.string)); YYERROR; } if (strlcpy(new_repo->path, (yyvsp[0].v.string), sizeof(new_repo->path)) >= sizeof(new_repo->path)) yyerror("path too long"); } } free((yyvsp[0].v.string)); } #line 2094 "../gotd/parse.c" break; case 54: /* repoopts1: PERMIT RO STRING */ #line 710 "../gotd/parse.y" { if (gotd_proc_id == PROC_AUTH) { conf_new_access_rule(new_repo, GOTD_ACCESS_PERMITTED, GOTD_AUTH_READ, (yyvsp[0].v.string)); } else free((yyvsp[0].v.string)); } #line 2106 "../gotd/parse.c" break; case 55: /* repoopts1: PERMIT RW STRING */ #line 717 "../gotd/parse.y" { if (gotd_proc_id == PROC_AUTH) { conf_new_access_rule(new_repo, GOTD_ACCESS_PERMITTED, GOTD_AUTH_READ | GOTD_AUTH_WRITE, (yyvsp[0].v.string)); } else free((yyvsp[0].v.string)); } #line 2119 "../gotd/parse.c" break; case 56: /* repoopts1: DENY STRING */ #line 725 "../gotd/parse.y" { if (gotd_proc_id == PROC_AUTH) { conf_new_access_rule(new_repo, GOTD_ACCESS_DENIED, 0, (yyvsp[0].v.string)); } else free((yyvsp[0].v.string)); } #line 2131 "../gotd/parse.c" break; #line 2135 "../gotd/parse.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; *++yyvsp = yyval; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ { const int yylhs = yyr1[yyn] - YYNTOKENS; const int yyi = yypgoto[yylhs] + *yyssp; yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp ? yytable[yyi] : yydefgoto[yylhs]); } goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; yyerror (YY_("syntax error")); } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (0) YYERROR; ++yynerrs; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ /* Pop stack until we find a state that shifts the error token. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYSYMBOL_YYerror; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", YY_ACCESSING_SYMBOL (yystate), yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturnlab; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturnlab; /*-----------------------------------------------------------. | yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | `-----------------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; goto yyreturnlab; /*----------------------------------------------------------. | yyreturnlab -- parsing is finished, clean up and return. | `----------------------------------------------------------*/ yyreturnlab: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", YY_ACCESSING_SYMBOL (+*yyssp), yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif return yyresult; } #line 747 "../gotd/parse.y" struct keywords { const char *k_name; int k_val; }; int yyerror(const char *fmt, ...) { va_list ap; char *msg; file->errors++; va_start(ap, fmt); if (vasprintf(&msg, fmt, ap) == -1) fatalx("yyerror vasprintf"); va_end(ap); logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); free(msg); return (0); } int kw_cmp(const void *k, const void *e) { return (strcmp(k, ((const struct keywords *)e)->k_name)); } int lookup(char *s) { /* This has to be sorted always. */ static const struct keywords keywords[] = { { "branch", BRANCH }, { "connection", CONNECTION }, { "deny", DENY }, { "email", EMAIL }, { "from", FROM }, { "insecure", INSECURE }, { "limit", LIMIT }, { "listen", LISTEN }, { "namespace", NAMESPACE }, { "notify", NOTIFY }, { "on", ON }, { "password", PASSWORD }, { "path", PATH }, { "permit", PERMIT }, { "port", PORT }, { "protect", PROTECT }, { "reference", REFERENCE }, { "relay", RELAY }, { "reply", REPLY }, { "repository", REPOSITORY }, { "request", REQUEST }, { "ro", RO }, { "rw", RW }, { "tag", TAG }, { "timeout", TIMEOUT }, { "to", TO }, { "url", URL }, { "user", USER }, }; const struct keywords *p; p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), sizeof(keywords[0]), kw_cmp); if (p) return (p->k_val); else return (STRING); } #define MAXPUSHBACK 128 unsigned char *parsebuf; int parseindex; unsigned char pushback_buffer[MAXPUSHBACK]; int pushback_index = 0; int lgetc(int quotec) { int c, next; if (parsebuf) { /* Read character from the parsebuffer instead of input. */ if (parseindex >= 0) { c = parsebuf[parseindex++]; if (c != '\0') return (c); parsebuf = NULL; } else parseindex++; } if (pushback_index) return (pushback_buffer[--pushback_index]); if (quotec) { c = getc(file->stream); if (c == EOF) yyerror("reached end of file while parsing " "quoted string"); return (c); } c = getc(file->stream); while (c == '\\') { next = getc(file->stream); if (next != '\n') { c = next; break; } yylval.lineno = file->lineno; file->lineno++; c = getc(file->stream); } return (c); } int lungetc(int c) { if (c == EOF) return (EOF); if (parsebuf) { parseindex--; if (parseindex >= 0) return (c); } if (pushback_index < MAXPUSHBACK-1) return (pushback_buffer[pushback_index++] = c); else return (EOF); } int findeol(void) { int c; parsebuf = NULL; /* Skip to either EOF or the first real EOL. */ while (1) { if (pushback_index) c = pushback_buffer[--pushback_index]; else c = lgetc(0); if (c == '\n') { file->lineno++; break; } if (c == EOF) break; } return (ERROR); } int yylex(void) { unsigned char buf[8096]; unsigned char *p, *val; int quotec, next, c; int token; top: p = buf; c = lgetc(0); while (c == ' ' || c == '\t') c = lgetc(0); /* nothing */ yylval.lineno = file->lineno; if (c == '#') { c = lgetc(0); while (c != '\n' && c != EOF) c = lgetc(0); /* nothing */ } if (c == '$' && parsebuf == NULL) { while (1) { c = lgetc(0); if (c == EOF) return (0); if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } if (isalnum(c) || c == '_') { *p++ = c; continue; } *p = '\0'; lungetc(c); break; } val = symget(buf); if (val == NULL) { yyerror("macro '%s' not defined", buf); return (findeol()); } parsebuf = val; parseindex = 0; goto top; } switch (c) { case '\'': case '"': quotec = c; while (1) { c = lgetc(quotec); if (c == EOF) return (0); if (c == '\n') { file->lineno++; continue; } else if (c == '\\') { next = lgetc(quotec); if (next == EOF) return (0); if (next == quotec || c == ' ' || c == '\t') c = next; else if (next == '\n') { file->lineno++; continue; } else lungetc(next); } else if (c == quotec) { *p = '\0'; break; } else if (c == '\0') { yyerror("syntax error"); return (findeol()); } if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } *p++ = c; } yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "yylex: strdup"); return (STRING); } #define allowed_to_end_number(x) \ (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') if (c == '-' || isdigit(c)) { do { *p++ = c; if ((unsigned)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && isdigit(c)); lungetc(c); if (p == buf + 1 && buf[0] == '-') goto nodigits; if (c == EOF || allowed_to_end_number(c)) { const char *errstr = NULL; *p = '\0'; yylval.v.number = strtonum(buf, LLONG_MIN, LLONG_MAX, &errstr); if (errstr) { yyerror("\"%s\" invalid number: %s", buf, errstr); return (findeol()); } return (NUMBER); } else { nodigits: while (p > buf + 1) lungetc(*--p); c = *--p; if (c == '-') return (c); } } #define allowed_in_string(x) \ (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ x != '{' && x != '}' && \ x != '!' && x != '=' && x != '#' && \ x != ',')) if (isalnum(c) || c == ':' || c == '_') { do { *p++ = c; if ((unsigned)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && (allowed_in_string(c))); lungetc(c); *p = '\0'; token = lookup(buf); if (token == STRING) { yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "yylex: strdup"); } return (token); } if (c == '\n') { yylval.lineno = file->lineno; file->lineno++; } if (c == EOF) return (0); return (c); } int check_file_secrecy(int fd, const char *fname) { struct stat st; if (fstat(fd, &st)) { log_warn("cannot stat %s", fname); return (-1); } if (st.st_uid != 0 && st.st_uid != getuid()) { log_warnx("%s: owner not root or current user", fname); return (-1); } if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { log_warnx("%s: group writable or world read/writable", fname); return (-1); } return (0); } struct file * newfile(const char *name, int secret, int required) { struct file *nfile; nfile = calloc(1, sizeof(struct file)); if (nfile == NULL) { log_warn("calloc"); return (NULL); } nfile->name = strdup(name); if (nfile->name == NULL) { log_warn("strdup"); free(nfile); return (NULL); } nfile->stream = fopen(nfile->name, "r"); if (nfile->stream == NULL) { if (required) log_warn("open %s", nfile->name); free(nfile->name); free(nfile); return (NULL); } else if (secret && check_file_secrecy(fileno(nfile->stream), nfile->name)) { fclose(nfile->stream); free(nfile->name); free(nfile); return (NULL); } nfile->lineno = 1; return (nfile); } static void closefile(struct file *xfile) { fclose(xfile->stream); free(xfile->name); free(xfile); } int parse_config(const char *filename, enum gotd_procid proc_id, struct gotd *env) { struct sym *sym, *next; struct gotd_repo *repo; int require_config_file = (proc_id != PROC_GITWRAPPER); memset(env, 0, sizeof(*env)); gotd = env; gotd_proc_id = proc_id; TAILQ_INIT(&gotd->repos); /* Apply default values. */ if (strlcpy(gotd->unix_socket_path, GOTD_UNIX_SOCKET, sizeof(gotd->unix_socket_path)) >= sizeof(gotd->unix_socket_path)) { fprintf(stderr, "%s: unix socket path too long", __func__); return -1; } if (strlcpy(gotd->user_name, GOTD_USER, sizeof(gotd->user_name)) >= sizeof(gotd->user_name)) { fprintf(stderr, "%s: user name too long", __func__); return -1; } gotd->request_timeout.tv_sec = GOTD_DEFAULT_REQUEST_TIMEOUT; gotd->request_timeout.tv_usec = 0; file = newfile(filename, 0, require_config_file); if (file == NULL) return require_config_file ? -1 : 0; yyparse(); errors = file->errors; closefile(file); /* Free macros and check which have not been used. */ TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { if ((gotd->verbosity > 1) && !sym->used) fprintf(stderr, "warning: macro '%s' not used\n", sym->nam); if (!sym->persist) { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } if (errors) return (-1); TAILQ_FOREACH(repo, &gotd->repos, entry) { if (repo->path[0] == '\0') { log_warnx("repository \"%s\": no path provided in " "configuration file", repo->name); return (-1); } } if (proc_id == PROC_GOTD && TAILQ_EMPTY(&gotd->repos)) { log_warnx("no repository defined in configuration file"); return (-1); } return (0); } static int uid_connection_limit_cmp(const void *pa, const void *pb) { const struct gotd_uid_connection_limit *a = pa, *b = pb; if (a->uid < b->uid) return -1; else if (a->uid > b->uid); return 1; return 0; } static int conf_limit_user_connections(const char *user, int maximum) { uid_t uid; struct gotd_uid_connection_limit *limit; size_t nlimits; if (maximum < 1) { yyerror("max connections cannot be smaller 1"); return -1; } if (maximum > GOTD_MAXCLIENTS) { yyerror("max connections must be <= %d", GOTD_MAXCLIENTS); return -1; } if (gotd_parseuid(user, &uid) == -1) { yyerror("%s: no such user", user); return -1; } limit = gotd_find_uid_connection_limit(gotd->connection_limits, gotd->nconnection_limits, uid); if (limit) { limit->max_connections = maximum; return 0; } limit = gotd->connection_limits; nlimits = gotd->nconnection_limits + 1; limit = reallocarray(limit, nlimits, sizeof(*limit)); if (limit == NULL) fatal("reallocarray"); limit[nlimits - 1].uid = uid; limit[nlimits - 1].max_connections = maximum; gotd->connection_limits = limit; gotd->nconnection_limits = nlimits; qsort(gotd->connection_limits, gotd->nconnection_limits, sizeof(gotd->connection_limits[0]), uid_connection_limit_cmp); return 0; } static struct gotd_repo * conf_new_repo(const char *name) { struct gotd_repo *repo; if (name[0] == '\0') { fatalx("syntax error: empty repository name found in %s", file->name); } if (strchr(name, '\n') != NULL) fatalx("repository names must not contain linefeeds: %s", name); repo = calloc(1, sizeof(*repo)); if (repo == NULL) fatalx("%s: calloc", __func__); STAILQ_INIT(&repo->rules); TAILQ_INIT(&repo->protected_tag_namespaces); TAILQ_INIT(&repo->protected_branch_namespaces); TAILQ_INIT(&repo->protected_branches); TAILQ_INIT(&repo->protected_branches); TAILQ_INIT(&repo->notification_refs); TAILQ_INIT(&repo->notification_ref_namespaces); STAILQ_INIT(&repo->notification_targets); if (strlcpy(repo->name, name, sizeof(repo->name)) >= sizeof(repo->name)) fatalx("%s: strlcpy", __func__); TAILQ_INSERT_TAIL(&gotd->repos, repo, entry); gotd->nrepos++; return repo; }; static void conf_new_access_rule(struct gotd_repo *repo, enum gotd_access access, int authorization, char *identifier) { struct gotd_access_rule *rule; rule = calloc(1, sizeof(*rule)); if (rule == NULL) fatal("calloc"); rule->access = access; rule->authorization = authorization; rule->identifier = identifier; STAILQ_INSERT_TAIL(&repo->rules, rule, entry); } static int refname_is_valid(char *refname) { if (strncmp(refname, "refs/", 5) != 0) { yyerror("reference name must begin with \"refs/\": %s", refname); return 0; } if (!got_ref_name_is_valid(refname)) { yyerror("invalid reference name: %s", refname); return 0; } return 1; } static int conf_protect_ref_namespace(char **new, struct got_pathlist_head *refs, char *namespace) { const struct got_error *error; struct got_pathlist_entry *pe; char *s; *new = NULL; got_path_strip_trailing_slashes(namespace); if (!refname_is_valid(namespace)) return -1; if (asprintf(&s, "%s/", namespace) == -1) { yyerror("asprintf: %s", strerror(errno)); return -1; } error = got_pathlist_insert(&pe, refs, s, NULL); if (error || pe == NULL) { free(s); if (error) yyerror("got_pathlist_insert: %s", error->msg); else yyerror("duplicate protected namespace %s", namespace); return -1; } *new = s; return 0; } static int conf_protect_tag_namespace(struct gotd_repo *repo, char *namespace) { struct got_pathlist_entry *pe; char *new; if (conf_protect_ref_namespace(&new, &repo->protected_tag_namespaces, namespace) == -1) return -1; TAILQ_FOREACH(pe, &repo->protected_branch_namespaces, entry) { if (strcmp(pe->path, new) == 0) { yyerror("duplicate protected namespace %s", namespace); return -1; } } return 0; } static int conf_protect_branch_namespace(struct gotd_repo *repo, char *namespace) { struct got_pathlist_entry *pe; char *new; if (conf_protect_ref_namespace(&new, &repo->protected_branch_namespaces, namespace) == -1) return -1; TAILQ_FOREACH(pe, &repo->protected_tag_namespaces, entry) { if (strcmp(pe->path, new) == 0) { yyerror("duplicate protected namespace %s", namespace); return -1; } } return 0; } static int conf_protect_branch(struct gotd_repo *repo, char *branchname) { const struct got_error *error; struct got_pathlist_entry *new; char *refname; if (strncmp(branchname, "refs/heads/", 11) != 0) { if (asprintf(&refname, "refs/heads/%s", branchname) == -1) { yyerror("asprintf: %s", strerror(errno)); return -1; } } else { refname = strdup(branchname); if (refname == NULL) { yyerror("strdup: %s", strerror(errno)); return -1; } } if (!refname_is_valid(refname)) { free(refname); return -1; } error = got_pathlist_insert(&new, &repo->protected_branches, refname, NULL); if (error || new == NULL) { free(refname); if (error) yyerror("got_pathlist_insert: %s", error->msg); else yyerror("duplicate protect branch %s", branchname); return -1; } return 0; } static int conf_notify_branch(struct gotd_repo *repo, char *branchname) { const struct got_error *error; struct got_pathlist_entry *pe; char *refname; if (strncmp(branchname, "refs/heads/", 11) != 0) { if (asprintf(&refname, "refs/heads/%s", branchname) == -1) { yyerror("asprintf: %s", strerror(errno)); return -1; } } else { refname = strdup(branchname); if (refname == NULL) { yyerror("strdup: %s", strerror(errno)); return -1; } } if (!refname_is_valid(refname)) { free(refname); return -1; } error = got_pathlist_insert(&pe, &repo->notification_refs, refname, NULL); if (error) { free(refname); yyerror("got_pathlist_insert: %s", error->msg); return -1; } if (pe == NULL) free(refname); return 0; } static int conf_notify_ref_namespace(struct gotd_repo *repo, char *namespace) { const struct got_error *error; struct got_pathlist_entry *pe; char *s; got_path_strip_trailing_slashes(namespace); if (!refname_is_valid(namespace)) return -1; if (asprintf(&s, "%s/", namespace) == -1) { yyerror("asprintf: %s", strerror(errno)); return -1; } error = got_pathlist_insert(&pe, &repo->notification_ref_namespaces, s, NULL); if (error) { free(s); yyerror("got_pathlist_insert: %s", error->msg); return -1; } if (pe == NULL) free(s); return 0; } static int conf_notify_email(struct gotd_repo *repo, char *sender, char *recipient, char *responder, char *hostname, char *port) { struct gotd_notification_target *target; STAILQ_FOREACH(target, &repo->notification_targets, entry) { if (target->type != GOTD_NOTIFICATION_VIA_EMAIL) continue; if (strcmp(target->conf.email.recipient, recipient) == 0) { yyerror("duplicate email notification for '%s' in " "repository '%s'", recipient, repo->name); return -1; } } target = calloc(1, sizeof(*target)); if (target == NULL) fatal("calloc"); target->type = GOTD_NOTIFICATION_VIA_EMAIL; if (sender) { target->conf.email.sender = strdup(sender); if (target->conf.email.sender == NULL) fatal("strdup"); } target->conf.email.recipient = strdup(recipient); if (target->conf.email.recipient == NULL) fatal("strdup"); if (responder) { target->conf.email.responder = strdup(responder); if (target->conf.email.responder == NULL) fatal("strdup"); } if (hostname) { target->conf.email.hostname = strdup(hostname); if (target->conf.email.hostname == NULL) fatal("strdup"); } if (port) { target->conf.email.port = strdup(port); if (target->conf.email.port == NULL) fatal("strdup"); } STAILQ_INSERT_TAIL(&repo->notification_targets, target, entry); return 0; } static int conf_notify_http(struct gotd_repo *repo, char *url, char *user, char *password, int insecure) { const struct got_error *error; struct gotd_notification_target *target; char *proto, *hostname, *port, *path; int tls = 0, ret = 0; error = gotd_parse_url(&proto, &hostname, &port, &path, url); if (error) { yyerror("invalid HTTP notification URL '%s' in " "repository '%s': %s", url, repo->name, error->msg); return -1; } tls = !strcmp(proto, "https"); if (strcmp(proto, "http") != 0 && strcmp(proto, "https") != 0) { yyerror("invalid protocol '%s' in notification URL '%s' in " "repository '%s", proto, url, repo->name); ret = -1; goto done; } if (port == NULL) { if (strcmp(proto, "http") == 0) port = strdup("80"); if (strcmp(proto, "https") == 0) port = strdup("443"); if (port == NULL) { error = got_error_from_errno("strdup"); ret = -1; goto done; } } if ((user != NULL && password == NULL) || (user == NULL && password != NULL)) { yyerror("missing username or password"); ret = -1; goto done; } if (!insecure && strcmp(proto, "http") == 0 && (user != NULL || password != NULL)) { yyerror("%s: HTTP notifications with basic authentication " "over plaintext HTTP will leak credentials; add the " "'insecure' config keyword if this is intentional", url); ret = -1; goto done; } STAILQ_FOREACH(target, &repo->notification_targets, entry) { if (target->type != GOTD_NOTIFICATION_VIA_HTTP) continue; if (target->conf.http.tls == tls && !strcmp(target->conf.http.hostname, hostname) && !strcmp(target->conf.http.port, port) && !strcmp(target->conf.http.path, path)) { yyerror("duplicate notification for URL '%s' in " "repository '%s'", url, repo->name); ret = -1; goto done; } } target = calloc(1, sizeof(*target)); if (target == NULL) fatal("calloc"); target->type = GOTD_NOTIFICATION_VIA_HTTP; target->conf.http.tls = tls; target->conf.http.hostname = hostname; target->conf.http.port = port; target->conf.http.path = path; hostname = port = path = NULL; if (user) { target->conf.http.user = strdup(user); if (target->conf.http.user == NULL) fatal("strdup"); target->conf.http.password = strdup(password); if (target->conf.http.password == NULL) fatal("strdup"); } STAILQ_INSERT_TAIL(&repo->notification_targets, target, entry); done: free(proto); free(hostname); free(port); free(path); return ret; } int symset(const char *nam, const char *val, int persist) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) break; } if (sym != NULL) { if (sym->persist == 1) return (0); else { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } sym = calloc(1, sizeof(*sym)); if (sym == NULL) return (-1); sym->nam = strdup(nam); if (sym->nam == NULL) { free(sym); return (-1); } sym->val = strdup(val); if (sym->val == NULL) { free(sym->nam); free(sym); return (-1); } sym->used = 0; sym->persist = persist; TAILQ_INSERT_TAIL(&symhead, sym, entry); return (0); } char * symget(const char *nam) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) { sym->used = 1; return (sym->val); } } return (NULL); } struct gotd_repo * gotd_find_repo_by_name(const char *repo_name, struct gotd_repolist *repos) { struct gotd_repo *repo; size_t namelen; TAILQ_FOREACH(repo, repos, entry) { namelen = strlen(repo->name); if (strncmp(repo->name, repo_name, namelen) != 0) continue; if (repo_name[namelen] == '\0' || strcmp(&repo_name[namelen], ".git") == 0) return repo; } return NULL; } struct gotd_repo * gotd_find_repo_by_path(const char *repo_path, struct gotd *gotd) { struct gotd_repo *repo; TAILQ_FOREACH(repo, &gotd->repos, entry) { if (strcmp(repo->path, repo_path) == 0) return repo; } return NULL; } struct gotd_uid_connection_limit * gotd_find_uid_connection_limit(struct gotd_uid_connection_limit *limits, size_t nlimits, uid_t uid) { /* This array is always sorted to allow for binary search. */ int i, left = 0, right = nlimits - 1; while (left <= right) { i = ((left + right) / 2); if (limits[i].uid == uid) return &limits[i]; if (limits[i].uid > uid) left = i + 1; else right = i - 1; } return NULL; } int gotd_parseuid(const char *s, uid_t *uid) { struct passwd *pw; const char *errstr; if ((pw = getpwnam(s)) != NULL) { *uid = pw->pw_uid; if (*uid == UID_MAX) return -1; return 0; } *uid = strtonum(s, 0, UID_MAX - 1, &errstr); if (errstr) return -1; return 0; } const struct got_error * gotd_parse_url(char **proto, char **host, char **port, char **request_path, const char *url) { const struct got_error *err = NULL; char *s, *p, *q; *proto = *host = *port = *request_path = NULL; p = strstr(url, "://"); if (!p) return got_error(GOT_ERR_PARSE_URI); *proto = strndup(url, p - url); if (*proto == NULL) { err = got_error_from_errno("strndup"); goto done; } s = p + 3; p = strstr(s, "/"); if (p == NULL) { err = got_error(GOT_ERR_PARSE_URI); goto done; } q = memchr(s, ':', p - s); if (q) { *host = strndup(s, q - s); if (*host == NULL) { err = got_error_from_errno("strndup"); goto done; } if ((*host)[0] == '\0') { err = got_error(GOT_ERR_PARSE_URI); goto done; } *port = strndup(q + 1, p - (q + 1)); if (*port == NULL) { err = got_error_from_errno("strndup"); goto done; } if ((*port)[0] == '\0') { err = got_error(GOT_ERR_PARSE_URI); goto done; } } else { *host = strndup(s, p - s); if (*host == NULL) { err = got_error_from_errno("strndup"); goto done; } if ((*host)[0] == '\0') { err = got_error(GOT_ERR_PARSE_URI); goto done; } } while (p[0] == '/' && p[1] == '/') p++; *request_path = strdup(p); if (*request_path == NULL) { err = got_error_from_errno("strdup"); goto done; } if ((*request_path)[0] == '\0') { err = got_error(GOT_ERR_PARSE_URI); goto done; } done: if (err) { free(*proto); *proto = NULL; free(*host); *host = NULL; free(*port); *port = NULL; free(*request_path); *request_path = NULL; } return err; } static char * port_sprintf(int p) { static char portno[32]; int n; n = snprintf(portno, sizeof(portno), "%lld", (long long)p); if (n < 0 || (size_t)n >= sizeof(portno)) fatalx("port number too long: %lld", (long long)p); return portno; } got-portable-0.101/gotd/gotd.c0000664000175100017510000016042614644144735011662 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_opentemp.h" #include "got_path.h" #include "got_repository.h" #include "got_object.h" #include "got_reference.h" #include "got_diff.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_object_cache.h" #include "got_lib_hash.h" #include "got_lib_gitproto.h" #include "got_lib_pack.h" #include "got_lib_repository.h" #include "gotd.h" #include "log.h" #include "listen.h" #include "auth.h" #include "session_read.h" #include "session_write.h" #include "repo_read.h" #include "repo_write.h" #include "notify.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif enum gotd_client_state { GOTD_CLIENT_STATE_NEW, GOTD_CLIENT_STATE_ACCESS_GRANTED, }; struct gotd_child_proc { pid_t pid; enum gotd_procid type; char repo_name[NAME_MAX]; char repo_path[PATH_MAX]; int pipe[2]; struct gotd_imsgev iev; struct event tmo; TAILQ_ENTRY(gotd_child_proc) entry; }; TAILQ_HEAD(gotd_procs, gotd_child_proc) procs; struct gotd_client { STAILQ_ENTRY(gotd_client) entry; enum gotd_client_state state; uint32_t id; int fd; struct gotd_imsgev iev; struct event tmo; uid_t euid; gid_t egid; char *username; struct gotd_child_proc *repo; struct gotd_child_proc *auth; struct gotd_child_proc *session; int required_auth; }; STAILQ_HEAD(gotd_clients, gotd_client); static struct gotd_clients gotd_clients[GOTD_CLIENT_TABLE_SIZE]; static SIPHASH_KEY clients_hash_key; volatile int client_cnt; static struct timeval auth_timeout = { 5, 0 }; static struct gotd gotd; void gotd_sighdlr(int sig, short event, void *arg); static void gotd_shutdown(void); static const struct got_error *start_session_child(struct gotd_client *, struct gotd_repo *, char *, const char *, int, int); static const struct got_error *start_repo_child(struct gotd_client *, enum gotd_procid, struct gotd_repo *, char *, const char *, int, int); static const struct got_error *start_auth_child(struct gotd_client *, int, struct gotd_repo *, char *, const char *, int, int); static void kill_proc(struct gotd_child_proc *, int); static void disconnect(struct gotd_client *); static void drop_privs(struct passwd *); __dead static void usage(void) { fprintf(stderr, "usage: %s [-dnv] [-f config-file]\n", getprogname()); exit(1); } static void drop_privs(struct passwd *pw) { /* Drop root privileges. */ if (setgid(pw->pw_gid) == -1) fatal("setgid %d failed", pw->pw_gid); if (setuid(pw->pw_uid) == -1) fatal("setuid %d failed", pw->pw_uid); } static int unix_socket_listen(const char *unix_socket_path, uid_t uid, gid_t gid) { struct sockaddr_un sun; int fd = -1; mode_t old_umask, mode; int sock_flags = SOCK_STREAM | SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif fd = socket(AF_UNIX, sock_flags, 0); if (fd == -1) { log_warn("socket"); return -1; } sun.sun_family = AF_UNIX; if (strlcpy(sun.sun_path, unix_socket_path, sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) { log_warnx("%s: name too long", unix_socket_path); close(fd); return -1; } if (unlink(unix_socket_path) == -1) { if (errno != ENOENT) { log_warn("unlink %s", unix_socket_path); close(fd); return -1; } } old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { log_warn("bind: %s", unix_socket_path); close(fd); umask(old_umask); return -1; } umask(old_umask); if (chmod(unix_socket_path, mode) == -1) { log_warn("chmod %o %s", mode, unix_socket_path); close(fd); unlink(unix_socket_path); return -1; } if (chown(unix_socket_path, uid, gid) == -1) { log_warn("chown %s uid=%d gid=%d", unix_socket_path, uid, gid); close(fd); unlink(unix_socket_path); return -1; } if (listen(fd, GOTD_UNIX_SOCKET_BACKLOG) == -1) { log_warn("listen"); close(fd); unlink(unix_socket_path); return -1; } return fd; } static uint64_t client_hash(uint32_t client_id) { return SipHash24(&clients_hash_key, &client_id, sizeof(client_id)); } static void add_client(struct gotd_client *client) { uint64_t slot = client_hash(client->id) % nitems(gotd_clients); STAILQ_INSERT_HEAD(&gotd_clients[slot], client, entry); client_cnt++; } static struct gotd_client * find_client(uint32_t client_id) { uint64_t slot; struct gotd_client *c; slot = client_hash(client_id) % nitems(gotd_clients); STAILQ_FOREACH(c, &gotd_clients[slot], entry) { if (c->id == client_id) return c; } return NULL; } static struct gotd_client * find_client_by_proc_fd(int fd) { uint64_t slot; for (slot = 0; slot < nitems(gotd_clients); slot++) { struct gotd_client *c; STAILQ_FOREACH(c, &gotd_clients[slot], entry) { if (c->repo && c->repo->iev.ibuf.fd == fd) return c; if (c->auth && c->auth->iev.ibuf.fd == fd) return c; if (c->session && c->session->iev.ibuf.fd == fd) return c; } } return NULL; } static int client_is_reading(struct gotd_client *client) { return (client->required_auth & (GOTD_AUTH_READ | GOTD_AUTH_WRITE)) == GOTD_AUTH_READ; } static int client_is_writing(struct gotd_client *client) { return (client->required_auth & (GOTD_AUTH_READ | GOTD_AUTH_WRITE)) == (GOTD_AUTH_READ | GOTD_AUTH_WRITE); } static const struct got_error * ensure_client_is_not_writing(struct gotd_client *client) { if (client_is_writing(client)) { return got_error_fmt(GOT_ERR_BAD_PACKET, "uid %d made a read-request but is writing to " "a repository", client->euid); } return NULL; } static const struct got_error * ensure_client_is_not_reading(struct gotd_client *client) { if (client_is_reading(client)) { return got_error_fmt(GOT_ERR_BAD_PACKET, "uid %d made a write-request but is reading from " "a repository", client->euid); } return NULL; } static void proc_done(struct gotd_child_proc *proc) { struct gotd_client *client; TAILQ_REMOVE(&procs, proc, entry); client = find_client_by_proc_fd(proc->iev.ibuf.fd); if (client != NULL) { if (proc == client->repo) client->repo = NULL; if (proc == client->auth) client->auth = NULL; if (proc == client->session) client->session = NULL; disconnect(client); } if (proc == gotd.notify_proc) gotd.notify_proc = NULL; evtimer_del(&proc->tmo); if (proc->iev.ibuf.fd != -1) { event_del(&proc->iev.ev); msgbuf_clear(&proc->iev.ibuf.w); close(proc->iev.ibuf.fd); } free(proc); } static void kill_repo_proc(struct gotd_client *client) { if (client->repo == NULL) return; kill_proc(client->repo, 0); client->repo = NULL; } static void kill_auth_proc(struct gotd_client *client) { if (client->auth == NULL) return; kill_proc(client->auth, 0); client->auth = NULL; } static void kill_session_proc(struct gotd_client *client) { if (client->session == NULL) return; kill_proc(client->session, 0); client->session = NULL; } static void disconnect(struct gotd_client *client) { struct gotd_imsg_disconnect idisconnect; struct gotd_child_proc *listen_proc = gotd.listen_proc; uint64_t slot; log_debug("uid %d: disconnecting", client->euid); kill_auth_proc(client); kill_session_proc(client); kill_repo_proc(client); idisconnect.client_id = client->id; if (gotd_imsg_compose_event(&listen_proc->iev, GOTD_IMSG_DISCONNECT, PROC_GOTD, -1, &idisconnect, sizeof(idisconnect)) == -1) log_warn("imsg compose DISCONNECT"); slot = client_hash(client->id) % nitems(gotd_clients); STAILQ_REMOVE(&gotd_clients[slot], client, gotd_client, entry); imsg_clear(&client->iev.ibuf); event_del(&client->iev.ev); evtimer_del(&client->tmo); if (client->fd != -1) close(client->fd); else if (client->iev.ibuf.fd != -1) close(client->iev.ibuf.fd); free(client->username); free(client); client_cnt--; } static void disconnect_on_error(struct gotd_client *client, const struct got_error *err) { struct imsgbuf ibuf; if (err->code != GOT_ERR_EOF) { log_warnx("uid %d: %s", client->euid, err->msg); if (client->fd != -1) { imsg_init(&ibuf, client->fd); gotd_imsg_send_error(&ibuf, 0, PROC_GOTD, err); imsg_clear(&ibuf); } } disconnect(client); } static const struct got_error * send_repo_info(struct gotd_imsgev *iev, struct gotd_repo *repo) { const struct got_error *err = NULL; struct gotd_imsg_info_repo irepo; memset(&irepo, 0, sizeof(irepo)); if (strlcpy(irepo.repo_name, repo->name, sizeof(irepo.repo_name)) >= sizeof(irepo.repo_name)) return got_error_msg(GOT_ERR_NO_SPACE, "repo name too long"); if (strlcpy(irepo.repo_path, repo->path, sizeof(irepo.repo_path)) >= sizeof(irepo.repo_path)) return got_error_msg(GOT_ERR_NO_SPACE, "repo path too long"); if (gotd_imsg_compose_event(iev, GOTD_IMSG_INFO_REPO, PROC_GOTD, -1, &irepo, sizeof(irepo)) == -1) { err = got_error_from_errno("imsg compose INFO_REPO"); if (err) return err; } return NULL; } static const struct got_error * send_client_info(struct gotd_imsgev *iev, struct gotd_client *client) { const struct got_error *err = NULL; struct gotd_imsg_info_client iclient; struct gotd_child_proc *proc; memset(&iclient, 0, sizeof(iclient)); iclient.euid = client->euid; iclient.egid = client->egid; proc = client->repo; if (proc) { if (strlcpy(iclient.repo_name, proc->repo_path, sizeof(iclient.repo_name)) >= sizeof(iclient.repo_name)) { return got_error_msg(GOT_ERR_NO_SPACE, "repo name too long"); } if (client_is_writing(client)) iclient.is_writing = 1; iclient.repo_child_pid = proc->pid; } if (client->session) iclient.session_child_pid = client->session->pid; if (gotd_imsg_compose_event(iev, GOTD_IMSG_INFO_CLIENT, PROC_GOTD, -1, &iclient, sizeof(iclient)) == -1) { err = got_error_from_errno("imsg compose INFO_CLIENT"); if (err) return err; } return NULL; } static const struct got_error * send_info(struct gotd_client *client) { const struct got_error *err = NULL; struct gotd_imsg_info info; uint64_t slot; struct gotd_repo *repo; if (client->euid != 0) return got_error_set_errno(EPERM, "info"); info.pid = gotd.pid; info.verbosity = gotd.verbosity; info.nrepos = gotd.nrepos; info.nclients = client_cnt - 1; if (gotd_imsg_compose_event(&client->iev, GOTD_IMSG_INFO, PROC_GOTD, -1, &info, sizeof(info)) == -1) { err = got_error_from_errno("imsg compose INFO"); if (err) return err; } TAILQ_FOREACH(repo, &gotd.repos, entry) { err = send_repo_info(&client->iev, repo); if (err) return err; } for (slot = 0; slot < nitems(gotd_clients); slot++) { struct gotd_client *c; STAILQ_FOREACH(c, &gotd_clients[slot], entry) { if (c->id == client->id) continue; err = send_client_info(&client->iev, c); if (err) return err; } } return NULL; } static const struct got_error * stop_gotd(struct gotd_client *client) { if (client->euid != 0) return got_error_set_errno(EPERM, "stop"); gotd_shutdown(); /* NOTREACHED */ return NULL; } static const struct got_error * start_client_authentication(struct gotd_client *client, struct imsg *imsg) { const struct got_error *err; struct gotd_imsg_list_refs ireq; struct gotd_repo *repo = NULL; size_t datalen; log_debug("list-refs request from uid %d", client->euid); if (client->state != GOTD_CLIENT_STATE_NEW) return got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected list-refs request received"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ireq)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ireq, imsg->data, datalen); if (ireq.client_is_reading) { err = ensure_client_is_not_writing(client); if (err) return err; repo = gotd_find_repo_by_name(ireq.repo_name, &gotd.repos); if (repo == NULL) return got_error(GOT_ERR_NOT_GIT_REPO); err = start_auth_child(client, GOTD_AUTH_READ, repo, gotd.argv0, gotd.confpath, gotd.daemonize, gotd.verbosity); if (err) return err; } else { err = ensure_client_is_not_reading(client); if (err) return err; repo = gotd_find_repo_by_name(ireq.repo_name, &gotd.repos); if (repo == NULL) return got_error(GOT_ERR_NOT_GIT_REPO); err = start_auth_child(client, GOTD_AUTH_READ | GOTD_AUTH_WRITE, repo, gotd.argv0, gotd.confpath, gotd.daemonize, gotd.verbosity); if (err) return err; } evtimer_add(&client->tmo, &auth_timeout); /* Flow continues upon authentication success/failure or timeout. */ return NULL; } static void gotd_request(int fd, short events, void *arg) { struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_client *client = iev->handler_arg; const struct got_error *err = NULL; struct imsg imsg; ssize_t n; if (events & EV_WRITE) { while (ibuf->w.queued) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno == EPIPE) { /* * The client has closed its socket. * This can happen when Git clients are * done sending pack file data. */ msgbuf_clear(&ibuf->w); continue; } else if (n == -1 && errno != EAGAIN) { err = got_error_from_errno("msgbuf_write"); disconnect_on_error(client, err); return; } if (n == 0) { /* Connection closed. */ err = got_error(GOT_ERR_EOF); disconnect_on_error(client, err); return; } } /* Disconnect gotctl(8) now that messages have been sent. */ if (!client_is_reading(client) && !client_is_writing(client)) { disconnect(client); return; } } if ((events & EV_READ) == 0) return; memset(&imsg, 0, sizeof(imsg)); while (err == NULL) { err = gotd_imsg_recv(&imsg, ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_READ) err = NULL; break; } evtimer_del(&client->tmo); switch (imsg.hdr.type) { case GOTD_IMSG_INFO: err = send_info(client); break; case GOTD_IMSG_STOP: err = stop_gotd(client); break; case GOTD_IMSG_LIST_REFS: err = start_client_authentication(client, &imsg); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); } if (err) { disconnect_on_error(client, err); } else { gotd_imsg_event_add(&client->iev); } } static void gotd_auth_timeout(int fd, short events, void *arg) { struct gotd_client *client = arg; log_debug("disconnecting uid %d due to authentication timeout", client->euid); disconnect(client); } static const struct got_error * recv_connect(uint32_t *client_id, struct imsg *imsg) { const struct got_error *err = NULL; struct gotd_imsg_connect iconnect; size_t datalen; int s = -1; struct gotd_client *client = NULL; *client_id = 0; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(iconnect)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iconnect, imsg->data, sizeof(iconnect)); s = imsg_get_fd(imsg); if (s == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } if (find_client(iconnect.client_id)) { err = got_error_msg(GOT_ERR_CLIENT_ID, "duplicate client ID"); goto done; } client = calloc(1, sizeof(*client)); if (client == NULL) { err = got_error_from_errno("calloc"); goto done; } *client_id = iconnect.client_id; client->state = GOTD_CLIENT_STATE_NEW; client->id = iconnect.client_id; client->fd = s; s = -1; /* The auth process will verify UID/GID for us. */ client->euid = iconnect.euid; client->egid = iconnect.egid; imsg_init(&client->iev.ibuf, client->fd); client->iev.handler = gotd_request; client->iev.events = EV_READ; client->iev.handler_arg = client; event_set(&client->iev.ev, client->fd, EV_READ, gotd_request, &client->iev); gotd_imsg_event_add(&client->iev); evtimer_set(&client->tmo, gotd_auth_timeout, client); add_client(client); log_debug("%s: new client uid %d connected on fd %d", __func__, client->euid, client->fd); done: if (err) { struct gotd_child_proc *listen_proc = gotd.listen_proc; struct gotd_imsg_disconnect idisconnect; idisconnect.client_id = client->id; if (gotd_imsg_compose_event(&listen_proc->iev, GOTD_IMSG_DISCONNECT, PROC_GOTD, -1, &idisconnect, sizeof(idisconnect)) == -1) log_warn("imsg compose DISCONNECT"); if (s != -1) close(s); } return err; } static const char *gotd_proc_names[PROC_MAX] = { "parent", "listen", "auth", "session_read", "session_write", "repo_read", "repo_write", "gitwrapper", "notify" }; static void kill_proc(struct gotd_child_proc *proc, int fatal) { struct timeval tv = { 5, 0 }; log_debug("kill -%d %d", fatal ? SIGKILL : SIGTERM, proc->pid); if (proc->iev.ibuf.fd != -1) { event_del(&proc->iev.ev); msgbuf_clear(&proc->iev.ibuf.w); close(proc->iev.ibuf.fd); proc->iev.ibuf.fd = -1; } if (!evtimer_pending(&proc->tmo, NULL) && !fatal) evtimer_add(&proc->tmo, &tv); if (fatal) { log_warnx("sending SIGKILL to PID %d", proc->pid); kill(proc->pid, SIGKILL); } else kill(proc->pid, SIGTERM); } static void kill_proc_timeout(int fd, short ev, void *d) { struct gotd_child_proc *proc = d; log_warnx("timeout waiting for PID %d to terminate;" " retrying with force", proc->pid); kill_proc(proc, 1); } static void gotd_shutdown(void) { uint64_t slot; log_debug("shutting down"); for (slot = 0; slot < nitems(gotd_clients); slot++) { struct gotd_client *c, *tmp; STAILQ_FOREACH_SAFE(c, &gotd_clients[slot], entry, tmp) disconnect(c); } kill_proc(gotd.listen_proc, 0); log_info("terminating"); exit(0); } static struct gotd_child_proc * find_proc_by_pid(pid_t pid) { struct gotd_child_proc *proc = NULL; TAILQ_FOREACH(proc, &procs, entry) if (proc->pid == pid) break; return proc; } void gotd_sighdlr(int sig, short event, void *arg) { struct gotd_child_proc *proc; pid_t pid; int status; /* * Normal signal handler rules don't apply because libevent * decouples for us. */ switch (sig) { case SIGHUP: log_info("%s: ignoring SIGHUP", __func__); break; case SIGUSR1: log_info("%s: ignoring SIGUSR1", __func__); break; case SIGTERM: case SIGINT: gotd_shutdown(); break; case SIGCHLD: for (;;) { pid = waitpid(WAIT_ANY, &status, WNOHANG); if (pid == -1) { if (errno == EINTR) continue; if (errno == ECHILD) break; fatal("waitpid"); } if (pid == 0) break; log_debug("reaped pid %d", pid); proc = find_proc_by_pid(pid); if (proc == NULL) { log_info("caught exit of unknown child %d", pid); continue; } if (WIFSIGNALED(status)) { log_warnx("child PID %d terminated with" " signal %d", pid, WTERMSIG(status)); } proc_done(proc); } break; default: fatalx("unexpected signal"); } } static const struct got_error * ensure_proc_is_reading(struct gotd_client *client, struct gotd_child_proc *proc) { if (!client_is_reading(client)) { kill_proc(proc, 1); return got_error_fmt(GOT_ERR_BAD_PACKET, "PID %d handled a read-request for uid %d but this " "user is not reading from a repository", proc->pid, client->euid); } return NULL; } static const struct got_error * ensure_proc_is_writing(struct gotd_client *client, struct gotd_child_proc *proc) { if (!client_is_writing(client)) { kill_proc(proc, 1); return got_error_fmt(GOT_ERR_BAD_PACKET, "PID %d handled a write-request for uid %d but this " "user is not writing to a repository", proc->pid, client->euid); } return NULL; } static int verify_imsg_src(struct gotd_client *client, struct gotd_child_proc *proc, struct imsg *imsg) { const struct got_error *err; int ret = 0; if (proc->type == PROC_REPO_READ || proc->type == PROC_REPO_WRITE) { if (client->repo == NULL) fatalx("no process found for uid %d", client->euid); if (proc->pid != client->repo->pid) { kill_proc(proc, 1); log_warnx("received message from PID %d for uid %d, " "while PID %d is the process serving this user", proc->pid, client->euid, client->repo->pid); return 0; } } if (proc->type == PROC_SESSION_READ || proc->type == PROC_SESSION_WRITE) { if (client->session == NULL) { log_warnx("no session found for uid %d", client->euid); return 0; } if (proc->pid != client->session->pid) { kill_proc(proc, 1); log_warnx("received message from PID %d for uid %d, " "while PID %d is the process serving this user", proc->pid, client->euid, client->session->pid); return 0; } } switch (imsg->hdr.type) { case GOTD_IMSG_ERROR: ret = 1; break; case GOTD_IMSG_CONNECT: if (proc->type != PROC_LISTEN) { err = got_error_fmt(GOT_ERR_BAD_PACKET, "new connection for uid %d from PID %d " "which is not the listen process", client->euid, proc->pid); } else ret = 1; break; case GOTD_IMSG_ACCESS_GRANTED: if (proc->type != PROC_AUTH) { err = got_error_fmt(GOT_ERR_BAD_PACKET, "authentication of uid %d from PID %d " "which is not the auth process", client->euid, proc->pid); } else ret = 1; break; case GOTD_IMSG_CLIENT_SESSION_READY: if (proc->type != PROC_SESSION_READ && proc->type != PROC_SESSION_WRITE) { err = got_error_fmt(GOT_ERR_BAD_PACKET, "unexpected \"ready\" signal from PID %d", proc->pid); } else ret = 1; break; case GOTD_IMSG_REPO_CHILD_READY: if (proc->type != PROC_REPO_READ && proc->type != PROC_REPO_WRITE) { err = got_error_fmt(GOT_ERR_BAD_PACKET, "unexpected \"ready\" signal from PID %d", proc->pid); } else ret = 1; break; case GOTD_IMSG_PACKFILE_DONE: err = ensure_proc_is_reading(client, proc); if (err) log_warnx("uid %d: %s", client->euid, err->msg); else ret = 1; break; case GOTD_IMSG_PACKFILE_INSTALL: case GOTD_IMSG_REF_UPDATES_START: case GOTD_IMSG_REF_UPDATE: err = ensure_proc_is_writing(client, proc); if (err) log_warnx("uid %d: %s", client->euid, err->msg); else ret = 1; break; default: log_debug("%s: unexpected imsg %d", __func__, imsg->hdr.type); break; } return ret; } static const struct got_error * connect_repo_child(struct gotd_client *client, struct gotd_child_proc *repo_proc) { static const struct got_error *err; struct gotd_imsgev *session_iev = &client->session->iev; struct gotd_imsg_connect_repo_child ireq; int pipe[2]; int sock_flags = SOCK_STREAM | SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif if (client->state != GOTD_CLIENT_STATE_ACCESS_GRANTED) return got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected repo child ready signal received"); if (socketpair(AF_UNIX, sock_flags, PF_UNSPEC, pipe) == -1) fatal("socketpair"); memset(&ireq, 0, sizeof(ireq)); ireq.proc_id = repo_proc->type; /* Pass repo child pipe to session child process. */ if (gotd_imsg_compose_event(session_iev, GOTD_IMSG_CONNECT_REPO_CHILD, PROC_GOTD, pipe[0], &ireq, sizeof(ireq)) == -1) { err = got_error_from_errno("imsg compose CONNECT_REPO_CHILD"); close(pipe[0]); close(pipe[1]); return err; } /* Pass session child pipe to repo child process. */ if (gotd_imsg_compose_event(&repo_proc->iev, GOTD_IMSG_CONNECT_REPO_CHILD, PROC_GOTD, pipe[1], NULL, 0) == -1) { err = got_error_from_errno("imsg compose CONNECT_REPO_CHILD"); close(pipe[1]); return err; } return NULL; } static void gotd_dispatch_listener(int fd, short event, void *arg) { struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_child_proc *proc = gotd.listen_proc; ssize_t n; int shut = 0; struct imsg imsg; if (proc->iev.ibuf.fd != fd) fatalx("%s: unexpected fd %d", __func__, fd); if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno != EAGAIN) fatal("msgbuf_write"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } for (;;) { const struct got_error *err = NULL; struct gotd_client *client = NULL; uint32_t client_id = 0; int do_disconnect = 0; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: do_disconnect = 1; err = gotd_imsg_recv_error(&client_id, &imsg); break; case GOTD_IMSG_CONNECT: err = recv_connect(&client_id, &imsg); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } client = find_client(client_id); if (client == NULL) { log_warnx("%s: client not found", __func__); imsg_free(&imsg); continue; } if (err) log_warnx("uid %d: %s", client->euid, err->msg); if (do_disconnect) { if (err) disconnect_on_error(client, err); else disconnect(client); } imsg_free(&imsg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } static void gotd_dispatch_notifier(int fd, short event, void *arg) { struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_child_proc *proc = gotd.notify_proc; ssize_t n; int shut = 0; struct imsg imsg; if (proc->iev.ibuf.fd != fd) fatalx("%s: unexpected fd %d", __func__, fd); if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno != EAGAIN) fatal("msgbuf_write"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); /* * Do not exit all of gotd if the notification handler dies. * We can continue operating without notifications until an * operator intervenes. */ log_warnx("notify child process (pid %d) closed its imsg pipe " "unexpectedly", proc->pid); proc_done(proc); } } static void gotd_dispatch_auth_child(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_client *client; struct gotd_repo *repo = NULL; ssize_t n; int shut = 0; struct imsg imsg; uint32_t client_id = 0; int do_disconnect = 0; size_t datalen; client = find_client_by_proc_fd(fd); if (client == NULL) { /* Can happen during process teardown. */ warnx("cannot find client for fd %d", fd); shut = 1; goto done; } if (client->auth == NULL) fatalx("cannot find auth child process for fd %d", fd); if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno != EAGAIN) fatal("msgbuf_write"); if (n == 0) { /* Connection closed. */ shut = 1; } goto done; } if (client->auth->iev.ibuf.fd != fd) fatalx("%s: unexpected fd %d", __func__, fd); if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ return; evtimer_del(&client->tmo); datalen = imsg.hdr.len - IMSG_HEADER_SIZE; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: do_disconnect = 1; err = gotd_imsg_recv_error(&client_id, &imsg); break; case GOTD_IMSG_ACCESS_GRANTED: if (client->state != GOTD_CLIENT_STATE_NEW) { do_disconnect = 1; err = got_error(GOT_ERR_PRIVSEP_MSG); } break; default: do_disconnect = 1; log_debug("unexpected imsg %d", imsg.hdr.type); break; } if (!verify_imsg_src(client, client->auth, &imsg)) { do_disconnect = 1; log_debug("dropping imsg type %d from PID %d", imsg.hdr.type, client->auth->pid); } if (do_disconnect) { if (err) disconnect_on_error(client, err); else disconnect(client); imsg_free(&imsg); return; } client->state = GOTD_CLIENT_STATE_ACCESS_GRANTED; if (datalen > 0) client->username = strndup(imsg.data, datalen); imsg_free(&imsg); if (client->username == NULL && asprintf(&client->username, "uid %d", client->euid) == -1) { err = got_error_from_errno("asprintf"); goto done; } repo = gotd_find_repo_by_name(client->auth->repo_name, &gotd.repos); if (repo == NULL) { err = got_error(GOT_ERR_NOT_GIT_REPO); goto done; } kill_auth_proc(client); log_info("authenticated %s for repository %s", client->username, repo->name); err = start_session_child(client, repo, gotd.argv0, gotd.confpath, gotd.daemonize, gotd.verbosity); if (err) goto done; done: if (err) log_warnx("uid %d: %s", client->euid, err->msg); /* We might have killed the auth process by now. */ if (client->auth != NULL) { if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); } } } static const struct got_error * connect_session(struct gotd_client *client) { const struct got_error *err = NULL; struct gotd_imsg_connect iconnect; int s; struct ibuf *wbuf; memset(&iconnect, 0, sizeof(iconnect)); s = dup(client->fd); if (s == -1) return got_error_from_errno("dup"); iconnect.client_id = client->id; iconnect.euid = client->euid; iconnect.egid = client->egid; iconnect.username_len = strlen(client->username); wbuf = imsg_create(&client->session->iev.ibuf, GOTD_IMSG_CONNECT, PROC_GOTD, gotd.pid, sizeof(iconnect) + iconnect.username_len); if (wbuf == NULL) { err = got_error_from_errno("imsg compose CONNECT"); close(s); return err; } if (imsg_add(wbuf, &iconnect, sizeof(iconnect)) == -1) { close(s); return got_error_from_errno("imsg_add CONNECT"); } if (imsg_add(wbuf, client->username, iconnect.username_len) == -1) { close(s); return got_error_from_errno("imsg_add CONNECT"); } ibuf_fd_set(wbuf, s); imsg_close(&client->session->iev.ibuf, wbuf); gotd_imsg_event_add(&client->session->iev); /* * We are no longer interested in messages from this client. * Further client requests will be handled by the session process. */ msgbuf_clear(&client->iev.ibuf.w); imsg_clear(&client->iev.ibuf); event_del(&client->iev.ev); client->fd = -1; /* will be closed via copy in client->iev.ibuf.fd */ return NULL; } static void gotd_dispatch_client_session(int fd, short event, void *arg) { struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_child_proc *proc = NULL; struct gotd_client *client = NULL; ssize_t n; int shut = 0; struct imsg imsg; client = find_client_by_proc_fd(fd); if (client == NULL) { /* Can happen during process teardown. */ warnx("cannot find client for fd %d", fd); shut = 1; goto done; } if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno != EAGAIN) fatal("msgbuf_write"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } proc = client->session; if (proc == NULL) fatalx("cannot find session child process for fd %d", fd); for (;;) { const struct got_error *err = NULL; uint32_t client_id = 0; int do_disconnect = 0, do_start_repo_child = 0; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: do_disconnect = 1; err = gotd_imsg_recv_error(&client_id, &imsg); break; case GOTD_IMSG_CLIENT_SESSION_READY: if (client->state != GOTD_CLIENT_STATE_ACCESS_GRANTED) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } do_start_repo_child = 1; break; case GOTD_IMSG_DISCONNECT: do_disconnect = 1; break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } if (!verify_imsg_src(client, proc, &imsg)) { log_debug("dropping imsg type %d from PID %d", imsg.hdr.type, proc->pid); imsg_free(&imsg); continue; } if (err) log_warnx("uid %d: %s", client->euid, err->msg); if (do_start_repo_child) { struct gotd_repo *repo; const char *name = client->session->repo_name; repo = gotd_find_repo_by_name(name, &gotd.repos); if (repo != NULL) { enum gotd_procid proc_type; if (client->required_auth & GOTD_AUTH_WRITE) proc_type = PROC_REPO_WRITE; else proc_type = PROC_REPO_READ; err = start_repo_child(client, proc_type, repo, gotd.argv0, gotd.confpath, gotd.daemonize, gotd.verbosity); } else err = got_error(GOT_ERR_NOT_GIT_REPO); if (err) { log_warnx("uid %d: %s", client->euid, err->msg); do_disconnect = 1; } } if (do_disconnect) { if (err) disconnect_on_error(client, err); else disconnect(client); } imsg_free(&imsg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); disconnect(client); } } static const struct got_error * connect_notifier_and_session(struct gotd_client *client) { const struct got_error *err = NULL; struct gotd_imsgev *session_iev = &client->session->iev; int pipe[2]; int sock_flags = SOCK_STREAM|SOCK_NONBLOCK; if (gotd.notify_proc == NULL) return NULL; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif if (socketpair(AF_UNIX, sock_flags, PF_UNSPEC, pipe) == -1) return got_error_from_errno("socketpair"); /* Pass notifier pipe to session . */ if (gotd_imsg_compose_event(session_iev, GOTD_IMSG_CONNECT_NOTIFIER, PROC_GOTD, pipe[0], NULL, 0) == -1) { err = got_error_from_errno("imsg compose CONNECT_NOTIFIER"); close(pipe[0]); close(pipe[1]); return err; } /* Pass session pipe to notifier. */ if (gotd_imsg_compose_event(&gotd.notify_proc->iev, GOTD_IMSG_CONNECT_SESSION, PROC_GOTD, pipe[1], NULL, 0) == -1) { err = got_error_from_errno("imsg compose CONNECT_SESSION"); close(pipe[1]); return err; } return NULL; } static void gotd_dispatch_repo_child(int fd, short event, void *arg) { struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_child_proc *proc = NULL; struct gotd_client *client; ssize_t n; int shut = 0; struct imsg imsg; client = find_client_by_proc_fd(fd); if (client == NULL) { /* Can happen during process teardown. */ warnx("cannot find client for fd %d", fd); shut = 1; goto done; } if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno != EAGAIN) fatal("msgbuf_write"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } proc = client->repo; if (proc == NULL) fatalx("cannot find child process for fd %d", fd); for (;;) { const struct got_error *err = NULL; uint32_t client_id = 0; int do_disconnect = 0; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: do_disconnect = 1; err = gotd_imsg_recv_error(&client_id, &imsg); break; case GOTD_IMSG_REPO_CHILD_READY: err = connect_session(client); if (err) break; err = connect_notifier_and_session(client); if (err) break; err = connect_repo_child(client, proc); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } if (!verify_imsg_src(client, proc, &imsg)) { log_debug("dropping imsg type %d from PID %d", imsg.hdr.type, proc->pid); imsg_free(&imsg); continue; } if (err) log_warnx("uid %d: %s", client->euid, err->msg); if (do_disconnect) { if (err) disconnect_on_error(client, err); else disconnect(client); } imsg_free(&imsg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); disconnect(client); } } static pid_t start_child(enum gotd_procid proc_id, const char *repo_path, char *argv0, const char *confpath, int fd, int daemonize, int verbosity) { char *argv[11]; int argc = 0; pid_t pid; switch (pid = fork()) { case -1: fatal("cannot fork"); case 0: break; default: close(fd); return pid; } if (fd != GOTD_FILENO_MSG_PIPE) { if (dup2(fd, GOTD_FILENO_MSG_PIPE) == -1) fatal("cannot setup imsg fd"); } else if (fcntl(fd, F_SETFD, 0) == -1) fatal("cannot setup imsg fd"); argv[argc++] = argv0; switch (proc_id) { case PROC_LISTEN: argv[argc++] = (char *)"-L"; break; case PROC_AUTH: argv[argc++] = (char *)"-A"; break; case PROC_SESSION_READ: argv[argc++] = (char *)"-s"; break; case PROC_SESSION_WRITE: argv[argc++] = (char *)"-S"; break; case PROC_REPO_READ: argv[argc++] = (char *)"-R"; break; case PROC_REPO_WRITE: argv[argc++] = (char *)"-W"; break; case PROC_NOTIFY: argv[argc++] = (char *)"-N"; break; default: fatalx("invalid process id %d", proc_id); } argv[argc++] = (char *)"-f"; argv[argc++] = (char *)confpath; if (repo_path) { argv[argc++] = (char *)"-P"; argv[argc++] = (char *)repo_path; } if (!daemonize) argv[argc++] = (char *)"-d"; if (verbosity > 0) argv[argc++] = (char *)"-v"; if (verbosity > 1) argv[argc++] = (char *)"-v"; argv[argc++] = NULL; execvp(argv0, argv); fatal("execvp"); } static void start_listener(char *argv0, const char *confpath, int daemonize, int verbosity) { struct gotd_child_proc *proc; int sock_flags = SOCK_STREAM|SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif proc = calloc(1, sizeof(*proc)); if (proc == NULL) fatal("calloc"); TAILQ_INSERT_HEAD(&procs, proc, entry); /* proc->tmo is initialized in main() after event_init() */ proc->type = PROC_LISTEN; if (socketpair(AF_UNIX, sock_flags, PF_UNSPEC, proc->pipe) == -1) fatal("socketpair"); proc->pid = start_child(proc->type, NULL, argv0, confpath, proc->pipe[1], daemonize, verbosity); imsg_init(&proc->iev.ibuf, proc->pipe[0]); proc->iev.handler = gotd_dispatch_listener; proc->iev.events = EV_READ; proc->iev.handler_arg = NULL; gotd.listen_proc = proc; } static void start_notifier(char *argv0, const char *confpath, int daemonize, int verbosity) { struct gotd_child_proc *proc; int sock_flags = SOCK_STREAM | SOCK_NONBLOCK; proc = calloc(1, sizeof(*proc)); if (proc == NULL) fatal("calloc"); TAILQ_INSERT_HEAD(&procs, proc, entry); /* proc->tmo is initialized in main() after event_init() */ proc->type = PROC_NOTIFY; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif if (socketpair(AF_UNIX, sock_flags, PF_UNSPEC, proc->pipe) == -1) fatal("socketpair"); proc->pid = start_child(proc->type, NULL, argv0, confpath, proc->pipe[1], daemonize, verbosity); imsg_init(&proc->iev.ibuf, proc->pipe[0]); proc->iev.handler = gotd_dispatch_notifier; proc->iev.events = EV_READ; proc->iev.handler_arg = NULL; event_set(&proc->iev.ev, proc->iev.ibuf.fd, EV_READ, gotd_dispatch_notifier, &proc->iev); gotd.notify_proc = proc; } static const struct got_error * start_session_child(struct gotd_client *client, struct gotd_repo *repo, char *argv0, const char *confpath, int daemonize, int verbosity) { struct gotd_child_proc *proc; int sock_flags = SOCK_STREAM | SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif proc = calloc(1, sizeof(*proc)); if (proc == NULL) return got_error_from_errno("calloc"); TAILQ_INSERT_HEAD(&procs, proc, entry); evtimer_set(&proc->tmo, kill_proc_timeout, proc); if (client_is_reading(client)) proc->type = PROC_SESSION_READ; else proc->type = PROC_SESSION_WRITE; if (strlcpy(proc->repo_name, repo->name, sizeof(proc->repo_name)) >= sizeof(proc->repo_name)) fatalx("repository name too long: %s", repo->name); log_debug("starting client uid %d session for repository %s", client->euid, repo->name); if (strlcpy(proc->repo_path, repo->path, sizeof(proc->repo_path)) >= sizeof(proc->repo_path)) fatalx("repository path too long: %s", repo->path); if (socketpair(AF_UNIX, sock_flags, PF_UNSPEC, proc->pipe) == -1) fatal("socketpair"); proc->pid = start_child(proc->type, proc->repo_path, argv0, confpath, proc->pipe[1], daemonize, verbosity); imsg_init(&proc->iev.ibuf, proc->pipe[0]); log_debug("proc %s %s is on fd %d", gotd_proc_names[proc->type], proc->repo_path, proc->pipe[0]); proc->iev.handler = gotd_dispatch_client_session; proc->iev.events = EV_READ; proc->iev.handler_arg = NULL; event_set(&proc->iev.ev, proc->iev.ibuf.fd, EV_READ, gotd_dispatch_client_session, &proc->iev); gotd_imsg_event_add(&proc->iev); client->session = proc; return NULL; } static const struct got_error * start_repo_child(struct gotd_client *client, enum gotd_procid proc_type, struct gotd_repo *repo, char *argv0, const char *confpath, int daemonize, int verbosity) { struct gotd_child_proc *proc; int sock_flags = SOCK_STREAM|SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif if (proc_type != PROC_REPO_READ && proc_type != PROC_REPO_WRITE) return got_error_msg(GOT_ERR_NOT_IMPL, "bad process type"); proc = calloc(1, sizeof(*proc)); if (proc == NULL) return got_error_from_errno("calloc"); TAILQ_INSERT_HEAD(&procs, proc, entry); evtimer_set(&proc->tmo, kill_proc_timeout, proc); proc->type = proc_type; if (strlcpy(proc->repo_name, repo->name, sizeof(proc->repo_name)) >= sizeof(proc->repo_name)) fatalx("repository name too long: %s", repo->name); log_debug("starting %s for repository %s", proc->type == PROC_REPO_READ ? "reader" : "writer", repo->name); if (strlcpy(proc->repo_path, repo->path, sizeof(proc->repo_path)) >= sizeof(proc->repo_path)) fatalx("repository path too long: %s", repo->path); if (realpath(repo->path, proc->repo_path) == NULL) fatal("%s", repo->path); if (socketpair(AF_UNIX, sock_flags, PF_UNSPEC, proc->pipe) == -1) fatal("socketpair"); proc->pid = start_child(proc->type, proc->repo_path, argv0, confpath, proc->pipe[1], daemonize, verbosity); imsg_init(&proc->iev.ibuf, proc->pipe[0]); log_debug("proc %s %s is on fd %d", gotd_proc_names[proc->type], proc->repo_path, proc->pipe[0]); proc->iev.handler = gotd_dispatch_repo_child; proc->iev.events = EV_READ; proc->iev.handler_arg = NULL; event_set(&proc->iev.ev, proc->iev.ibuf.fd, EV_READ, gotd_dispatch_repo_child, &proc->iev); gotd_imsg_event_add(&proc->iev); client->repo = proc; return NULL; } static const struct got_error * start_auth_child(struct gotd_client *client, int required_auth, struct gotd_repo *repo, char *argv0, const char *confpath, int daemonize, int verbosity) { const struct got_error *err = NULL; struct gotd_child_proc *proc; struct gotd_imsg_auth iauth; int fd; int sock_flags = SOCK_STREAM|SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif memset(&iauth, 0, sizeof(iauth)); fd = dup(client->fd); if (fd == -1) return got_error_from_errno("dup"); proc = calloc(1, sizeof(*proc)); if (proc == NULL) { err = got_error_from_errno("calloc"); close(fd); return err; } TAILQ_INSERT_HEAD(&procs, proc, entry); evtimer_set(&proc->tmo, kill_proc_timeout, proc); proc->type = PROC_AUTH; if (strlcpy(proc->repo_name, repo->name, sizeof(proc->repo_name)) >= sizeof(proc->repo_name)) fatalx("repository name too long: %s", repo->name); log_debug("starting auth for uid %d repository %s", client->euid, repo->name); if (strlcpy(proc->repo_path, repo->path, sizeof(proc->repo_path)) >= sizeof(proc->repo_path)) fatalx("repository path too long: %s", repo->path); if (realpath(repo->path, proc->repo_path) == NULL) fatal("%s", repo->path); if (socketpair(AF_UNIX, sock_flags, PF_UNSPEC, proc->pipe) == -1) fatal("socketpair"); proc->pid = start_child(proc->type, proc->repo_path, argv0, confpath, proc->pipe[1], daemonize, verbosity); imsg_init(&proc->iev.ibuf, proc->pipe[0]); log_debug("proc %s %s is on fd %d", gotd_proc_names[proc->type], proc->repo_path, proc->pipe[0]); proc->iev.handler = gotd_dispatch_auth_child; proc->iev.events = EV_READ; proc->iev.handler_arg = NULL; event_set(&proc->iev.ev, proc->iev.ibuf.fd, EV_READ, gotd_dispatch_auth_child, &proc->iev); gotd_imsg_event_add(&proc->iev); iauth.euid = client->euid; iauth.egid = client->egid; iauth.required_auth = required_auth; iauth.client_id = client->id; if (gotd_imsg_compose_event(&proc->iev, GOTD_IMSG_AUTHENTICATE, PROC_GOTD, fd, &iauth, sizeof(iauth)) == -1) { log_warn("imsg compose AUTHENTICATE"); close(fd); /* Let the auth_timeout handler tidy up. */ } client->auth = proc; client->required_auth = required_auth; return NULL; } static void apply_unveil_repo_readonly(const char *repo_path, int need_tmpdir) { if (need_tmpdir) { if (unveil(GOT_TMPDIR_STR, "rwc") == -1) fatal("unveil %s", GOT_TMPDIR_STR); } if (unveil(repo_path, "r") == -1) fatal("unveil %s", repo_path); if (unveil(NULL, NULL) == -1) fatal("unveil"); } static void apply_unveil_repo_readwrite(const char *repo_path) { if (unveil(repo_path, "rwc") == -1) fatal("unveil %s", repo_path); if (unveil(GOT_TMPDIR_STR, "rwc") == -1) fatal("unveil %s", GOT_TMPDIR_STR); if (unveil(NULL, NULL) == -1) fatal("unveil"); } static void apply_unveil_none(void) { if (unveil("/", "") == -1) fatal("unveil"); if (unveil(NULL, NULL) == -1) fatal("unveil"); } static void apply_unveil_selfexec(void) { if (unveil(gotd.argv0, "x") == -1) fatal("unveil %s", gotd.argv0); if (unveil(NULL, NULL) == -1) fatal("unveil"); } static void set_max_datasize(void) { struct rlimit rl; if (getrlimit(RLIMIT_DATA, &rl) != 0) return; rl.rlim_cur = rl.rlim_max; setrlimit(RLIMIT_DATA, &rl); } static void unveil_notification_helpers(void) { const char *helpers[] = { GOTD_PATH_PROG_NOTIFY_EMAIL, GOTD_PATH_PROG_NOTIFY_HTTP, }; size_t i; for (i = 0; i < nitems(helpers); i++) { if (unveil(helpers[i], "x") == 0) continue; fatal("unveil %s", helpers[i]); } if (unveil(NULL, NULL) == -1) fatal("unveil"); } int main(int argc, char **argv) { const struct got_error *error = NULL; int ch, fd = -1, daemonize = 1, verbosity = 0, noaction = 0; const char *confpath = GOTD_CONF_PATH; char *argv0 = argv[0]; char title[2048]; struct passwd *pw = NULL; char *repo_path = NULL; enum gotd_procid proc_id = PROC_GOTD; struct event evsigint, evsigterm, evsighup, evsigusr1, evsigchld; int *pack_fds = NULL, *temp_fds = NULL; struct gotd_repo *repo = NULL; char *default_sender = NULL; char hostname[_POSIX_HOST_NAME_MAX + 1]; FILE *diff_f1 = NULL, *diff_f2 = NULL; int diff_fd1 = -1, diff_fd2 = -1; TAILQ_INIT(&procs); log_init(1, LOG_DAEMON); /* Log to stderr until daemonized. */ while ((ch = getopt(argc, argv, "Adf:LnNP:RsSvW")) != -1) { switch (ch) { case 'A': proc_id = PROC_AUTH; break; case 'd': daemonize = 0; break; case 'f': confpath = optarg; break; case 'L': proc_id = PROC_LISTEN; break; case 'n': noaction = 1; break; case 'N': proc_id = PROC_NOTIFY; break; case 'P': repo_path = realpath(optarg, NULL); if (repo_path == NULL) fatal("realpath '%s'", optarg); break; case 'R': proc_id = PROC_REPO_READ; break; case 's': proc_id = PROC_SESSION_READ; break; case 'S': proc_id = PROC_SESSION_WRITE; break; case 'v': if (verbosity < 3) verbosity++; break; case 'W': proc_id = PROC_REPO_WRITE; break; default: usage(); } } argc -= optind; argv += optind; if (argc != 0) usage(); if (geteuid() && (proc_id == PROC_GOTD || proc_id == PROC_LISTEN)) fatalx("need root privileges"); if (parse_config(confpath, proc_id, &gotd) != 0) return 1; pw = getpwnam(gotd.user_name); if (pw == NULL) fatalx("user %s not found", gotd.user_name); if (pw->pw_uid == 0) fatalx("cannot run %s as the superuser", getprogname()); if (noaction) { fprintf(stderr, "configuration OK\n"); return 0; } gotd.argv0 = argv0; gotd.daemonize = daemonize; gotd.verbosity = verbosity; gotd.confpath = confpath; /* Require an absolute path in argv[0] for reliable re-exec. */ if (!got_path_is_absolute(argv0)) fatalx("bad path \"%s\": must be an absolute path", argv0); log_init(daemonize ? 0 : 1, LOG_DAEMON); log_setverbose(verbosity); if (proc_id == PROC_GOTD) { snprintf(title, sizeof(title), "%s", gotd_proc_names[proc_id]); arc4random_buf(&clients_hash_key, sizeof(clients_hash_key)); if (daemonize && daemon(1, 0) == -1) fatal("daemon"); gotd.pid = getpid(); start_listener(argv0, confpath, daemonize, verbosity); start_notifier(argv0, confpath, daemonize, verbosity); } else if (proc_id == PROC_LISTEN) { snprintf(title, sizeof(title), "%s", gotd_proc_names[proc_id]); if (verbosity) { log_info("socket: %s", gotd.unix_socket_path); log_info("user: %s", pw->pw_name); } fd = unix_socket_listen(gotd.unix_socket_path, pw->pw_uid, pw->pw_gid); if (fd == -1) { fatal("cannot listen on unix socket %s", gotd.unix_socket_path); } } else if (proc_id == PROC_AUTH) { snprintf(title, sizeof(title), "%s %s", gotd_proc_names[proc_id], repo_path); } else if (proc_id == PROC_REPO_READ || proc_id == PROC_REPO_WRITE || proc_id == PROC_SESSION_READ || proc_id == PROC_SESSION_WRITE) { error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) fatalx("cannot open pack tempfiles: %s", error->msg); error = got_repo_temp_fds_open(&temp_fds); if (error != NULL) fatalx("cannot open pack tempfiles: %s", error->msg); if (repo_path == NULL) fatalx("repository path not specified"); snprintf(title, sizeof(title), "%s %s", gotd_proc_names[proc_id], repo_path); } else if (proc_id == PROC_NOTIFY) { snprintf(title, sizeof(title), "%s", gotd_proc_names[proc_id]); if (gethostname(hostname, sizeof(hostname)) == -1) fatal("gethostname"); if (asprintf(&default_sender, "%s@%s", pw->pw_name, hostname) == -1) fatal("asprintf"); } else fatal("invalid process id %d", proc_id); setproctitle("%s", title); log_procinit(title); if (proc_id != PROC_GOTD && proc_id != PROC_LISTEN && proc_id != PROC_REPO_READ && proc_id != PROC_REPO_WRITE) { /* Drop root privileges. */ if (setgid(pw->pw_gid) == -1) fatal("setgid %d failed", pw->pw_gid); if (setuid(pw->pw_uid) == -1) fatal("setuid %d failed", pw->pw_uid); } event_init(); switch (proc_id) { case PROC_GOTD: #ifndef PROFILE /* "exec" promise will be limited to argv[0] via unveil(2). */ if (pledge("stdio proc exec sendfd recvfd unveil", NULL) == -1) err(1, "pledge"); #endif break; case PROC_LISTEN: #ifndef PROFILE if (pledge("stdio sendfd unix unveil", NULL) == -1) err(1, "pledge"); #endif /* * Ensure that AF_UNIX bind(2) cannot be used with any other * sockets by revoking all filesystem access via unveil(2). */ apply_unveil_none(); enter_chroot(GOTD_EMPTY_PATH); drop_privs(pw); listen_main(title, fd, gotd.connection_limits, gotd.nconnection_limits); /* NOTREACHED */ break; case PROC_AUTH: #ifndef PROFILE if (pledge("stdio getpw recvfd unix unveil", NULL) == -1) err(1, "pledge"); #endif /* * We need the "unix" pledge promise for getpeername(2) only. * Ensure that AF_UNIX bind(2) cannot be used by revoking all * filesystem access via unveil(2). Access to password database * files will still work since "getpw" bypasses unveil(2). */ apply_unveil_none(); drop_privs(pw); auth_main(title, &gotd.repos, repo_path); /* NOTREACHED */ break; case PROC_SESSION_READ: case PROC_SESSION_WRITE: #ifndef PROFILE /* * The "recvfd" promise is only needed during setup and * will be removed in a later pledge(2) call. */ if (pledge("stdio rpath wpath cpath recvfd sendfd fattr flock " "unveil", NULL) == -1) err(1, "pledge"); #endif if (proc_id == PROC_SESSION_READ) apply_unveil_repo_readonly(repo_path, 1); else { apply_unveil_repo_readwrite(repo_path); repo = gotd_find_repo_by_path(repo_path, &gotd); if (repo == NULL) fatalx("no repository for path %s", repo_path); } drop_privs(pw); if (proc_id == PROC_SESSION_READ) session_read_main(title, repo_path, pack_fds, temp_fds, &gotd.request_timeout, repo); else session_write_main(title, repo_path, pack_fds, temp_fds, &gotd.request_timeout, repo); /* NOTREACHED */ break; case PROC_REPO_READ: set_max_datasize(); #ifndef PROFILE if (pledge("stdio rpath recvfd unveil", NULL) == -1) err(1, "pledge"); #endif apply_unveil_repo_readonly(repo_path, 0); if (enter_chroot(repo_path)) { log_info("change repo path %s", repo_path); free(repo_path); repo_path = strdup("/"); if (repo_path == NULL) fatal("strdup"); log_info("repo path is now %s", repo_path); } drop_privs(pw); repo_read_main(title, repo_path, pack_fds, temp_fds); /* NOTREACHED */ exit(0); case PROC_REPO_WRITE: set_max_datasize(); diff_f1 = got_opentemp(); if (diff_f1 == NULL) fatal("got_opentemp"); diff_f2 = got_opentemp(); if (diff_f2 == NULL) fatal("got_opentemp"); diff_fd1 = got_opentempfd(); if (diff_fd1 == -1) fatal("got_opentempfd"); diff_fd2 = got_opentempfd(); if (diff_fd2 == -1) fatal("got_opentempfd"); #ifndef PROFILE if (pledge("stdio rpath recvfd unveil", NULL) == -1) err(1, "pledge"); #endif apply_unveil_repo_readonly(repo_path, 0); repo = gotd_find_repo_by_path(repo_path, &gotd); if (repo == NULL) fatalx("no repository for path %s", repo_path); if (enter_chroot(repo_path)) { free(repo_path); repo_path = strdup("/"); if (repo_path == NULL) fatal("strdup"); } drop_privs(pw); repo_write_main(title, repo_path, pack_fds, temp_fds, diff_f1, diff_f2, diff_fd1, diff_fd2, &repo->protected_tag_namespaces, &repo->protected_branch_namespaces, &repo->protected_branches); /* NOTREACHED */ exit(0); case PROC_NOTIFY: #ifndef PROFILE if (pledge("stdio proc exec recvfd unveil", NULL) == -1) err(1, "pledge"); #endif /* * Limit "exec" promise to notification helpers via unveil(2). */ unveil_notification_helpers(); drop_privs(pw); notify_main(title, &gotd.repos, default_sender); /* NOTREACHED */ exit(0); default: fatal("invalid process id %d", proc_id); } if (proc_id != PROC_GOTD) fatal("invalid process id %d", proc_id); evtimer_set(&gotd.listen_proc->tmo, kill_proc_timeout, gotd.listen_proc); if (gotd.notify_proc) { evtimer_set(&gotd.notify_proc->tmo, kill_proc_timeout, gotd.notify_proc); } apply_unveil_selfexec(); signal_set(&evsigint, SIGINT, gotd_sighdlr, NULL); signal_set(&evsigterm, SIGTERM, gotd_sighdlr, NULL); signal_set(&evsighup, SIGHUP, gotd_sighdlr, NULL); signal_set(&evsigusr1, SIGUSR1, gotd_sighdlr, NULL); signal_set(&evsigchld, SIGCHLD, gotd_sighdlr, NULL); signal(SIGPIPE, SIG_IGN); signal_add(&evsigint, NULL); signal_add(&evsigterm, NULL); signal_add(&evsighup, NULL); signal_add(&evsigusr1, NULL); signal_add(&evsigchld, NULL); gotd_imsg_event_add(&gotd.listen_proc->iev); if (gotd.notify_proc) gotd_imsg_event_add(&gotd.notify_proc->iev); event_dispatch(); free(repo_path); free(default_sender); gotd_shutdown(); return 0; } got-portable-0.101/gotd/listen.c0000664000175100017510000002647314644144735012226 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_compat.h" #include "gotd.h" #include "log.h" #include "listen.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif struct gotd_listen_client { STAILQ_ENTRY(gotd_listen_client) entry; uint32_t id; int fd; uid_t euid; }; STAILQ_HEAD(gotd_listen_clients, gotd_listen_client); static struct gotd_listen_clients gotd_listen_clients[GOTD_CLIENT_TABLE_SIZE]; static SIPHASH_KEY clients_hash_key; static volatile int listen_client_cnt; static int inflight; struct gotd_uid_connection_counter { STAILQ_ENTRY(gotd_uid_connection_counter) entry; uid_t euid; int nconnections; }; STAILQ_HEAD(gotd_client_uids, gotd_uid_connection_counter); static struct gotd_client_uids gotd_client_uids[GOTD_CLIENT_TABLE_SIZE]; static SIPHASH_KEY uid_hash_key; static struct { pid_t pid; const char *title; int fd; struct gotd_imsgev iev; struct gotd_imsgev pause; struct gotd_uid_connection_limit *connection_limits; size_t nconnection_limits; } gotd_listen; static int inflight; static void listen_shutdown(void); static void listen_sighdlr(int sig, short event, void *arg) { /* * Normal signal handler rules don't apply because libevent * decouples for us. */ switch (sig) { case SIGHUP: break; case SIGUSR1: break; case SIGTERM: case SIGINT: listen_shutdown(); /* NOTREACHED */ break; default: fatalx("unexpected signal"); } } static uint64_t client_hash(uint32_t client_id) { return SipHash24(&clients_hash_key, &client_id, sizeof(client_id)); } static void add_client(struct gotd_listen_client *client) { uint64_t slot = client_hash(client->id) % nitems(gotd_listen_clients); STAILQ_INSERT_HEAD(&gotd_listen_clients[slot], client, entry); listen_client_cnt++; } static struct gotd_listen_client * find_client(uint32_t client_id) { uint64_t slot; struct gotd_listen_client *c; slot = client_hash(client_id) % nitems(gotd_listen_clients); STAILQ_FOREACH(c, &gotd_listen_clients[slot], entry) { if (c->id == client_id) return c; } return NULL; } static uint32_t get_client_id(void) { int duplicate = 0; uint32_t id; do { id = arc4random(); duplicate = (find_client(id) != NULL); } while (duplicate || id == 0); return id; } static uint64_t uid_hash(uid_t euid) { return SipHash24(&uid_hash_key, &euid, sizeof(euid)); } static void add_uid_connection_counter(struct gotd_uid_connection_counter *counter) { uint64_t slot = uid_hash(counter->euid) % nitems(gotd_client_uids); STAILQ_INSERT_HEAD(&gotd_client_uids[slot], counter, entry); } static void remove_uid_connection_counter(struct gotd_uid_connection_counter *counter) { uint64_t slot = uid_hash(counter->euid) % nitems(gotd_client_uids); STAILQ_REMOVE(&gotd_client_uids[slot], counter, gotd_uid_connection_counter, entry); } static struct gotd_uid_connection_counter * find_uid_connection_counter(uid_t euid) { uint64_t slot; struct gotd_uid_connection_counter *c; slot = uid_hash(euid) % nitems(gotd_client_uids); STAILQ_FOREACH(c, &gotd_client_uids[slot], entry) { if (c->euid == euid) return c; } return NULL; } static const struct got_error * disconnect(struct gotd_listen_client *client) { struct gotd_uid_connection_counter *counter; uint64_t slot; int client_fd; log_debug("client on fd %d disconnecting", client->fd); slot = client_hash(client->id) % nitems(gotd_listen_clients); STAILQ_REMOVE(&gotd_listen_clients[slot], client, gotd_listen_client, entry); counter = find_uid_connection_counter(client->euid); if (counter) { if (counter->nconnections > 0) counter->nconnections--; if (counter->nconnections == 0) { remove_uid_connection_counter(counter); free(counter); } } client_fd = client->fd; free(client); inflight--; listen_client_cnt--; if (close(client_fd) == -1) return got_error_from_errno("close"); return NULL; } static int accept_reserve(int fd, struct sockaddr *addr, socklen_t *addrlen, int reserve, volatile int *counter) { int ret; int sock_flags = SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif if (getdtablecount() + reserve + ((*counter + 1) * GOTD_FD_NEEDED) >= getdtablesize()) { log_debug("inflight fds exceeded"); errno = EMFILE; return -1; } #ifdef __APPLE__ /* TA: silence warning from GCC. */ (void)sock_flags; ret = accept(fd, addr, addrlen); #else ret = accept4(fd, addr, addrlen, sock_flags); #endif if (ret > -1) { (*counter)++; } return ret; } static void gotd_accept_paused(int fd, short event, void *arg) { event_add(&gotd_listen.iev.ev, NULL); } static void gotd_accept(int fd, short event, void *arg) { struct gotd_imsgev *iev = arg; struct sockaddr_storage ss; struct timeval backoff; socklen_t len; int s = -1; struct gotd_listen_client *client = NULL; struct gotd_uid_connection_counter *counter = NULL; struct gotd_imsg_connect iconn; uid_t euid; gid_t egid; backoff.tv_sec = 1; backoff.tv_usec = 0; if (event_add(&gotd_listen.iev.ev, NULL) == -1) { log_warn("event_add"); return; } if (event & EV_TIMEOUT) return; len = sizeof(ss); /* Other backoff conditions apart from EMFILE/ENFILE? */ s = accept_reserve(fd, (struct sockaddr *)&ss, &len, GOTD_FD_RESERVE, &inflight); if (s == -1) { switch (errno) { case EINTR: case EWOULDBLOCK: case ECONNABORTED: return; case EMFILE: case ENFILE: event_del(&gotd_listen.iev.ev); evtimer_add(&gotd_listen.pause.ev, &backoff); return; default: log_warn("accept"); return; } } if (listen_client_cnt >= GOTD_MAXCLIENTS) goto err; if (getpeereid(s, &euid, &egid) == -1) { log_warn("getpeerid"); goto err; } counter = find_uid_connection_counter(euid); if (counter == NULL) { counter = calloc(1, sizeof(*counter)); if (counter == NULL) { log_warn("%s: calloc", __func__); goto err; } counter->euid = euid; counter->nconnections = 1; add_uid_connection_counter(counter); } else { int max_connections = GOTD_MAX_CONN_PER_UID; struct gotd_uid_connection_limit *limit; limit = gotd_find_uid_connection_limit( gotd_listen.connection_limits, gotd_listen.nconnection_limits, euid); if (limit) max_connections = limit->max_connections; if (counter->nconnections >= max_connections) { log_warnx("maximum connections exceeded for uid %d", euid); goto err; } counter->nconnections++; } client = calloc(1, sizeof(*client)); if (client == NULL) { log_warn("%s: calloc", __func__); goto err; } client->id = get_client_id(); client->fd = s; client->euid = euid; s = -1; add_client(client); log_debug("%s: new client connected on fd %d uid %d gid %d", __func__, client->fd, euid, egid); memset(&iconn, 0, sizeof(iconn)); iconn.client_id = client->id; iconn.euid = euid; iconn.egid = egid; s = dup(client->fd); if (s == -1) { log_warn("%s: dup", __func__); goto err; } if (gotd_imsg_compose_event(iev, GOTD_IMSG_CONNECT, PROC_LISTEN, s, &iconn, sizeof(iconn)) == -1) { log_warn("imsg compose CONNECT"); goto err; } return; err: inflight--; if (client) disconnect(client); if (s != -1) close(s); } static const struct got_error * recv_disconnect(struct imsg *imsg) { struct gotd_imsg_disconnect idisconnect; size_t datalen; struct gotd_listen_client *client = NULL; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(idisconnect)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&idisconnect, imsg->data, sizeof(idisconnect)); log_debug("client disconnecting"); client = find_client(idisconnect.client_id); if (client == NULL) return got_error(GOT_ERR_CLIENT_ID); return disconnect(client); } static void listen_dispatch(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; ssize_t n; int shut = 0; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) /* Connection closed. */ shut = 1; } if (event & EV_WRITE) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno != EAGAIN) fatal("msgbuf_write"); if (n == 0) /* Connection closed. */ shut = 1; } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_DISCONNECT: err = recv_disconnect(&imsg); if (err) log_warnx("disconnect: %s", err->msg); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void listen_main(const char *title, int gotd_socket, struct gotd_uid_connection_limit *connection_limits, size_t nconnection_limits) { struct gotd_imsgev iev; struct event evsigint, evsigterm, evsighup, evsigusr1; arc4random_buf(&clients_hash_key, sizeof(clients_hash_key)); arc4random_buf(&uid_hash_key, sizeof(uid_hash_key)); gotd_listen.title = title; gotd_listen.pid = getpid(); gotd_listen.fd = gotd_socket; gotd_listen.connection_limits = connection_limits; gotd_listen.nconnection_limits = nconnection_limits; signal_set(&evsigint, SIGINT, listen_sighdlr, NULL); signal_set(&evsigterm, SIGTERM, listen_sighdlr, NULL); signal_set(&evsighup, SIGHUP, listen_sighdlr, NULL); signal_set(&evsigusr1, SIGUSR1, listen_sighdlr, NULL); signal(SIGPIPE, SIG_IGN); signal_add(&evsigint, NULL); signal_add(&evsigterm, NULL); signal_add(&evsighup, NULL); signal_add(&evsigusr1, NULL); imsg_init(&iev.ibuf, GOTD_FILENO_MSG_PIPE); iev.handler = listen_dispatch; iev.events = EV_READ; iev.handler_arg = NULL; event_set(&iev.ev, iev.ibuf.fd, EV_READ, listen_dispatch, &iev); if (event_add(&iev.ev, NULL) == -1) fatalx("event add"); event_set(&gotd_listen.iev.ev, gotd_listen.fd, EV_READ | EV_PERSIST, gotd_accept, &iev); if (event_add(&gotd_listen.iev.ev, NULL)) fatalx("event add"); evtimer_set(&gotd_listen.pause.ev, gotd_accept_paused, NULL); event_dispatch(); listen_shutdown(); } static void listen_shutdown(void) { log_debug("%s: shutting down", gotd_listen.title); free(gotd_listen.connection_limits); if (gotd_listen.fd != -1) close(gotd_listen.fd); exit(0); } got-portable-0.101/gotd/gotd.h0000664000175100017510000003244614644144735011667 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #define GOTD_UNIX_SOCKET "/var/run/gotd.sock" #define GOTD_UNIX_SOCKET_BACKLOG 10 #define GOTD_USER "_gotd" #define GOTD_CONF_PATH "/etc/gotd.conf" #ifndef GOTD_EMPTY_PATH #define GOTD_EMPTY_PATH "/var/empty" #endif #ifndef GOT_LIBEXECDIR #define GOT_LIBEXECDIR /usr/libexec #endif #define GOTD_STRINGIFY(x) #x #define GOTD_STRINGVAL(x) GOTD_STRINGIFY(x) #define GOTD_PROG_NOTIFY_EMAIL got-notify-email #define GOTD_PROG_NOTIFY_HTTP got-notify-http #define GOTD_PATH_PROG_NOTIFY_EMAIL \ GOTD_STRINGVAL(GOT_LIBEXECDIR) "/" \ GOTD_STRINGVAL(GOTD_PROG_NOTIFY_EMAIL) #define GOTD_PATH_PROG_NOTIFY_HTTP \ GOTD_STRINGVAL(GOT_LIBEXECDIR) "/" \ GOTD_STRINGVAL(GOTD_PROG_NOTIFY_HTTP) #define GOTD_MAXCLIENTS 1024 #define GOTD_MAX_CONN_PER_UID 4 #define GOTD_FD_RESERVE 5 #define GOTD_FD_NEEDED 6 #define GOTD_FILENO_MSG_PIPE 3 #define GOTD_DEFAULT_REQUEST_TIMEOUT 3600 /* Client hash tables need some extra room. */ #define GOTD_CLIENT_TABLE_SIZE (GOTD_MAXCLIENTS * 4) enum gotd_procid { PROC_GOTD = 0, PROC_LISTEN, PROC_AUTH, PROC_SESSION_READ, PROC_SESSION_WRITE, PROC_REPO_READ, PROC_REPO_WRITE, PROC_GITWRAPPER, PROC_NOTIFY, PROC_MAX, }; struct gotd_imsgev { struct imsgbuf ibuf; void (*handler)(int, short, void *); void *handler_arg; struct event ev; short events; }; enum gotd_access { GOTD_ACCESS_DENIED = -1, GOTD_ACCESS_PERMITTED = 1 }; struct gotd_access_rule { STAILQ_ENTRY(gotd_access_rule) entry; enum gotd_access access; int authorization; #define GOTD_AUTH_READ 0x1 #define GOTD_AUTH_WRITE 0x2 char *identifier; }; STAILQ_HEAD(gotd_access_rule_list, gotd_access_rule); enum gotd_notification_target_type { GOTD_NOTIFICATION_VIA_EMAIL, GOTD_NOTIFICATION_VIA_HTTP }; struct gotd_notification_target { STAILQ_ENTRY(gotd_notification_target) entry; enum gotd_notification_target_type type; union { struct { char *sender; char *recipient; char *responder; char *hostname; char *port; } email; struct { int tls; char *hostname; char *port; char *path; char *user; char *password; } http; } conf; }; STAILQ_HEAD(gotd_notification_targets, gotd_notification_target); struct gotd_repo { TAILQ_ENTRY(gotd_repo) entry; char name[NAME_MAX]; char path[PATH_MAX]; struct gotd_access_rule_list rules; struct got_pathlist_head protected_tag_namespaces; struct got_pathlist_head protected_branch_namespaces; struct got_pathlist_head protected_branches; struct got_pathlist_head notification_refs; struct got_pathlist_head notification_ref_namespaces; struct gotd_notification_targets notification_targets; }; TAILQ_HEAD(gotd_repolist, gotd_repo); struct gotd_client_capability { char *key; char *value; }; struct gotd_object_id_array { struct got_object_id **ids; size_t nalloc; size_t nids; }; struct gotd_uid_connection_limit { uid_t uid; int max_connections; }; struct gotd_child_proc; struct gotd { pid_t pid; char unix_socket_path[PATH_MAX]; char user_name[32]; struct gotd_repolist repos; int nrepos; struct gotd_child_proc *listen_proc; struct gotd_child_proc *notify_proc; int notifications_enabled; struct timeval request_timeout; struct timeval auth_timeout; struct gotd_uid_connection_limit *connection_limits; size_t nconnection_limits; char *argv0; const char *confpath; int daemonize; int verbosity; }; enum gotd_imsg_type { /* An error occured while processing a request. */ GOTD_IMSG_ERROR, /* Commands used by gotctl(8). */ GOTD_IMSG_INFO, GOTD_IMSG_INFO_REPO, GOTD_IMSG_INFO_CLIENT, GOTD_IMSG_STOP, /* Request a list of references. */ GOTD_IMSG_LIST_REFS, GOTD_IMSG_LIST_REFS_INTERNAL, /* References. */ GOTD_IMSG_REFLIST, GOTD_IMSG_REF, GOTD_IMSG_SYMREF, /* Git protocol capabilities. */ GOTD_IMSG_CAPABILITIES, GOTD_IMSG_CAPABILITY, /* Git protocol chatter. */ GOTD_IMSG_WANT, /* The client wants an object. */ GOTD_IMSG_HAVE, /* The client has an object. */ GOTD_IMSG_ACK, /* The server has an object or a reference. */ GOTD_IMSG_NAK, /* The server does not have an object/ref. */ GOTD_IMSG_REF_UPDATE, /* The client wants to update a reference. */ GOTD_IMSG_REF_DELETE, /* The client wants to delete a reference. */ GOTD_IMSG_FLUSH, /* The client sent a flush packet. */ GOTD_IMSG_DONE, /* The client is done chatting. */ /* Sending or receiving a pack file. */ GOTD_IMSG_SEND_PACKFILE, /* The server is sending a pack file. */ GOTD_IMSG_RECV_PACKFILE, /* The server is receiving a pack file. */ GOTD_IMSG_PACKIDX_FILE, /* Temporary file handle for new pack index. */ GOTD_IMSG_PACKFILE_PIPE, /* Pipe to send/receive a pack file stream. */ GOTD_IMSG_PACKFILE_PROGRESS, /* Progress reporting. */ GOTD_IMSG_PACKFILE_READY, /* Pack file is ready to be sent. */ GOTD_IMSG_PACKFILE_STATUS, /* Received pack success/failure status. */ GOTD_IMSG_PACKFILE_INSTALL, /* Received pack file can be installed. */ GOTD_IMSG_PACKFILE_DONE, /* Pack file has been sent/received. */ /* Reference updates. */ GOTD_IMSG_REF_UPDATES_START, /* Ref updates starting. */ GOTD_IMSG_REF_UPDATE_OK, /* Update went OK. */ GOTD_IMSG_REF_UPDATE_NG, /* Update was not good. */ GOTD_IMSG_REFS_UPDATED, /* The server proccessed all ref updates. */ /* Client connections. */ GOTD_IMSG_DISCONNECT, GOTD_IMSG_CONNECT, /* Child process management. */ GOTD_IMSG_CLIENT_SESSION_READY, GOTD_IMSG_REPO_CHILD_READY, GOTD_IMSG_CONNECT_REPO_CHILD, /* Auth child process. */ GOTD_IMSG_AUTHENTICATE, GOTD_IMSG_ACCESS_GRANTED, /* Notify child process. */ GOTD_IMSG_CONNECT_NOTIFIER, GOTD_IMSG_CONNECT_SESSION, GOTD_IMSG_NOTIFY, GOTD_IMSG_NOTIFICATION_SENT }; /* Structure for GOTD_IMSG_ERROR. */ struct gotd_imsg_error { int code; /* an error code from got_error.h */ int errno_code; /* in case code equals GOT_ERR_ERRNO */ uint32_t client_id; char msg[GOT_ERR_MAX_MSG_SIZE]; } __attribute__((__packed__)); /* Structure for GOTD_IMSG_INFO. */ struct gotd_imsg_info { pid_t pid; int verbosity; int nrepos; int nclients; /* Followed by nrepos GOTD_IMSG_INFO_REPO messages. */ /* Followed by nclients GOTD_IMSG_INFO_CLIENT messages. */ }; /* Structure for GOTD_IMSG_INFO_REPO. */ struct gotd_imsg_info_repo { char repo_name[NAME_MAX]; char repo_path[PATH_MAX]; }; /* Structure for GOTD_IMSG_INFO_CLIENT */ struct gotd_imsg_info_client { uid_t euid; gid_t egid; char repo_name[NAME_MAX]; int is_writing; pid_t session_child_pid; pid_t repo_child_pid; }; /* Structure for GOTD_IMSG_LIST_REFS. */ struct gotd_imsg_list_refs { char repo_name[NAME_MAX]; int client_is_reading; /* 1 if reading, 0 if writing */ }; /* Structure for GOTD_IMSG_REFLIST. */ struct gotd_imsg_reflist { size_t nrefs; /* Followed by nrefs times of gotd_imsg_ref/gotd_imsg_symref data. */ } __attribute__((__packed__)); /* Structure for GOTD_IMSG_REF data. */ struct gotd_imsg_ref { uint8_t id[SHA1_DIGEST_LENGTH]; size_t name_len; /* Followed by name_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOTD_IMSG_SYMREF data. */ struct gotd_imsg_symref { size_t name_len; size_t target_len; uint8_t target_id[SHA1_DIGEST_LENGTH]; /* * Followed by name_len + target_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOTD_IMSG_CAPABILITIES data. */ struct gotd_imsg_capabilities { size_t ncapabilities; /* * Followed by ncapabilities * GOTD_IMSG_CAPABILITY. */ } __attribute__((__packed__)); /* Structure for GOTD_IMSG_CAPABILITY data. */ struct gotd_imsg_capability { size_t key_len; size_t value_len; /* * Followed by key_len + value_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOTD_IMSG_WANT data. */ struct gotd_imsg_want { uint8_t object_id[SHA1_DIGEST_LENGTH]; } __attribute__((__packed__)); /* Structure for GOTD_IMSG_HAVE data. */ struct gotd_imsg_have { uint8_t object_id[SHA1_DIGEST_LENGTH]; } __attribute__((__packed__)); /* Structure for GOTD_IMSG_ACK data. */ struct gotd_imsg_ack { uint8_t object_id[SHA1_DIGEST_LENGTH]; } __attribute__((__packed__)); /* Structure for GOTD_IMSG_NAK data. */ struct gotd_imsg_nak { uint8_t object_id[SHA1_DIGEST_LENGTH]; } __attribute__((__packed__)); /* Structure for GOTD_IMSG_PACKFILE_STATUS data. */ struct gotd_imsg_packfile_status { size_t reason_len; /* Followed by reason_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOTD_IMSG_REF_UPDATE data. */ struct gotd_imsg_ref_update { uint8_t old_id[SHA1_DIGEST_LENGTH]; uint8_t new_id[SHA1_DIGEST_LENGTH]; int ref_is_new; int delete_ref; size_t name_len; /* Followed by name_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOTD_IMSG_REF_UPDATES_START data. */ struct gotd_imsg_ref_updates_start { int nref_updates; /* Followed by nref_updates GOT_IMSG_REF_UPDATE_OK/NG messages. */ }; /* Structure for GOTD_IMSG_REF_UPDATE_OK data. */ struct gotd_imsg_ref_update_ok { uint8_t old_id[SHA1_DIGEST_LENGTH]; uint8_t new_id[SHA1_DIGEST_LENGTH]; int ref_is_new; size_t name_len; /* Followed by name_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOTD_IMSG_REF_UPDATE_NG data. */ struct gotd_imsg_ref_update_ng { uint8_t old_id[SHA1_DIGEST_LENGTH]; uint8_t new_id[SHA1_DIGEST_LENGTH]; size_t name_len; size_t reason_len; /* Followed by name_len + reason_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOTD_IMSG_SEND_PACKFILE data. */ struct gotd_imsg_send_packfile { int report_progress; /* delta cache file is sent as a file descriptor */ /* followed by two GOTD_IMSG_PACKFILE_PIPE messages */ }; /* Structure for GOTD_IMSG_RECV_PACKFILE data. */ struct gotd_imsg_recv_packfile { int report_status; /* pack destination temp file is sent as a file descriptor */ }; /* * Structure for GOTD_IMSG_PACKFILE_PROGRESS and * GOTD_IMSG_PACKFILE_READY data. */ struct gotd_imsg_packfile_progress { int ncolored; int nfound; int ntrees; off_t packfile_size; int ncommits; int nobj_total; int nobj_deltify; int nobj_written; }; /* Structure for GOTD_IMSG_PACKFILE_INSTALL. */ struct gotd_imsg_packfile_install { uint8_t pack_sha1[SHA1_DIGEST_LENGTH]; }; /* Structure for GOTD_IMSG_DISCONNECT data. */ struct gotd_imsg_disconnect { uint32_t client_id; }; /* Structure for GOTD_IMSG_CONNECT. */ struct gotd_imsg_connect { uint32_t client_id; uid_t euid; gid_t egid; size_t username_len; /* Followed by username_len data bytes. */ }; /* Structure for GOTD_IMSG_CONNECT_REPO_CHILD. */ struct gotd_imsg_connect_repo_child { enum gotd_procid proc_id; /* repo child imsg pipe is passed via imsg fd */ }; /* Structure for GOTD_IMSG_AUTHENTICATE. */ struct gotd_imsg_auth { uid_t euid; gid_t egid; int required_auth; uint32_t client_id; }; /* Structures for GOTD_IMSG_NOTIFY. */ enum gotd_notification_action { GOTD_NOTIF_ACTION_CREATED, GOTD_NOTIF_ACTION_REMOVED, GOTD_NOTIF_ACTION_CHANGED }; /* IMSG_NOTIFY session <-> repo_write */ struct gotd_imsg_notification_content { enum gotd_notification_action action; struct got_object_id old_id; struct got_object_id new_id; size_t refname_len; /* Followed by refname_len data bytes. */ }; /* IMSG_NOTIFY session -> notify*/ struct gotd_imsg_notify { char repo_name[NAME_MAX]; char subject_line[64]; size_t username_len; /* Followed by username_len data bytes. */ }; int enter_chroot(const char *); int parse_config(const char *, enum gotd_procid, struct gotd *); struct gotd_repo *gotd_find_repo_by_name(const char *, struct gotd_repolist *); struct gotd_repo *gotd_find_repo_by_path(const char *, struct gotd *); struct gotd_uid_connection_limit *gotd_find_uid_connection_limit( struct gotd_uid_connection_limit *limits, size_t nlimits, uid_t uid); int gotd_parseuid(const char *s, uid_t *uid); const struct got_error *gotd_parse_url(char **, char **, char **, char **, const char *); /* imsg.c */ const struct got_error *gotd_imsg_flush(struct imsgbuf *); const struct got_error *gotd_imsg_recv(struct imsg *, struct imsgbuf *, size_t); const struct got_error *gotd_imsg_poll_recv(struct imsg *, struct imsgbuf *, size_t); const struct got_error *gotd_imsg_recv_error(uint32_t *client_id, struct imsg *imsg); int gotd_imsg_send_error(struct imsgbuf *ibuf, uint32_t, uint32_t, const struct got_error *); int gotd_imsg_send_error_event(struct gotd_imsgev *, uint32_t, uint32_t, const struct got_error *); void gotd_imsg_event_add(struct gotd_imsgev *); int gotd_imsg_compose_event(struct gotd_imsgev *, uint16_t, uint32_t, int, void *, uint16_t); int gotd_imsg_forward(struct gotd_imsgev *, struct imsg *, int); void gotd_imsg_send_ack(struct got_object_id *, struct imsgbuf *, uint32_t, pid_t); void gotd_imsg_send_nak(struct got_object_id *, struct imsgbuf *, uint32_t, pid_t); got-portable-0.101/gotd/session_write.c0000664000175100017510000013343214644144735013617 /* * Copyright (c) 2022, 2023 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_repository.h" #include "got_object.h" #include "got_path.h" #include "got_reference.h" #include "got_opentemp.h" #include "got_lib_hash.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_object_cache.h" #include "got_lib_pack.h" #include "got_lib_repository.h" #include "got_lib_gitproto.h" #include "gotd.h" #include "log.h" #include "session_write.h" struct gotd_session_notif { STAILQ_ENTRY(gotd_session_notif) entry; int fd; enum gotd_notification_action action; char *refname; struct got_object_id old_id; struct got_object_id new_id; }; STAILQ_HEAD(gotd_session_notifications, gotd_session_notif) notifications; enum gotd_session_write_state { GOTD_STATE_EXPECT_LIST_REFS, GOTD_STATE_EXPECT_CAPABILITIES, GOTD_STATE_EXPECT_REF_UPDATE, GOTD_STATE_EXPECT_MORE_REF_UPDATES, GOTD_STATE_EXPECT_PACKFILE, GOTD_STATE_NOTIFY, }; static struct gotd_session_write { pid_t pid; const char *title; struct got_repository *repo; struct gotd_repo *repo_cfg; int *pack_fds; int *temp_fds; struct gotd_imsgev parent_iev; struct gotd_imsgev notifier_iev; struct timeval request_timeout; enum gotd_session_write_state state; struct gotd_imsgev repo_child_iev; } gotd_session; static struct gotd_session_client { struct gotd_client_capability *capabilities; size_t ncapa_alloc; size_t ncapabilities; uint32_t id; int fd; int delta_cache_fd; struct gotd_imsgev iev; struct event tmo; uid_t euid; gid_t egid; char *username; char *packfile_path; char *packidx_path; int nref_updates; int accept_flush_pkt; int flush_disconnect; } gotd_session_client; static void session_write_shutdown(void); static void disconnect(struct gotd_session_client *client) { log_debug("uid %d: disconnecting", client->euid); if (gotd_imsg_compose_event(&gotd_session.parent_iev, GOTD_IMSG_DISCONNECT, PROC_SESSION_WRITE, -1, NULL, 0) == -1) log_warn("imsg compose DISCONNECT"); imsg_clear(&gotd_session.repo_child_iev.ibuf); event_del(&gotd_session.repo_child_iev.ev); evtimer_del(&client->tmo); close(client->fd); if (client->delta_cache_fd != -1) close(client->delta_cache_fd); if (client->packfile_path) { if (unlink(client->packfile_path) == -1 && errno != ENOENT) log_warn("unlink %s: ", client->packfile_path); free(client->packfile_path); } if (client->packidx_path) { if (unlink(client->packidx_path) == -1 && errno != ENOENT) log_warn("unlink %s: ", client->packidx_path); free(client->packidx_path); } free(client->capabilities); session_write_shutdown(); } static void disconnect_on_error(struct gotd_session_client *client, const struct got_error *err) { struct imsgbuf ibuf; if (err->code != GOT_ERR_EOF) { log_warnx("uid %d: %s", client->euid, err->msg); imsg_init(&ibuf, client->fd); gotd_imsg_send_error(&ibuf, 0, PROC_SESSION_WRITE, err); imsg_clear(&ibuf); } disconnect(client); } static void gotd_request_timeout(int fd, short events, void *arg) { struct gotd_session_client *client = arg; log_warnx("disconnecting uid %d due to timeout", client->euid); disconnect(client); } static void session_write_sighdlr(int sig, short event, void *arg) { /* * Normal signal handler rules don't apply because libevent * decouples for us. */ switch (sig) { case SIGHUP: log_info("%s: ignoring SIGHUP", __func__); break; case SIGUSR1: log_info("%s: ignoring SIGUSR1", __func__); break; case SIGTERM: case SIGINT: session_write_shutdown(); /* NOTREACHED */ break; default: fatalx("unexpected signal"); } } static const struct got_error * recv_packfile_install(struct imsg *imsg) { struct gotd_imsg_packfile_install inst; size_t datalen; log_debug("packfile-install received"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(inst)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&inst, imsg->data, sizeof(inst)); return NULL; } static const struct got_error * recv_ref_updates_start(struct imsg *imsg) { struct gotd_imsg_ref_updates_start istart; size_t datalen; log_debug("ref-updates-start received"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(istart)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&istart, imsg->data, sizeof(istart)); return NULL; } static const struct got_error * recv_ref_update(struct imsg *imsg) { struct gotd_imsg_ref_update iref; size_t datalen; log_debug("ref-update received"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(iref)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iref, imsg->data, sizeof(iref)); return NULL; } static const struct got_error * send_ref_update_ok(struct gotd_session_client *client, struct gotd_imsg_ref_update *iref, const char *refname) { struct gotd_imsg_ref_update_ok iok; struct gotd_imsgev *iev = &client->iev; struct ibuf *wbuf; size_t len; memset(&iok, 0, sizeof(iok)); memcpy(iok.old_id, iref->old_id, SHA1_DIGEST_LENGTH); memcpy(iok.new_id, iref->new_id, SHA1_DIGEST_LENGTH); iok.name_len = strlen(refname); len = sizeof(iok) + iok.name_len; wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_REF_UPDATE_OK, PROC_SESSION_WRITE, gotd_session.pid, len); if (wbuf == NULL) return got_error_from_errno("imsg_create REF_UPDATE_OK"); if (imsg_add(wbuf, &iok, sizeof(iok)) == -1) return got_error_from_errno("imsg_add REF_UPDATE_OK"); if (imsg_add(wbuf, refname, iok.name_len) == -1) return got_error_from_errno("imsg_add REF_UPDATE_OK"); imsg_close(&iev->ibuf, wbuf); gotd_imsg_event_add(iev); return NULL; } static void send_refs_updated(struct gotd_session_client *client) { if (gotd_imsg_compose_event(&client->iev, GOTD_IMSG_REFS_UPDATED, PROC_SESSION_WRITE, -1, NULL, 0) == -1) log_warn("imsg compose REFS_UPDATED"); } static const struct got_error * send_ref_update_ng(struct gotd_session_client *client, struct gotd_imsg_ref_update *iref, const char *refname, const char *reason) { const struct got_error *ng_err; struct gotd_imsg_ref_update_ng ing; struct gotd_imsgev *iev = &client->iev; struct ibuf *wbuf; size_t len; memset(&ing, 0, sizeof(ing)); memcpy(ing.old_id, iref->old_id, SHA1_DIGEST_LENGTH); memcpy(ing.new_id, iref->new_id, SHA1_DIGEST_LENGTH); ing.name_len = strlen(refname); ng_err = got_error_fmt(GOT_ERR_REF_BUSY, "%s", reason); ing.reason_len = strlen(ng_err->msg); len = sizeof(ing) + ing.name_len + ing.reason_len; wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_REF_UPDATE_NG, PROC_SESSION_WRITE, gotd_session.pid, len); if (wbuf == NULL) return got_error_from_errno("imsg_create REF_UPDATE_NG"); if (imsg_add(wbuf, &ing, sizeof(ing)) == -1) return got_error_from_errno("imsg_add REF_UPDATE_NG"); if (imsg_add(wbuf, refname, ing.name_len) == -1) return got_error_from_errno("imsg_add REF_UPDATE_NG"); if (imsg_add(wbuf, ng_err->msg, ing.reason_len) == -1) return got_error_from_errno("imsg_add REF_UPDATE_NG"); imsg_close(&iev->ibuf, wbuf); gotd_imsg_event_add(iev); return NULL; } static const struct got_error * install_pack(struct gotd_session_client *client, const char *repo_path, struct imsg *imsg) { const struct got_error *err = NULL; struct gotd_imsg_packfile_install inst; char hex[SHA1_DIGEST_STRING_LENGTH]; size_t datalen; char *packfile_path = NULL, *packidx_path = NULL; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(inst)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&inst, imsg->data, sizeof(inst)); if (client->packfile_path == NULL) return got_error_msg(GOT_ERR_BAD_REQUEST, "client has no pack file"); if (client->packidx_path == NULL) return got_error_msg(GOT_ERR_BAD_REQUEST, "client has no pack file index"); if (got_sha1_digest_to_str(inst.pack_sha1, hex, sizeof(hex)) == NULL) return got_error_msg(GOT_ERR_NO_SPACE, "could not convert pack file SHA1 to hex"); if (asprintf(&packfile_path, "/%s/%s/pack-%s.pack", repo_path, GOT_OBJECTS_PACK_DIR, hex) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (asprintf(&packidx_path, "/%s/%s/pack-%s.idx", repo_path, GOT_OBJECTS_PACK_DIR, hex) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (rename(client->packfile_path, packfile_path) == -1) { err = got_error_from_errno3("rename", client->packfile_path, packfile_path); goto done; } free(client->packfile_path); client->packfile_path = NULL; if (rename(client->packidx_path, packidx_path) == -1) { err = got_error_from_errno3("rename", client->packidx_path, packidx_path); goto done; } /* Ensure we re-read the pack index list upon next access. */ gotd_session.repo->pack_path_mtime.tv_sec = 0; gotd_session.repo->pack_path_mtime.tv_nsec = 0; free(client->packidx_path); client->packidx_path = NULL; done: free(packfile_path); free(packidx_path); return err; } static const struct got_error * begin_ref_updates(struct gotd_session_client *client, struct imsg *imsg) { struct gotd_imsg_ref_updates_start istart; size_t datalen; if (client->nref_updates != -1) return got_error(GOT_ERR_PRIVSEP_MSG); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(istart)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&istart, imsg->data, sizeof(istart)); if (istart.nref_updates <= 0) return got_error(GOT_ERR_PRIVSEP_MSG); client->nref_updates = istart.nref_updates; return NULL; } static const struct got_error * validate_namespace(const char *namespace) { size_t len = strlen(namespace); if (len < 5 || strncmp("refs/", namespace, 5) != 0 || namespace[len - 1] != '/') { return got_error_fmt(GOT_ERR_BAD_REF_NAME, "reference namespace '%s'", namespace); } return NULL; } static const struct got_error * queue_notification(struct got_object_id *old_id, struct got_object_id *new_id, struct got_repository *repo, struct got_reference *ref) { const struct got_error *err = NULL; struct gotd_repo *repo_cfg = gotd_session.repo_cfg; struct gotd_imsgev *iev = &gotd_session.repo_child_iev; struct got_pathlist_entry *pe; struct gotd_session_notif *notif; if (iev->ibuf.fd == -1 || STAILQ_EMPTY(&repo_cfg->notification_targets)) return NULL; /* notifications unused */ TAILQ_FOREACH(pe, &repo_cfg->notification_refs, entry) { const char *refname = pe->path; if (strcmp(got_ref_get_name(ref), refname) == 0) break; } if (pe == NULL) { TAILQ_FOREACH(pe, &repo_cfg->notification_ref_namespaces, entry) { const char *namespace = pe->path; err = validate_namespace(namespace); if (err) return err; if (strncmp(namespace, got_ref_get_name(ref), strlen(namespace)) == 0) break; } } /* * If a branch or a reference namespace was specified in the * configuration file then only send notifications if a match * was found. */ if (pe == NULL && (!TAILQ_EMPTY(&repo_cfg->notification_refs) || !TAILQ_EMPTY(&repo_cfg->notification_ref_namespaces))) return NULL; notif = calloc(1, sizeof(*notif)); if (notif == NULL) return got_error_from_errno("calloc"); notif->fd = -1; if (old_id == NULL) notif->action = GOTD_NOTIF_ACTION_CREATED; else if (new_id == NULL) notif->action = GOTD_NOTIF_ACTION_REMOVED; else notif->action = GOTD_NOTIF_ACTION_CHANGED; if (old_id != NULL) memcpy(¬if->old_id, old_id, sizeof(notif->old_id)); if (new_id != NULL) memcpy(¬if->new_id, new_id, sizeof(notif->new_id)); notif->refname = strdup(got_ref_get_name(ref)); if (notif->refname == NULL) { err = got_error_from_errno("strdup"); goto done; } STAILQ_INSERT_TAIL(¬ifications, notif, entry); done: if (err && notif) { free(notif->refname); free(notif); } return err; } /* Forward notification content to the NOTIFY process. */ static const struct got_error * forward_notification(struct gotd_session_client *client, struct imsg *imsg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = &gotd_session.notifier_iev; struct gotd_session_notif *notif; struct gotd_imsg_notification_content icontent; char *refname = NULL, *id_str = NULL; size_t datalen; struct gotd_imsg_notify inotify; const char *action; struct ibuf *wbuf; memset(&inotify, 0, sizeof(inotify)); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(icontent)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&icontent, imsg->data, sizeof(icontent)); if (datalen != sizeof(icontent) + icontent.refname_len) return got_error(GOT_ERR_PRIVSEP_LEN); refname = strndup(imsg->data + sizeof(icontent), icontent.refname_len); if (refname == NULL) return got_error_from_errno("strndup"); notif = STAILQ_FIRST(¬ifications); if (notif == NULL) return got_error(GOT_ERR_PRIVSEP_MSG); STAILQ_REMOVE(¬ifications, notif, gotd_session_notif, entry); if (notif->action != icontent.action || notif->fd == -1 || strcmp(notif->refname, refname) != 0) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } if (notif->action == GOTD_NOTIF_ACTION_CREATED) { if (memcmp(¬if->new_id, &icontent.new_id, sizeof(notif->new_id)) != 0) { err = got_error_msg(GOT_ERR_PRIVSEP_MSG, "received notification content for unknown event"); goto done; } } else if (notif->action == GOTD_NOTIF_ACTION_REMOVED) { if (memcmp(¬if->old_id, &icontent.old_id, sizeof(notif->old_id)) != 0) { err = got_error_msg(GOT_ERR_PRIVSEP_MSG, "received notification content for unknown event"); goto done; } } else if (memcmp(¬if->old_id, &icontent.old_id, sizeof(notif->old_id)) != 0 || memcmp(¬if->new_id, &icontent.new_id, sizeof(notif->old_id)) != 0) { err = got_error_msg(GOT_ERR_PRIVSEP_MSG, "received notification content for unknown event"); goto done; } switch (notif->action) { case GOTD_NOTIF_ACTION_CREATED: action = "created"; err = got_object_id_str(&id_str, ¬if->new_id); if (err) goto done; break; case GOTD_NOTIF_ACTION_REMOVED: action = "removed"; err = got_object_id_str(&id_str, ¬if->old_id); if (err) goto done; break; case GOTD_NOTIF_ACTION_CHANGED: action = "changed"; err = got_object_id_str(&id_str, ¬if->new_id); if (err) goto done; break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } strlcpy(inotify.repo_name, gotd_session.repo_cfg->name, sizeof(inotify.repo_name)); snprintf(inotify.subject_line, sizeof(inotify.subject_line), "%s: %s %s %s: %.12s", gotd_session.repo_cfg->name, client->username, action, notif->refname, id_str); inotify.username_len = strlen(client->username); wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_NOTIFY, PROC_SESSION_WRITE, gotd_session.pid, sizeof(inotify) + inotify.username_len); if (wbuf == NULL) { err = got_error_from_errno("imsg_create NOTIFY"); goto done; } if (imsg_add(wbuf, &inotify, sizeof(inotify)) == -1) { err = got_error_from_errno("imsg_add NOTIFY"); goto done; } if (imsg_add(wbuf, client->username, inotify.username_len) == -1) { err = got_error_from_errno("imsg_add NOTIFY"); goto done; } ibuf_fd_set(wbuf, notif->fd); notif->fd = -1; imsg_close(&iev->ibuf, wbuf); gotd_imsg_event_add(iev); done: if (notif->fd != -1) close(notif->fd); free(notif); free(refname); free(id_str); return err; } /* Request notification content from REPO_WRITE process. */ static const struct got_error * request_notification(struct gotd_session_notif *notif) { const struct got_error *err = NULL; struct gotd_imsgev *iev = &gotd_session.repo_child_iev; struct gotd_imsg_notification_content icontent; struct ibuf *wbuf; size_t len; int fd; fd = got_opentempfd(); if (fd == -1) return got_error_from_errno("got_opentemp"); memset(&icontent, 0, sizeof(icontent)); icontent.action = notif->action; memcpy(&icontent.old_id, ¬if->old_id, sizeof(notif->old_id)); memcpy(&icontent.new_id, ¬if->new_id, sizeof(notif->new_id)); icontent.refname_len = strlen(notif->refname); len = sizeof(icontent) + icontent.refname_len; wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_NOTIFY, PROC_SESSION_WRITE, gotd_session.pid, len); if (wbuf == NULL) { err = got_error_from_errno("imsg_create NOTIFY"); goto done; } if (imsg_add(wbuf, &icontent, sizeof(icontent)) == -1) { err = got_error_from_errno("imsg_add NOTIFY"); goto done; } if (imsg_add(wbuf, notif->refname, icontent.refname_len) == -1) { err = got_error_from_errno("imsg_add NOTIFY"); goto done; } notif->fd = dup(fd); if (notif->fd == -1) { err = got_error_from_errno("dup"); goto done; } ibuf_fd_set(wbuf, fd); fd = -1; imsg_close(&iev->ibuf, wbuf); gotd_imsg_event_add(iev); done: if (err && fd != -1) close(fd); return err; } static const struct got_error * update_ref(int *shut, struct gotd_session_client *client, const char *repo_path, struct imsg *imsg) { const struct got_error *err = NULL; struct got_repository *repo = gotd_session.repo; struct got_reference *ref = NULL; struct gotd_imsg_ref_update iref; struct got_object_id old_id, new_id; struct gotd_session_notif *notif; struct got_object_id *id = NULL; char *refname = NULL; size_t datalen; int locked = 0; char hex1[SHA1_DIGEST_STRING_LENGTH]; char hex2[SHA1_DIGEST_STRING_LENGTH]; log_debug("update-ref from uid %d", client->euid); if (client->nref_updates <= 0) return got_error(GOT_ERR_PRIVSEP_MSG); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(iref)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iref, imsg->data, sizeof(iref)); if (datalen != sizeof(iref) + iref.name_len) return got_error(GOT_ERR_PRIVSEP_LEN); refname = strndup(imsg->data + sizeof(iref), iref.name_len); if (refname == NULL) return got_error_from_errno("strndup"); log_debug("updating ref %s for uid %d", refname, client->euid); memset(&old_id, 0, sizeof(old_id)); memcpy(old_id.sha1, iref.old_id, SHA1_DIGEST_LENGTH); memset(&new_id, 0, sizeof(new_id)); memcpy(new_id.sha1, iref.new_id, SHA1_DIGEST_LENGTH); err = got_repo_find_object_id(iref.delete_ref ? &old_id : &new_id, repo); if (err) goto done; if (iref.ref_is_new) { err = got_ref_open(&ref, repo, refname, 0); if (err) { if (err->code != GOT_ERR_NOT_REF) goto done; err = got_ref_alloc(&ref, refname, &new_id); if (err) goto done; err = got_ref_write(ref, repo); /* will lock/unlock */ if (err) goto done; err = queue_notification(NULL, &new_id, repo, ref); if (err) goto done; } else { err = got_ref_resolve(&id, repo, ref); if (err) goto done; got_object_id_hex(&new_id, hex1, sizeof(hex1)); got_object_id_hex(id, hex2, sizeof(hex2)); err = got_error_fmt(GOT_ERR_REF_BUSY, "Addition %s: %s failed; %s: %s has been " "created by someone else while transaction " "was in progress", got_ref_get_name(ref), hex1, got_ref_get_name(ref), hex2); goto done; } } else if (iref.delete_ref) { err = got_ref_open(&ref, repo, refname, 1 /* lock */); if (err) goto done; locked = 1; err = got_ref_resolve(&id, repo, ref); if (err) goto done; if (got_object_id_cmp(id, &old_id) != 0) { got_object_id_hex(&old_id, hex1, sizeof(hex1)); got_object_id_hex(id, hex2, sizeof(hex2)); err = got_error_fmt(GOT_ERR_REF_BUSY, "Deletion %s: %s failed; %s: %s has been " "created by someone else while transaction " "was in progress", got_ref_get_name(ref), hex1, got_ref_get_name(ref), hex2); goto done; } err = got_ref_delete(ref, repo); if (err) goto done; err = queue_notification(&old_id, NULL, repo, ref); if (err) goto done; free(id); id = NULL; } else { err = got_ref_open(&ref, repo, refname, 1 /* lock */); if (err) goto done; locked = 1; err = got_ref_resolve(&id, repo, ref); if (err) goto done; if (got_object_id_cmp(id, &old_id) != 0) { got_object_id_hex(&old_id, hex1, sizeof(hex1)); got_object_id_hex(id, hex2, sizeof(hex2)); err = got_error_fmt(GOT_ERR_REF_BUSY, "Update %s: %s failed; %s: %s has been " "created by someone else while transaction " "was in progress", got_ref_get_name(ref), hex1, got_ref_get_name(ref), hex2); goto done; } if (got_object_id_cmp(&new_id, &old_id) != 0) { err = got_ref_change_ref(ref, &new_id); if (err) goto done; err = got_ref_write(ref, repo); if (err) goto done; err = queue_notification(&old_id, &new_id, repo, ref); if (err) goto done; } free(id); id = NULL; } done: if (err) { if (err->code == GOT_ERR_LOCKFILE_TIMEOUT) { err = got_error_fmt(GOT_ERR_LOCKFILE_TIMEOUT, "could not acquire exclusive file lock for %s", refname); } send_ref_update_ng(client, &iref, refname, err->msg); } else send_ref_update_ok(client, &iref, refname); if (client->nref_updates > 0) { client->nref_updates--; if (client->nref_updates == 0) { send_refs_updated(client); notif = STAILQ_FIRST(¬ifications); if (notif) { gotd_session.state = GOTD_STATE_NOTIFY; err = request_notification(notif); if (err) { log_warn("could not send notification: " "%s", err->msg); client->flush_disconnect = 1; } } else client->flush_disconnect = 1; } } if (locked) { const struct got_error *unlock_err; unlock_err = got_ref_unlock(ref); if (unlock_err && err == NULL) err = unlock_err; } if (ref) got_ref_close(ref); free(refname); free(id); return err; } static const struct got_error * recv_notification_content(struct imsg *imsg) { struct gotd_imsg_notification_content inotif; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(inotif)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&inotif, imsg->data, sizeof(inotif)); return NULL; } static void session_dispatch_repo_child(int fd, short event, void *arg) { struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_session_client *client = &gotd_session_client; ssize_t n; int shut = 0; struct imsg imsg; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno != EAGAIN) fatal("msgbuf_write"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } for (;;) { const struct got_error *err = NULL; uint32_t client_id = 0; int do_disconnect = 0; int do_ref_updates = 0, do_ref_update = 0; int do_packfile_install = 0, do_notify = 0; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: do_disconnect = 1; err = gotd_imsg_recv_error(&client_id, &imsg); break; case GOTD_IMSG_PACKFILE_INSTALL: err = recv_packfile_install(&imsg); if (err == NULL) do_packfile_install = 1; break; case GOTD_IMSG_REF_UPDATES_START: err = recv_ref_updates_start(&imsg); if (err == NULL) do_ref_updates = 1; break; case GOTD_IMSG_REF_UPDATE: err = recv_ref_update(&imsg); if (err == NULL) do_ref_update = 1; break; case GOTD_IMSG_NOTIFY: err = recv_notification_content(&imsg); if (err == NULL) do_notify = 1; break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } if (do_disconnect || err) { if (err) disconnect_on_error(client, err); else disconnect(client); } else { struct gotd_session_notif *notif; if (do_packfile_install) err = install_pack(client, gotd_session.repo->path, &imsg); else if (do_ref_updates) err = begin_ref_updates(client, &imsg); else if (do_ref_update) err = update_ref(&shut, client, gotd_session.repo->path, &imsg); else if (do_notify) err = forward_notification(client, &imsg); if (err) log_warnx("uid %d: %s", client->euid, err->msg); notif = STAILQ_FIRST(¬ifications); if (notif && do_notify) { /* Request content for next notification. */ err = request_notification(notif); if (err) { log_warn("could not send notification: " "%s", err->msg); shut = 1; } } } imsg_free(&imsg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } static const struct got_error * recv_capabilities(struct gotd_session_client *client, struct imsg *imsg) { struct gotd_imsg_capabilities icapas; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(icapas)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&icapas, imsg->data, sizeof(icapas)); client->ncapa_alloc = icapas.ncapabilities; client->capabilities = calloc(client->ncapa_alloc, sizeof(*client->capabilities)); if (client->capabilities == NULL) { client->ncapa_alloc = 0; return got_error_from_errno("calloc"); } log_debug("expecting %zu capabilities from uid %d", client->ncapa_alloc, client->euid); return NULL; } static const struct got_error * recv_capability(struct gotd_session_client *client, struct imsg *imsg) { struct gotd_imsg_capability icapa; struct gotd_client_capability *capa; size_t datalen; char *key, *value = NULL; if (client->capabilities == NULL || client->ncapabilities >= client->ncapa_alloc) { return got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected capability received"); } memset(&icapa, 0, sizeof(icapa)); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(icapa)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&icapa, imsg->data, sizeof(icapa)); if (datalen != sizeof(icapa) + icapa.key_len + icapa.value_len) return got_error(GOT_ERR_PRIVSEP_LEN); key = strndup(imsg->data + sizeof(icapa), icapa.key_len); if (key == NULL) return got_error_from_errno("strndup"); if (icapa.value_len > 0) { value = strndup(imsg->data + sizeof(icapa) + icapa.key_len, icapa.value_len); if (value == NULL) { free(key); return got_error_from_errno("strndup"); } } capa = &client->capabilities[client->ncapabilities++]; capa->key = key; capa->value = value; if (value) log_debug("uid %d: capability %s=%s", client->euid, key, value); else log_debug("uid %d: capability %s", client->euid, key); return NULL; } static const struct got_error * forward_ref_update(struct gotd_session_client *client, struct imsg *imsg) { const struct got_error *err = NULL; struct gotd_imsg_ref_update ireq; struct gotd_imsg_ref_update *iref = NULL; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(ireq)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ireq, imsg->data, sizeof(ireq)); if (datalen != sizeof(ireq) + ireq.name_len) return got_error(GOT_ERR_PRIVSEP_LEN); iref = malloc(datalen); if (iref == NULL) return got_error_from_errno("malloc"); memcpy(iref, imsg->data, datalen); if (gotd_imsg_compose_event(&gotd_session.repo_child_iev, GOTD_IMSG_REF_UPDATE, PROC_SESSION_WRITE, -1, iref, datalen) == -1) err = got_error_from_errno("imsg compose REF_UPDATE"); free(iref); return err; } static int client_has_capability(struct gotd_session_client *client, const char *capastr) { struct gotd_client_capability *capa; size_t i; if (client->ncapabilities == 0) return 0; for (i = 0; i < client->ncapabilities; i++) { capa = &client->capabilities[i]; if (strcmp(capa->key, capastr) == 0) return 1; } return 0; } static const struct got_error * recv_packfile(struct gotd_session_client *client) { const struct got_error *err = NULL; struct gotd_imsg_recv_packfile ipack; char *basepath = NULL, *pack_path = NULL, *idx_path = NULL; int packfd = -1, idxfd = -1; int pipe[2] = { -1, -1 }; if (client->packfile_path) { return got_error_fmt(GOT_ERR_PRIVSEP_MSG, "uid %d already has a pack file", client->euid); } if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe) == -1) return got_error_from_errno("socketpair"); /* Send pack pipe end 0 to repo child process. */ if (gotd_imsg_compose_event(&gotd_session.repo_child_iev, GOTD_IMSG_PACKFILE_PIPE, PROC_SESSION_WRITE, pipe[0], NULL, 0) == -1) { err = got_error_from_errno("imsg compose PACKFILE_PIPE"); pipe[0] = -1; goto done; } pipe[0] = -1; /* Send pack pipe end 1 to gotsh(1) (expects just an fd, no data). */ if (gotd_imsg_compose_event(&client->iev, GOTD_IMSG_PACKFILE_PIPE, PROC_SESSION_WRITE, pipe[1], NULL, 0) == -1) err = got_error_from_errno("imsg compose PACKFILE_PIPE"); pipe[1] = -1; if (asprintf(&basepath, "%s/%s/receiving-from-uid-%d.pack", got_repo_get_path(gotd_session.repo), GOT_OBJECTS_PACK_DIR, client->euid) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_opentemp_named_fd(&pack_path, &packfd, basepath, ""); if (err) goto done; if (fchmod(packfd, GOT_DEFAULT_PACK_MODE) == -1) { err = got_error_from_errno2("fchmod", pack_path); goto done; } free(basepath); if (asprintf(&basepath, "%s/%s/receiving-from-uid-%d.idx", got_repo_get_path(gotd_session.repo), GOT_OBJECTS_PACK_DIR, client->euid) == -1) { err = got_error_from_errno("asprintf"); basepath = NULL; goto done; } err = got_opentemp_named_fd(&idx_path, &idxfd, basepath, ""); if (err) goto done; if (fchmod(idxfd, GOT_DEFAULT_PACK_MODE) == -1) { err = got_error_from_errno2("fchmod", idx_path); goto done; } if (gotd_imsg_compose_event(&gotd_session.repo_child_iev, GOTD_IMSG_PACKIDX_FILE, PROC_SESSION_WRITE, idxfd, NULL, 0) == -1) { err = got_error_from_errno("imsg compose PACKIDX_FILE"); idxfd = -1; goto done; } idxfd = -1; memset(&ipack, 0, sizeof(ipack)); if (client_has_capability(client, GOT_CAPA_REPORT_STATUS)) ipack.report_status = 1; if (gotd_imsg_compose_event(&gotd_session.repo_child_iev, GOTD_IMSG_RECV_PACKFILE, PROC_SESSION_WRITE, packfd, &ipack, sizeof(ipack)) == -1) { err = got_error_from_errno("imsg compose RECV_PACKFILE"); packfd = -1; goto done; } packfd = -1; done: free(basepath); if (pipe[0] != -1 && close(pipe[0]) == -1 && err == NULL) err = got_error_from_errno("close"); if (pipe[1] != -1 && close(pipe[1]) == -1 && err == NULL) err = got_error_from_errno("close"); if (packfd != -1 && close(packfd) == -1 && err == NULL) err = got_error_from_errno("close"); if (idxfd != -1 && close(idxfd) == -1 && err == NULL) err = got_error_from_errno("close"); if (err) { free(pack_path); free(idx_path); } else { client->packfile_path = pack_path; client->packidx_path = idx_path; } return err; } static void session_dispatch_client(int fd, short events, void *arg) { struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_session_client *client = &gotd_session_client; const struct got_error *err = NULL; struct imsg imsg; ssize_t n; if (events & EV_WRITE) { while (ibuf->w.queued) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno == EPIPE) { /* * The client has closed its socket. * This can happen when Git clients are * done sending pack file data. */ msgbuf_clear(&ibuf->w); continue; } else if (n == -1 && errno != EAGAIN) { err = got_error_from_errno("imsg_flush"); disconnect_on_error(client, err); return; } if (n == 0) { /* Connection closed. */ err = got_error(GOT_ERR_EOF); disconnect_on_error(client, err); return; } } if (client->flush_disconnect) { disconnect(client); return; } } if ((events & EV_READ) == 0) return; memset(&imsg, 0, sizeof(imsg)); while (err == NULL) { err = gotd_imsg_recv(&imsg, ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_READ) err = NULL; else if (err->code == GOT_ERR_EOF && gotd_session.state == GOTD_STATE_EXPECT_CAPABILITIES) { /* * The client has closed its socket before * sending its capability announcement. * This can happen when Git clients have * no ref-updates to send. */ disconnect_on_error(client, err); return; } break; } evtimer_del(&client->tmo); switch (imsg.hdr.type) { case GOTD_IMSG_CAPABILITIES: if (gotd_session.state != GOTD_STATE_EXPECT_CAPABILITIES) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected capabilities received"); break; } log_debug("receiving capabilities from uid %d", client->euid); err = recv_capabilities(client, &imsg); break; case GOTD_IMSG_CAPABILITY: if (gotd_session.state != GOTD_STATE_EXPECT_CAPABILITIES) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected capability received"); break; } err = recv_capability(client, &imsg); if (err || client->ncapabilities < client->ncapa_alloc) break; gotd_session.state = GOTD_STATE_EXPECT_REF_UPDATE; client->accept_flush_pkt = 1; log_debug("uid %d: expecting ref-update-lines", client->euid); break; case GOTD_IMSG_REF_UPDATE: if (gotd_session.state != GOTD_STATE_EXPECT_REF_UPDATE && gotd_session.state != GOTD_STATE_EXPECT_MORE_REF_UPDATES) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected ref-update-line received"); break; } log_debug("received ref-update-line from uid %d", client->euid); err = forward_ref_update(client, &imsg); if (err) break; gotd_session.state = GOTD_STATE_EXPECT_MORE_REF_UPDATES; client->accept_flush_pkt = 1; break; case GOTD_IMSG_FLUSH: if (gotd_session.state != GOTD_STATE_EXPECT_MORE_REF_UPDATES) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected flush-pkt received"); break; } if (!client->accept_flush_pkt) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected flush-pkt received"); break; } /* * Accept just one flush packet at a time. * Future client state transitions will set this flag * again if another flush packet is expected. */ client->accept_flush_pkt = 0; log_debug("received flush-pkt from uid %d", client->euid); if (gotd_session.state == GOTD_STATE_EXPECT_MORE_REF_UPDATES) { gotd_session.state = GOTD_STATE_EXPECT_PACKFILE; log_debug("uid %d: expecting packfile", client->euid); err = recv_packfile(client); } else { /* should not happen, see above */ err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected client state"); break; } break; default: log_debug("unexpected imsg %d", imsg.hdr.type); err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); } if (err) { if (err->code != GOT_ERR_EOF || (gotd_session.state != GOTD_STATE_EXPECT_PACKFILE && gotd_session.state != GOTD_STATE_NOTIFY)) disconnect_on_error(client, err); } else { gotd_imsg_event_add(iev); evtimer_add(&client->tmo, &gotd_session.request_timeout); } } static const struct got_error * list_refs_request(void) { static const struct got_error *err; struct gotd_session_client *client = &gotd_session_client; struct gotd_imsgev *iev = &gotd_session.repo_child_iev; int fd; if (gotd_session.state != GOTD_STATE_EXPECT_LIST_REFS) return got_error(GOT_ERR_PRIVSEP_MSG); fd = dup(client->fd); if (fd == -1) return got_error_from_errno("dup"); if (gotd_imsg_compose_event(iev, GOTD_IMSG_LIST_REFS_INTERNAL, PROC_SESSION_WRITE, fd, NULL, 0) == -1) { err = got_error_from_errno("imsg compose LIST_REFS_INTERNAL"); close(fd); return err; } gotd_session.state = GOTD_STATE_EXPECT_CAPABILITIES; log_debug("uid %d: expecting capabilities", client->euid); return NULL; } static const struct got_error * recv_connect(struct imsg *imsg) { struct gotd_session_client *client = &gotd_session_client; struct gotd_imsg_connect iconnect; size_t datalen; if (gotd_session.state != GOTD_STATE_EXPECT_LIST_REFS) return got_error(GOT_ERR_PRIVSEP_MSG); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(iconnect)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iconnect, imsg->data, sizeof(iconnect)); if (iconnect.username_len == 0 || datalen != sizeof(iconnect) + iconnect.username_len) return got_error(GOT_ERR_PRIVSEP_LEN); client->euid = iconnect.euid; client->egid = iconnect.egid; client->fd = imsg_get_fd(imsg); if (client->fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); client->username = strndup(imsg->data + sizeof(iconnect), iconnect.username_len); if (client->username == NULL) return got_error_from_errno("strndup"); imsg_init(&client->iev.ibuf, client->fd); client->iev.handler = session_dispatch_client; client->iev.events = EV_READ; client->iev.handler_arg = NULL; event_set(&client->iev.ev, client->iev.ibuf.fd, EV_READ, session_dispatch_client, &client->iev); gotd_imsg_event_add(&client->iev); evtimer_set(&client->tmo, gotd_request_timeout, client); evtimer_add(&client->tmo, &gotd_session.request_timeout); return NULL; } static void session_dispatch_notifier(int fd, short event, void *arg) { const struct got_error *err; struct gotd_session_client *client = &gotd_session_client; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; ssize_t n; int shut = 0; struct imsg imsg; struct gotd_session_notif *notif; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno != EAGAIN) fatal("msgbuf_write"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_NOTIFICATION_SENT: if (gotd_session.state != GOTD_STATE_NOTIFY) { log_warn("unexpected imsg %d", imsg.hdr.type); break; } notif = STAILQ_FIRST(¬ifications); if (notif == NULL) { disconnect(client); break; /* NOTREACHED */ } /* Request content for the next notification. */ err = request_notification(notif); if (err) { log_warn("could not send notification: %s", err->msg); disconnect(client); } break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); imsg_clear(&iev->ibuf); imsg_init(&iev->ibuf, -1); } } static const struct got_error * recv_notifier(struct imsg *imsg) { struct gotd_imsgev *iev = &gotd_session.notifier_iev; struct gotd_session_client *client = &gotd_session_client; size_t datalen; int fd; if (gotd_session.state != GOTD_STATE_EXPECT_LIST_REFS) return got_error(GOT_ERR_PRIVSEP_MSG); /* We should already have received a pipe to the listener. */ if (client->fd == -1) return got_error(GOT_ERR_PRIVSEP_MSG); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); fd = imsg_get_fd(imsg); if (fd == -1) return NULL; /* notifications unused */ imsg_init(&iev->ibuf, fd); iev->handler = session_dispatch_notifier; iev->events = EV_READ; iev->handler_arg = NULL; event_set(&iev->ev, iev->ibuf.fd, EV_READ, session_dispatch_notifier, iev); gotd_imsg_event_add(iev); return NULL; } static const struct got_error * recv_repo_child(struct imsg *imsg) { struct gotd_imsg_connect_repo_child ichild; struct gotd_session_client *client = &gotd_session_client; size_t datalen; int fd; if (gotd_session.state != GOTD_STATE_EXPECT_LIST_REFS) return got_error(GOT_ERR_PRIVSEP_MSG); /* We should already have received a pipe to the listener. */ if (client->fd == -1) return got_error(GOT_ERR_PRIVSEP_MSG); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ichild)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ichild, imsg->data, sizeof(ichild)); if (ichild.proc_id != PROC_REPO_WRITE) return got_error_msg(GOT_ERR_PRIVSEP_MSG, "bad child process type"); fd = imsg_get_fd(imsg); if (fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); imsg_init(&gotd_session.repo_child_iev.ibuf, fd); gotd_session.repo_child_iev.handler = session_dispatch_repo_child; gotd_session.repo_child_iev.events = EV_READ; gotd_session.repo_child_iev.handler_arg = NULL; event_set(&gotd_session.repo_child_iev.ev, gotd_session.repo_child_iev.ibuf.fd, EV_READ, session_dispatch_repo_child, &gotd_session.repo_child_iev); gotd_imsg_event_add(&gotd_session.repo_child_iev); /* The "recvfd" pledge promise is no longer needed. */ if (pledge("stdio rpath wpath cpath sendfd fattr flock", NULL) == -1) fatal("pledge"); return NULL; } static void session_dispatch(int fd, short event, void *arg) { struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_session_client *client = &gotd_session_client; ssize_t n; int shut = 0; struct imsg imsg; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno != EAGAIN) fatal("msgbuf_write"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } for (;;) { const struct got_error *err = NULL; uint32_t client_id = 0; int do_disconnect = 0, do_list_refs = 0; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: do_disconnect = 1; err = gotd_imsg_recv_error(&client_id, &imsg); break; case GOTD_IMSG_CONNECT: err = recv_connect(&imsg); break; case GOTD_IMSG_DISCONNECT: do_disconnect = 1; break; case GOTD_IMSG_CONNECT_NOTIFIER: err = recv_notifier(&imsg); break; case GOTD_IMSG_CONNECT_REPO_CHILD: err = recv_repo_child(&imsg); if (err) break; do_list_refs = 1; break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); if (do_disconnect) { if (err) disconnect_on_error(client, err); else disconnect(client); } else if (do_list_refs) err = list_refs_request(); if (err) log_warnx("uid %d: %s", client->euid, err->msg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void session_write_main(const char *title, const char *repo_path, int *pack_fds, int *temp_fds, struct timeval *request_timeout, struct gotd_repo *repo_cfg) { const struct got_error *err = NULL; struct event evsigint, evsigterm, evsighup, evsigusr1; STAILQ_INIT(¬ifications); gotd_session.title = title; gotd_session.pid = getpid(); gotd_session.pack_fds = pack_fds; gotd_session.temp_fds = temp_fds; memcpy(&gotd_session.request_timeout, request_timeout, sizeof(gotd_session.request_timeout)); gotd_session.repo_cfg = repo_cfg; imsg_init(&gotd_session.notifier_iev.ibuf, -1); err = got_repo_open(&gotd_session.repo, repo_path, NULL, pack_fds); if (err) goto done; if (!got_repo_is_bare(gotd_session.repo)) { err = got_error_msg(GOT_ERR_NOT_GIT_REPO, "bare git repository required"); goto done; } got_repo_temp_fds_set(gotd_session.repo, temp_fds); signal_set(&evsigint, SIGINT, session_write_sighdlr, NULL); signal_set(&evsigterm, SIGTERM, session_write_sighdlr, NULL); signal_set(&evsighup, SIGHUP, session_write_sighdlr, NULL); signal_set(&evsigusr1, SIGUSR1, session_write_sighdlr, NULL); signal(SIGPIPE, SIG_IGN); signal_add(&evsigint, NULL); signal_add(&evsigterm, NULL); signal_add(&evsighup, NULL); signal_add(&evsigusr1, NULL); gotd_session.state = GOTD_STATE_EXPECT_LIST_REFS; gotd_session_client.fd = -1; gotd_session_client.nref_updates = -1; gotd_session_client.delta_cache_fd = -1; gotd_session_client.accept_flush_pkt = 1; imsg_init(&gotd_session.parent_iev.ibuf, GOTD_FILENO_MSG_PIPE); gotd_session.parent_iev.handler = session_dispatch; gotd_session.parent_iev.events = EV_READ; gotd_session.parent_iev.handler_arg = NULL; event_set(&gotd_session.parent_iev.ev, gotd_session.parent_iev.ibuf.fd, EV_READ, session_dispatch, &gotd_session.parent_iev); if (gotd_imsg_compose_event(&gotd_session.parent_iev, GOTD_IMSG_CLIENT_SESSION_READY, PROC_SESSION_WRITE, -1, NULL, 0) == -1) { err = got_error_from_errno("imsg compose CLIENT_SESSION_READY"); goto done; } event_dispatch(); done: if (err) log_warnx("%s: %s", title, err->msg); session_write_shutdown(); } static void session_write_shutdown(void) { struct gotd_session_notif *notif; log_debug("%s: shutting down", gotd_session.title); while (!STAILQ_EMPTY(¬ifications)) { notif = STAILQ_FIRST(¬ifications); STAILQ_REMOVE_HEAD(¬ifications, entry); if (notif->fd != -1) close(notif->fd); free(notif->refname); free(notif); } if (gotd_session.repo) got_repo_close(gotd_session.repo); got_repo_pack_fds_close(gotd_session.pack_fds); got_repo_temp_fds_close(gotd_session.temp_fds); free(gotd_session_client.username); exit(0); } got-portable-0.101/gotd/Makefile.in0000664000175100017510000015542214644145543012624 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ sbin_PROGRAMS = gotd$(EXEEXT) @HOST_OPENBSD_FALSE@am__append_1 = chroot-notobsd.c @HOST_OPENBSD_TRUE@am__append_2 = chroot-openbsd.c @HOST_FREEBSD_TRUE@am__append_3 = -lmd subdir = gotd ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" \ "$(DESTDIR)$(man8dir)" PROGRAMS = $(sbin_PROGRAMS) am__gotd_SOURCES_DIST = gotd.c $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c $(top_srcdir)/lib/commit_graph.c \ $(top_srcdir)/lib/date.c $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c $(top_srcdir)/lib/diff.c \ $(top_srcdir)/lib/diff_atomize_text.c \ $(top_srcdir)/lib/diff_main.c $(top_srcdir)/lib/diff_myers.c \ $(top_srcdir)/lib/diff_output.c \ $(top_srcdir)/lib/diff_output_plain.c \ $(top_srcdir)/lib/diff_output_unidiff.c \ $(top_srcdir)/lib/diff_patience.c $(top_srcdir)/lib/diffreg.c \ $(top_srcdir)/lib/error.c $(top_srcdir)/lib/gitconfig.c \ $(top_srcdir)/lib/gotconfig.c $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/log.c $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_io.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_io.c \ $(top_srcdir)/lib/pack_index.c $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig.c \ $(top_srcdir)/lib/read_gotconfig.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c $(top_srcdir)/lib/sigs.c auth.c \ imsg.c listen.c notify.c parse.y privsep_stub.c repo_imsg.c \ repo_read.c repo_write.c session_read.c session_write.c \ chroot-notobsd.c chroot-openbsd.c am__dirstamp = $(am__leading_dot)dirstamp @HOST_OPENBSD_FALSE@am__objects_1 = chroot-notobsd.$(OBJEXT) @HOST_OPENBSD_TRUE@am__objects_2 = chroot-openbsd.$(OBJEXT) am_gotd_OBJECTS = gotd.$(OBJEXT) $(top_builddir)/lib/bloom.$(OBJEXT) \ $(top_builddir)/lib/buf.$(OBJEXT) \ $(top_builddir)/lib/commit_graph.$(OBJEXT) \ $(top_builddir)/lib/date.$(OBJEXT) \ $(top_builddir)/lib/deflate.$(OBJEXT) \ $(top_builddir)/lib/delta.$(OBJEXT) \ $(top_builddir)/lib/delta_cache.$(OBJEXT) \ $(top_builddir)/lib/deltify.$(OBJEXT) \ $(top_builddir)/lib/diff.$(OBJEXT) \ $(top_builddir)/lib/diff_atomize_text.$(OBJEXT) \ $(top_builddir)/lib/diff_main.$(OBJEXT) \ $(top_builddir)/lib/diff_myers.$(OBJEXT) \ $(top_builddir)/lib/diff_output.$(OBJEXT) \ $(top_builddir)/lib/diff_output_plain.$(OBJEXT) \ $(top_builddir)/lib/diff_output_unidiff.$(OBJEXT) \ $(top_builddir)/lib/diff_patience.$(OBJEXT) \ $(top_builddir)/lib/diffreg.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/gitconfig.$(OBJEXT) \ $(top_builddir)/lib/gotconfig.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/lockfile.$(OBJEXT) \ $(top_builddir)/lib/log.$(OBJEXT) \ $(top_builddir)/lib/murmurhash2.$(OBJEXT) \ $(top_builddir)/lib/object.$(OBJEXT) \ $(top_builddir)/lib/object_cache.$(OBJEXT) \ $(top_builddir)/lib/object_create.$(OBJEXT) \ $(top_builddir)/lib/object_idset.$(OBJEXT) \ $(top_builddir)/lib/object_open_io.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/opentemp.$(OBJEXT) \ $(top_builddir)/lib/pack.$(OBJEXT) \ $(top_builddir)/lib/pack_create.$(OBJEXT) \ $(top_builddir)/lib/pack_create_io.$(OBJEXT) \ $(top_builddir)/lib/pack_index.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/ratelimit.$(OBJEXT) \ $(top_builddir)/lib/read_gitconfig.$(OBJEXT) \ $(top_builddir)/lib/read_gotconfig.$(OBJEXT) \ $(top_builddir)/lib/reference.$(OBJEXT) \ $(top_builddir)/lib/reference_parse.$(OBJEXT) \ $(top_builddir)/lib/repository.$(OBJEXT) \ $(top_builddir)/lib/sigs.$(OBJEXT) auth.$(OBJEXT) \ imsg.$(OBJEXT) listen.$(OBJEXT) notify.$(OBJEXT) \ parse.$(OBJEXT) privsep_stub.$(OBJEXT) repo_imsg.$(OBJEXT) \ repo_read.$(OBJEXT) repo_write.$(OBJEXT) \ session_read.$(OBJEXT) session_write.$(OBJEXT) \ $(am__objects_1) $(am__objects_2) gotd_OBJECTS = $(am_gotd_OBJECTS) gotd_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/bloom.Po \ $(top_builddir)/lib/$(DEPDIR)/buf.Po \ $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po \ $(top_builddir)/lib/$(DEPDIR)/date.Po \ $(top_builddir)/lib/$(DEPDIR)/deflate.Po \ $(top_builddir)/lib/$(DEPDIR)/delta.Po \ $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/deltify.Po \ $(top_builddir)/lib/$(DEPDIR)/diff.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_main.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po \ $(top_builddir)/lib/$(DEPDIR)/diffreg.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/gitconfig.Po \ $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/lockfile.Po \ $(top_builddir)/lib/$(DEPDIR)/log.Po \ $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po \ $(top_builddir)/lib/$(DEPDIR)/object.Po \ $(top_builddir)/lib/$(DEPDIR)/object_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/object_create.Po \ $(top_builddir)/lib/$(DEPDIR)/object_idset.Po \ $(top_builddir)/lib/$(DEPDIR)/object_open_io.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/opentemp.Po \ $(top_builddir)/lib/$(DEPDIR)/pack.Po \ $(top_builddir)/lib/$(DEPDIR)/pack_create.Po \ $(top_builddir)/lib/$(DEPDIR)/pack_create_io.Po \ $(top_builddir)/lib/$(DEPDIR)/pack_index.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po \ $(top_builddir)/lib/$(DEPDIR)/read_gitconfig.Po \ $(top_builddir)/lib/$(DEPDIR)/read_gotconfig.Po \ $(top_builddir)/lib/$(DEPDIR)/reference.Po \ $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/repository.Po \ $(top_builddir)/lib/$(DEPDIR)/sigs.Po ./$(DEPDIR)/auth.Po \ ./$(DEPDIR)/chroot-notobsd.Po ./$(DEPDIR)/chroot-openbsd.Po \ ./$(DEPDIR)/gotd.Po ./$(DEPDIR)/imsg.Po ./$(DEPDIR)/listen.Po \ ./$(DEPDIR)/notify.Po ./$(DEPDIR)/parse.Po \ ./$(DEPDIR)/privsep_stub.Po ./$(DEPDIR)/repo_imsg.Po \ ./$(DEPDIR)/repo_read.Po ./$(DEPDIR)/repo_write.Po \ ./$(DEPDIR)/session_read.Po ./$(DEPDIR)/session_write.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \ -e s/c++$$/h++/ -e s/c$$/h/ YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS) AM_V_YACC = $(am__v_YACC_@AM_V@) am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@) am__v_YACC_0 = @echo " YACC " $@; am__v_YACC_1 = YLWRAP = $(top_srcdir)/etc/ylwrap SOURCES = $(gotd_SOURCES) DIST_SOURCES = $(am__gotd_SOURCES_DIST) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } man5dir = $(mandir)/man5 man8dir = $(mandir)/man8 NROFF = nroff MANS = $(man5_MANS) $(man8_MANS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp \ $(top_srcdir)/etc/ylwrap parse.c DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ -DGOTD_EMPTY_PATH='"@GOTD_EMPTY_PATHC@"' \ $(libuuid_CFLAGS) $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libevent_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ SUBDIRS = libexec gotd_SOURCES = gotd.c $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c $(top_srcdir)/lib/commit_graph.c \ $(top_srcdir)/lib/date.c $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c $(top_srcdir)/lib/diff.c \ $(top_srcdir)/lib/diff_atomize_text.c \ $(top_srcdir)/lib/diff_main.c $(top_srcdir)/lib/diff_myers.c \ $(top_srcdir)/lib/diff_output.c \ $(top_srcdir)/lib/diff_output_plain.c \ $(top_srcdir)/lib/diff_output_unidiff.c \ $(top_srcdir)/lib/diff_patience.c $(top_srcdir)/lib/diffreg.c \ $(top_srcdir)/lib/error.c $(top_srcdir)/lib/gitconfig.c \ $(top_srcdir)/lib/gotconfig.c $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/log.c $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_io.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_io.c \ $(top_srcdir)/lib/pack_index.c $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig.c \ $(top_srcdir)/lib/read_gotconfig.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c $(top_srcdir)/lib/sigs.c auth.c \ imsg.c listen.c notify.c parse.y privsep_stub.c repo_imsg.c \ repo_read.c repo_write.c session_read.c session_write.c \ $(am__append_1) $(am__append_2) gotd_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = gotd.8 gotd.conf.5 *.h man5_MANS = gotd.conf.5 man8_MANS = gotd.8 LDADD = -L$(top_builddir)/compat -lopenbsd-compat -lm $(libuuid_LIBS) \ $(zlib_LIBS) $(libbsd_LIBS) $(libevent_LIBS) $(libutil_LIBS) \ $(am__append_3) all: all-recursive .SUFFIXES: .SUFFIXES: .c .o .obj .y $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gotd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign gotd/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: > $(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: > $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/bloom.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/buf.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/commit_graph.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/date.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/deflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/deltify.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_atomize_text.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_main.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_myers.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_plain.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_unidiff.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_patience.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diffreg.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gitconfig.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gotconfig.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/lockfile.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/log.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/murmurhash2.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_create.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_idset.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_open_io.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/opentemp.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack_create.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack_create_io.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack_index.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/ratelimit.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/read_gitconfig.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/read_gotconfig.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/repository.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/sigs.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) gotd$(EXEEXT): $(gotd_OBJECTS) $(gotd_DEPENDENCIES) $(EXTRA_gotd_DEPENDENCIES) @rm -f gotd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gotd_OBJECTS) $(gotd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/bloom.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/buf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/commit_graph.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/date.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/deflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/deltify.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_myers.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_patience.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diffreg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gitconfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gotconfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/lockfile.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/log.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_create.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_idset.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_open_io.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/opentemp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack_create.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack_create_io.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack_index.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/ratelimit.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/read_gitconfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/read_gotconfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/repository.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/sigs.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chroot-notobsd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chroot-openbsd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gotd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imsg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/listen.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/notify.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/privsep_stub.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repo_imsg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repo_read.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repo_write.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/session_read.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/session_write.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .y.c: $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE) install-man5: $(man5_MANS) @$(NORMAL_INSTALL) @list1='$(man5_MANS)'; \ list2=''; \ test -n "$(man5dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man5dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man5dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.5[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \ done; } uninstall-man5: @$(NORMAL_UNINSTALL) @list='$(man5_MANS)'; test -n "$(man5dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man5dir)'; $(am__uninstall_files_from_dir) install-man8: $(man8_MANS) @$(NORMAL_INSTALL) @list1='$(man8_MANS)'; \ list2=''; \ test -n "$(man8dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.8[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ done; } uninstall-man8: @$(NORMAL_UNINSTALL) @list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(PROGRAMS) $(MANS) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -rm -f parse.c clean: clean-recursive clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am distclean: distclean-recursive -rm -f $(top_builddir)/lib/$(DEPDIR)/bloom.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/buf.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/date.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deltify.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_main.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diffreg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gitconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/lockfile.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/log.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_open_io.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create_io.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_index.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gitconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/sigs.Po -rm -f ./$(DEPDIR)/auth.Po -rm -f ./$(DEPDIR)/chroot-notobsd.Po -rm -f ./$(DEPDIR)/chroot-openbsd.Po -rm -f ./$(DEPDIR)/gotd.Po -rm -f ./$(DEPDIR)/imsg.Po -rm -f ./$(DEPDIR)/listen.Po -rm -f ./$(DEPDIR)/notify.Po -rm -f ./$(DEPDIR)/parse.Po -rm -f ./$(DEPDIR)/privsep_stub.Po -rm -f ./$(DEPDIR)/repo_imsg.Po -rm -f ./$(DEPDIR)/repo_read.Po -rm -f ./$(DEPDIR)/repo_write.Po -rm -f ./$(DEPDIR)/session_read.Po -rm -f ./$(DEPDIR)/session_write.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-man install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-man5 install-man8 install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(top_builddir)/lib/$(DEPDIR)/bloom.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/buf.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/date.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deltify.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_main.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diffreg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gitconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/lockfile.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/log.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_open_io.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create_io.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_index.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gitconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/sigs.Po -rm -f ./$(DEPDIR)/auth.Po -rm -f ./$(DEPDIR)/chroot-notobsd.Po -rm -f ./$(DEPDIR)/chroot-openbsd.Po -rm -f ./$(DEPDIR)/gotd.Po -rm -f ./$(DEPDIR)/imsg.Po -rm -f ./$(DEPDIR)/listen.Po -rm -f ./$(DEPDIR)/notify.Po -rm -f ./$(DEPDIR)/parse.Po -rm -f ./$(DEPDIR)/privsep_stub.Po -rm -f ./$(DEPDIR)/repo_imsg.Po -rm -f ./$(DEPDIR)/repo_read.Po -rm -f ./$(DEPDIR)/repo_write.Po -rm -f ./$(DEPDIR)/session_read.Po -rm -f ./$(DEPDIR)/session_write.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-man uninstall-sbinPROGRAMS uninstall-man: uninstall-man5 uninstall-man8 .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--depfiles check check-am clean clean-generic \ clean-sbinPROGRAMS cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-man5 \ install-man8 install-pdf install-pdf-am install-ps \ install-ps-am install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-man uninstall-man5 uninstall-man8 \ uninstall-sbinPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/gotd/repo_write.c0000664000175100017510000016761514644144735013113 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "buf.h" #include "got_error.h" #include "got_repository.h" #include "got_object.h" #include "got_reference.h" #include "got_path.h" #include "got_diff.h" #include "got_cancel.h" #include "got_commit_graph.h" #include "got_opentemp.h" #include "got_lib_delta.h" #include "got_lib_delta_cache.h" #include "got_lib_hash.h" #include "got_lib_object.h" #include "got_lib_object_cache.h" #include "got_lib_object_idset.h" #include "got_lib_object_parse.h" #include "got_lib_ratelimit.h" #include "got_lib_pack.h" #include "got_lib_pack_index.h" #include "got_lib_repository.h" #include "got_lib_poll.h" #include "log.h" #include "gotd.h" #include "repo_write.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif static struct repo_write { pid_t pid; const char *title; struct got_repository *repo; int *pack_fds; int *temp_fds; int session_fd; struct gotd_imsgev session_iev; struct got_pathlist_head *protected_tag_namespaces; struct got_pathlist_head *protected_branch_namespaces; struct got_pathlist_head *protected_branches; struct { FILE *f1; FILE *f2; int fd1; int fd2; } diff; int refs_listed; } repo_write; struct gotd_ref_update { STAILQ_ENTRY(gotd_ref_update) entry; struct got_reference *ref; int ref_is_new; int delete_ref; struct got_object_id old_id; struct got_object_id new_id; }; STAILQ_HEAD(gotd_ref_updates, gotd_ref_update); static struct repo_write_client { uint32_t id; int fd; int pack_pipe; struct got_pack pack; uint8_t pack_sha1[SHA1_DIGEST_LENGTH]; int packidx_fd; struct gotd_ref_updates ref_updates; int nref_updates; int nref_del; int nref_new; int nref_move; } repo_write_client; static volatile sig_atomic_t sigint_received; static volatile sig_atomic_t sigterm_received; static void catch_sigint(int signo) { sigint_received = 1; } static void catch_sigterm(int signo) { sigterm_received = 1; } static const struct got_error * check_cancelled(void *arg) { if (sigint_received || sigterm_received) return got_error(GOT_ERR_CANCELLED); return NULL; } static const struct got_error * send_peeled_tag_ref(struct got_reference *ref, struct got_object *obj, struct imsgbuf *ibuf) { const struct got_error *err = NULL; struct got_tag_object *tag; size_t namelen, len; char *peeled_refname = NULL; struct got_object_id *id; struct ibuf *wbuf; err = got_object_tag_open(&tag, repo_write.repo, obj); if (err) return err; if (asprintf(&peeled_refname, "%s^{}", got_ref_get_name(ref)) == -1) { err = got_error_from_errno("asprintf"); goto done; } id = got_object_tag_get_object_id(tag); namelen = strlen(peeled_refname); len = sizeof(struct gotd_imsg_ref) + namelen; if (len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) { err = got_error(GOT_ERR_NO_SPACE); goto done; } wbuf = imsg_create(ibuf, GOTD_IMSG_REF, PROC_REPO_WRITE, repo_write.pid, len); if (wbuf == NULL) { err = got_error_from_errno("imsg_create REF"); goto done; } /* Keep in sync with struct gotd_imsg_ref definition. */ if (imsg_add(wbuf, id->sha1, SHA1_DIGEST_LENGTH) == -1) { err = got_error_from_errno("imsg_add REF"); goto done; } if (imsg_add(wbuf, &namelen, sizeof(namelen)) == -1) { err = got_error_from_errno("imsg_add REF"); goto done; } if (imsg_add(wbuf, peeled_refname, namelen) == -1) { err = got_error_from_errno("imsg_add REF"); goto done; } imsg_close(ibuf, wbuf); done: got_object_tag_close(tag); return err; } static const struct got_error * send_ref(struct got_reference *ref, struct imsgbuf *ibuf) { const struct got_error *err; const char *refname = got_ref_get_name(ref); size_t namelen; struct got_object_id *id = NULL; struct got_object *obj = NULL; size_t len; struct ibuf *wbuf; namelen = strlen(refname); len = sizeof(struct gotd_imsg_ref) + namelen; if (len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) return got_error(GOT_ERR_NO_SPACE); err = got_ref_resolve(&id, repo_write.repo, ref); if (err) return err; wbuf = imsg_create(ibuf, GOTD_IMSG_REF, PROC_REPO_WRITE, repo_write.pid, len); if (wbuf == NULL) { err = got_error_from_errno("imsg_create REF"); goto done; } /* Keep in sync with struct gotd_imsg_ref definition. */ if (imsg_add(wbuf, id->sha1, SHA1_DIGEST_LENGTH) == -1) return got_error_from_errno("imsg_add REF"); if (imsg_add(wbuf, &namelen, sizeof(namelen)) == -1) return got_error_from_errno("imsg_add REF"); if (imsg_add(wbuf, refname, namelen) == -1) return got_error_from_errno("imsg_add REF"); imsg_close(ibuf, wbuf); err = got_object_open(&obj, repo_write.repo, id); if (err) goto done; if (obj->type == GOT_OBJ_TYPE_TAG) err = send_peeled_tag_ref(ref, obj, ibuf); done: if (obj) got_object_close(obj); free(id); return err; } static const struct got_error * list_refs(struct imsg *imsg) { const struct got_error *err; struct repo_write_client *client = &repo_write_client; struct got_reflist_head refs; struct got_reflist_entry *re; size_t datalen; struct gotd_imsg_reflist irefs; struct imsgbuf ibuf; int client_fd; TAILQ_INIT(&refs); client_fd = imsg_get_fd(imsg); if (client_fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); if (repo_write.refs_listed) { return got_error_msg(GOT_ERR_CLIENT_ID, "duplicate list-refs request"); } repo_write.refs_listed = 1; client->fd = client_fd; client->nref_updates = 0; client->nref_del = 0; client->nref_new = 0; client->nref_move = 0; imsg_init(&ibuf, client_fd); err = got_ref_list(&refs, repo_write.repo, "", got_ref_cmp_by_name, NULL); if (err) return err; memset(&irefs, 0, sizeof(irefs)); TAILQ_FOREACH(re, &refs, entry) { struct got_object_id *id; int obj_type; if (got_ref_is_symbolic(re->ref)) continue; irefs.nrefs++; /* Account for a peeled tag refs. */ err = got_ref_resolve(&id, repo_write.repo, re->ref); if (err) goto done; err = got_object_get_type(&obj_type, repo_write.repo, id); free(id); if (err) goto done; if (obj_type == GOT_OBJ_TYPE_TAG) irefs.nrefs++; } if (imsg_compose(&ibuf, GOTD_IMSG_REFLIST, PROC_REPO_WRITE, repo_write.pid, -1, &irefs, sizeof(irefs)) == -1) { err = got_error_from_errno("imsg_compose REFLIST"); goto done; } TAILQ_FOREACH(re, &refs, entry) { if (got_ref_is_symbolic(re->ref)) continue; err = send_ref(re->ref, &ibuf); if (err) goto done; } err = gotd_imsg_flush(&ibuf); done: got_ref_list_free(&refs); imsg_clear(&ibuf); return err; } static const struct got_error * validate_namespace(const char *namespace) { size_t len = strlen(namespace); if (len < 5 || strncmp("refs/", namespace, 5) != 0 || namespace[len -1] != '/') { return got_error_fmt(GOT_ERR_BAD_REF_NAME, "reference namespace '%s'", namespace); } return NULL; } static const struct got_error * protect_ref_namespace(const char *refname, const char *namespace) { const struct got_error *err; err = validate_namespace(namespace); if (err) return err; if (strncmp(namespace, refname, strlen(namespace)) == 0) return got_error_fmt(GOT_ERR_REFS_PROTECTED, "%s", namespace); return NULL; } static const struct got_error * verify_object_type(struct got_object_id *id, int expected_obj_type, struct got_pack *pack, struct got_packidx *packidx) { const struct got_error *err; char hex[SHA1_DIGEST_STRING_LENGTH]; struct got_object *obj; int idx; const char *typestr; idx = got_packidx_get_object_idx(packidx, id); if (idx == -1) { got_object_id_hex(id, hex, sizeof(hex)); return got_error_fmt(GOT_ERR_BAD_PACKFILE, "object %s is missing from pack file", hex); } err = got_object_open_from_packfile(&obj, id, pack, packidx, idx, repo_write.repo); if (err) return err; if (obj->type != expected_obj_type) { got_object_id_hex(id, hex, sizeof(hex)); got_object_type_label(&typestr, expected_obj_type); err = got_error_fmt(GOT_ERR_OBJ_TYPE, "%s is not pointing at a %s object", hex, typestr); } got_object_close(obj); return err; } static const struct got_error * protect_tag_namespace(const char *namespace, struct got_pack *pack, struct got_packidx *packidx, struct gotd_ref_update *ref_update) { const struct got_error *err; err = validate_namespace(namespace); if (err) return err; if (strncmp(namespace, got_ref_get_name(ref_update->ref), strlen(namespace)) != 0) return NULL; if (!ref_update->ref_is_new) return got_error_fmt(GOT_ERR_REFS_PROTECTED, "%s", namespace); return verify_object_type(&ref_update->new_id, GOT_OBJ_TYPE_TAG, pack, packidx); } static const struct got_error * protect_require_yca(struct got_object_id *tip_id, size_t max_commits_to_traverse, struct got_pack *pack, struct got_packidx *packidx, struct got_reference *ref) { const struct got_error *err; uint8_t *buf = NULL; size_t len; struct got_object_id *expected_yca_id = NULL; struct got_object *obj = NULL; struct got_commit_object *commit = NULL; char hex[SHA1_DIGEST_STRING_LENGTH]; const struct got_object_id_queue *parent_ids; struct got_object_id_queue ids; struct got_object_qid *pid, *qid; struct got_object_idset *traversed_set = NULL; int found_yca = 0, obj_type; STAILQ_INIT(&ids); err = got_ref_resolve(&expected_yca_id, repo_write.repo, ref); if (err) return err; err = got_object_get_type(&obj_type, repo_write.repo, expected_yca_id); if (err) goto done; if (obj_type != GOT_OBJ_TYPE_COMMIT) { got_object_id_hex(expected_yca_id, hex, sizeof(hex)); err = got_error_fmt(GOT_ERR_OBJ_TYPE, "%s is not pointing at a commit object", hex); goto done; } traversed_set = got_object_idset_alloc(); if (traversed_set == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } err = got_object_qid_alloc(&qid, tip_id); if (err) goto done; STAILQ_INSERT_TAIL(&ids, qid, entry); while (!STAILQ_EMPTY(&ids)) { err = check_cancelled(NULL); if (err) break; qid = STAILQ_FIRST(&ids); if (got_object_id_cmp(&qid->id, expected_yca_id) == 0) { found_yca = 1; break; } if (got_object_idset_num_elements(traversed_set) >= max_commits_to_traverse) break; if (got_object_idset_contains(traversed_set, &qid->id)) { STAILQ_REMOVE_HEAD(&ids, entry); got_object_qid_free(qid); qid = NULL; continue; } err = got_object_idset_add(traversed_set, &qid->id, NULL); if (err) goto done; err = got_object_open(&obj, repo_write.repo, &qid->id); if (err && err->code != GOT_ERR_NO_OBJ) goto done; err = NULL; if (obj) { err = got_object_commit_open(&commit, repo_write.repo, obj); if (err) goto done; } else { int idx; idx = got_packidx_get_object_idx(packidx, &qid->id); if (idx == -1) { got_object_id_hex(&qid->id, hex, sizeof(hex)); err = got_error_fmt(GOT_ERR_BAD_PACKFILE, "object %s is missing from pack file", hex); goto done; } err = got_object_open_from_packfile(&obj, &qid->id, pack, packidx, idx, repo_write.repo); if (err) goto done; if (obj->type != GOT_OBJ_TYPE_COMMIT) { got_object_id_hex(&qid->id, hex, sizeof(hex)); err = got_error_fmt(GOT_ERR_OBJ_TYPE, "%s is not pointing at a commit object", hex); goto done; } err = got_packfile_extract_object_to_mem(&buf, &len, obj, pack); if (err) goto done; err = got_object_parse_commit(&commit, buf, len); if (err) goto done; free(buf); buf = NULL; } got_object_close(obj); obj = NULL; STAILQ_REMOVE_HEAD(&ids, entry); got_object_qid_free(qid); qid = NULL; if (got_object_commit_get_nparents(commit) == 0) break; parent_ids = got_object_commit_get_parent_ids(commit); STAILQ_FOREACH(pid, parent_ids, entry) { err = check_cancelled(NULL); if (err) goto done; err = got_object_qid_alloc(&qid, &pid->id); if (err) goto done; STAILQ_INSERT_TAIL(&ids, qid, entry); qid = NULL; } got_object_commit_close(commit); commit = NULL; } if (!found_yca) { err = got_error_fmt(GOT_ERR_REF_PROTECTED, "%s", got_ref_get_name(ref)); } done: got_object_idset_free(traversed_set); got_object_id_queue_free(&ids); free(buf); if (obj) got_object_close(obj); if (commit) got_object_commit_close(commit); free(expected_yca_id); return err; } static const struct got_error * protect_branch_namespace(const char *namespace, struct got_pack *pack, struct got_packidx *packidx, struct gotd_ref_update *ref_update) { const struct got_error *err; err = validate_namespace(namespace); if (err) return err; if (strncmp(namespace, got_ref_get_name(ref_update->ref), strlen(namespace)) != 0) return NULL; if (ref_update->ref_is_new) { return verify_object_type(&ref_update->new_id, GOT_OBJ_TYPE_COMMIT, pack, packidx); } return protect_require_yca(&ref_update->new_id, be32toh(packidx->hdr.fanout_table[0xff]), pack, packidx, ref_update->ref); } static const struct got_error * protect_branch(const char *refname, struct got_pack *pack, struct got_packidx *packidx, struct gotd_ref_update *ref_update) { if (strcmp(refname, got_ref_get_name(ref_update->ref)) != 0) return NULL; /* Always allow new branches to be created. */ if (ref_update->ref_is_new) { return verify_object_type(&ref_update->new_id, GOT_OBJ_TYPE_COMMIT, pack, packidx); } return protect_require_yca(&ref_update->new_id, be32toh(packidx->hdr.fanout_table[0xff]), pack, packidx, ref_update->ref); } static const struct got_error * recv_ref_update(struct imsg *imsg) { static const char zero_id[SHA1_DIGEST_LENGTH]; const struct got_error *err = NULL; struct repo_write_client *client = &repo_write_client; struct gotd_imsg_ref_update iref; size_t datalen; char *refname = NULL; struct got_reference *ref = NULL; struct got_object_id *id = NULL; struct imsgbuf ibuf; struct gotd_ref_update *ref_update = NULL; log_debug("ref-update received"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(iref)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iref, imsg->data, sizeof(iref)); if (datalen != sizeof(iref) + iref.name_len) return got_error(GOT_ERR_PRIVSEP_LEN); imsg_init(&ibuf, client->fd); refname = strndup(imsg->data + sizeof(iref), iref.name_len); if (refname == NULL) return got_error_from_errno("strndup"); ref_update = calloc(1, sizeof(*ref_update)); if (ref_update == NULL) { err = got_error_from_errno("malloc"); goto done; } memcpy(ref_update->old_id.sha1, iref.old_id, SHA1_DIGEST_LENGTH); memcpy(ref_update->new_id.sha1, iref.new_id, SHA1_DIGEST_LENGTH); err = got_ref_open(&ref, repo_write.repo, refname, 0); if (err) { if (err->code != GOT_ERR_NOT_REF) goto done; if (memcmp(ref_update->new_id.sha1, zero_id, sizeof(zero_id)) == 0) { err = got_error_fmt(GOT_ERR_BAD_OBJ_ID, "%s", refname); goto done; } err = got_ref_alloc(&ref, refname, &ref_update->new_id); if (err) goto done; ref_update->ref_is_new = 1; client->nref_new++; } if (got_ref_is_symbolic(ref)) { err = got_error_fmt(GOT_ERR_BAD_REF_TYPE, "'%s' is a symbolic reference and cannot " "be updated", got_ref_get_name(ref)); goto done; } if (strncmp("refs/", got_ref_get_name(ref), 5) != 0) { err = got_error_fmt(GOT_ERR_BAD_REF_NAME, "%s: does not begin with 'refs/'", got_ref_get_name(ref)); goto done; } err = protect_ref_namespace(got_ref_get_name(ref), "refs/got/"); if (err) goto done; err = protect_ref_namespace(got_ref_get_name(ref), "refs/remotes/"); if (err) goto done; if (!ref_update->ref_is_new) { /* * Ensure the client's idea of this update is still valid. * At this point we can only return an error, to prevent * the client from uploading a pack file which will likely * have to be discarded. */ err = got_ref_resolve(&id, repo_write.repo, ref); if (err) goto done; if (got_object_id_cmp(id, &ref_update->old_id) != 0) { err = got_error_fmt(GOT_ERR_REF_BUSY, "%s has been modified by someone else " "while transaction was in progress", got_ref_get_name(ref)); goto done; } } gotd_imsg_send_ack(&ref_update->new_id, &ibuf, PROC_REPO_WRITE, repo_write.pid); ref_update->ref = ref; if (memcmp(ref_update->new_id.sha1, zero_id, sizeof(zero_id)) == 0) { ref_update->delete_ref = 1; client->nref_del++; } STAILQ_INSERT_HEAD(&client->ref_updates, ref_update, entry); client->nref_updates++; ref = NULL; ref_update = NULL; done: if (ref) got_ref_close(ref); free(ref_update); free(refname); free(id); return err; } static const struct got_error * pack_index_progress(void *arg, uint32_t nobj_total, uint32_t nobj_indexed, uint32_t nobj_loose, uint32_t nobj_resolved) { int p_indexed = 0, p_resolved = 0; int nobj_delta = nobj_total - nobj_loose; if (nobj_total > 0) p_indexed = (nobj_indexed * 100) / nobj_total; if (nobj_delta > 0) p_resolved = (nobj_resolved * 100) / nobj_delta; if (p_resolved > 0) { log_debug("indexing %d objects %d%%; resolving %d deltas %d%%", nobj_total, p_indexed, nobj_delta, p_resolved); } else log_debug("indexing %d objects %d%%", nobj_total, p_indexed); return NULL; } static const struct got_error * read_more_pack_stream(int infd, BUF *buf, size_t minsize) { const struct got_error *err = NULL; uint8_t readahead[65536]; size_t have, newlen; err = got_poll_read_full(infd, &have, readahead, sizeof(readahead), minsize); if (err) return err; err = buf_append(&newlen, buf, readahead, have); if (err) return err; return NULL; } static const struct got_error * copy_object_type_and_size(uint8_t *type, uint64_t *size, int infd, int outfd, off_t *outsize, BUF *buf, size_t *buf_pos, struct got_hash *ctx) { const struct got_error *err = NULL; uint8_t t = 0; uint64_t s = 0; uint8_t sizebuf[8]; size_t i = 0; off_t obj_offset = *outsize; do { /* We do not support size values which don't fit in 64 bit. */ if (i > 9) return got_error_fmt(GOT_ERR_OBJ_TOO_LARGE, "packfile offset %lld", (long long)obj_offset); if (buf_len(buf) - *buf_pos < sizeof(sizebuf[0])) { err = read_more_pack_stream(infd, buf, sizeof(sizebuf[0])); if (err) return err; } sizebuf[i] = buf_getc(buf, *buf_pos); *buf_pos += sizeof(sizebuf[i]); if (i == 0) { t = (sizebuf[i] & GOT_PACK_OBJ_SIZE0_TYPE_MASK) >> GOT_PACK_OBJ_SIZE0_TYPE_MASK_SHIFT; s = (sizebuf[i] & GOT_PACK_OBJ_SIZE0_VAL_MASK); } else { size_t shift = 4 + 7 * (i - 1); s |= ((sizebuf[i] & GOT_PACK_OBJ_SIZE_VAL_MASK) << shift); } i++; } while (sizebuf[i - 1] & GOT_PACK_OBJ_SIZE_MORE); err = got_pack_hwrite(outfd, sizebuf, i, ctx); if (err) return err; *outsize += i; *type = t; *size = s; return NULL; } static const struct got_error * copy_ref_delta(int infd, int outfd, off_t *outsize, BUF *buf, size_t *buf_pos, struct got_hash *ctx) { const struct got_error *err = NULL; size_t remain = buf_len(buf) - *buf_pos; if (remain < SHA1_DIGEST_LENGTH) { err = read_more_pack_stream(infd, buf, SHA1_DIGEST_LENGTH - remain); if (err) return err; } err = got_pack_hwrite(outfd, buf_get(buf) + *buf_pos, SHA1_DIGEST_LENGTH, ctx); if (err) return err; *buf_pos += SHA1_DIGEST_LENGTH; return NULL; } static const struct got_error * copy_offset_delta(int infd, int outfd, off_t *outsize, BUF *buf, size_t *buf_pos, struct got_hash *ctx) { const struct got_error *err = NULL; uint64_t o = 0; uint8_t offbuf[8]; size_t i = 0; off_t obj_offset = *outsize; do { /* We do not support offset values which don't fit in 64 bit. */ if (i > 8) return got_error_fmt(GOT_ERR_OBJ_TOO_LARGE, "packfile offset %lld", (long long)obj_offset); if (buf_len(buf) - *buf_pos < sizeof(offbuf[0])) { err = read_more_pack_stream(infd, buf, sizeof(offbuf[0])); if (err) return err; } offbuf[i] = buf_getc(buf, *buf_pos); *buf_pos += sizeof(offbuf[i]); if (i == 0) o = (offbuf[i] & GOT_PACK_OBJ_DELTA_OFF_VAL_MASK); else { o++; o <<= 7; o += (offbuf[i] & GOT_PACK_OBJ_DELTA_OFF_VAL_MASK); } i++; } while (offbuf[i - 1] & GOT_PACK_OBJ_DELTA_OFF_MORE); if (o < sizeof(struct got_packfile_hdr) || o > *outsize) return got_error(GOT_ERR_PACK_OFFSET); err = got_pack_hwrite(outfd, offbuf, i, ctx); if (err) return err; *outsize += i; return NULL; } static const struct got_error * copy_zstream(int infd, int outfd, off_t *outsize, BUF *buf, size_t *buf_pos, struct got_hash *ctx) { const struct got_error *err = NULL; z_stream z; int zret; char voidbuf[1024]; size_t consumed_total = 0; off_t zstream_offset = *outsize; memset(&z, 0, sizeof(z)); z.zalloc = Z_NULL; z.zfree = Z_NULL; zret = inflateInit(&z); if (zret != Z_OK) { if (zret == Z_ERRNO) return got_error_from_errno("inflateInit"); if (zret == Z_MEM_ERROR) { errno = ENOMEM; return got_error_from_errno("inflateInit"); } return got_error_msg(GOT_ERR_DECOMPRESSION, "inflateInit failed"); } while (zret != Z_STREAM_END) { size_t last_total_in, consumed; /* * Decompress into the void. Object data will be parsed * later, when the pack file is indexed. For now, we just * want to locate the end of the compressed stream. */ while (zret != Z_STREAM_END && buf_len(buf) - *buf_pos > 0) { last_total_in = z.total_in; z.next_in = buf_get(buf) + *buf_pos; z.avail_in = buf_len(buf) - *buf_pos; z.next_out = voidbuf; z.avail_out = sizeof(voidbuf); zret = inflate(&z, Z_SYNC_FLUSH); if (zret != Z_OK && zret != Z_BUF_ERROR && zret != Z_STREAM_END) { err = got_error_fmt(GOT_ERR_DECOMPRESSION, "packfile offset %lld", (long long)zstream_offset); goto done; } consumed = z.total_in - last_total_in; err = got_pack_hwrite(outfd, buf_get(buf) + *buf_pos, consumed, ctx); if (err) goto done; err = buf_discard(buf, *buf_pos + consumed); if (err) goto done; *buf_pos = 0; consumed_total += consumed; } if (zret != Z_STREAM_END) { err = read_more_pack_stream(infd, buf, 1); if (err) goto done; } } if (err == NULL) *outsize += consumed_total; done: inflateEnd(&z); return err; } static const struct got_error * validate_object_type(int obj_type) { switch (obj_type) { case GOT_OBJ_TYPE_BLOB: case GOT_OBJ_TYPE_COMMIT: case GOT_OBJ_TYPE_TREE: case GOT_OBJ_TYPE_TAG: case GOT_OBJ_TYPE_REF_DELTA: case GOT_OBJ_TYPE_OFFSET_DELTA: return NULL; default: break; } return got_error(GOT_ERR_OBJ_TYPE); } static const struct got_error * ensure_all_objects_exist_locally(struct gotd_ref_updates *ref_updates) { const struct got_error *err = NULL; struct gotd_ref_update *ref_update; struct got_object *obj; STAILQ_FOREACH(ref_update, ref_updates, entry) { err = got_object_open(&obj, repo_write.repo, &ref_update->new_id); if (err) return err; got_object_close(obj); } return NULL; } static const struct got_error * recv_packdata(off_t *outsize, uint32_t *nobj, uint8_t *sha1, int infd, int outfd) { const struct got_error *err; struct repo_write_client *client = &repo_write_client; struct got_packfile_hdr hdr; size_t have; uint32_t nhave = 0; struct got_hash ctx; uint8_t expected_sha1[SHA1_DIGEST_LENGTH]; char hex[SHA1_DIGEST_STRING_LENGTH]; BUF *buf = NULL; size_t buf_pos = 0, remain; ssize_t w; *outsize = 0; *nobj = 0; /* if only deleting references there's nothing to read */ if (client->nref_updates == client->nref_del) return NULL; got_hash_init(&ctx, GOT_HASH_SHA1); err = got_poll_read_full(infd, &have, &hdr, sizeof(hdr), sizeof(hdr)); if (err) return err; if (have != sizeof(hdr)) return got_error_msg(GOT_ERR_BAD_PACKFILE, "short pack file"); *outsize += have; if (hdr.signature != htobe32(GOT_PACKFILE_SIGNATURE)) return got_error_msg(GOT_ERR_BAD_PACKFILE, "bad packfile signature"); if (hdr.version != htobe32(GOT_PACKFILE_VERSION)) return got_error_msg(GOT_ERR_BAD_PACKFILE, "bad packfile version"); *nobj = be32toh(hdr.nobjects); if (*nobj == 0) { /* * Clients which are creating new references only * will send us an empty pack file. */ if (client->nref_updates > 0 && client->nref_updates == client->nref_new) return NULL; /* * Clients which only move existing refs will send us an empty * pack file. All referenced objects must exist locally. */ err = ensure_all_objects_exist_locally(&client->ref_updates); if (err) { if (err->code != GOT_ERR_NO_OBJ) return err; return got_error_msg(GOT_ERR_BAD_PACKFILE, "bad packfile with zero objects"); } client->nref_move = client->nref_updates; return NULL; } log_debug("expecting %d objects", *nobj); err = got_pack_hwrite(outfd, &hdr, sizeof(hdr), &ctx); if (err) return err; err = buf_alloc(&buf, 65536); if (err) return err; while (nhave != *nobj) { uint8_t obj_type; uint64_t obj_size; err = copy_object_type_and_size(&obj_type, &obj_size, infd, outfd, outsize, buf, &buf_pos, &ctx); if (err) goto done; err = validate_object_type(obj_type); if (err) goto done; if (obj_type == GOT_OBJ_TYPE_REF_DELTA) { err = copy_ref_delta(infd, outfd, outsize, buf, &buf_pos, &ctx); if (err) goto done; } else if (obj_type == GOT_OBJ_TYPE_OFFSET_DELTA) { err = copy_offset_delta(infd, outfd, outsize, buf, &buf_pos, &ctx); if (err) goto done; } err = copy_zstream(infd, outfd, outsize, buf, &buf_pos, &ctx); if (err) goto done; nhave++; } log_debug("received %u objects", *nobj); got_hash_final(&ctx, expected_sha1); remain = buf_len(buf) - buf_pos; if (remain < SHA1_DIGEST_LENGTH) { err = read_more_pack_stream(infd, buf, SHA1_DIGEST_LENGTH - remain); if (err) return err; } got_sha1_digest_to_str(expected_sha1, hex, sizeof(hex)); log_debug("expect SHA1: %s", hex); got_sha1_digest_to_str(buf_get(buf) + buf_pos, hex, sizeof(hex)); log_debug("actual SHA1: %s", hex); if (memcmp(buf_get(buf) + buf_pos, expected_sha1, SHA1_DIGEST_LENGTH) != 0) { err = got_error(GOT_ERR_PACKFILE_CSUM); goto done; } memcpy(sha1, expected_sha1, SHA1_DIGEST_LENGTH); w = write(outfd, expected_sha1, SHA1_DIGEST_LENGTH); if (w == -1) { err = got_error_from_errno("write"); goto done; } if (w != SHA1_DIGEST_LENGTH) { err = got_error(GOT_ERR_IO); goto done; } *outsize += SHA1_DIGEST_LENGTH; if (fsync(outfd) == -1) { err = got_error_from_errno("fsync"); goto done; } if (lseek(outfd, 0L, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } done: buf_free(buf); return err; } static const struct got_error * report_pack_status(const struct got_error *unpack_err) { const struct got_error *err = NULL; struct repo_write_client *client = &repo_write_client; struct gotd_imsg_packfile_status istatus; struct ibuf *wbuf; struct imsgbuf ibuf; const char *unpack_ok = "unpack ok\n"; size_t len; imsg_init(&ibuf, client->fd); if (unpack_err) istatus.reason_len = strlen(unpack_err->msg); else istatus.reason_len = strlen(unpack_ok); len = sizeof(istatus) + istatus.reason_len; wbuf = imsg_create(&ibuf, GOTD_IMSG_PACKFILE_STATUS, PROC_REPO_WRITE, repo_write.pid, len); if (wbuf == NULL) { err = got_error_from_errno("imsg_create PACKFILE_STATUS"); goto done; } if (imsg_add(wbuf, &istatus, sizeof(istatus)) == -1) { err = got_error_from_errno("imsg_add PACKFILE_STATUS"); goto done; } if (imsg_add(wbuf, err ? err->msg : unpack_ok, istatus.reason_len) == -1) { err = got_error_from_errno("imsg_add PACKFILE_STATUS"); goto done; } imsg_close(&ibuf, wbuf); err = gotd_imsg_flush(&ibuf); done: imsg_clear(&ibuf); return err; } static const struct got_error * recv_packfile(int *have_packfile, struct imsg *imsg) { const struct got_error *err = NULL, *unpack_err; struct repo_write_client *client = &repo_write_client; struct gotd_imsg_recv_packfile ireq; FILE *tempfiles[3] = { NULL, NULL, NULL }; struct repo_tempfile { int fd; int idx; } repo_tempfiles[3] = { { - 1, - 1 }, { - 1, - 1 }, { - 1, - 1 }, }; int i; size_t datalen; struct imsgbuf ibuf; struct got_ratelimit rl; struct got_pack *pack = NULL; off_t pack_filesize = 0; uint32_t nobj = 0; log_debug("packfile request received"); *have_packfile = 0; got_ratelimit_init(&rl, 2, 0); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ireq)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ireq, imsg->data, sizeof(ireq)); if (client->pack_pipe == -1 || client->packidx_fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); imsg_init(&ibuf, client->fd); pack = &client->pack; memset(pack, 0, sizeof(*pack)); pack->fd = imsg_get_fd(imsg); if (pack->fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); err = got_delta_cache_alloc(&pack->delta_cache); if (err) return err; for (i = 0; i < nitems(repo_tempfiles); i++) { struct repo_tempfile *t = &repo_tempfiles[i]; err = got_repo_temp_fds_get(&t->fd, &t->idx, repo_write.repo); if (err) goto done; } for (i = 0; i < nitems(tempfiles); i++) { int fd; FILE *f; fd = dup(repo_tempfiles[i].fd); if (fd == -1) { err = got_error_from_errno("dup"); goto done; } f = fdopen(fd, "w+"); if (f == NULL) { err = got_error_from_errno("fdopen"); close(fd); goto done; } tempfiles[i] = f; } err = gotd_imsg_flush(&ibuf); if (err) goto done; log_debug("receiving pack data"); unpack_err = recv_packdata(&pack_filesize, &nobj, client->pack_sha1, client->pack_pipe, pack->fd); if (ireq.report_status) { err = report_pack_status(unpack_err); if (err) { /* Git clients hang up after sending the pack file. */ if (err->code == GOT_ERR_EOF) err = NULL; } } if (unpack_err) err = unpack_err; if (err) goto done; log_debug("pack data received"); /* * Clients which are creating new references only will * send us an empty pack file. */ if (nobj == 0 && pack_filesize == sizeof(struct got_packfile_hdr) && client->nref_updates > 0 && client->nref_updates == client->nref_new) goto done; /* * Clients which are deleting references only will send * no pack file. */ if (nobj == 0 && client->nref_del > 0 && client->nref_updates == client->nref_del) goto done; /* * Clients which only move existing refs will send us an empty * pack file. All referenced objects must exist locally. */ if (nobj == 0 && pack_filesize == sizeof(struct got_packfile_hdr) && client->nref_move > 0 && client->nref_updates == client->nref_move) goto done; pack->filesize = pack_filesize; *have_packfile = 1; log_debug("begin indexing pack (%lld bytes in size)", (long long)pack->filesize); err = got_pack_index(pack, client->packidx_fd, tempfiles[0], tempfiles[1], tempfiles[2], client->pack_sha1, pack_index_progress, NULL, &rl); if (err) goto done; log_debug("done indexing pack"); if (fsync(client->packidx_fd) == -1) { err = got_error_from_errno("fsync"); goto done; } if (lseek(client->packidx_fd, 0L, SEEK_SET) == -1) err = got_error_from_errno("lseek"); done: if (close(client->pack_pipe) == -1 && err == NULL) err = got_error_from_errno("close"); client->pack_pipe = -1; for (i = 0; i < nitems(repo_tempfiles); i++) { struct repo_tempfile *t = &repo_tempfiles[i]; if (t->idx != -1) got_repo_temp_fds_put(t->idx, repo_write.repo); } for (i = 0; i < nitems(tempfiles); i++) { if (tempfiles[i] && fclose(tempfiles[i]) == EOF && err == NULL) err = got_error_from_errno("fclose"); } if (err) got_pack_close(pack); imsg_clear(&ibuf); return err; } static const struct got_error * verify_packfile(void) { const struct got_error *err = NULL, *close_err; struct repo_write_client *client = &repo_write_client; struct gotd_ref_update *ref_update; struct got_packidx *packidx = NULL; struct stat sb; char *id_str = NULL; struct got_object *obj = NULL; struct got_pathlist_entry *pe; char hex[SHA1_DIGEST_STRING_LENGTH]; if (STAILQ_EMPTY(&client->ref_updates)) { return got_error_msg(GOT_ERR_BAD_REQUEST, "cannot verify pack file without any ref-updates"); } if (client->pack.fd == -1) { return got_error_msg(GOT_ERR_BAD_REQUEST, "invalid pack file handle during pack verification"); } if (client->packidx_fd == -1) { return got_error_msg(GOT_ERR_BAD_REQUEST, "invalid pack index handle during pack verification"); } if (fstat(client->packidx_fd, &sb) == -1) return got_error_from_errno("pack index fstat"); packidx = malloc(sizeof(*packidx)); memset(packidx, 0, sizeof(*packidx)); packidx->fd = client->packidx_fd; client->packidx_fd = -1; packidx->len = sb.st_size; err = got_packidx_init_hdr(packidx, 1, client->pack.filesize); if (err) return err; STAILQ_FOREACH(ref_update, &client->ref_updates, entry) { if (ref_update->delete_ref) continue; TAILQ_FOREACH(pe, repo_write.protected_tag_namespaces, entry) { err = protect_tag_namespace(pe->path, &client->pack, packidx, ref_update); if (err) goto done; } /* * Objects which already exist in our repository need * not be present in the pack file. */ err = got_object_open(&obj, repo_write.repo, &ref_update->new_id); if (err && err->code != GOT_ERR_NO_OBJ) goto done; err = NULL; if (obj) { got_object_close(obj); obj = NULL; } else { int idx = got_packidx_get_object_idx(packidx, &ref_update->new_id); if (idx == -1) { got_object_id_hex(&ref_update->new_id, hex, sizeof(hex)); err = got_error_fmt(GOT_ERR_BAD_PACKFILE, "object %s is missing from pack file", hex); goto done; } } TAILQ_FOREACH(pe, repo_write.protected_branch_namespaces, entry) { err = protect_branch_namespace(pe->path, &client->pack, packidx, ref_update); if (err) goto done; } TAILQ_FOREACH(pe, repo_write.protected_branches, entry) { err = protect_branch(pe->path, &client->pack, packidx, ref_update); if (err) goto done; } } done: close_err = got_packidx_close(packidx); if (close_err && err == NULL) err = close_err; free(id_str); if (obj) got_object_close(obj); return err; } static const struct got_error * protect_refs_from_deletion(void) { const struct got_error *err = NULL; struct repo_write_client *client = &repo_write_client; struct gotd_ref_update *ref_update; struct got_pathlist_entry *pe; const char *refname; STAILQ_FOREACH(ref_update, &client->ref_updates, entry) { if (!ref_update->delete_ref) continue; refname = got_ref_get_name(ref_update->ref); TAILQ_FOREACH(pe, repo_write.protected_tag_namespaces, entry) { err = protect_ref_namespace(refname, pe->path); if (err) return err; } TAILQ_FOREACH(pe, repo_write.protected_branch_namespaces, entry) { err = protect_ref_namespace(refname, pe->path); if (err) return err; } TAILQ_FOREACH(pe, repo_write.protected_branches, entry) { if (strcmp(refname, pe->path) == 0) { return got_error_fmt(GOT_ERR_REF_PROTECTED, "%s", refname); } } } return NULL; } static const struct got_error * install_packfile(struct gotd_imsgev *iev) { struct repo_write_client *client = &repo_write_client; struct gotd_imsg_packfile_install inst; int ret; memset(&inst, 0, sizeof(inst)); memcpy(inst.pack_sha1, client->pack_sha1, SHA1_DIGEST_LENGTH); ret = gotd_imsg_compose_event(iev, GOTD_IMSG_PACKFILE_INSTALL, PROC_REPO_WRITE, -1, &inst, sizeof(inst)); if (ret == -1) return got_error_from_errno("imsg_compose PACKFILE_INSTALL"); return NULL; } static const struct got_error * send_ref_updates_start(int nref_updates, struct gotd_imsgev *iev) { struct gotd_imsg_ref_updates_start istart; int ret; memset(&istart, 0, sizeof(istart)); istart.nref_updates = nref_updates; ret = gotd_imsg_compose_event(iev, GOTD_IMSG_REF_UPDATES_START, PROC_REPO_WRITE, -1, &istart, sizeof(istart)); if (ret == -1) return got_error_from_errno("imsg_compose REF_UPDATES_START"); return NULL; } static const struct got_error * send_ref_update(struct gotd_ref_update *ref_update, struct gotd_imsgev *iev) { struct gotd_imsg_ref_update iref; const char *refname = got_ref_get_name(ref_update->ref); struct ibuf *wbuf; size_t len; memset(&iref, 0, sizeof(iref)); memcpy(iref.old_id, ref_update->old_id.sha1, SHA1_DIGEST_LENGTH); memcpy(iref.new_id, ref_update->new_id.sha1, SHA1_DIGEST_LENGTH); iref.ref_is_new = ref_update->ref_is_new; iref.delete_ref = ref_update->delete_ref; iref.name_len = strlen(refname); len = sizeof(iref) + iref.name_len; wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_REF_UPDATE, PROC_REPO_WRITE, repo_write.pid, len); if (wbuf == NULL) return got_error_from_errno("imsg_create REF_UPDATE"); if (imsg_add(wbuf, &iref, sizeof(iref)) == -1) return got_error_from_errno("imsg_add REF_UPDATE"); if (imsg_add(wbuf, refname, iref.name_len) == -1) return got_error_from_errno("imsg_add REF_UPDATE"); imsg_close(&iev->ibuf, wbuf); gotd_imsg_event_add(iev); return NULL; } static const struct got_error * update_refs(struct gotd_imsgev *iev) { const struct got_error *err = NULL; struct repo_write_client *client = &repo_write_client; struct gotd_ref_update *ref_update; err = send_ref_updates_start(client->nref_updates, iev); if (err) return err; STAILQ_FOREACH(ref_update, &client->ref_updates, entry) { err = send_ref_update(ref_update, iev); if (err) goto done; } done: return err; } static const struct got_error * receive_pack_pipe(struct imsg *imsg, struct gotd_imsgev *iev) { struct repo_write_client *client = &repo_write_client; size_t datalen; log_debug("receiving pack pipe descriptor"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); if (client->pack_pipe != -1) return got_error(GOT_ERR_PRIVSEP_MSG); client->pack_pipe = imsg_get_fd(imsg); if (client->pack_pipe == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); return NULL; } static const struct got_error * receive_pack_idx(struct imsg *imsg, struct gotd_imsgev *iev) { struct repo_write_client *client = &repo_write_client; size_t datalen; log_debug("receiving pack index output file"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); if (client->packidx_fd != -1) return got_error(GOT_ERR_PRIVSEP_MSG); client->packidx_fd = imsg_get_fd(imsg); if (client->packidx_fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); return NULL; } static const struct got_error * notify_removed_ref(const char *refname, struct got_object_id *id, struct gotd_imsgev *iev, int fd) { const struct got_error *err; char *id_str; err = got_object_id_str(&id_str, id); if (err) return err; dprintf(fd, "Removed %s: %s\n", refname, id_str); free(id_str); return err; } static const char * format_author(char *author) { char *smallerthan; smallerthan = strchr(author, '<'); if (smallerthan && smallerthan[1] != '\0') author = smallerthan + 1; author[strcspn(author, "@>")] = '\0'; return author; } static const struct got_error * print_commit_oneline(struct got_commit_object *commit, struct got_object_id *id, struct got_repository *repo, int fd) { const struct got_error *err = NULL; char *id_str = NULL, *logmsg0 = NULL; char *s, *nl; char *committer = NULL, *author = NULL; time_t committer_time; err = got_object_id_str(&id_str, id); if (err) return err; committer_time = got_object_commit_get_committer_time(commit); err = got_object_commit_get_logmsg(&logmsg0, commit); if (err) goto done; s = logmsg0; while (isspace((unsigned char)s[0])) s++; nl = strchr(s, '\n'); if (nl) { *nl = '\0'; } if (strcmp(got_object_commit_get_author(commit), got_object_commit_get_committer(commit)) != 0) { author = strdup(got_object_commit_get_author(commit)); if (author == NULL) { err = got_error_from_errno("strdup"); goto done; } dprintf(fd, "%lld %.7s %.8s %s\n", (long long)committer_time, id_str, format_author(author), s); } else { committer = strdup(got_object_commit_get_committer(commit)); dprintf(fd, "%lld %.7s %.8s %s\n", (long long)committer_time, id_str, format_author(committer), s); } if (fsync(fd) == -1 && err == NULL) err = got_error_from_errno("fsync"); done: free(id_str); free(logmsg0); free(committer); free(author); return err; } static const struct got_error * print_diffstat(struct got_diffstat_cb_arg *dsa, int fd) { struct got_pathlist_entry *pe; TAILQ_FOREACH(pe, dsa->paths, entry) { struct got_diff_changed_path *cp = pe->data; int pad = dsa->max_path_len - pe->path_len + 1; dprintf(fd, " %c %s%*c | %*d+ %*d-\n", cp->status, pe->path, pad, ' ', dsa->add_cols + 1, cp->add, dsa->rm_cols + 1, cp->rm); } dprintf(fd, "\n%d file%s changed, %d insertion%s(+), %d deletion%s(-)\n\n", dsa->nfiles, dsa->nfiles > 1 ? "s" : "", dsa->ins, dsa->ins != 1 ? "s" : "", dsa->del, dsa->del != 1 ? "s" : ""); return NULL; } static const struct got_error * print_commit(struct got_commit_object *commit, struct got_object_id *id, struct got_repository *repo, struct got_pathlist_head *changed_paths, struct got_diffstat_cb_arg *diffstat, int fd) { const struct got_error *err = NULL; char *id_str, *logmsg0, *logmsg, *line; time_t committer_time; const char *author, *committer; err = got_object_id_str(&id_str, id); if (err) return err; dprintf(fd, "commit %s\n", id_str); free(id_str); id_str = NULL; dprintf(fd, "from: %s\n", got_object_commit_get_author(commit)); author = got_object_commit_get_author(commit); committer = got_object_commit_get_committer(commit); if (strcmp(author, committer) != 0) dprintf(fd, "via: %s\n", committer); committer_time = got_object_commit_get_committer_time(commit); dprintf(fd, "date: %lld\n", (long long)committer_time); if (got_object_commit_get_nparents(commit) > 1) { const struct got_object_id_queue *parent_ids; struct got_object_qid *qid; int n = 1; parent_ids = got_object_commit_get_parent_ids(commit); STAILQ_FOREACH(qid, parent_ids, entry) { err = got_object_id_str(&id_str, &qid->id); if (err) goto done; dprintf(fd, "parent %d: %s\n", n++, id_str); free(id_str); id_str = NULL; } } err = got_object_commit_get_logmsg(&logmsg0, commit); if (err) goto done; dprintf(fd, "messagelen: %zu\n", strlen(logmsg0)); logmsg = logmsg0; do { line = strsep(&logmsg, "\n"); if (line) dprintf(fd, " %s\n", line); } while (line); free(logmsg0); err = print_diffstat(diffstat, fd); if (err) goto done; if (fsync(fd) == -1 && err == NULL) err = got_error_from_errno("fsync"); done: free(id_str); return err; } static const struct got_error * get_changed_paths(struct got_pathlist_head *paths, struct got_commit_object *commit, struct got_repository *repo, struct got_diffstat_cb_arg *dsa) { const struct got_error *err = NULL; struct got_object_id *tree_id1 = NULL, *tree_id2 = NULL; struct got_tree_object *tree1 = NULL, *tree2 = NULL; struct got_object_qid *qid; got_diff_blob_cb cb = got_diff_tree_collect_changed_paths; FILE *f1 = repo_write.diff.f1, *f2 = repo_write.diff.f2; int fd1 = repo_write.diff.fd1, fd2 = repo_write.diff.fd2; if (dsa) cb = got_diff_tree_compute_diffstat; err = got_opentemp_truncate(f1); if (err) return err; err = got_opentemp_truncate(f2); if (err) return err; err = got_opentemp_truncatefd(fd1); if (err) return err; err = got_opentemp_truncatefd(fd2); if (err) return err; qid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); if (qid != NULL) { struct got_commit_object *pcommit; err = got_object_open_as_commit(&pcommit, repo, &qid->id); if (err) return err; tree_id1 = got_object_id_dup( got_object_commit_get_tree_id(pcommit)); if (tree_id1 == NULL) { got_object_commit_close(pcommit); return got_error_from_errno("got_object_id_dup"); } got_object_commit_close(pcommit); } if (tree_id1) { err = got_object_open_as_tree(&tree1, repo, tree_id1); if (err) goto done; } tree_id2 = got_object_commit_get_tree_id(commit); err = got_object_open_as_tree(&tree2, repo, tree_id2); if (err) goto done; err = got_diff_tree(tree1, tree2, f1, f2, fd1, fd2, "", "", repo, cb, dsa ? (void *)dsa : paths, dsa ? 1 : 0); done: if (tree1) got_object_tree_close(tree1); if (tree2) got_object_tree_close(tree2); free(tree_id1); return err; } static const struct got_error * print_commits(struct got_object_id *root_id, struct got_object_id *end_id, struct got_repository *repo, int fd) { const struct got_error *err; struct got_commit_graph *graph; struct got_object_id_queue reversed_commits; struct got_object_qid *qid; struct got_commit_object *commit = NULL; struct got_pathlist_head changed_paths; int ncommits = 0; const int shortlog_threshold = 50; STAILQ_INIT(&reversed_commits); TAILQ_INIT(&changed_paths); /* XXX first-parent only for now */ err = got_commit_graph_open(&graph, "/", 1); if (err) return err; err = got_commit_graph_bfsort(graph, root_id, repo, check_cancelled, NULL); if (err) goto done; for (;;) { struct got_object_id id; err = got_commit_graph_iter_next(&id, graph, repo, check_cancelled, NULL); if (err) { if (err->code == GOT_ERR_ITER_COMPLETED) err = NULL; break; } err = got_object_open_as_commit(&commit, repo, &id); if (err) break; if (end_id && got_object_id_cmp(&id, end_id) == 0) break; err = got_object_qid_alloc(&qid, &id); if (err) break; STAILQ_INSERT_HEAD(&reversed_commits, qid, entry); ncommits++; got_object_commit_close(commit); if (end_id == NULL) break; } STAILQ_FOREACH(qid, &reversed_commits, entry) { struct got_diffstat_cb_arg dsa = { 0, 0, 0, 0, 0, 0, &changed_paths, 0, 0, GOT_DIFF_ALGORITHM_PATIENCE }; err = got_object_open_as_commit(&commit, repo, &qid->id); if (err) break; if (ncommits > shortlog_threshold) { err = print_commit_oneline(commit, &qid->id, repo, fd); if (err) break; } else { err = get_changed_paths(&changed_paths, commit, repo, &dsa); if (err) break; err = print_commit(commit, &qid->id, repo, &changed_paths, &dsa, fd); } got_object_commit_close(commit); commit = NULL; got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL); } done: if (commit) got_object_commit_close(commit); while (!STAILQ_EMPTY(&reversed_commits)) { qid = STAILQ_FIRST(&reversed_commits); STAILQ_REMOVE_HEAD(&reversed_commits, entry); got_object_qid_free(qid); } got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL); got_commit_graph_close(graph); return err; } static const struct got_error * print_tag(struct got_object_id *id, const char *refname, struct got_repository *repo, int fd) { const struct got_error *err = NULL; struct got_tag_object *tag = NULL; const char *tagger = NULL; char *id_str = NULL, *tagmsg0 = NULL, *tagmsg, *line; time_t tagger_time; err = got_object_open_as_tag(&tag, repo, id); if (err) return err; tagger = got_object_tag_get_tagger(tag); tagger_time = got_object_tag_get_tagger_time(tag); err = got_object_id_str(&id_str, got_object_tag_get_object_id(tag)); if (err) goto done; dprintf(fd, "tag %s\n", refname); dprintf(fd, "from: %s\n", tagger); dprintf(fd, "date: %lld\n", (long long)tagger_time); switch (got_object_tag_get_object_type(tag)) { case GOT_OBJ_TYPE_BLOB: dprintf(fd, "object: %s %s\n", GOT_OBJ_LABEL_BLOB, id_str); break; case GOT_OBJ_TYPE_TREE: dprintf(fd, "object: %s %s\n", GOT_OBJ_LABEL_TREE, id_str); break; case GOT_OBJ_TYPE_COMMIT: dprintf(fd, "object: %s %s\n", GOT_OBJ_LABEL_COMMIT, id_str); break; case GOT_OBJ_TYPE_TAG: dprintf(fd, "object: %s %s\n", GOT_OBJ_LABEL_TAG, id_str); break; default: break; } tagmsg0 = strdup(got_object_tag_get_message(tag)); if (tagmsg0 == NULL) { err = got_error_from_errno("strdup"); goto done; } dprintf(fd, "messagelen: %zu\n", strlen(tagmsg0)); tagmsg = tagmsg0; do { line = strsep(&tagmsg, "\n"); if (line) dprintf(fd, " %s\n", line); } while (line); free(tagmsg0); done: if (tag) got_object_tag_close(tag); free(id_str); return err; } static const struct got_error * notify_changed_ref(const char *refname, struct got_object_id *old_id, struct got_object_id *new_id, struct gotd_imsgev *iev, int fd) { const struct got_error *err; int old_obj_type, new_obj_type; const char *label; char *new_id_str = NULL; err = got_object_get_type(&old_obj_type, repo_write.repo, old_id); if (err) return err; err = got_object_get_type(&new_obj_type, repo_write.repo, new_id); if (err) return err; switch (new_obj_type) { case GOT_OBJ_TYPE_COMMIT: err = print_commits(new_id, old_obj_type == GOT_OBJ_TYPE_COMMIT ? old_id : NULL, repo_write.repo, fd); break; case GOT_OBJ_TYPE_TAG: err = print_tag(new_id, refname, repo_write.repo, fd); break; default: err = got_object_type_label(&label, new_obj_type); if (err) goto done; err = got_object_id_str(&new_id_str, new_id); if (err) goto done; dprintf(fd, "%s: %s object %s\n", refname, label, new_id_str); break; } done: free(new_id_str); return err; } static const struct got_error * notify_created_ref(const char *refname, struct got_object_id *id, struct gotd_imsgev *iev, int fd) { const struct got_error *err; int obj_type; err = got_object_get_type(&obj_type, repo_write.repo, id); if (err) return err; if (obj_type == GOT_OBJ_TYPE_TAG) return print_tag(id, refname, repo_write.repo, fd); return print_commits(id, NULL, repo_write.repo, fd); } static const struct got_error * render_notification(struct imsg *imsg, struct gotd_imsgev *iev) { const struct got_error *err = NULL; struct gotd_imsg_notification_content ireq; size_t datalen, len; char *refname = NULL; struct ibuf *wbuf; int fd = -1; fd = imsg_get_fd(imsg); if (fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(ireq)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&ireq, imsg->data, sizeof(ireq)); if (datalen != sizeof(ireq) + ireq.refname_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } refname = strndup(imsg->data + sizeof(ireq), ireq.refname_len); if (refname == NULL) { err = got_error_from_errno("strndup"); goto done; } switch (ireq.action) { case GOTD_NOTIF_ACTION_CREATED: err = notify_created_ref(refname, &ireq.new_id, iev, fd); break; case GOTD_NOTIF_ACTION_REMOVED: err = notify_removed_ref(refname, &ireq.old_id, iev, fd); break; case GOTD_NOTIF_ACTION_CHANGED: err = notify_changed_ref(refname, &ireq.old_id, &ireq.new_id, iev, fd); break; } if (err != NULL) goto done; if (fsync(fd) == -1) { err = got_error_from_errno("fsync"); goto done; } len = sizeof(ireq) + ireq.refname_len; wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_NOTIFY, PROC_REPO_WRITE, repo_write.pid, len); if (wbuf == NULL) { err = got_error_from_errno("imsg_create REF"); goto done; } if (imsg_add(wbuf, &ireq, sizeof(ireq)) == -1) { err = got_error_from_errno("imsg_add NOTIFY"); goto done; } if (imsg_add(wbuf, refname, ireq.refname_len) == -1) { err = got_error_from_errno("imsg_add NOTIFY"); goto done; } imsg_close(&iev->ibuf, wbuf); gotd_imsg_event_add(iev); done: free(refname); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); return err; } static void repo_write_dispatch_session(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; struct repo_write_client *client = &repo_write_client; ssize_t n; int shut = 0, have_packfile = 0; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) /* Connection closed. */ shut = 1; } if (event & EV_WRITE) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno != EAGAIN) fatal("msgbuf_write"); if (n == 0) /* Connection closed. */ shut = 1; } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; if (imsg.hdr.type != GOTD_IMSG_LIST_REFS_INTERNAL && !repo_write.refs_listed) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } switch (imsg.hdr.type) { case GOTD_IMSG_LIST_REFS_INTERNAL: err = list_refs(&imsg); if (err) log_warnx("ls-refs: %s", err->msg); break; case GOTD_IMSG_REF_UPDATE: err = recv_ref_update(&imsg); if (err) log_warnx("ref-update: %s", err->msg); break; case GOTD_IMSG_PACKFILE_PIPE: err = receive_pack_pipe(&imsg, iev); if (err) { log_warnx("receiving pack pipe: %s", err->msg); break; } break; case GOTD_IMSG_PACKIDX_FILE: err = receive_pack_idx(&imsg, iev); if (err) { log_warnx("receiving pack index: %s", err->msg); break; } break; case GOTD_IMSG_RECV_PACKFILE: err = protect_refs_from_deletion(); if (err) break; err = recv_packfile(&have_packfile, &imsg); if (err) { log_warnx("receive packfile: %s", err->msg); break; } if (have_packfile) { err = verify_packfile(); if (err) { log_warnx("verify packfile: %s", err->msg); break; } err = install_packfile(iev); if (err) { log_warnx("install packfile: %s", err->msg); break; } /* * Ensure we re-read the pack index list * upon next access. */ repo_write.repo->pack_path_mtime.tv_sec = 0; repo_write.repo->pack_path_mtime.tv_nsec = 0; } err = update_refs(iev); if (err) { log_warnx("update refs: %s", err->msg); } break; case GOTD_IMSG_NOTIFY: err = render_notification(&imsg, iev); if (err) { log_warnx("render notification: %s", err->msg); shut = 1; } break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } if (!shut && check_cancelled(NULL) == NULL) { if (err && gotd_imsg_send_error_event(iev, PROC_REPO_WRITE, client->id, err) == -1) { log_warnx("could not send error to parent: %s", err->msg); } gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } static const struct got_error * recv_connect(struct imsg *imsg) { struct gotd_imsgev *iev = &repo_write.session_iev; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); if (repo_write.session_fd != -1) return got_error(GOT_ERR_PRIVSEP_MSG); repo_write.session_fd = imsg_get_fd(imsg); if (repo_write.session_fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); imsg_init(&iev->ibuf, repo_write.session_fd); iev->handler = repo_write_dispatch_session; iev->events = EV_READ; iev->handler_arg = NULL; event_set(&iev->ev, iev->ibuf.fd, EV_READ, repo_write_dispatch_session, iev); gotd_imsg_event_add(iev); return NULL; } static void repo_write_dispatch(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; ssize_t n; int shut = 0; struct repo_write_client *client = &repo_write_client; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) /* Connection closed. */ shut = 1; } if (event & EV_WRITE) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno != EAGAIN) fatal("msgbuf_write"); if (n == 0) /* Connection closed. */ shut = 1; } while (err == NULL && check_cancelled(NULL) == NULL) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_CONNECT_REPO_CHILD: err = recv_connect(&imsg); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } if (!shut && check_cancelled(NULL) == NULL) { if (err && gotd_imsg_send_error_event(iev, PROC_REPO_WRITE, client->id, err) == -1) { log_warnx("could not send error to parent: %s", err->msg); } gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void repo_write_main(const char *title, const char *repo_path, int *pack_fds, int *temp_fds, FILE *diff_f1, FILE *diff_f2, int diff_fd1, int diff_fd2, struct got_pathlist_head *protected_tag_namespaces, struct got_pathlist_head *protected_branch_namespaces, struct got_pathlist_head *protected_branches) { const struct got_error *err = NULL; struct repo_write_client *client = &repo_write_client; struct gotd_imsgev iev; client->fd = -1; client->pack_pipe = -1; client->packidx_fd = -1; client->pack.fd = -1; repo_write.title = title; repo_write.pid = getpid(); repo_write.pack_fds = pack_fds; repo_write.temp_fds = temp_fds; repo_write.session_fd = -1; repo_write.session_iev.ibuf.fd = -1; repo_write.protected_tag_namespaces = protected_tag_namespaces; repo_write.protected_branch_namespaces = protected_branch_namespaces; repo_write.protected_branches = protected_branches; repo_write.diff.f1 = diff_f1; repo_write.diff.f2 = diff_f2; repo_write.diff.fd1 = diff_fd1; repo_write.diff.fd2 = diff_fd2; STAILQ_INIT(&repo_write_client.ref_updates); err = got_repo_open(&repo_write.repo, repo_path, NULL, pack_fds); if (err) goto done; if (!got_repo_is_bare(repo_write.repo)) { err = got_error_msg(GOT_ERR_NOT_GIT_REPO, "bare git repository required"); goto done; } got_repo_temp_fds_set(repo_write.repo, temp_fds); signal(SIGINT, catch_sigint); signal(SIGTERM, catch_sigterm); signal(SIGPIPE, SIG_IGN); signal(SIGHUP, SIG_IGN); imsg_init(&iev.ibuf, GOTD_FILENO_MSG_PIPE); iev.handler = repo_write_dispatch; iev.events = EV_READ; iev.handler_arg = NULL; event_set(&iev.ev, iev.ibuf.fd, EV_READ, repo_write_dispatch, &iev); if (gotd_imsg_compose_event(&iev, GOTD_IMSG_REPO_CHILD_READY, PROC_REPO_WRITE, -1, NULL, 0) == -1) { err = got_error_from_errno("imsg compose REPO_CHILD_READY"); goto done; } event_dispatch(); done: if (fclose(diff_f1) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (fclose(diff_f2) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (close(diff_fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (close(diff_fd2) == -1 && err == NULL) err = got_error_from_errno("close"); if (err) log_warnx("%s: %s", title, err->msg); repo_write_shutdown(); } void repo_write_shutdown(void) { struct repo_write_client *client = &repo_write_client; struct gotd_ref_update *ref_update; log_debug("%s: shutting down", repo_write.title); while (!STAILQ_EMPTY(&client->ref_updates)) { ref_update = STAILQ_FIRST(&client->ref_updates); STAILQ_REMOVE_HEAD(&client->ref_updates, entry); got_ref_close(ref_update->ref); free(ref_update); } got_pack_close(&client->pack); if (client->fd != -1) close(client->fd); if (client->pack_pipe != -1) close(client->pack_pipe); if (client->packidx_fd != -1) close(client->packidx_fd); if (repo_write.repo) got_repo_close(repo_write.repo); got_repo_pack_fds_close(repo_write.pack_fds); got_repo_temp_fds_close(repo_write.temp_fds); if (repo_write.session_fd != -1) close(repo_write.session_fd); exit(0); } got-portable-0.101/gotd/imsg.c0000664000175100017510000001126614644144735011661 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_lib_poll.h" #include "gotd.h" const struct got_error * gotd_imsg_recv_error(uint32_t *client_id, struct imsg *imsg) { struct gotd_imsg_error ierr; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ierr)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ierr, imsg->data, sizeof(ierr)); if (client_id) *client_id = ierr.client_id; if (ierr.code == GOT_ERR_ERRNO) errno = ierr.errno_code; return got_error_msg(ierr.code, ierr.msg); } const struct got_error * gotd_imsg_flush(struct imsgbuf *ibuf) { const struct got_error *err = NULL; while (ibuf->w.queued > 0) { err = got_poll_fd(ibuf->fd, POLLOUT, INFTIM); if (err) break; if (imsg_flush(ibuf) == -1) { if (errno != EAGAIN) { imsg_clear(ibuf); err = got_error_from_errno("imsg_flush"); break; } } } return err; } const struct got_error * gotd_imsg_recv(struct imsg *imsg, struct imsgbuf *ibuf, size_t min_datalen) { ssize_t n; n = imsg_get(ibuf, imsg); if (n == -1) return got_error_from_errno("imsg_get"); if (n == 0) { n = imsg_read(ibuf); if (n == -1) { if (errno == EAGAIN) return got_error(GOT_ERR_PRIVSEP_READ); return got_error_from_errno("imsg_read"); } if (n == 0) return got_error(GOT_ERR_EOF); n = imsg_get(ibuf, imsg); if (n == -1) return got_error_from_errno("imsg_get"); } if (imsg->hdr.len < IMSG_HEADER_SIZE + min_datalen) return got_error(GOT_ERR_PRIVSEP_LEN); return NULL; } const struct got_error * gotd_imsg_poll_recv(struct imsg *imsg, struct imsgbuf *ibuf, size_t min_datalen) { const struct got_error *err = NULL; for (;;) { err = gotd_imsg_recv(imsg, ibuf, min_datalen); if (err == NULL || err->code != GOT_ERR_PRIVSEP_READ) return err; err = got_poll_fd(ibuf->fd, POLLIN, INFTIM); if (err) break; } return err; } int gotd_imsg_send_error(struct imsgbuf *ibuf, uint32_t peerid, uint32_t client_id, const struct got_error *err) { const struct got_error *flush_err; struct gotd_imsg_error ierr; int ret; ierr.code = err->code; if (err->code == GOT_ERR_ERRNO) ierr.errno_code = errno; else ierr.errno_code = 0; ierr.client_id = client_id; strlcpy(ierr.msg, err->msg, sizeof(ierr.msg)); ret = imsg_compose(ibuf, GOTD_IMSG_ERROR, peerid, getpid(), -1, &ierr, sizeof(ierr)); if (ret == -1) return -1; flush_err = gotd_imsg_flush(ibuf); if (flush_err) return -1; return 0; } int gotd_imsg_send_error_event(struct gotd_imsgev *iev, uint32_t peerid, uint32_t client_id, const struct got_error *err) { struct gotd_imsg_error ierr; int ret; ierr.code = err->code; if (err->code == GOT_ERR_ERRNO) ierr.errno_code = errno; else ierr.errno_code = 0; ierr.client_id = client_id; strlcpy(ierr.msg, err->msg, sizeof(ierr.msg)); ret = gotd_imsg_compose_event(iev, GOTD_IMSG_ERROR, peerid, -1, &ierr, sizeof(ierr)); if (ret == -1) return -1; return 0; } void gotd_imsg_event_add(struct gotd_imsgev *iev) { iev->events = EV_READ; if (iev->ibuf.w.queued) iev->events |= EV_WRITE; event_del(&iev->ev); event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); event_add(&iev->ev, NULL); } int gotd_imsg_compose_event(struct gotd_imsgev *iev, uint16_t type, uint32_t peerid, int fd, void *data, uint16_t datalen) { int ret; ret = imsg_compose(&iev->ibuf, type, peerid, getpid(), fd, data, datalen); if (ret != -1) gotd_imsg_event_add(iev); return ret; } int gotd_imsg_forward(struct gotd_imsgev *iev, struct imsg *imsg, int fd) { return gotd_imsg_compose_event(iev, imsg->hdr.type, imsg->hdr.peerid, fd, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); } got-portable-0.101/gotd/session_write.h0000664000175100017510000000161514644143163013613 /* * Copyright (c) 2022, 2023 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void session_write_main(const char *, const char *, int *, int *, struct timeval *, struct gotd_repo *); got-portable-0.101/gotd/libexec/0000775000175100017510000000000014644145570012241 5got-portable-0.101/gotd/libexec/Makefile.am0000664000175100017510000000005314644144735014215 SUBDIRS = got-notify-email got-notify-http got-portable-0.101/gotd/libexec/got-notify-http/0000775000175100017510000000000014644145570015315 5got-portable-0.101/gotd/libexec/got-notify-http/Makefile.am0000664000175100017510000000125114644144735017272 libexec_PROGRAMS = got-notify-http include $(top_builddir)/Makefile.common EXTRA_DIST = utf8d.h got_notify_http_SOURCES = got-notify-http.c \ $(top_srcdir)/lib/bufio.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/log.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pollfd.c got_notify_http_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(libtls_LIBS) if HOST_FREEBSD LDADD += -lmd endif if HOST_OPENBSD LDADD += -ltls endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) $(libtls_CFLAGS) got-portable-0.101/gotd/libexec/got-notify-http/utf8d.h0000664000175100017510000000513714644143163016442 /* * Copyright (c) 2008-2009 Bjoern Hoehrmann * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ // See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. #define UTF8_ACCEPT 0 #define UTF8_REJECT 1 static const uint8_t utf8d[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8 }; static uint32_t inline decode(uint32_t* state, uint32_t* codep, uint32_t byte) { uint32_t type = utf8d[byte]; *codep = (*state != UTF8_ACCEPT) ? (byte & 0x3fu) | (*codep << 6) : (0xff >> type) & (byte); *state = utf8d[256 + *state*16 + type]; return *state; } got-portable-0.101/gotd/libexec/got-notify-http/got-notify-http.c0000664000175100017510000005316314644144735020467 /* * Copyright (c) 2024 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_opentemp.h" #include "got_version.h" #include "bufio.h" #include "log.h" #include "utf8d.h" #define USERAGENT "got-notify-http/" GOT_VERSION_STR static int http_timeout = 300; /* 5 minutes in seconds */ __dead static void usage(void) { fprintf(stderr, "usage: %s [-c] -r repo -h host -p port -u user path\n", getprogname()); exit(1); } static int dial(const char *host, const char *port) { struct addrinfo hints, *res, *res0; const char *cause = NULL; int s, error, save_errno; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; error = getaddrinfo(host, port, &hints, &res0); if (error) errx(1, "failed to resolve %s:%s: %s", host, port, gai_strerror(error)); s = -1; for (res = res0; res; res = res->ai_next) { s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s == -1) { cause = "socket"; continue; } if (connect(s, res->ai_addr, res->ai_addrlen) == -1) { cause = "connect"; save_errno = errno; close(s); errno = save_errno; s = -1; continue; } break; } freeaddrinfo(res0); if (s == -1) fatal("%s %s:%s", cause, host, port); return s; } static void escape(FILE *fp, const uint8_t *s) { uint32_t codepoint, state; const uint8_t *start = s; state = 0; for (; *s; ++s) { switch (decode(&state, &codepoint, *s)) { case UTF8_ACCEPT: switch (codepoint) { case '"': case '\\': fprintf(fp, "\\%c", *s); break; case '\b': fprintf(fp, "\\b"); break; case '\f': fprintf(fp, "\\f"); break; case '\n': fprintf(fp, "\\n"); break; case '\r': fprintf(fp, "\\r"); break; case '\t': fprintf(fp, "\\t"); break; default: /* other control characters */ if (codepoint < ' ' || codepoint == 0x7F) { fprintf(fp, "\\u%04x", codepoint); break; } fwrite(start, 1, s - start + 1, fp); break; } start = s + 1; break; case UTF8_REJECT: /* bad UTF-8 sequence; try to recover */ fputs("\\uFFFD", fp); state = UTF8_ACCEPT; start = s + 1; break; } } } static void json_field(FILE *fp, const char *key, const char *val, int comma) { fprintf(fp, "\"%s\":\"", key); escape(fp, val); fprintf(fp, "\"%s", comma ? "," : ""); } static void json_date(FILE *fp, const char *key, const char *date, int comma) { fprintf(fp, "\"%s\":%s%s", key, date, comma ? "," : ""); } static void json_author(FILE *fp, const char *type, char *address, int comma) { char *gt, *lt, *at, *email, *endname; fprintf(fp, "\"%s\":{", type); gt = strchr(address, '<'); if (gt != NULL) { /* long format, e.g. "Omar Polo " */ json_field(fp, "full", address, 1); endname = gt; while (endname > address && endname[-1] == ' ') endname--; *endname = '\0'; json_field(fp, "name", address, 1); email = gt + 1; lt = strchr(email, '>'); if (lt) *lt = '\0'; json_field(fp, "mail", email, 1); at = strchr(email, '@'); if (at) *at = '\0'; json_field(fp, "user", email, 0); } else { /* short format only shows the username */ json_field(fp, "user", address, 0); } fprintf(fp, "}%s", comma ? "," : ""); } static int jsonify_branch_rm(FILE *fp, char *line, const char *repo, const char *user) { char *ref, *id; line = strchr(line, ' '); if (line == NULL) errx(1, "invalid branch rm line"); line += strspn(line, " "); ref = line; line = strchr(line, ':'); if (line == NULL) errx(1, "invalid branch rm line"); *line++ = '\0'; id = line + strspn(line, " "); fputc('{', fp); json_field(fp, "type", "branch-deleted", 1); json_field(fp, "repo", repo, 1); json_field(fp, "authenticated_user", user, 1); json_field(fp, "ref", ref, 1); json_field(fp, "id", id, 0); fputc('}', fp); return 0; } static int jsonify_commit_short(FILE *fp, char *line, const char *repo, const char *user) { char *t, *date, *id, *author, *message; t = line; date = t; if ((t = strchr(t, ' ')) == NULL) errx(1, "malformed line"); *t++ = '\0'; id = t; if ((t = strchr(t, ' ')) == NULL) errx(1, "malformed line"); *t++ = '\0'; author = t; if ((t = strchr(t, ' ')) == NULL) errx(1, "malformed line"); *t++ = '\0'; message = t; fprintf(fp, "{\"type\":\"commit\",\"short\":true,"); json_field(fp, "repo", repo, 1); json_field(fp, "authenticated_user", user, 1); json_field(fp, "id", id, 1); json_author(fp, "committer", author, 1); json_date(fp, "date", date, 1); json_field(fp, "short_message", message, 0); fprintf(fp, "}"); return 0; } static int jsonify_commit(FILE *fp, const char *repo, const char *user, char **line, ssize_t *linesize) { const char *errstr; char *author = NULL; char *filename, *t; char *l; ssize_t linelen; int parent = 0; int msglen = 0, msgwrote = 0; int n, files = 0; int done = 0; enum { P_FROM, P_VIA, P_DATE, P_PARENT, P_MSGLEN, P_MSG, P_DST, P_SUM, } phase = P_FROM; l = *line; if (strncmp(l, "commit ", 7) != 0) errx(1, "%s: unexpected line: %s", __func__, l); l += 7; fprintf(fp, "{\"type\":\"commit\",\"short\":false,"); json_field(fp, "repo", repo, 1); json_field(fp, "authenticated_user", user, 1); json_field(fp, "id", l, 1); while (!done) { if ((linelen = getline(line, linesize, stdin)) == -1) break; if ((*line)[linelen - 1] == '\n') (*line)[--linelen] = '\0'; l = *line; switch (phase) { case P_FROM: if (strncmp(l, "from: ", 6) != 0) errx(1, "unexpected from line"); l += 6; author = strdup(l); if (author == NULL) fatal("strdup"); json_author(fp, "author", l, 1); phase = P_VIA; break; case P_VIA: /* optional */ if (!strncmp(l, "via: ", 5)) { l += 5; json_author(fp, "committer", l, 1); phase = P_DATE; break; } if (author == NULL) /* impossible */ fatalx("from not specified"); json_author(fp, "committer", author, 1); free(author); author = NULL; phase = P_DATE; /* fallthrough */ case P_DATE: /* optional */ if (!strncmp(l, "date: ", 6)) { l += 6; json_date(fp, "date", l, 1); phase = P_PARENT; break; } phase = P_PARENT; /* fallthough */ case P_PARENT: /* optional - more than one */ if (!strncmp(l, "parent ", 7)) { l += 7; l += strcspn(l, ":"); l += strspn(l, " "); if (parent == 0) { parent = 1; fprintf(fp, "\"parents\":["); } fputc('"', fp); escape(fp, l); fputc('"', fp); break; } if (parent != 0) { fprintf(fp, "],"); parent = 0; } phase = P_MSGLEN; /* fallthrough */ case P_MSGLEN: if (strncmp(l, "messagelen: ", 12) != 0) errx(1, "unexpected messagelen line"); l += 12; msglen = strtonum(l, 1, INT_MAX, &errstr); if (errstr) errx(1, "message len is %s: %s", errstr, l); msglen++; phase = P_MSG; break; case P_MSG: /* * The commit message is indented with one extra * space which is not accounted for in messagelen, * but we also strip the trailing \n so that * accounts for it. * * Since we read line-by-line and there is always * a \n added at the end of the message, * tolerate one byte less than advertised. */ if (*l != ' ') errx(1, "unexpected line in commit message"); l++; /* skip leading space */ linelen--; if (msgwrote == 0 && linelen != 0) { json_field(fp, "short_message", l, 1); fprintf(fp, "\"message\":\""); escape(fp, l); escape(fp, "\n"); msgwrote += linelen; } else if (msgwrote != 0) { escape(fp, l); escape(fp, "\n"); } msglen -= linelen + 1; if (msglen <= 1) { fprintf(fp, "\","); phase = P_DST; break; } break; case P_DST: if (files == 0 && !strcmp(l, " ")) break; if (files == 0) fputs("\"diffstat\":{\"files\":[", fp); if (*l == '\0') { fputs("],", fp); phase = P_SUM; break; } if (*l != ' ') errx(1, "bad diffstat line"); l++; if (files != 0) fputc(',', fp); fputc('{', fp); switch (*l) { case 'A': json_field(fp, "action", "added", 1); break; case 'D': json_field(fp, "action", "deleted", 1); break; case 'M': json_field(fp, "action", "modified", 1); break; case 'm': json_field(fp, "action", "mode changed", 1); break; default: json_field(fp, "action", "unknown", 1); break; } l++; while (*l == ' ') *l++ = '\0'; if (*l == '\0') errx(1, "invalid diffstat: no filename"); filename = l; l = strrchr(l, '|'); if (l == NULL) errx(1, "invalid diffstat: no separator"); t = l - 1; while (t > filename && *t == ' ') *t-- = '\0'; json_field(fp, "file", filename, 1); l++; while (*l == ' ') l++; t = strchr(l, '+'); if (t == NULL) errx(1, "invalid diffstat: no added counter"); *t++ = '\0'; n = strtonum(l, 0, INT_MAX, &errstr); if (errstr) errx(1, "added counter is %s: %s", errstr, l); fprintf(fp, "\"added\":%d,", n); l = ++t; while (*l == ' ') l++; t = strchr(l, '-'); if (t == NULL) errx(1, "invalid diffstat: no del counter"); *t = '\0'; n = strtonum(l, 0, INT_MAX, &errstr); if (errstr) errx(1, "del counter is %s: %s", errstr, l); fprintf(fp, "\"removed\":%d", n); fputc('}', fp); files++; break; case P_SUM: fputs("\"total\":{", fp); t = l; l = strchr(l, ' '); if (l == NULL) errx(1, "missing number of additions"); *l++ = '\0'; n = strtonum(t, 0, INT_MAX, &errstr); if (errstr) errx(1, "add counter is %s: %s", errstr, t); fprintf(fp, "\"added\":%d,", n); l = strchr(l, ','); if (l == NULL) errx(1, "missing number of deletions"); l++; while (*l == ' ') l++; t = strchr(l, ' '); if (t == NULL) errx(1, "malformed diffstat sum line"); *t = '\0'; n = strtonum(l, 0, INT_MAX, &errstr); if (errstr) errx(1, "del counter is %s: %s", errstr, l); fprintf(fp, "\"removed\":%d", n); fputs("}}", fp); done = 1; break; default: /* unreachable */ errx(1, "unexpected line: %s", *line); } } if (ferror(stdin)) fatalx("getline"); if (!done) fatalx("%s: unexpected EOF", __func__); fputc('}', fp); return 0; } static int jsonify_tag(FILE *fp, const char *repo, const char *user, char **line, ssize_t *linesize) { const char *errstr; char *l; ssize_t linelen; int msglen = 0, msgwrote = 0; int done = 0; enum { P_FROM, P_DATE, P_OBJECT, P_MSGLEN, P_MSG, } phase = P_FROM; l = *line; if (strncmp(l, "tag ", 4) != 0) errx(1, "%s: unexpected line: %s", __func__, l); l += 4; fputc('{', fp); json_field(fp, "type", "tag", 1); json_field(fp, "repo", repo, 1); json_field(fp, "authenticated_user", user, 1); json_field(fp, "tag", l, 1); while (!done) { if ((linelen = getline(line, linesize, stdin)) == -1) break; if ((*line)[linelen - 1] == '\n') (*line)[--linelen] = '\0'; l = *line; switch (phase) { case P_FROM: if (strncmp(l, "from: ", 6) != 0) errx(1, "unexpected from line"); l += 6; json_author(fp, "tagger", l, 1); phase = P_DATE; break; case P_DATE: /* optional */ if (!strncmp(l, "date: ", 6)) { l += 6; json_date(fp, "date", l, 1); phase = P_OBJECT; break; } phase = P_OBJECT; /* fallthough */ case P_OBJECT: /* optional */ if (!strncmp(l, "object: ", 8)) { char *type, *id; l += 8; type = l; id = strchr(l, ' '); if (id == NULL) errx(1, "malformed tag object line"); *id++ = '\0'; fputs("\"object\":{", fp); json_field(fp, "type", type, 1); json_field(fp, "id", id, 0); fputs("},", fp); phase = P_MSGLEN; break; } phase = P_MSGLEN; /* fallthrough */ case P_MSGLEN: if (strncmp(l, "messagelen: ", 12) != 0) errx(1, "unexpected messagelen line"); l += 12; msglen = strtonum(l, 1, INT_MAX, &errstr); if (errstr) errx(1, "message len is %s: %s", errstr, l); msglen++; phase = P_MSG; break; case P_MSG: if (*l != ' ') errx(1, "unexpected line in tag message"); l++; /* skip leading space */ linelen--; if (msgwrote == 0 && linelen != 0) { fprintf(fp, "\"message\":\""); escape(fp, l); escape(fp, "\n"); msgwrote += linelen; } else if (msgwrote != 0) { escape(fp, l); escape(fp, "\n"); } msglen -= linelen + 1; if (msglen <= 0) { fprintf(fp, "\""); done = 1; break; } break; default: /* unreachable */ errx(1, "unexpected line: %s", *line); } } if (ferror(stdin)) fatal("getline"); if (!done) fatalx("%s: unexpected EOF", __func__); fputc('}', fp); return 0; } static int jsonify(FILE *fp, const char *repo, const char *user) { char *line = NULL; size_t linesize = 0; ssize_t linelen; int needcomma = 0; fprintf(fp, "{\"notifications\":["); while ((linelen = getline(&line, &linesize, stdin)) != -1) { if (line[linelen - 1] == '\n') line[--linelen] = '\0'; if (*line == '\0') continue; if (needcomma) fputc(',', fp); needcomma = 1; if (strncmp(line, "Removed refs/heads/", 19) == 0) { if (jsonify_branch_rm(fp, line, repo, user) == -1) fatal("jsonify_branch_rm"); continue; } if (strncmp(line, "commit ", 7) == 0) { if (jsonify_commit(fp, repo, user, &line, &linesize) == -1) fatal("jsonify_commit"); continue; } if (*line >= '0' && *line <= '9') { if (jsonify_commit_short(fp, line, repo, user) == -1) fatal("jsonify_commit_short"); continue; } if (strncmp(line, "tag ", 4) == 0) { if (jsonify_tag(fp, repo, user, &line, &linesize) == -1) fatal("jsonify_tag"); continue; } errx(1, "unexpected line: %s", line); } if (ferror(stdin)) fatal("getline"); fprintf(fp, "]}"); return 0; } static char sixet2ch(int c) { c &= 0x3F; if (c < 26) return 'A' + c; c -= 26; if (c < 26) return 'a' + c; c -= 26; if (c < 10) return '0' + c; c -= 10; if (c == 0) return '+'; if (c == 1) return '/'; errx(1, "invalid sixet 0x%x", c); } static char * basic_auth(const char *username, const char *password) { char *str, *tmp, *end, *s, *p; char buf[3]; int len, i, r; r = asprintf(&str, "%s:%s", username, password); if (r == -1) fatal("asprintf"); /* * Will need 4 * r/3 bytes to encode the string, plus a * rounding to the next multiple of 4 for padding, plus NUL. */ len = 4 * r / 3; len = (len + 3) & ~3; len++; tmp = calloc(1, len); if (tmp == NULL) fatal("calloc"); s = str; p = tmp; while (*s != '\0') { memset(buf, 0, sizeof(buf)); for (i = 0; i < 3 && *s != '\0'; ++i, ++s) buf[i] = *s; *p++ = sixet2ch(buf[0] >> 2); *p++ = sixet2ch((buf[1] >> 4) | (buf[0] << 4)); if (i > 1) *p++ = sixet2ch((buf[1] << 2) | (buf[2] >> 6)); if (i > 2) *p++ = sixet2ch(buf[2]); } for (end = tmp + len - 1; p < end; ++p) *p = '='; free(str); return tmp; } static inline int bufio2poll(struct bufio *bio) { int f, ret = 0; /* * If we have data queued up, retry for both POLLIN and POLLOUT * since we want to push this data to the server while still * processing an eventual reply. Otherwise, we could wait * indefinitely for the server to reply without us having * sent the HTTP request completely. */ if (bio->wbuf.len) return POLLIN|POLLOUT; f = bufio_ev(bio); if (f & BUFIO_WANT_READ) ret |= POLLIN; if (f & BUFIO_WANT_WRITE) ret |= POLLOUT; return ret; } int main(int argc, char **argv) { FILE *tmpfp; struct bufio bio; struct pollfd pfd; struct timespec timeout; const char *username; const char *password; const char *timeoutstr; const char *errstr; const char *repo = NULL; const char *host = NULL, *port = NULL, *path = NULL; const char *gotd_auth_user = NULL; char *auth, *line, *spc; size_t len; ssize_t r; off_t paylen; int tls = 0; int response_code = 0, done = 0; int ch, flags, ret, nonstd = 0; #ifndef PROFILE if (pledge("stdio rpath tmppath dns inet", NULL) == -1) err(1, "pledge"); #endif log_init(0, LOG_DAEMON); while ((ch = getopt(argc, argv, "ch:p:r:u:")) != -1) { switch (ch) { case 'c': tls = 1; break; case 'h': host = optarg; break; case 'p': port = optarg; break; case 'r': repo = optarg; break; case 'u': gotd_auth_user = optarg; break; default: usage(); } } argc -= optind; argv += optind; if (host == NULL || repo == NULL || gotd_auth_user == NULL || argc != 1) usage(); if (tls && port == NULL) port = "443"; path = argv[0]; username = getenv("GOT_NOTIFY_HTTP_USER"); password = getenv("GOT_NOTIFY_HTTP_PASS"); if ((username != NULL && password == NULL) || (username == NULL && password != NULL)) fatalx("username or password are not specified"); if (username && *password == '\0') fatalx("password can't be empty"); /* used by the regression test suite */ timeoutstr = getenv("GOT_NOTIFY_TIMEOUT"); if (timeoutstr) { http_timeout = strtonum(timeoutstr, 0, 600, &errstr); if (errstr != NULL) fatalx("timeout in seconds is %s: %s", errstr, timeoutstr); } memset(&timeout, 0, sizeof(timeout)); timeout.tv_sec = http_timeout; tmpfp = got_opentemp(); if (tmpfp == NULL) fatal("opentemp"); jsonify(tmpfp, repo, gotd_auth_user); paylen = ftello(tmpfp); if (paylen == -1) fatal("ftello"); if (fseeko(tmpfp, 0, SEEK_SET) == -1) fatal("fseeko"); #ifndef PROFILE /* drop tmppath */ if (pledge("stdio rpath dns inet", NULL) == -1) err(1, "pledge"); #endif memset(&pfd, 0, sizeof(pfd)); pfd.fd = dial(host, port); if ((flags = fcntl(pfd.fd, F_GETFL)) == -1) fatal("fcntl(F_GETFL)"); if (fcntl(pfd.fd, F_SETFL, flags | O_NONBLOCK) == -1) fatal("fcntl(F_SETFL)"); if (bufio_init(&bio) == -1) fatal("bufio_init"); bufio_set_fd(&bio, pfd.fd); if (tls && bufio_starttls(&bio, host, 0, NULL, 0, NULL, 0) == -1) fatal("bufio_starttls"); #ifndef PROFILE /* drop rpath dns inet */ if (pledge("stdio", NULL) == -1) err(1, "pledge"); /* revoke fs access */ if (landlock_no_fs() == -1) err(1, "landlock_no_fs"); if (cap_enter() == -1) err(1, "cap_enter"); #endif if ((!tls && strcmp(port, "80") != 0) || (tls && strcmp(port, "443")) != 0) nonstd = 1; ret = bufio_compose_fmt(&bio, "POST %s HTTP/1.1\r\n" "Host: %s%s%s\r\n" "Content-Type: application/json\r\n" "Content-Length: %lld\r\n" "User-Agent: %s\r\n" "Connection: close\r\n", path, host, nonstd ? ":" : "", nonstd ? port : "", (long long)paylen, USERAGENT); if (ret == -1) fatal("bufio_compose_fmt"); if (username) { auth = basic_auth(username, password); ret = bufio_compose_fmt(&bio, "Authorization: basic %s\r\n", auth); if (ret == -1) fatal("bufio_compose_fmt"); free(auth); } if (bufio_compose(&bio, "\r\n", 2) == -1) fatal("bufio_compose"); while (!done) { struct timespec elapsed, start, stop; char buf[BUFSIZ]; pfd.events = bufio2poll(&bio); clock_gettime(CLOCK_MONOTONIC, &start); ret = ppoll(&pfd, 1, &timeout, NULL); if (ret == -1) fatal("poll"); clock_gettime(CLOCK_MONOTONIC, &stop); timespecsub(&stop, &start, &elapsed); timespecsub(&timeout, &elapsed, &timeout); if (ret == 0 || timeout.tv_sec <= 0) fatalx("timeout"); if (bio.wbuf.len > 0) { if (bufio_write(&bio) == -1 && errno != EAGAIN) fatalx("bufio_write: %s", bufio_io_err(&bio)); } r = bufio_read(&bio); if (r == -1 && errno != EAGAIN) fatalx("bufio_read: %s", bufio_io_err(&bio)); if (r == 0) fatalx("unexpected EOF from upstream HTTP server"); for (;;) { line = buf_getdelim(&bio.rbuf, "\r\n", &len); if (line == NULL) break; if (response_code && *line == '\0') { /* * end of headers, don't bother * reading the body, if there is. */ done = 1; break; } if (response_code) { buf_drain(&bio.rbuf, len); continue; } spc = strchr(line, ' '); if (spc == NULL) fatalx("bad HTTP response from server"); *spc++ = '\0'; if (strcasecmp(line, "HTTP/1.1") != 0) log_warnx("unexpected protocol: %s", line); line = spc; spc = strchr(line, ' '); if (spc == NULL) fatalx("bad HTTP response from server"); *spc++ = '\0'; response_code = strtonum(line, 100, 599, &errstr); if (errstr != NULL) log_warnx("response code is %s: %s", errstr, line); buf_drain(&bio.rbuf, len); } if (done) break; if (!feof(tmpfp) && bio.wbuf.len < sizeof(buf)) { len = fread(buf, 1, sizeof(buf), tmpfp); if (len == 0) { if (ferror(tmpfp)) fatal("fread"); continue; } if (bufio_compose(&bio, buf, len) == -1) fatal("buf_compose"); } } if (response_code >= 200 && response_code < 300) return 0; fatalx("request failed with code %d", response_code); } got-portable-0.101/gotd/libexec/got-notify-http/Makefile.in0000664000175100017510000005543014644145543017311 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-notify-http$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd @HOST_OPENBSD_TRUE@am__append_2 = -ltls subdir = gotd/libexec/got-notify-http ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_notify_http_OBJECTS = got-notify-http.$(OBJEXT) \ $(top_builddir)/lib/bufio.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/log.$(OBJEXT) \ $(top_builddir)/lib/opentemp.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) got_notify_http_OBJECTS = $(am_got_notify_http_OBJECTS) got_notify_http_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/bufio.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/log.Po \ $(top_builddir)/lib/$(DEPDIR)/opentemp.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ ./$(DEPDIR)/got-notify-http.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_notify_http_SOURCES) DIST_SOURCES = $(got_notify_http_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) $(libtls_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ EXTRA_DIST = utf8d.h got_notify_http_SOURCES = got-notify-http.c \ $(top_srcdir)/lib/bufio.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/log.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pollfd.c got_notify_http_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(libtls_LIBS) \ $(am__append_1) $(am__append_2) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gotd/libexec/got-notify-http/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign gotd/libexec/got-notify-http/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files clean-libexecPROGRAMS: -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: > $(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: > $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/bufio.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/log.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/opentemp.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-notify-http$(EXEEXT): $(got_notify_http_OBJECTS) $(got_notify_http_DEPENDENCIES) $(EXTRA_got_notify_http_DEPENDENCIES) @rm -f got-notify-http$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_notify_http_OBJECTS) $(got_notify_http_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/bufio.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/log.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/opentemp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-notify-http.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/bufio.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/log.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f ./$(DEPDIR)/got-notify-http.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/bufio.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/log.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f ./$(DEPDIR)/got-notify-http.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/gotd/libexec/Makefile.in0000664000175100017510000004552314644145543014237 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = gotd/libexec ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ SUBDIRS = got-notify-email got-notify-http all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gotd/libexec/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign gotd/libexec/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic cscopelist-am ctags ctags-am \ distclean distclean-generic distclean-tags distdir dvi dvi-am \ html html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags tags-am uninstall uninstall-am .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/gotd/libexec/got-notify-email/0000775000175100017510000000000014644145570015425 5got-portable-0.101/gotd/libexec/got-notify-email/Makefile.am0000664000175100017510000000102414644144735017400 libexec_PROGRAMS = got-notify-email include $(top_builddir)/Makefile.common got_notify_email_SOURCES = got-notify-email.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/log.c \ $(top_srcdir)/lib/pollfd.c got_notify_email_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.101/gotd/libexec/got-notify-email/got-notify-email.c0000664000175100017510000002541214644144735020703 /* * Copyright (c) 2024 Stefan Sperling * Copyright (c) 2008, 2012 Gilles Chehade * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "log.h" #include "got_error.h" #include "got_lib_poll.h" #define SMTP_LINE_MAX 65535 static int smtp_timeout = 60; /* in seconds */ static char smtp_buf[SMTP_LINE_MAX]; static size_t smtp_buflen; __dead static void usage(void) { fprintf(stderr, "usage: %s [-f sender] [-r responder] " "[-s subject] [-h hostname] [-p port] recipient\n", getprogname()); exit(1); } static int dial(const char *host, const char *port) { struct addrinfo hints, *res, *res0; const char *cause = NULL; int s, error, save_errno; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; error = getaddrinfo(host, port, &hints, &res0); if (error) fatalx("failed to resolve %s:%s: %s", host, port, gai_strerror(error)); s = -1; for (res = res0; res; res = res->ai_next) { s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s == -1) { cause = "socket"; continue; } if (connect(s, res->ai_addr, res->ai_addrlen) == -1) { cause = "connect"; save_errno = errno; close(s); errno = save_errno; s = -1; continue; } break; } freeaddrinfo(res0); if (s == -1) fatal("%s %s:%s", cause, host, port); return s; } static char * set_default_fromaddr(void) { struct passwd *pw = NULL; char *s; char hostname[255]; pw = getpwuid(getuid()); if (pw == NULL) { fatalx("my UID %d was not found in password database", getuid()); } if (gethostname(hostname, sizeof(hostname)) == -1) fatal("gethostname"); if (asprintf(&s, "%s@%s", pw->pw_name, hostname) == -1) fatal("asprintf"); return s; } static int read_smtp_code(int s, const char *code) { const struct got_error *error; char *endl; size_t linelen; ssize_t r; for (;;) { endl = memmem(smtp_buf, smtp_buflen, "\r\n", 2); if (endl != NULL) break; if (smtp_buflen == sizeof(smtp_buf)) fatalx("line too long"); error = got_poll_fd(s, POLLIN, smtp_timeout); if (error) fatalx("poll: %s", error->msg); r = read(s, smtp_buf + smtp_buflen, sizeof(smtp_buf) - smtp_buflen); if (r == -1) fatal("read"); if (r == 0) fatalx("unexpected EOF"); smtp_buflen += r; } linelen = endl - smtp_buf; if (linelen < 3) fatalx("invalid SMTP response"); if (strncmp(code, smtp_buf, 3) != 0) { smtp_buf[3] = '\0'; log_warnx("unexpected SMTP message code: %s", smtp_buf); return -1; } /* * Normally we would get just one reply, but the regress doesn't * use a real SMTP server and queues all the replies upfront. */ linelen += 2; memmove(smtp_buf, smtp_buf + linelen, smtp_buflen - linelen); smtp_buflen -= linelen; return 0; } static int send_smtp_msg(int s, const char *fmt, ...) { const struct got_error *error; char buf[512]; int len; va_list ap; va_start(ap, fmt); len = vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); if (len < 0) { log_warn("vsnprintf"); return -1; } if (len >= sizeof(buf)) { log_warnx("%s: buffer too small for message '%s...'", __func__, buf); return -1; } error = got_poll_write_full(s, buf, len); if (error) { log_warnx("write: %s", error->msg); return -1; } return 0; } static const struct got_error * print_date(int s, char *date, int shortfmt) { const struct got_error *error; struct tm tm; char *t, datebuf[26]; const char *errstr; time_t ts; date[strcspn(date, " \n")] = '\0'; ts = strtonum(date, INT64_MIN, INT64_MAX, &errstr); if (errstr) return got_error_set_errno(EINVAL, errstr); if (gmtime_r(&ts, &tm) == NULL) return got_error_set_errno(EINVAL, "gmtime_r"); if (!shortfmt) { t = asctime_r(&tm, datebuf); if (t == NULL) return got_error_set_errno(EINVAL, "invalid timestamp"); t[strcspn(t, "\n")] = '\0'; error = got_poll_write_full(s, t, strlen(t)); if (error) return error; return got_poll_write_full(s, " UTC\n", 5); } if (strftime(datebuf, sizeof(datebuf), "%F ", &tm) == 0) return got_error_set_errno(EINVAL, "invalid timestamp"); return got_poll_write_full(s, datebuf, strlen(datebuf)); } /* from usr.sbin/smtpd/util.c */ static int bsnprintf(char *str, size_t size, const char *format, ...) { int ret; va_list ap; va_start(ap, format); ret = vsnprintf(str, size, format, ap); va_end(ap); if (ret < 0 || (size_t)ret >= size) return 0; return 1; } /* based on usr.sbin/smtpd/to.c */ static const char * time_to_text(time_t when, char *buf, size_t buf_size) { struct tm *lt; const char *day[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; const char *month[] = {"Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec"}; const char *tz; long offset; lt = gmtime(&when); if (lt == NULL || when == 0) fatalx("time_to_text: localtime"); offset = lt->tm_gmtoff; tz = lt->tm_zone; /* We do not use strftime because it is subject to locale substitution*/ if (!bsnprintf(buf, buf_size, "%s, %d %s %d %02d:%02d:%02d %c%02d%02d (%s)", day[lt->tm_wday], lt->tm_mday, month[lt->tm_mon], lt->tm_year + 1900, lt->tm_hour, lt->tm_min, lt->tm_sec, offset >= 0 ? '+' : '-', abs((int)offset / 3600), abs((int)offset % 3600) / 60, tz)) fatalx("time_to_text: bsnprintf"); return buf; } static void send_email(int s, const char *myfromaddr, const char *fromaddr, const char *recipient, const char *replytoaddr, const char *subject) { const struct got_error *error; char *line = NULL; size_t linesize = 0; ssize_t linelen; int firstline = 1, shortfmt = 0; char datebuf[40]; const char *datestr; datestr = time_to_text(time(NULL), datebuf, sizeof(datebuf)); if (read_smtp_code(s, "220")) fatalx("unexpected SMTP greeting received"); if (send_smtp_msg(s, "HELO localhost\r\n")) fatalx("could not send HELO"); if (read_smtp_code(s, "250")) fatalx("unexpected SMTP response received"); if (send_smtp_msg(s, "MAIL FROM:<%s>\r\n", myfromaddr)) fatalx("could not send MAIL FROM"); if (read_smtp_code(s, "250")) fatalx("unexpected SMTP response received"); if (send_smtp_msg(s, "RCPT TO:<%s>\r\n", recipient)) fatalx("could not send MAIL FROM"); if (read_smtp_code(s, "250")) fatalx("unexpected SMTP response received"); if (send_smtp_msg(s, "DATA\r\n")) fatalx("could not send MAIL FROM"); if (read_smtp_code(s, "354")) fatalx("unexpected SMTP response received"); if (send_smtp_msg(s, "From: %s\r\n", fromaddr)) fatalx("could not send From header"); if (send_smtp_msg(s, "To: %s\r\n", recipient)) fatalx("could not send To header"); if (replytoaddr) { if (send_smtp_msg(s, "Reply-To: %s\r\n", replytoaddr)) fatalx("could not send Reply-To header"); } if (send_smtp_msg(s, "Date: %s\r\n", datestr)) fatalx("could not send Date header"); if (send_smtp_msg(s, "Subject: %s\r\n", subject)) fatalx("could not send Subject header"); if (send_smtp_msg(s, "\r\n")) fatalx("could not send body delimiter"); while ((linelen = getline(&line, &linesize, stdin)) != -1) { if (firstline && isdigit((unsigned char)line[0])) shortfmt = 1; firstline = 0; if (line[0] == '.') { /* dot stuffing */ error = got_poll_write_full(s, ".", 1); if (error) fatalx("write: %s", error->msg); } if (shortfmt) { char *t; t = strchr(line, ' '); if (t != NULL) { *t++ = '\0'; error = print_date(s, line, shortfmt); if (error) fatalx("write: %s", error->msg); error = got_poll_write_full(s, t, strlen(t)); continue; } } if (!shortfmt && !strncmp(line, "date: ", 6)) { error = got_poll_write_full(s, line, 6); if (error) fatalx("write: %s", error->msg); error = print_date(s, line + 6, shortfmt); if (error) fatalx("write: %s", error->msg); continue; } error = got_poll_write_full(s, line, linelen); if (error) fatalx("write: %s", error->msg); } if (send_smtp_msg(s, "\r\n.\r\n")) fatalx("could not send data terminator"); if (read_smtp_code(s, "250")) fatalx("unexpected SMTP response received"); if (send_smtp_msg(s, "QUIT\r\n")) fatalx("could not send QUIT"); if (read_smtp_code(s, "221")) fatalx("unexpected SMTP response received"); close(s); free(line); } int main(int argc, char *argv[]) { char *default_fromaddr = NULL; const char *fromaddr = NULL, *recipient = NULL, *replytoaddr = NULL; const char *subject = "gotd notification"; const char *hostname = "127.0.0.1"; const char *port = "25"; const char *errstr; char *timeoutstr; int ch, s; log_init(0, LOG_DAEMON); while ((ch = getopt(argc, argv, "f:r:s:h:p:")) != -1) { switch (ch) { case 'h': hostname = optarg; break; case 'f': fromaddr = optarg; break; case 'p': port = optarg; break; case 'r': replytoaddr = optarg; break; case 's': subject = optarg; break; default: usage(); /* NOTREACHED */ break; } } argc -= optind; argv += optind; if (argc != 1) usage(); /* used by the regression test suite */ timeoutstr = getenv("GOT_NOTIFY_EMAIL_TIMEOUT"); if (timeoutstr) { smtp_timeout = strtonum(timeoutstr, 0, 600, &errstr); if (errstr != NULL) fatalx("timeout in seconds is %s: %s", errstr, timeoutstr); } #ifndef PROFILE if (pledge("stdio dns inet getpw", NULL) == -1) err(1, "pledge"); #endif default_fromaddr = set_default_fromaddr(); #ifndef PROFILE if (pledge("stdio dns inet", NULL) == -1) err(1, "pledge"); #endif recipient = argv[0]; if (fromaddr == NULL) fromaddr = default_fromaddr; s = dial(hostname, port); #ifndef PROFILE if (pledge("stdio", NULL) == -1) err(1, "pledge"); /* revoke fs access */ if (landlock_no_fs() == -1) err(1, "landlock_no_fs"); if (cap_enter() == -1) err(1, "cap_enter"); #endif send_email(s, default_fromaddr, fromaddr, recipient, replytoaddr, subject); free(default_fromaddr); return 0; } got-portable-0.101/gotd/libexec/got-notify-email/Makefile.in0000664000175100017510000005350014644145543017415 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-notify-email$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = gotd/libexec/got-notify-email ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_notify_email_OBJECTS = got-notify-email.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/log.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) got_notify_email_OBJECTS = $(am_got_notify_email_OBJECTS) got_notify_email_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/log.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ ./$(DEPDIR)/got-notify-email.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_notify_email_SOURCES) DIST_SOURCES = $(got_notify_email_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_notify_email_SOURCES = got-notify-email.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/log.c \ $(top_srcdir)/lib/pollfd.c got_notify_email_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gotd/libexec/got-notify-email/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign gotd/libexec/got-notify-email/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files clean-libexecPROGRAMS: -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: > $(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: > $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/log.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-notify-email$(EXEEXT): $(got_notify_email_OBJECTS) $(got_notify_email_DEPENDENCIES) $(EXTRA_got_notify_email_DEPENDENCIES) @rm -f got-notify-email$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_notify_email_OBJECTS) $(got_notify_email_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/log.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-notify-email.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/log.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f ./$(DEPDIR)/got-notify-email.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/log.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f ./$(DEPDIR)/got-notify-email.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/gotd/repo_read.h0000644000175100017510000000157014644143163012654 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void repo_read_main(const char *, const char *, int *, int *); void repo_read_shutdown(void); got-portable-0.101/gotd/parse.y0000664000175100017510000011704014644144735012057 /* * Copyright (c) 2022 Stefan Sperling * Copyright (c) 2016-2019, 2020-2021 Tracey Emery * Copyright (c) 2004, 2005 Esben Norby * Copyright (c) 2004 Ryan McBride * Copyright (c) 2002, 2003, 2004 Henning Brauer * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. * Copyright (c) 2001 Theo de Raadt. All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ %{ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_reference.h" #include "log.h" #include "gotd.h" #include "auth.h" #include "listen.h" TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); static struct file { TAILQ_ENTRY(file) entry; FILE *stream; char *name; int lineno; int errors; } *file; struct file *newfile(const char *, int, int); static void closefile(struct file *); int check_file_secrecy(int, const char *); int yyparse(void); int yylex(void); int yyerror(const char *, ...) __attribute__((__format__ (printf, 1, 2))) __attribute__((__nonnull__ (1))); int kw_cmp(const void *, const void *); int lookup(char *); int lgetc(int); int lungetc(int); int findeol(void); static char *port_sprintf(int); TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); struct sym { TAILQ_ENTRY(sym) entry; int used; int persist; char *nam; char *val; }; int symset(const char *, const char *, int); char *symget(const char *); static int errors; static struct gotd *gotd; static struct gotd_repo *new_repo; static int conf_limit_user_connections(const char *, int); static struct gotd_repo *conf_new_repo(const char *); static void conf_new_access_rule(struct gotd_repo *, enum gotd_access, int, char *); static int conf_protect_ref_namespace(char **, struct got_pathlist_head *, char *); static int conf_protect_tag_namespace(struct gotd_repo *, char *); static int conf_protect_branch_namespace( struct gotd_repo *, char *); static int conf_protect_branch(struct gotd_repo *, char *); static int conf_notify_branch(struct gotd_repo *, char *); static int conf_notify_ref_namespace(struct gotd_repo *, char *); static int conf_notify_email(struct gotd_repo *, char *, char *, char *, char *, char *); static int conf_notify_http(struct gotd_repo *, char *, char *, char *, int); static enum gotd_procid gotd_proc_id; typedef struct { union { long long number; char *string; struct timeval tv; } v; int lineno; } YYSTYPE; %} %token PATH ERROR LISTEN ON USER REPOSITORY PERMIT DENY %token RO RW CONNECTION LIMIT REQUEST TIMEOUT %token PROTECT NAMESPACE BRANCH TAG REFERENCE RELAY PORT %token NOTIFY EMAIL FROM REPLY TO URL PASSWORD INSECURE %token STRING %token NUMBER %type timeout %% grammar : | grammar '\n' | grammar varset '\n' | grammar main '\n' | grammar repository '\n' ; varset : STRING '=' STRING { char *s = $1; while (*s++) { if (isspace((unsigned char)*s)) { yyerror("macro name cannot contain " "whitespace"); free($1); free($3); YYERROR; } } if (symset($1, $3, 0) == -1) fatal("cannot store variable"); free($1); free($3); } ; timeout : NUMBER { if ($1 < 0) { yyerror("invalid timeout: %lld", $1); YYERROR; } $$.tv_sec = $1; $$.tv_usec = 0; } | STRING { const char *errstr; const char *type = "seconds"; size_t len; int mul = 1; if (*$1 == '\0') { yyerror("invalid number of seconds: %s", $1); free($1); YYERROR; } len = strlen($1); switch ($1[len - 1]) { case 'S': case 's': $1[len - 1] = '\0'; break; case 'M': case 'm': type = "minutes"; mul = 60; $1[len - 1] = '\0'; break; case 'H': case 'h': type = "hours"; mul = 60 * 60; $1[len - 1] = '\0'; break; } $$.tv_usec = 0; $$.tv_sec = strtonum($1, 0, INT_MAX / mul, &errstr); if (errstr) { yyerror("number of %s is %s: %s", type, errstr, $1); free($1); YYERROR; } $$.tv_sec *= mul; free($1); } ; main : LISTEN ON STRING { if (!got_path_is_absolute($3)) yyerror("bad unix socket path \"%s\": " "must be an absolute path", $3); if (gotd_proc_id == PROC_LISTEN) { if (strlcpy(gotd->unix_socket_path, $3, sizeof(gotd->unix_socket_path)) >= sizeof(gotd->unix_socket_path)) { yyerror("%s: unix socket path too long", __func__); free($3); YYERROR; } } free($3); } | USER STRING { if (strlcpy(gotd->user_name, $2, sizeof(gotd->user_name)) >= sizeof(gotd->user_name)) { yyerror("%s: user name too long", __func__); free($2); YYERROR; } free($2); } | connection ; connection : CONNECTION '{' optnl conflags_l '}' | CONNECTION conflags conflags_l : conflags optnl conflags_l | conflags optnl ; conflags : REQUEST TIMEOUT timeout { if ($3.tv_sec <= 0) { yyerror("invalid timeout: %lld", (long long)$3.tv_sec); YYERROR; } memcpy(&gotd->request_timeout, &$3, sizeof(gotd->request_timeout)); } | LIMIT USER STRING NUMBER { if (gotd_proc_id == PROC_LISTEN && conf_limit_user_connections($3, $4) == -1) { free($3); YYERROR; } free($3); } ; protect : PROTECT '{' optnl protectflags_l '}' | PROTECT protectflags protectflags_l : protectflags optnl protectflags_l | protectflags optnl ; protectflags : TAG NAMESPACE STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_REPO_WRITE) { if (conf_protect_tag_namespace(new_repo, $3)) { free($3); YYERROR; } } free($3); } | BRANCH NAMESPACE STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_REPO_WRITE) { if (conf_protect_branch_namespace(new_repo, $3)) { free($3); YYERROR; } } free($3); } | BRANCH STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_REPO_WRITE) { if (conf_protect_branch(new_repo, $2)) { free($2); YYERROR; } } free($2); } ; notify : NOTIFY '{' optnl notifyflags_l '}' | NOTIFY notifyflags notifyflags_l : notifyflags optnl notifyflags_l | notifyflags optnl ; notifyflags : BRANCH STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_branch(new_repo, $2)) { free($2); YYERROR; } } free($2); } | REFERENCE NAMESPACE STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_ref_namespace(new_repo, $3)) { free($3); YYERROR; } } free($3); } | EMAIL TO STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, NULL, $3, NULL, NULL, NULL)) { free($3); YYERROR; } } free($3); } | EMAIL FROM STRING TO STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, $3, $5, NULL, NULL, NULL)) { free($3); free($5); YYERROR; } } free($3); free($5); } | EMAIL TO STRING REPLY TO STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, NULL, $3, $6, NULL, NULL)) { free($3); free($6); YYERROR; } } free($3); free($6); } | EMAIL FROM STRING TO STRING REPLY TO STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, $3, $5, $8, NULL, NULL)) { free($3); free($5); free($8); YYERROR; } } free($3); free($5); free($8); } | EMAIL TO STRING RELAY STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, NULL, $3, NULL, $5, NULL)) { free($3); free($5); YYERROR; } } free($3); free($5); } | EMAIL FROM STRING TO STRING RELAY STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, $3, $5, NULL, $7, NULL)) { free($3); free($5); free($7); YYERROR; } } free($3); free($5); free($7); } | EMAIL TO STRING REPLY TO STRING RELAY STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, NULL, $3, $6, $8, NULL)) { free($3); free($6); free($8); YYERROR; } } free($3); free($6); free($8); } | EMAIL FROM STRING TO STRING REPLY TO STRING RELAY STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, $3, $5, $8, $10, NULL)) { free($3); free($5); free($8); free($10); YYERROR; } } free($3); free($5); free($8); free($10); } | EMAIL TO STRING RELAY STRING PORT STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, NULL, $3, NULL, $5, $7)) { free($3); free($5); free($7); YYERROR; } } free($3); free($5); free($7); } | EMAIL FROM STRING TO STRING RELAY STRING PORT STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, $3, $5, NULL, $7, $9)) { free($3); free($5); free($7); free($9); YYERROR; } } free($3); free($5); free($7); free($9); } | EMAIL TO STRING REPLY TO STRING RELAY STRING PORT STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, NULL, $3, $6, $8, $10)) { free($3); free($6); free($8); free($10); YYERROR; } } free($3); free($6); free($8); free($10); } | EMAIL FROM STRING TO STRING REPLY TO STRING RELAY STRING PORT STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, $3, $5, $8, $10, $12)) { free($3); free($5); free($8); free($10); free($12); YYERROR; } } free($3); free($5); free($8); free($10); free($12); } | EMAIL TO STRING RELAY STRING PORT NUMBER { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, NULL, $3, NULL, $5, port_sprintf($7))) { free($3); free($5); YYERROR; } } free($3); free($5); } | EMAIL FROM STRING TO STRING RELAY STRING PORT NUMBER { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, $3, $5, NULL, $7, port_sprintf($9))) { free($3); free($5); free($7); YYERROR; } } free($3); free($5); free($7); } | EMAIL TO STRING REPLY TO STRING RELAY STRING PORT NUMBER { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, NULL, $3, $6, $8, port_sprintf($10))) { free($3); free($6); free($8); YYERROR; } } free($3); free($6); free($8); } | EMAIL FROM STRING TO STRING REPLY TO STRING RELAY STRING PORT NUMBER { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_email(new_repo, $3, $5, $8, $10, port_sprintf($12))) { free($3); free($5); free($8); free($10); YYERROR; } } free($3); free($5); free($8); free($10); } | URL STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_http(new_repo, $2, NULL, NULL, 0)) { free($2); YYERROR; } } free($2); } | URL STRING USER STRING PASSWORD STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_http(new_repo, $2, $4, $6, 0)) { free($2); free($4); free($6); YYERROR; } } free($2); free($4); free($6); } | URL STRING USER STRING PASSWORD STRING INSECURE { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_NOTIFY) { if (conf_notify_http(new_repo, $2, $4, $6, 1)) { free($2); free($4); free($6); YYERROR; } } free($2); free($4); free($6); } ; repository : REPOSITORY STRING { struct gotd_repo *repo; TAILQ_FOREACH(repo, &gotd->repos, entry) { if (strcmp(repo->name, $2) == 0) { yyerror("duplicate repository '%s'", $2); free($2); YYERROR; } } if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_AUTH || gotd_proc_id == PROC_REPO_WRITE || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_GITWRAPPER | gotd_proc_id == PROC_NOTIFY) { new_repo = conf_new_repo($2); } free($2); } '{' optnl repoopts2 '}' { } ; repoopts1 : PATH STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_AUTH || gotd_proc_id == PROC_REPO_WRITE || gotd_proc_id == PROC_SESSION_WRITE || gotd_proc_id == PROC_GITWRAPPER || gotd_proc_id == PROC_NOTIFY) { if (!got_path_is_absolute($2)) { yyerror("%s: path %s is not absolute", __func__, $2); free($2); YYERROR; } if (realpath($2, new_repo->path) == NULL) { /* * To give admins a chance to create * missing repositories at run-time * we only warn about ENOENT here. * * And ignore 'permission denied' when * running in gitwrapper. Users may be * able to access this repository via * gotd regardless. */ if (errno == ENOENT) { yyerror("realpath %s: %s", $2, strerror(errno)); } else if (errno != EACCES || gotd_proc_id != PROC_GITWRAPPER) { yyerror("realpath %s: %s", $2, strerror(errno)); free($2); YYERROR; } if (strlcpy(new_repo->path, $2, sizeof(new_repo->path)) >= sizeof(new_repo->path)) yyerror("path too long"); } } free($2); } | PERMIT RO STRING { if (gotd_proc_id == PROC_AUTH) { conf_new_access_rule(new_repo, GOTD_ACCESS_PERMITTED, GOTD_AUTH_READ, $3); } else free($3); } | PERMIT RW STRING { if (gotd_proc_id == PROC_AUTH) { conf_new_access_rule(new_repo, GOTD_ACCESS_PERMITTED, GOTD_AUTH_READ | GOTD_AUTH_WRITE, $3); } else free($3); } | DENY STRING { if (gotd_proc_id == PROC_AUTH) { conf_new_access_rule(new_repo, GOTD_ACCESS_DENIED, 0, $2); } else free($2); } | protect | notify ; repoopts2 : repoopts2 repoopts1 nl | repoopts1 optnl ; nl : '\n' optnl ; optnl : '\n' optnl /* zero or more newlines */ | /* empty */ ; %% struct keywords { const char *k_name; int k_val; }; int yyerror(const char *fmt, ...) { va_list ap; char *msg; file->errors++; va_start(ap, fmt); if (vasprintf(&msg, fmt, ap) == -1) fatalx("yyerror vasprintf"); va_end(ap); logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); free(msg); return (0); } int kw_cmp(const void *k, const void *e) { return (strcmp(k, ((const struct keywords *)e)->k_name)); } int lookup(char *s) { /* This has to be sorted always. */ static const struct keywords keywords[] = { { "branch", BRANCH }, { "connection", CONNECTION }, { "deny", DENY }, { "email", EMAIL }, { "from", FROM }, { "insecure", INSECURE }, { "limit", LIMIT }, { "listen", LISTEN }, { "namespace", NAMESPACE }, { "notify", NOTIFY }, { "on", ON }, { "password", PASSWORD }, { "path", PATH }, { "permit", PERMIT }, { "port", PORT }, { "protect", PROTECT }, { "reference", REFERENCE }, { "relay", RELAY }, { "reply", REPLY }, { "repository", REPOSITORY }, { "request", REQUEST }, { "ro", RO }, { "rw", RW }, { "tag", TAG }, { "timeout", TIMEOUT }, { "to", TO }, { "url", URL }, { "user", USER }, }; const struct keywords *p; p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), sizeof(keywords[0]), kw_cmp); if (p) return (p->k_val); else return (STRING); } #define MAXPUSHBACK 128 unsigned char *parsebuf; int parseindex; unsigned char pushback_buffer[MAXPUSHBACK]; int pushback_index = 0; int lgetc(int quotec) { int c, next; if (parsebuf) { /* Read character from the parsebuffer instead of input. */ if (parseindex >= 0) { c = parsebuf[parseindex++]; if (c != '\0') return (c); parsebuf = NULL; } else parseindex++; } if (pushback_index) return (pushback_buffer[--pushback_index]); if (quotec) { c = getc(file->stream); if (c == EOF) yyerror("reached end of file while parsing " "quoted string"); return (c); } c = getc(file->stream); while (c == '\\') { next = getc(file->stream); if (next != '\n') { c = next; break; } yylval.lineno = file->lineno; file->lineno++; c = getc(file->stream); } return (c); } int lungetc(int c) { if (c == EOF) return (EOF); if (parsebuf) { parseindex--; if (parseindex >= 0) return (c); } if (pushback_index < MAXPUSHBACK-1) return (pushback_buffer[pushback_index++] = c); else return (EOF); } int findeol(void) { int c; parsebuf = NULL; /* Skip to either EOF or the first real EOL. */ while (1) { if (pushback_index) c = pushback_buffer[--pushback_index]; else c = lgetc(0); if (c == '\n') { file->lineno++; break; } if (c == EOF) break; } return (ERROR); } int yylex(void) { unsigned char buf[8096]; unsigned char *p, *val; int quotec, next, c; int token; top: p = buf; c = lgetc(0); while (c == ' ' || c == '\t') c = lgetc(0); /* nothing */ yylval.lineno = file->lineno; if (c == '#') { c = lgetc(0); while (c != '\n' && c != EOF) c = lgetc(0); /* nothing */ } if (c == '$' && parsebuf == NULL) { while (1) { c = lgetc(0); if (c == EOF) return (0); if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } if (isalnum(c) || c == '_') { *p++ = c; continue; } *p = '\0'; lungetc(c); break; } val = symget(buf); if (val == NULL) { yyerror("macro '%s' not defined", buf); return (findeol()); } parsebuf = val; parseindex = 0; goto top; } switch (c) { case '\'': case '"': quotec = c; while (1) { c = lgetc(quotec); if (c == EOF) return (0); if (c == '\n') { file->lineno++; continue; } else if (c == '\\') { next = lgetc(quotec); if (next == EOF) return (0); if (next == quotec || c == ' ' || c == '\t') c = next; else if (next == '\n') { file->lineno++; continue; } else lungetc(next); } else if (c == quotec) { *p = '\0'; break; } else if (c == '\0') { yyerror("syntax error"); return (findeol()); } if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } *p++ = c; } yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "yylex: strdup"); return (STRING); } #define allowed_to_end_number(x) \ (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') if (c == '-' || isdigit(c)) { do { *p++ = c; if ((unsigned)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && isdigit(c)); lungetc(c); if (p == buf + 1 && buf[0] == '-') goto nodigits; if (c == EOF || allowed_to_end_number(c)) { const char *errstr = NULL; *p = '\0'; yylval.v.number = strtonum(buf, LLONG_MIN, LLONG_MAX, &errstr); if (errstr) { yyerror("\"%s\" invalid number: %s", buf, errstr); return (findeol()); } return (NUMBER); } else { nodigits: while (p > buf + 1) lungetc(*--p); c = *--p; if (c == '-') return (c); } } #define allowed_in_string(x) \ (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ x != '{' && x != '}' && \ x != '!' && x != '=' && x != '#' && \ x != ',')) if (isalnum(c) || c == ':' || c == '_') { do { *p++ = c; if ((unsigned)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && (allowed_in_string(c))); lungetc(c); *p = '\0'; token = lookup(buf); if (token == STRING) { yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "yylex: strdup"); } return (token); } if (c == '\n') { yylval.lineno = file->lineno; file->lineno++; } if (c == EOF) return (0); return (c); } int check_file_secrecy(int fd, const char *fname) { struct stat st; if (fstat(fd, &st)) { log_warn("cannot stat %s", fname); return (-1); } if (st.st_uid != 0 && st.st_uid != getuid()) { log_warnx("%s: owner not root or current user", fname); return (-1); } if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { log_warnx("%s: group writable or world read/writable", fname); return (-1); } return (0); } struct file * newfile(const char *name, int secret, int required) { struct file *nfile; nfile = calloc(1, sizeof(struct file)); if (nfile == NULL) { log_warn("calloc"); return (NULL); } nfile->name = strdup(name); if (nfile->name == NULL) { log_warn("strdup"); free(nfile); return (NULL); } nfile->stream = fopen(nfile->name, "r"); if (nfile->stream == NULL) { if (required) log_warn("open %s", nfile->name); free(nfile->name); free(nfile); return (NULL); } else if (secret && check_file_secrecy(fileno(nfile->stream), nfile->name)) { fclose(nfile->stream); free(nfile->name); free(nfile); return (NULL); } nfile->lineno = 1; return (nfile); } static void closefile(struct file *xfile) { fclose(xfile->stream); free(xfile->name); free(xfile); } int parse_config(const char *filename, enum gotd_procid proc_id, struct gotd *env) { struct sym *sym, *next; struct gotd_repo *repo; int require_config_file = (proc_id != PROC_GITWRAPPER); memset(env, 0, sizeof(*env)); gotd = env; gotd_proc_id = proc_id; TAILQ_INIT(&gotd->repos); /* Apply default values. */ if (strlcpy(gotd->unix_socket_path, GOTD_UNIX_SOCKET, sizeof(gotd->unix_socket_path)) >= sizeof(gotd->unix_socket_path)) { fprintf(stderr, "%s: unix socket path too long", __func__); return -1; } if (strlcpy(gotd->user_name, GOTD_USER, sizeof(gotd->user_name)) >= sizeof(gotd->user_name)) { fprintf(stderr, "%s: user name too long", __func__); return -1; } gotd->request_timeout.tv_sec = GOTD_DEFAULT_REQUEST_TIMEOUT; gotd->request_timeout.tv_usec = 0; file = newfile(filename, 0, require_config_file); if (file == NULL) return require_config_file ? -1 : 0; yyparse(); errors = file->errors; closefile(file); /* Free macros and check which have not been used. */ TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { if ((gotd->verbosity > 1) && !sym->used) fprintf(stderr, "warning: macro '%s' not used\n", sym->nam); if (!sym->persist) { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } if (errors) return (-1); TAILQ_FOREACH(repo, &gotd->repos, entry) { if (repo->path[0] == '\0') { log_warnx("repository \"%s\": no path provided in " "configuration file", repo->name); return (-1); } } if (proc_id == PROC_GOTD && TAILQ_EMPTY(&gotd->repos)) { log_warnx("no repository defined in configuration file"); return (-1); } return (0); } static int uid_connection_limit_cmp(const void *pa, const void *pb) { const struct gotd_uid_connection_limit *a = pa, *b = pb; if (a->uid < b->uid) return -1; else if (a->uid > b->uid); return 1; return 0; } static int conf_limit_user_connections(const char *user, int maximum) { uid_t uid; struct gotd_uid_connection_limit *limit; size_t nlimits; if (maximum < 1) { yyerror("max connections cannot be smaller 1"); return -1; } if (maximum > GOTD_MAXCLIENTS) { yyerror("max connections must be <= %d", GOTD_MAXCLIENTS); return -1; } if (gotd_parseuid(user, &uid) == -1) { yyerror("%s: no such user", user); return -1; } limit = gotd_find_uid_connection_limit(gotd->connection_limits, gotd->nconnection_limits, uid); if (limit) { limit->max_connections = maximum; return 0; } limit = gotd->connection_limits; nlimits = gotd->nconnection_limits + 1; limit = reallocarray(limit, nlimits, sizeof(*limit)); if (limit == NULL) fatal("reallocarray"); limit[nlimits - 1].uid = uid; limit[nlimits - 1].max_connections = maximum; gotd->connection_limits = limit; gotd->nconnection_limits = nlimits; qsort(gotd->connection_limits, gotd->nconnection_limits, sizeof(gotd->connection_limits[0]), uid_connection_limit_cmp); return 0; } static struct gotd_repo * conf_new_repo(const char *name) { struct gotd_repo *repo; if (name[0] == '\0') { fatalx("syntax error: empty repository name found in %s", file->name); } if (strchr(name, '\n') != NULL) fatalx("repository names must not contain linefeeds: %s", name); repo = calloc(1, sizeof(*repo)); if (repo == NULL) fatalx("%s: calloc", __func__); STAILQ_INIT(&repo->rules); TAILQ_INIT(&repo->protected_tag_namespaces); TAILQ_INIT(&repo->protected_branch_namespaces); TAILQ_INIT(&repo->protected_branches); TAILQ_INIT(&repo->protected_branches); TAILQ_INIT(&repo->notification_refs); TAILQ_INIT(&repo->notification_ref_namespaces); STAILQ_INIT(&repo->notification_targets); if (strlcpy(repo->name, name, sizeof(repo->name)) >= sizeof(repo->name)) fatalx("%s: strlcpy", __func__); TAILQ_INSERT_TAIL(&gotd->repos, repo, entry); gotd->nrepos++; return repo; }; static void conf_new_access_rule(struct gotd_repo *repo, enum gotd_access access, int authorization, char *identifier) { struct gotd_access_rule *rule; rule = calloc(1, sizeof(*rule)); if (rule == NULL) fatal("calloc"); rule->access = access; rule->authorization = authorization; rule->identifier = identifier; STAILQ_INSERT_TAIL(&repo->rules, rule, entry); } static int refname_is_valid(char *refname) { if (strncmp(refname, "refs/", 5) != 0) { yyerror("reference name must begin with \"refs/\": %s", refname); return 0; } if (!got_ref_name_is_valid(refname)) { yyerror("invalid reference name: %s", refname); return 0; } return 1; } static int conf_protect_ref_namespace(char **new, struct got_pathlist_head *refs, char *namespace) { const struct got_error *error; struct got_pathlist_entry *pe; char *s; *new = NULL; got_path_strip_trailing_slashes(namespace); if (!refname_is_valid(namespace)) return -1; if (asprintf(&s, "%s/", namespace) == -1) { yyerror("asprintf: %s", strerror(errno)); return -1; } error = got_pathlist_insert(&pe, refs, s, NULL); if (error || pe == NULL) { free(s); if (error) yyerror("got_pathlist_insert: %s", error->msg); else yyerror("duplicate protected namespace %s", namespace); return -1; } *new = s; return 0; } static int conf_protect_tag_namespace(struct gotd_repo *repo, char *namespace) { struct got_pathlist_entry *pe; char *new; if (conf_protect_ref_namespace(&new, &repo->protected_tag_namespaces, namespace) == -1) return -1; TAILQ_FOREACH(pe, &repo->protected_branch_namespaces, entry) { if (strcmp(pe->path, new) == 0) { yyerror("duplicate protected namespace %s", namespace); return -1; } } return 0; } static int conf_protect_branch_namespace(struct gotd_repo *repo, char *namespace) { struct got_pathlist_entry *pe; char *new; if (conf_protect_ref_namespace(&new, &repo->protected_branch_namespaces, namespace) == -1) return -1; TAILQ_FOREACH(pe, &repo->protected_tag_namespaces, entry) { if (strcmp(pe->path, new) == 0) { yyerror("duplicate protected namespace %s", namespace); return -1; } } return 0; } static int conf_protect_branch(struct gotd_repo *repo, char *branchname) { const struct got_error *error; struct got_pathlist_entry *new; char *refname; if (strncmp(branchname, "refs/heads/", 11) != 0) { if (asprintf(&refname, "refs/heads/%s", branchname) == -1) { yyerror("asprintf: %s", strerror(errno)); return -1; } } else { refname = strdup(branchname); if (refname == NULL) { yyerror("strdup: %s", strerror(errno)); return -1; } } if (!refname_is_valid(refname)) { free(refname); return -1; } error = got_pathlist_insert(&new, &repo->protected_branches, refname, NULL); if (error || new == NULL) { free(refname); if (error) yyerror("got_pathlist_insert: %s", error->msg); else yyerror("duplicate protect branch %s", branchname); return -1; } return 0; } static int conf_notify_branch(struct gotd_repo *repo, char *branchname) { const struct got_error *error; struct got_pathlist_entry *pe; char *refname; if (strncmp(branchname, "refs/heads/", 11) != 0) { if (asprintf(&refname, "refs/heads/%s", branchname) == -1) { yyerror("asprintf: %s", strerror(errno)); return -1; } } else { refname = strdup(branchname); if (refname == NULL) { yyerror("strdup: %s", strerror(errno)); return -1; } } if (!refname_is_valid(refname)) { free(refname); return -1; } error = got_pathlist_insert(&pe, &repo->notification_refs, refname, NULL); if (error) { free(refname); yyerror("got_pathlist_insert: %s", error->msg); return -1; } if (pe == NULL) free(refname); return 0; } static int conf_notify_ref_namespace(struct gotd_repo *repo, char *namespace) { const struct got_error *error; struct got_pathlist_entry *pe; char *s; got_path_strip_trailing_slashes(namespace); if (!refname_is_valid(namespace)) return -1; if (asprintf(&s, "%s/", namespace) == -1) { yyerror("asprintf: %s", strerror(errno)); return -1; } error = got_pathlist_insert(&pe, &repo->notification_ref_namespaces, s, NULL); if (error) { free(s); yyerror("got_pathlist_insert: %s", error->msg); return -1; } if (pe == NULL) free(s); return 0; } static int conf_notify_email(struct gotd_repo *repo, char *sender, char *recipient, char *responder, char *hostname, char *port) { struct gotd_notification_target *target; STAILQ_FOREACH(target, &repo->notification_targets, entry) { if (target->type != GOTD_NOTIFICATION_VIA_EMAIL) continue; if (strcmp(target->conf.email.recipient, recipient) == 0) { yyerror("duplicate email notification for '%s' in " "repository '%s'", recipient, repo->name); return -1; } } target = calloc(1, sizeof(*target)); if (target == NULL) fatal("calloc"); target->type = GOTD_NOTIFICATION_VIA_EMAIL; if (sender) { target->conf.email.sender = strdup(sender); if (target->conf.email.sender == NULL) fatal("strdup"); } target->conf.email.recipient = strdup(recipient); if (target->conf.email.recipient == NULL) fatal("strdup"); if (responder) { target->conf.email.responder = strdup(responder); if (target->conf.email.responder == NULL) fatal("strdup"); } if (hostname) { target->conf.email.hostname = strdup(hostname); if (target->conf.email.hostname == NULL) fatal("strdup"); } if (port) { target->conf.email.port = strdup(port); if (target->conf.email.port == NULL) fatal("strdup"); } STAILQ_INSERT_TAIL(&repo->notification_targets, target, entry); return 0; } static int conf_notify_http(struct gotd_repo *repo, char *url, char *user, char *password, int insecure) { const struct got_error *error; struct gotd_notification_target *target; char *proto, *hostname, *port, *path; int tls = 0, ret = 0; error = gotd_parse_url(&proto, &hostname, &port, &path, url); if (error) { yyerror("invalid HTTP notification URL '%s' in " "repository '%s': %s", url, repo->name, error->msg); return -1; } tls = !strcmp(proto, "https"); if (strcmp(proto, "http") != 0 && strcmp(proto, "https") != 0) { yyerror("invalid protocol '%s' in notification URL '%s' in " "repository '%s", proto, url, repo->name); ret = -1; goto done; } if (port == NULL) { if (strcmp(proto, "http") == 0) port = strdup("80"); if (strcmp(proto, "https") == 0) port = strdup("443"); if (port == NULL) { error = got_error_from_errno("strdup"); ret = -1; goto done; } } if ((user != NULL && password == NULL) || (user == NULL && password != NULL)) { yyerror("missing username or password"); ret = -1; goto done; } if (!insecure && strcmp(proto, "http") == 0 && (user != NULL || password != NULL)) { yyerror("%s: HTTP notifications with basic authentication " "over plaintext HTTP will leak credentials; add the " "'insecure' config keyword if this is intentional", url); ret = -1; goto done; } STAILQ_FOREACH(target, &repo->notification_targets, entry) { if (target->type != GOTD_NOTIFICATION_VIA_HTTP) continue; if (target->conf.http.tls == tls && !strcmp(target->conf.http.hostname, hostname) && !strcmp(target->conf.http.port, port) && !strcmp(target->conf.http.path, path)) { yyerror("duplicate notification for URL '%s' in " "repository '%s'", url, repo->name); ret = -1; goto done; } } target = calloc(1, sizeof(*target)); if (target == NULL) fatal("calloc"); target->type = GOTD_NOTIFICATION_VIA_HTTP; target->conf.http.tls = tls; target->conf.http.hostname = hostname; target->conf.http.port = port; target->conf.http.path = path; hostname = port = path = NULL; if (user) { target->conf.http.user = strdup(user); if (target->conf.http.user == NULL) fatal("strdup"); target->conf.http.password = strdup(password); if (target->conf.http.password == NULL) fatal("strdup"); } STAILQ_INSERT_TAIL(&repo->notification_targets, target, entry); done: free(proto); free(hostname); free(port); free(path); return ret; } int symset(const char *nam, const char *val, int persist) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) break; } if (sym != NULL) { if (sym->persist == 1) return (0); else { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } sym = calloc(1, sizeof(*sym)); if (sym == NULL) return (-1); sym->nam = strdup(nam); if (sym->nam == NULL) { free(sym); return (-1); } sym->val = strdup(val); if (sym->val == NULL) { free(sym->nam); free(sym); return (-1); } sym->used = 0; sym->persist = persist; TAILQ_INSERT_TAIL(&symhead, sym, entry); return (0); } char * symget(const char *nam) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) { sym->used = 1; return (sym->val); } } return (NULL); } struct gotd_repo * gotd_find_repo_by_name(const char *repo_name, struct gotd_repolist *repos) { struct gotd_repo *repo; size_t namelen; TAILQ_FOREACH(repo, repos, entry) { namelen = strlen(repo->name); if (strncmp(repo->name, repo_name, namelen) != 0) continue; if (repo_name[namelen] == '\0' || strcmp(&repo_name[namelen], ".git") == 0) return repo; } return NULL; } struct gotd_repo * gotd_find_repo_by_path(const char *repo_path, struct gotd *gotd) { struct gotd_repo *repo; TAILQ_FOREACH(repo, &gotd->repos, entry) { if (strcmp(repo->path, repo_path) == 0) return repo; } return NULL; } struct gotd_uid_connection_limit * gotd_find_uid_connection_limit(struct gotd_uid_connection_limit *limits, size_t nlimits, uid_t uid) { /* This array is always sorted to allow for binary search. */ int i, left = 0, right = nlimits - 1; while (left <= right) { i = ((left + right) / 2); if (limits[i].uid == uid) return &limits[i]; if (limits[i].uid > uid) left = i + 1; else right = i - 1; } return NULL; } int gotd_parseuid(const char *s, uid_t *uid) { struct passwd *pw; const char *errstr; if ((pw = getpwnam(s)) != NULL) { *uid = pw->pw_uid; if (*uid == UID_MAX) return -1; return 0; } *uid = strtonum(s, 0, UID_MAX - 1, &errstr); if (errstr) return -1; return 0; } const struct got_error * gotd_parse_url(char **proto, char **host, char **port, char **request_path, const char *url) { const struct got_error *err = NULL; char *s, *p, *q; *proto = *host = *port = *request_path = NULL; p = strstr(url, "://"); if (!p) return got_error(GOT_ERR_PARSE_URI); *proto = strndup(url, p - url); if (*proto == NULL) { err = got_error_from_errno("strndup"); goto done; } s = p + 3; p = strstr(s, "/"); if (p == NULL) { err = got_error(GOT_ERR_PARSE_URI); goto done; } q = memchr(s, ':', p - s); if (q) { *host = strndup(s, q - s); if (*host == NULL) { err = got_error_from_errno("strndup"); goto done; } if ((*host)[0] == '\0') { err = got_error(GOT_ERR_PARSE_URI); goto done; } *port = strndup(q + 1, p - (q + 1)); if (*port == NULL) { err = got_error_from_errno("strndup"); goto done; } if ((*port)[0] == '\0') { err = got_error(GOT_ERR_PARSE_URI); goto done; } } else { *host = strndup(s, p - s); if (*host == NULL) { err = got_error_from_errno("strndup"); goto done; } if ((*host)[0] == '\0') { err = got_error(GOT_ERR_PARSE_URI); goto done; } } while (p[0] == '/' && p[1] == '/') p++; *request_path = strdup(p); if (*request_path == NULL) { err = got_error_from_errno("strdup"); goto done; } if ((*request_path)[0] == '\0') { err = got_error(GOT_ERR_PARSE_URI); goto done; } done: if (err) { free(*proto); *proto = NULL; free(*host); *host = NULL; free(*port); *port = NULL; free(*request_path); *request_path = NULL; } return err; } static char * port_sprintf(int p) { static char portno[32]; int n; n = snprintf(portno, sizeof(portno), "%lld", (long long)p); if (n < 0 || (size_t)n >= sizeof(portno)) fatalx("port number too long: %lld", (long long)p); return portno; } got-portable-0.101/gotd/repo_read.c0000664000175100017510000005614614644144735012670 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_cancel.h" #include "got_object.h" #include "got_repository.h" #include "got_reference.h" #include "got_repository_admin.h" #include "got_path.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_object_idset.h" #include "got_lib_hash.h" #include "got_lib_pack.h" #include "got_lib_ratelimit.h" #include "got_lib_pack_create.h" #include "got_lib_poll.h" #include "log.h" #include "gotd.h" #include "repo_read.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif static struct repo_read { pid_t pid; const char *title; struct got_repository *repo; int *pack_fds; int *temp_fds; int session_fd; struct gotd_imsgev session_iev; int refs_listed; } repo_read; static struct repo_read_client { uint32_t id; int fd; int delta_cache_fd; int report_progress; int pack_pipe; struct got_object_idset *want_ids; struct got_object_idset *have_ids; } repo_read_client; static volatile sig_atomic_t sigint_received; static volatile sig_atomic_t sigterm_received; static void catch_sigint(int signo) { sigint_received = 1; } static void catch_sigterm(int signo) { sigterm_received = 1; } static const struct got_error * check_cancelled(void *arg) { if (sigint_received || sigterm_received) return got_error(GOT_ERR_CANCELLED); return NULL; } static const struct got_error * send_symref(struct got_reference *symref, struct got_object_id *target_id, struct imsgbuf *ibuf) { const struct got_error *err = NULL; struct gotd_imsg_symref isymref; const char *refname = got_ref_get_name(symref); const char *target = got_ref_get_symref_target(symref); size_t len; struct ibuf *wbuf; memset(&isymref, 0, sizeof(isymref)); isymref.name_len = strlen(refname); isymref.target_len = strlen(target); memcpy(isymref.target_id, target_id->sha1, sizeof(isymref.target_id)); len = sizeof(isymref) + isymref.name_len + isymref.target_len; if (len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) { err = got_error(GOT_ERR_NO_SPACE); goto done; } wbuf = imsg_create(ibuf, GOTD_IMSG_SYMREF, 0, 0, len); if (wbuf == NULL) { err = got_error_from_errno("imsg_create SYMREF"); goto done; } if (imsg_add(wbuf, &isymref, sizeof(isymref)) == -1) { err = got_error_from_errno("imsg_add SYMREF"); goto done; } if (imsg_add(wbuf, refname, isymref.name_len) == -1) { err = got_error_from_errno("imsg_add SYMREF"); goto done; } if (imsg_add(wbuf, target, isymref.target_len) == -1) { err = got_error_from_errno("imsg_add SYMREF"); goto done; } imsg_close(ibuf, wbuf); done: free(target_id); return err; } static const struct got_error * send_peeled_tag_ref(struct got_reference *ref, struct got_object *obj, struct imsgbuf *ibuf) { const struct got_error *err = NULL; struct got_tag_object *tag; size_t namelen, len; char *peeled_refname = NULL; struct got_object_id *id; struct ibuf *wbuf; err = got_object_tag_open(&tag, repo_read.repo, obj); if (err) return err; if (asprintf(&peeled_refname, "%s^{}", got_ref_get_name(ref)) == -1) { err = got_error_from_errno("asprintf"); goto done; } id = got_object_tag_get_object_id(tag); namelen = strlen(peeled_refname); len = sizeof(struct gotd_imsg_ref) + namelen; if (len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) { err = got_error(GOT_ERR_NO_SPACE); goto done; } wbuf = imsg_create(ibuf, GOTD_IMSG_REF, PROC_REPO_READ, repo_read.pid, len); if (wbuf == NULL) { err = got_error_from_errno("imsg_create MREF"); goto done; } /* Keep in sync with struct gotd_imsg_ref definition. */ if (imsg_add(wbuf, id->sha1, SHA1_DIGEST_LENGTH) == -1) { err = got_error_from_errno("imsg_add REF"); goto done; } if (imsg_add(wbuf, &namelen, sizeof(namelen)) == -1) { err = got_error_from_errno("imsg_add REF"); goto done; } if (imsg_add(wbuf, peeled_refname, namelen) == -1) { err = got_error_from_errno("imsg_add REF"); goto done; } imsg_close(ibuf, wbuf); done: got_object_tag_close(tag); return err; } static const struct got_error * send_ref(struct got_reference *ref, struct imsgbuf *ibuf) { const struct got_error *err; const char *refname = got_ref_get_name(ref); size_t namelen; struct got_object_id *id = NULL; struct got_object *obj = NULL; size_t len; struct ibuf *wbuf; namelen = strlen(refname); len = sizeof(struct gotd_imsg_ref) + namelen; if (len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) return got_error(GOT_ERR_NO_SPACE); err = got_ref_resolve(&id, repo_read.repo, ref); if (err) return err; wbuf = imsg_create(ibuf, GOTD_IMSG_REF, PROC_REPO_READ, repo_read.pid, len); if (wbuf == NULL) { err = got_error_from_errno("imsg_create REF"); goto done; } /* Keep in sync with struct gotd_imsg_ref definition. */ if (imsg_add(wbuf, id->sha1, SHA1_DIGEST_LENGTH) == -1) return got_error_from_errno("imsg_add REF"); if (imsg_add(wbuf, &namelen, sizeof(namelen)) == -1) return got_error_from_errno("imsg_add REF"); if (imsg_add(wbuf, refname, namelen) == -1) return got_error_from_errno("imsg_add REF"); imsg_close(ibuf, wbuf); err = got_object_open(&obj, repo_read.repo, id); if (err) goto done; if (obj->type == GOT_OBJ_TYPE_TAG) err = send_peeled_tag_ref(ref, obj, ibuf); done: if (obj) got_object_close(obj); free(id); return err; } static const struct got_error * list_refs(struct imsg *imsg) { const struct got_error *err; struct repo_read_client *client = &repo_read_client; struct got_reflist_head refs; struct got_reflist_entry *re; size_t datalen; struct gotd_imsg_reflist irefs; struct imsgbuf ibuf; int client_fd; struct got_object_id *head_target_id = NULL; TAILQ_INIT(&refs); client_fd = imsg_get_fd(imsg); if (client_fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); if (repo_read.refs_listed) { return got_error_msg(GOT_ERR_CLIENT_ID, "duplicate list-refs request"); } repo_read.refs_listed = 1; client->fd = client_fd; imsg_init(&ibuf, client_fd); err = got_ref_list(&refs, repo_read.repo, "", got_ref_cmp_by_name, NULL); if (err) return err; memset(&irefs, 0, sizeof(irefs)); TAILQ_FOREACH(re, &refs, entry) { struct got_object_id *id; int obj_type; if (got_ref_is_symbolic(re->ref)) { const char *refname = got_ref_get_name(re->ref); if (strcmp(refname, GOT_REF_HEAD) != 0) continue; err = got_ref_resolve(&head_target_id, repo_read.repo, re->ref); if (err) { if (err->code != GOT_ERR_NOT_REF) return err; /* * HEAD points to a non-existent branch. * Do not advertise it. * Matches git-daemon's behaviour. */ head_target_id = NULL; err = NULL; } else irefs.nrefs++; continue; } irefs.nrefs++; /* Account for a peeled tag refs. */ err = got_ref_resolve(&id, repo_read.repo, re->ref); if (err) goto done; err = got_object_get_type(&obj_type, repo_read.repo, id); free(id); if (err) goto done; if (obj_type == GOT_OBJ_TYPE_TAG) irefs.nrefs++; } if (imsg_compose(&ibuf, GOTD_IMSG_REFLIST, PROC_REPO_READ, repo_read.pid, -1, &irefs, sizeof(irefs)) == -1) { err = got_error_from_errno("imsg_compose REFLIST"); goto done; } /* * Send the HEAD symref first. In Git-protocol versions < 2 * the HEAD symref must be announced on the initial line of * the server's ref advertisement. * For now, we do not advertise symrefs other than HEAD. */ TAILQ_FOREACH(re, &refs, entry) { if (!got_ref_is_symbolic(re->ref) || strcmp(got_ref_get_name(re->ref), GOT_REF_HEAD) != 0 || head_target_id == NULL) continue; err = send_symref(re->ref, head_target_id, &ibuf); if (err) goto done; break; } TAILQ_FOREACH(re, &refs, entry) { if (got_ref_is_symbolic(re->ref)) continue; err = send_ref(re->ref, &ibuf); if (err) goto done; } err = gotd_imsg_flush(&ibuf); done: got_ref_list_free(&refs); imsg_clear(&ibuf); return err; } static const struct got_error * append_object_id(struct got_object_id *id, void *data, void *arg) { struct gotd_object_id_array *array = arg; const size_t alloc_chunksz = 256; if (array->ids == NULL) { array->ids = reallocarray(NULL, alloc_chunksz, sizeof(*array->ids)); if (array->ids == NULL) return got_error_from_errno("reallocarray"); array->nalloc = alloc_chunksz; array->nids = 0; } else if (array->nalloc <= array->nids) { struct got_object_id **new; new = recallocarray(array->ids, array->nalloc, array->nalloc + alloc_chunksz, sizeof(*new)); if (new == NULL) return got_error_from_errno("recallocarray"); array->ids = new; array->nalloc += alloc_chunksz; } array->ids[array->nids] = id; array->nids++; return NULL; } static const struct got_error * recv_want(struct imsg *imsg) { const struct got_error *err; struct repo_read_client *client = &repo_read_client; struct gotd_imsg_want iwant; size_t datalen; char hex[SHA1_DIGEST_STRING_LENGTH]; struct got_object_id id; int obj_type; struct imsgbuf ibuf; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(iwant)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iwant, imsg->data, sizeof(iwant)); memset(&id, 0, sizeof(id)); memcpy(id.sha1, iwant.object_id, SHA1_DIGEST_LENGTH); if (log_getverbose() > 0 && got_object_id_hex(&id, hex, sizeof(hex))) log_debug("client wants %s", hex); imsg_init(&ibuf, client->fd); err = got_object_get_type(&obj_type, repo_read.repo, &id); if (err) return err; if (obj_type != GOT_OBJ_TYPE_COMMIT && obj_type != GOT_OBJ_TYPE_TAG) return got_error(GOT_ERR_OBJ_TYPE); if (!got_object_idset_contains(client->want_ids, &id)) { err = got_object_idset_add(client->want_ids, &id, NULL); if (err) return err; } gotd_imsg_send_ack(&id, &ibuf, PROC_REPO_READ, repo_read.pid); imsg_clear(&ibuf); return err; } static const struct got_error * recv_have(struct imsg *imsg) { const struct got_error *err; struct repo_read_client *client = &repo_read_client; struct gotd_imsg_have ihave; size_t datalen; char hex[SHA1_DIGEST_STRING_LENGTH]; struct got_object_id id; int obj_type; struct imsgbuf ibuf; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ihave)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ihave, imsg->data, sizeof(ihave)); memset(&id, 0, sizeof(id)); memcpy(id.sha1, ihave.object_id, SHA1_DIGEST_LENGTH); if (log_getverbose() > 0 && got_object_id_hex(&id, hex, sizeof(hex))) log_debug("client has %s", hex); imsg_init(&ibuf, client->fd); err = got_object_get_type(&obj_type, repo_read.repo, &id); if (err) { if (err->code == GOT_ERR_NO_OBJ) { gotd_imsg_send_nak(&id, &ibuf, PROC_REPO_READ, repo_read.pid); err = NULL; } goto done; } if (obj_type != GOT_OBJ_TYPE_COMMIT && obj_type != GOT_OBJ_TYPE_TAG) { gotd_imsg_send_nak(&id, &ibuf, PROC_REPO_READ, repo_read.pid); err = got_error(GOT_ERR_OBJ_TYPE); goto done; } if (!got_object_idset_contains(client->have_ids, &id)) { err = got_object_idset_add(client->have_ids, &id, NULL); if (err) goto done; } gotd_imsg_send_ack(&id, &ibuf, PROC_REPO_READ, repo_read.pid); done: imsg_clear(&ibuf); return err; } struct repo_read_pack_progress_arg { int report_progress; struct imsgbuf *ibuf; int sent_ready; }; static const struct got_error * pack_progress(void *arg, int ncolored, int nfound, int ntrees, off_t packfile_size, int ncommits, int nobj_total, int nobj_deltify, int nobj_written) { struct repo_read_pack_progress_arg *a = arg; struct gotd_imsg_packfile_progress iprog; int ret; if (!a->report_progress) return NULL; if (packfile_size > 0 && a->sent_ready) return NULL; memset(&iprog, 0, sizeof(iprog)); iprog.ncolored = ncolored; iprog.nfound = nfound; iprog.ntrees = ntrees; iprog.packfile_size = packfile_size; iprog.ncommits = ncommits; iprog.nobj_total = nobj_total; iprog.nobj_deltify = nobj_deltify; iprog.nobj_written = nobj_written; /* Using synchronous writes since we are blocking the event loop. */ if (packfile_size == 0) { ret = imsg_compose(a->ibuf, GOTD_IMSG_PACKFILE_PROGRESS, PROC_REPO_READ, repo_read.pid, -1, &iprog, sizeof(iprog)); if (ret == -1) { return got_error_from_errno("imsg compose " "PACKFILE_PROGRESS"); } } else { a->sent_ready = 1; ret = imsg_compose(a->ibuf, GOTD_IMSG_PACKFILE_READY, PROC_REPO_READ, repo_read.pid, -1, &iprog, sizeof(iprog)); if (ret == -1) { return got_error_from_errno("imsg compose " "PACKFILE_READY"); } } return gotd_imsg_flush(a->ibuf); } static const struct got_error * receive_delta_cache_fd(struct imsg *imsg, struct gotd_imsgev *iev) { struct repo_read_client *client = &repo_read_client; struct gotd_imsg_send_packfile ireq; size_t datalen; log_debug("receiving delta cache file"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ireq)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ireq, imsg->data, sizeof(ireq)); if (client->delta_cache_fd != -1) return got_error(GOT_ERR_PRIVSEP_MSG); client->delta_cache_fd = imsg_get_fd(imsg); if (client->delta_cache_fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); client->report_progress = ireq.report_progress; return NULL; } static const struct got_error * receive_pack_pipe(struct imsg *imsg, struct gotd_imsgev *iev) { struct repo_read_client *client = &repo_read_client; size_t datalen; log_debug("receiving pack pipe descriptor"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); if (client->pack_pipe != -1) return got_error(GOT_ERR_PRIVSEP_MSG); client->pack_pipe = imsg_get_fd(imsg); if (client->pack_pipe == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); return NULL; } static const struct got_error * send_packfile(struct imsg *imsg, struct gotd_imsgev *iev) { const struct got_error *err = NULL; struct repo_read_client *client = &repo_read_client; uint8_t packsha1[SHA1_DIGEST_LENGTH]; char hex[SHA1_DIGEST_STRING_LENGTH]; FILE *delta_cache = NULL; struct imsgbuf ibuf; struct repo_read_pack_progress_arg pa; struct got_ratelimit rl; struct gotd_object_id_array want_ids; struct gotd_object_id_array have_ids; log_debug("packfile request received"); memset(&want_ids, 0, sizeof(want_ids)); memset(&have_ids, 0, sizeof(have_ids)); got_ratelimit_init(&rl, 2, 0); if (client->delta_cache_fd == -1 || client->pack_pipe == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); imsg_init(&ibuf, client->fd); delta_cache = fdopen(client->delta_cache_fd, "w+"); if (delta_cache == NULL) { err = got_error_from_errno("fdopen"); goto done; } client->delta_cache_fd = -1; memset(&pa, 0, sizeof(pa)); pa.ibuf = &ibuf; pa.report_progress = client->report_progress; err = got_object_idset_for_each(client->want_ids, append_object_id, &want_ids); if (err) goto done; err = got_object_idset_for_each(client->have_ids, append_object_id, &have_ids); if (err) goto done; err = got_pack_create(packsha1, client->pack_pipe, delta_cache, have_ids.ids, have_ids.nids, want_ids.ids, want_ids.nids, repo_read.repo, 0, 1, 0, pack_progress, &pa, &rl, check_cancelled, NULL); if (err) goto done; if (log_getverbose() > 0 && got_sha1_digest_to_str(packsha1, hex, sizeof(hex))) log_debug("sent pack-%s.pack", hex); if (gotd_imsg_compose_event(iev, GOTD_IMSG_PACKFILE_DONE, PROC_REPO_READ, -1, NULL, 0) == -1) err = got_error_from_errno("imsg compose PACKFILE_DONE"); done: if (client->delta_cache_fd != -1 && close(client->delta_cache_fd) == -1 && err == NULL) err = got_error_from_errno("close"); client->delta_cache_fd = -1; if (delta_cache != NULL && fclose(delta_cache) == EOF && err == NULL) err = got_error_from_errno("fclose"); imsg_clear(&ibuf); free(want_ids.ids); free(have_ids.ids); return err; } static void repo_read_dispatch_session(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; ssize_t n; int shut = 0; struct repo_read_client *client = &repo_read_client; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) /* Connection closed. */ shut = 1; } if (event & EV_WRITE) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno != EAGAIN) fatal("msgbuf_write"); if (n == 0) /* Connection closed. */ shut = 1; } while (err == NULL && check_cancelled(NULL) == NULL) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get", __func__); if (n == 0) /* No more messages. */ break; if (imsg.hdr.type != GOTD_IMSG_LIST_REFS_INTERNAL && !repo_read.refs_listed) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } switch (imsg.hdr.type) { case GOTD_IMSG_LIST_REFS_INTERNAL: err = list_refs(&imsg); if (err) log_warnx("ls-refs: %s", err->msg); break; case GOTD_IMSG_WANT: err = recv_want(&imsg); if (err) log_warnx("want-line: %s", err->msg); break; case GOTD_IMSG_HAVE: err = recv_have(&imsg); if (err) log_warnx("have-line: %s", err->msg); break; case GOTD_IMSG_SEND_PACKFILE: err = receive_delta_cache_fd(&imsg, iev); if (err) log_warnx("receiving delta cache: %s", err->msg); break; case GOTD_IMSG_PACKFILE_PIPE: err = receive_pack_pipe(&imsg, iev); if (err) { log_warnx("receiving pack pipe: %s", err->msg); break; } err = send_packfile(&imsg, iev); if (err) log_warnx("sending packfile: %s", err->msg); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } if (!shut && check_cancelled(NULL) == NULL) { if (err && gotd_imsg_send_error_event(iev, PROC_REPO_READ, client->id, err) == -1) { log_warnx("could not send error to parent: %s", err->msg); } gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } static const struct got_error * recv_connect(struct imsg *imsg) { struct gotd_imsgev *iev = &repo_read.session_iev; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); if (repo_read.session_fd != -1) return got_error(GOT_ERR_PRIVSEP_MSG); repo_read.session_fd = imsg_get_fd(imsg); if (repo_read.session_fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); imsg_init(&iev->ibuf, repo_read.session_fd); iev->handler = repo_read_dispatch_session; iev->events = EV_READ; iev->handler_arg = NULL; event_set(&iev->ev, iev->ibuf.fd, EV_READ, repo_read_dispatch_session, iev); gotd_imsg_event_add(iev); return NULL; } static void repo_read_dispatch(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; ssize_t n; int shut = 0; struct repo_read_client *client = &repo_read_client; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) fatal("imsg_read error"); if (n == 0) /* Connection closed. */ shut = 1; } if (event & EV_WRITE) { n = msgbuf_write(&ibuf->w); if (n == -1 && errno != EAGAIN) fatal("msgbuf_write"); if (n == 0) /* Connection closed. */ shut = 1; } while (err == NULL && check_cancelled(NULL) == NULL) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_CONNECT_REPO_CHILD: err = recv_connect(&imsg); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } if (!shut && check_cancelled(NULL) == NULL) { if (err && gotd_imsg_send_error_event(iev, PROC_REPO_READ, client->id, err) == -1) { log_warnx("could not send error to parent: %s", err->msg); } gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void repo_read_main(const char *title, const char *repo_path, int *pack_fds, int *temp_fds) { const struct got_error *err = NULL; struct repo_read_client *client = &repo_read_client; struct gotd_imsgev iev; client->fd = -1; client->delta_cache_fd = -1; client->pack_pipe = -1; client->have_ids = got_object_idset_alloc(); if (client->have_ids == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } client->want_ids = got_object_idset_alloc(); if (client->want_ids == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } repo_read.title = title; repo_read.pid = getpid(); repo_read.pack_fds = pack_fds; repo_read.temp_fds = temp_fds; repo_read.session_fd = -1; repo_read.session_iev.ibuf.fd = -1; err = got_repo_open(&repo_read.repo, repo_path, NULL, pack_fds); if (err) goto done; if (!got_repo_is_bare(repo_read.repo)) { err = got_error_msg(GOT_ERR_NOT_GIT_REPO, "bare git repository required"); goto done; } got_repo_temp_fds_set(repo_read.repo, temp_fds); signal(SIGINT, catch_sigint); signal(SIGTERM, catch_sigterm); signal(SIGPIPE, SIG_IGN); signal(SIGHUP, SIG_IGN); imsg_init(&iev.ibuf, GOTD_FILENO_MSG_PIPE); iev.handler = repo_read_dispatch; iev.events = EV_READ; iev.handler_arg = NULL; event_set(&iev.ev, iev.ibuf.fd, EV_READ, repo_read_dispatch, &iev); if (gotd_imsg_compose_event(&iev, GOTD_IMSG_REPO_CHILD_READY, PROC_REPO_READ, -1, NULL, 0) == -1) { err = got_error_from_errno("imsg compose REPO_CHILD_READY"); goto done; } event_dispatch(); done: if (err) log_warnx("%s: %s", title, err->msg); repo_read_shutdown(); } void repo_read_shutdown(void) { struct repo_read_client *client = &repo_read_client; log_debug("%s: shutting down", repo_read.title); if (client->have_ids) got_object_idset_free(client->have_ids); if (client->want_ids) got_object_idset_free(client->want_ids); if (client->fd != -1) close(client->fd); if (client->delta_cache_fd != -1) close(client->delta_cache_fd); if (client->pack_pipe != -1) close(client->pack_pipe); if (repo_read.repo) got_repo_close(repo_read.repo); got_repo_pack_fds_close(repo_read.pack_fds); got_repo_temp_fds_close(repo_read.temp_fds); if (repo_read.session_fd != -1) close(repo_read.session_fd); exit(0); } got-portable-0.101/gotd/gotd.80000664000175100017510000000540714644143163011576 .\" .\" Copyright (c) 2022 Stefan Sperling .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt GOTD 8 .Os .Sh NAME .Nm gotd .Nd Game of Trees Daemon .Sh SYNOPSIS .Nm .Op Fl dnv .Op Fl f Ar config-file .Sh DESCRIPTION .Nm is a Git repository server which listens on a .Xr unix 4 socket and relies on its companion tool .Xr gotsh 1 to handle Git-protocol communication over the network, via .Xr ssh 1 . .Pp The Git repository format is described in .Xr git-repository 5 . .Pp .Nm requires a configuration file in order to run. The configuration file format is described in .Xr gotd.conf 5 . .Pp It is recommended to restrict .Xr ssh 1 features available to users of .Nm . See .Xr gotsh 1 for details. .Pp The options for .Nm are as follows: .Bl -tag -width Ds .It Fl d Do not daemonize. Send log output to stderr. .It Fl f Ar config-file Set the path to the configuration file. If not specified, the file .Pa /etc/gotd.conf will be used. .It Fl n Configtest mode. Only check the configuration file for validity. .It Fl v Verbose mode. Verbosity increases if this option is used multiple times. .El .Sh FILES .Bl -tag -width Ds -compact .It Pa /etc/gotd.conf Default location of the configuration file. .It Pa /var/run/gotd.sock Default location of the unix socket which .Nm is listening on. This path can be configured in .Xr gotd.conf 5 . .El .Sh EXAMPLES Create an empty repository to be served by .Nm , ensuring that it can only be accessed by the _gotd user: .Pp .Dl # mkdir -p /git/myrepo.git .Dl # chmod 700 /git/myrepo.git .Dl # chown _gotd /git/myrepo.git .Dl # su -m _gotd -c 'gotadmin init /git/myrepo.git' .Pp Add the new repository to .Xr gotd.conf 5 granting read-write access to the flan_hacker user account, and restart .Nm : .Pp .Dl # cat >> /etc/gotd.conf < inclusion * portable: portably wrap socket functions between BSDs/Linux * portable: improve homebrew support for MacOS # got-portable 0.74 (2022-07-14) * portable: made the 'date' command more portable in the test suite. * portable: improved error-handling for commands on BSD-systems without coreutils being installed. * portable: reworked how 'sed' is wrapped portably, so that it now doesn't use any bashisms, and will therefore run under strict POSIX-sh (dash on Ubuntu, for instance). # got-portable 0.73 (2022-07-04) * Changes as found in got-0.73. * portable: the libexec helpers now support Capsicum on FreeBSD, which is similar to OpenBSD's pledge() syscall. * Some portable work has taken place, but these have been merged upstream and hence will be in the got-0.73 changes file. # got-portable 0.71 (2022-06-23) * portable: fix cross-compilation, from Leah Neukirchen # got-portable 0.70 (2022-05-13) * Changes from got-0.70; no -portable specific changes worth mentioning. # got-portable 0.69 (2022-04-24) * portable: added Apline Linux to the core set of OSes when checking CI/CD - this therefore implies -portable can build on muscl as well as glibc. * portable: fixed compilation of -portable on Alpine Linux with respect to Landlock by using the correct header file. * portable: added SipHash as a -portable implementation. # got-portable 0.68.1 (2022-03-22) * portable: fix up a bad merge whereby a code block that should have been removed was left in-situ. # got-portable 0.68 (2022-03-22) * Changes from got-0.68 * portable: support for the following operating systems: - FreeBSD - NetBSD - DragonFlyBSD - MacOS # got-portable 0.67; (2022-02-20) * Changes from got-0.66 * Landlock support: portable now has support for the landlock API which is similar to unveil(), allowing restrictions to which part of the filesystem a process can access. # got-portable 0.66; (2022-01-12) * Changes from got-0.65 # got-portable 0.65; (2022-01-06) * Added timespec*() compat-wrappers for BSD-time functions. # got-portable 0.64; (2021-11-24) * regress: make tests POSIX-compliant by making them run under dash (Ubuntu) # got-portable 0.62; (2021-10-17) * Changes from got-0.62 # got-portable 0.61; (2021-10-09) * Port regress tests. * Improve FreeBSD compatibility. # got-portable 0.60; (2021-09-21) * First portable version released for Linux. got-portable-0.101/libexec/0000775000175100017510000000000014644145571011305 5got-portable-0.101/libexec/Makefile.am0000664000175100017510000000041514644144735013262 SUBDIRS = got-fetch-http \ got-fetch-pack \ got-index-pack \ got-read-blob \ got-read-commit \ got-read-gitconfig \ got-read-gotconfig \ got-read-object \ got-read-pack \ got-read-patch \ got-read-tag \ got-read-tree \ got-send-pack got-portable-0.101/libexec/got-send-pack/0000775000175100017510000000000014644145571013741 5got-portable-0.101/libexec/got-send-pack/Makefile.am0000664000175100017510000000142314644144735015716 libexec_PROGRAMS = got-send-pack include $(top_builddir)/Makefile.common got_send_pack_SOURCES = \ got-send-pack.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gitproto.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pkt.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/reference_parse.c got_send_pack_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.101/libexec/got-send-pack/Makefile.in0000664000175100017510000006257114644145544015741 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-send-pack$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-send-pack ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_send_pack_OBJECTS = got-send-pack.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/gitproto.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pkt.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) \ $(top_builddir)/lib/ratelimit.$(OBJEXT) \ $(top_builddir)/lib/reference_parse.$(OBJEXT) got_send_pack_OBJECTS = $(am_got_send_pack_OBJECTS) got_send_pack_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/gitproto.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pkt.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po \ $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po \ ./$(DEPDIR)/got-send-pack.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_send_pack_SOURCES) DIST_SOURCES = $(got_send_pack_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_send_pack_SOURCES = \ got-send-pack.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gitproto.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pkt.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/reference_parse.c got_send_pack_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-send-pack/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-send-pack/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files clean-libexecPROGRAMS: -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: > $(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: > $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gitproto.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pkt.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/ratelimit.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-send-pack$(EXEEXT): $(got_send_pack_OBJECTS) $(got_send_pack_DEPENDENCIES) $(EXTRA_got_send_pack_DEPENDENCIES) @rm -f got-send-pack$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_send_pack_OBJECTS) $(got_send_pack_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gitproto.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pkt.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/ratelimit.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-send-pack.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gitproto.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pkt.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f ./$(DEPDIR)/got-send-pack.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gitproto.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pkt.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f ./$(DEPDIR)/got-send-pack.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/libexec/got-send-pack/got-send-pack.c0000664000175100017510000004567314644144735016501 /* * Copyright (c) 2019 Ori Bernstein * Copyright (c) 2021 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_version.h" #include "got_fetch.h" #include "got_reference.h" #include "got_lib_hash.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_privsep.h" #include "got_lib_pack.h" #include "got_lib_pkt.h" #include "got_lib_gitproto.h" #include "got_lib_ratelimit.h" #include "got_lib_poll.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif struct got_object *indexed; static int chattygot; static const struct got_capability got_capabilities[] = { { GOT_CAPA_AGENT, "got/" GOT_VERSION_STR }, { GOT_CAPA_OFS_DELTA, NULL }, #if 0 { GOT_CAPA_SIDE_BAND_64K, NULL }, #endif { GOT_CAPA_REPORT_STATUS, NULL }, { GOT_CAPA_DELETE_REFS, NULL }, }; static const struct got_error * send_upload_progress(struct imsgbuf *ibuf, off_t bytes, struct got_ratelimit *rl) { const struct got_error *err = NULL; int elapsed = 0; if (rl) { err = got_ratelimit_check(&elapsed, rl); if (err || !elapsed) return err; } if (imsg_compose(ibuf, GOT_IMSG_SEND_UPLOAD_PROGRESS, 0, 0, -1, &bytes, sizeof(bytes)) == -1) return got_error_from_errno( "imsg_compose SEND_UPLOAD_PROGRESS"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * send_pack_request(struct imsgbuf *ibuf) { if (imsg_compose(ibuf, GOT_IMSG_SEND_PACK_REQUEST, 0, 0, -1, NULL, 0) == -1) return got_error_from_errno("imsg_compose SEND_PACK_REQUEST"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * send_done(struct imsgbuf *ibuf) { if (imsg_compose(ibuf, GOT_IMSG_SEND_DONE, 0, 0, -1, NULL, 0) == -1) return got_error_from_errno("imsg_compose SEND_DONE"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * recv_packfd(int *packfd, struct imsgbuf *ibuf) { const struct got_error *err; struct imsg imsg; *packfd = -1; err = got_privsep_recv_imsg(&imsg, ibuf, 0); if (err) return err; if (imsg.hdr.type == GOT_IMSG_STOP) { err = got_error(GOT_ERR_CANCELLED); goto done; } if (imsg.hdr.type != GOT_IMSG_SEND_PACKFD) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } if (imsg.hdr.len - IMSG_HEADER_SIZE != 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } *packfd = imsg_get_fd(&imsg); done: imsg_free(&imsg); return err; } static const struct got_error * send_pack_file(int sendfd, int packfd, struct imsgbuf *ibuf) { const struct got_error *err; unsigned char buf[8192]; ssize_t r; off_t wtotal = 0; struct got_ratelimit rl; if (lseek(packfd, 0L, SEEK_SET) == -1) return got_error_from_errno("lseek"); got_ratelimit_init(&rl, 0, 500); for (;;) { r = read(packfd, buf, sizeof(buf)); if (r == -1) return got_error_from_errno("read"); if (r == 0) break; err = got_poll_write_full(sendfd, buf, r); if (err) return NULL; wtotal += r; err = send_upload_progress(ibuf, wtotal, &rl); if (err) return err; } return send_upload_progress(ibuf, wtotal, NULL); } static const struct got_error * send_error(const char *buf, size_t len) { static char msg[1024]; size_t i; for (i = 0; i < len && i < sizeof(msg) - 1; i++) { if (!isprint((unsigned char)buf[i])) return got_error_msg(GOT_ERR_BAD_PACKET, "non-printable error message received from server"); msg[i] = buf[i]; } msg[i] = '\0'; return got_error_msg(GOT_ERR_SEND_FAILED, msg); } static const struct got_error * send_their_ref(struct imsgbuf *ibuf, struct got_object_id *refid, const char *refname) { struct ibuf *wbuf; size_t len, reflen = strlen(refname); len = sizeof(struct got_imsg_send_remote_ref) + reflen; if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE) return got_error(GOT_ERR_NO_SPACE); wbuf = imsg_create(ibuf, GOT_IMSG_SEND_REMOTE_REF, 0, 0, len); if (wbuf == NULL) return got_error_from_errno("imsg_create SEND_REMOTE_REF"); /* Keep in sync with struct got_imsg_send_remote_ref definition! */ if (imsg_add(wbuf, refid, sizeof(*refid)) == -1) return got_error_from_errno("imsg_add SEND_REMOTE_REF"); if (imsg_add(wbuf, &reflen, sizeof(reflen)) == -1) return got_error_from_errno("imsg_add SEND_REMOTE_REF"); if (imsg_add(wbuf, refname, reflen) == -1) return got_error_from_errno("imsg_add SEND_REMOTE_REF"); imsg_close(ibuf, wbuf); return got_privsep_flush_imsg(ibuf); } static const struct got_error * send_ref_status(struct imsgbuf *ibuf, const char *refname, int success, struct got_pathlist_head *refs, struct got_pathlist_head *delete_refs) { struct ibuf *wbuf; size_t i, len, reflen, errmsglen = 0; struct got_pathlist_entry *pe; int ref_valid = 0; char *eol, *sp; const char *errmsg = ""; eol = strchr(refname, '\n'); if (eol == NULL) { return got_error_msg(GOT_ERR_BAD_PACKET, "unexpected message from server"); } *eol = '\0'; sp = strchr(refname, ' '); if (sp != NULL) { *sp++ = '\0'; errmsg = sp; errmsglen = strlen(errmsg); for (i = 0; i < errmsglen; ++i) { if (!isprint((unsigned char)errmsg[i])) { return got_error_msg(GOT_ERR_BAD_PACKET, "non-printable error message received " "from the server"); } } } reflen = strlen(refname); if (!got_ref_name_is_valid(refname)) { return got_error_msg(GOT_ERR_BAD_PACKET, "unexpected message from server"); } TAILQ_FOREACH(pe, refs, entry) { if (strcmp(refname, pe->path) == 0) { ref_valid = 1; break; } } if (!ref_valid) { TAILQ_FOREACH(pe, delete_refs, entry) { if (strcmp(refname, pe->path) == 0) { ref_valid = 1; break; } } } if (!ref_valid) { return got_error_msg(GOT_ERR_BAD_PACKET, "unexpected message from server"); } len = sizeof(struct got_imsg_send_ref_status) + reflen + errmsglen; if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE) return got_error(GOT_ERR_NO_SPACE); wbuf = imsg_create(ibuf, GOT_IMSG_SEND_REF_STATUS, 0, 0, len); if (wbuf == NULL) return got_error_from_errno("imsg_create SEND_REF_STATUS"); /* Keep in sync with struct got_imsg_send_ref_status definition! */ if (imsg_add(wbuf, &success, sizeof(success)) == -1) return got_error_from_errno("imsg_add SEND_REF_STATUS"); if (imsg_add(wbuf, &reflen, sizeof(reflen)) == -1) return got_error_from_errno("imsg_add SEND_REF_STATUS"); if (imsg_add(wbuf, &errmsglen, sizeof(errmsglen)) == -1) return got_error_from_errno("imsg_add SEND_REF_STATUS"); if (imsg_add(wbuf, refname, reflen) == -1) return got_error_from_errno("imsg_add SEND_REF_STATUS"); if (imsg_add(wbuf, errmsg, errmsglen) == -1) return got_error_from_errno("imsg_add SEND_REF_STATUS"); imsg_close(ibuf, wbuf); return got_privsep_flush_imsg(ibuf); } static const struct got_error * describe_refchange(int *n, int *sent_my_capabilites, const char *my_capabilities, char *buf, size_t bufsize, const char *refname, const char *old_hashstr, const char *new_hashstr) { *n = snprintf(buf, bufsize, "%s %s %s", old_hashstr, new_hashstr, refname); if (*n < 0 || (size_t)*n >= bufsize) return got_error(GOT_ERR_NO_SPACE); /* * We must announce our capabilities along with the first * reference. Unfortunately, the protocol requires an embedded * NUL as a separator between reference name and capabilities, * which we have to deal with here. * It also requires a linefeed for terminating packet data. */ if (!*sent_my_capabilites && my_capabilities != NULL) { int m; if (*n >= bufsize - 1) return got_error(GOT_ERR_NO_SPACE); m = snprintf(buf + *n + 1, /* offset after '\0' */ bufsize - (*n + 1), "%s\n", my_capabilities); if (m < 0 || *n + m >= bufsize) return got_error(GOT_ERR_NO_SPACE); *n += m; *sent_my_capabilites = 1; } else { *n = strlcat(buf, "\n", bufsize); if (*n >= bufsize) return got_error(GOT_ERR_NO_SPACE); } return NULL; } static const struct got_error * send_pack(int fd, struct got_pathlist_head *refs, struct got_pathlist_head *delete_refs, struct imsgbuf *ibuf) { const struct got_error *err = NULL; char buf[GOT_PKT_MAX]; const unsigned char zero_id[SHA1_DIGEST_LENGTH] = { 0 }; char old_hashstr[SHA1_DIGEST_STRING_LENGTH]; char new_hashstr[SHA1_DIGEST_STRING_LENGTH]; struct got_pathlist_head their_refs; int is_firstpkt = 1; int n, nsent = 0; int packfd = -1; char *id_str = NULL, *refname = NULL; struct got_object_id *id = NULL; char *server_capabilities = NULL, *my_capabilities = NULL; struct got_pathlist_entry *pe; int sent_my_capabilites = 0; TAILQ_INIT(&their_refs); if (TAILQ_EMPTY(refs) && TAILQ_EMPTY(delete_refs)) return got_error(GOT_ERR_SEND_EMPTY); while (1) { err = got_pkt_readpkt(&n, fd, buf, sizeof(buf), chattygot, INFTIM); if (err) goto done; if (n == 0) break; if (n >= 4 && strncmp(buf, "ERR ", 4) == 0) { err = send_error(&buf[4], n - 4); goto done; } free(id_str); free(refname); err = got_gitproto_parse_refline(&id_str, &refname, &server_capabilities, buf, n); if (err) goto done; if (is_firstpkt) { if (server_capabilities == NULL) { server_capabilities = strdup(""); if (server_capabilities == NULL) { err = got_error_from_errno("strdup"); goto done; } } if (chattygot && server_capabilities[0] != '\0') fprintf(stderr, "%s: server capabilities: %s\n", getprogname(), server_capabilities); err = got_gitproto_match_capabilities(&my_capabilities, NULL, server_capabilities, got_capabilities, nitems(got_capabilities)); if (err) goto done; if (chattygot) fprintf(stderr, "%s: my capabilities:%s\n", getprogname(), my_capabilities ? my_capabilities : ""); is_firstpkt = 0; } if (strstr(refname, "^{}")) { if (chattygot) { fprintf(stderr, "%s: ignoring %s\n", getprogname(), refname); } continue; } id = malloc(sizeof(*id)); if (id == NULL) { err = got_error_from_errno("malloc"); goto done; } if (!got_parse_object_id(id, id_str, GOT_HASH_SHA1)) { err = got_error(GOT_ERR_BAD_OBJ_ID_STR); goto done; } err = send_their_ref(ibuf, id, refname); if (err) goto done; err = got_pathlist_append(&their_refs, refname, id); if (err) goto done; if (chattygot) fprintf(stderr, "%s: remote has %s %s\n", getprogname(), refname, id_str); free(id_str); id_str = NULL; refname = NULL; /* do not free; owned by their_refs */ id = NULL; /* do not free; owned by their_refs */ } if (!TAILQ_EMPTY(delete_refs)) { if (my_capabilities == NULL || strstr(my_capabilities, GOT_CAPA_DELETE_REFS) == NULL) { err = got_error(GOT_ERR_CAPA_DELETE_REFS); goto done; } } TAILQ_FOREACH(pe, delete_refs, entry) { const char *refname = pe->path; struct got_pathlist_entry *their_pe; struct got_object_id *their_id = NULL; TAILQ_FOREACH(their_pe, &their_refs, entry) { const char *their_refname = their_pe->path; if (got_path_cmp(refname, their_refname, strlen(refname), strlen(their_refname)) == 0) { their_id = their_pe->data; break; } } if (their_id == NULL) { err = got_error_fmt(GOT_ERR_NOT_REF, "%s does not exist in remote repository", refname); goto done; } got_object_id_hex(their_id, old_hashstr, sizeof(old_hashstr)); got_sha1_digest_to_str(zero_id, new_hashstr, sizeof(new_hashstr)); err = describe_refchange(&n, &sent_my_capabilites, my_capabilities, buf, sizeof(buf), refname, old_hashstr, new_hashstr); if (err) goto done; err = got_pkt_writepkt(fd, buf, n, chattygot); if (err) goto done; if (chattygot) { fprintf(stderr, "%s: deleting %s %s\n", getprogname(), refname, old_hashstr); } nsent++; } TAILQ_FOREACH(pe, refs, entry) { const char *refname = pe->path; struct got_object_id *id = pe->data; struct got_object_id *their_id = NULL; struct got_pathlist_entry *their_pe; TAILQ_FOREACH(their_pe, &their_refs, entry) { const char *their_refname = their_pe->path; if (got_path_cmp(refname, their_refname, strlen(refname), strlen(their_refname)) == 0) { their_id = their_pe->data; break; } } if (their_id) { if (got_object_id_cmp(id, their_id) == 0) { if (chattygot) { fprintf(stderr, "%s: no change for %s\n", getprogname(), refname); } continue; } got_object_id_hex(their_id, old_hashstr, sizeof(old_hashstr)); } else { got_sha1_digest_to_str(zero_id, old_hashstr, sizeof(old_hashstr)); } got_object_id_hex(id, new_hashstr, sizeof(new_hashstr)); err = describe_refchange(&n, &sent_my_capabilites, my_capabilities, buf, sizeof(buf), refname, old_hashstr, new_hashstr); if (err) goto done; err = got_pkt_writepkt(fd, buf, n, chattygot); if (err) goto done; if (chattygot) { if (their_id) { fprintf(stderr, "%s: updating %s %s -> %s\n", getprogname(), refname, old_hashstr, new_hashstr); } else { fprintf(stderr, "%s: creating %s %s\n", getprogname(), refname, new_hashstr); } } nsent++; } err = got_pkt_flushpkt(fd, chattygot); if (err) goto done; err = send_pack_request(ibuf); if (err) goto done; err = recv_packfd(&packfd, ibuf); if (err) goto done; if (packfd != -1) { err = send_pack_file(fd, packfd, ibuf); if (err) goto done; } err = got_pkt_readpkt(&n, fd, buf, sizeof(buf), chattygot, INFTIM); if (err) goto done; if (n >= 4 && strncmp(buf, "ERR ", 4) == 0) { err = send_error(&buf[4], n - 4); goto done; } else if (n < 10 || strncmp(buf, "unpack ok\n", 10) != 0) { err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected message from server"); goto done; } while (nsent > 0) { err = got_pkt_readpkt(&n, fd, buf, sizeof(buf), chattygot, INFTIM); if (err) goto done; if (n < 3) { err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected message from server"); goto done; } else if (n >= 4 && strncmp(buf, "ERR ", 4) == 0) { err = send_error(&buf[4], n - 4); goto done; } else if (strncmp(buf, "ok ", 3) == 0) { err = send_ref_status(ibuf, buf + 3, 1, refs, delete_refs); if (err) goto done; } else if (strncmp(buf, "ng ", 3) == 0) { err = send_ref_status(ibuf, buf + 3, 0, refs, delete_refs); if (err) goto done; } else { err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected message from server"); goto done; } nsent--; } err = send_done(ibuf); done: got_pathlist_free(&their_refs, GOT_PATHLIST_FREE_ALL); free(id_str); free(id); free(refname); free(server_capabilities); return err; } int main(int argc, char **argv) { const struct got_error *err = NULL; int sendfd = -1; struct imsgbuf ibuf; struct imsg imsg; struct got_pathlist_head refs; struct got_pathlist_head delete_refs; struct got_imsg_send_request send_req; struct got_imsg_send_ref href; size_t datalen, i; #if 0 static int attached; while (!attached) sleep (1); #endif TAILQ_INIT(&refs); TAILQ_INIT(&delete_refs); imsg_init(&ibuf, GOT_IMSG_FD_CHILD); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; goto done; } if (imsg.hdr.type == GOT_IMSG_STOP) goto done; if (imsg.hdr.type != GOT_IMSG_SEND_REQUEST) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(send_req)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&send_req, imsg.data, sizeof(send_req)); sendfd = imsg_get_fd(&imsg); imsg_free(&imsg); if (send_req.verbosity > 0) chattygot += send_req.verbosity; for (i = 0; i < send_req.nrefs; i++) { struct got_object_id *id; char *refname; if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; goto done; } if (imsg.hdr.type == GOT_IMSG_STOP) goto done; if (imsg.hdr.type != GOT_IMSG_SEND_REF) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(href)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&href, imsg.data, sizeof(href)); if (datalen - sizeof(href) < href.name_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } refname = malloc(href.name_len + 1); if (refname == NULL) { err = got_error_from_errno("malloc"); goto done; } memcpy(refname, imsg.data + sizeof(href), href.name_len); refname[href.name_len] = '\0'; /* * Prevent sending of references that won't make any * sense outside the local repository's context. */ if (strncmp(refname, "refs/got/", 9) == 0 || strncmp(refname, "refs/remotes/", 13) == 0) { err = got_error_fmt(GOT_ERR_SEND_BAD_REF, "%s", refname); goto done; } id = malloc(sizeof(*id)); if (id == NULL) { free(refname); err = got_error_from_errno("malloc"); goto done; } memcpy(id, &href.id, sizeof(*id)); if (href.delete) err = got_pathlist_append(&delete_refs, refname, id); else err = got_pathlist_append(&refs, refname, id); if (err) { free(refname); free(id); goto done; } imsg_free(&imsg); } err = send_pack(sendfd, &refs, &delete_refs, &ibuf); done: got_pathlist_free(&refs, GOT_PATHLIST_FREE_ALL); got_pathlist_free(&delete_refs, GOT_PATHLIST_FREE_ALL); if (sendfd != -1 && close(sendfd) == -1 && err == NULL) err = got_error_from_errno("close"); if (err != NULL && err->code != GOT_ERR_CANCELLED) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); } exit(0); } got-portable-0.101/libexec/got-read-gotconfig/0000775000175100017510000000000014644145571014764 5got-portable-0.101/libexec/got-read-gotconfig/Makefile.am0000664000175100017510000000127614644144735016747 libexec_PROGRAMS = got-read-gotconfig include $(top_builddir)/Makefile.common got_read_gotconfig_SOURCES = \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ got-read-gotconfig.c \ gotconfig.h \ parse.y got_read_gotconfig_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(libbsd_LIBS) $(zlib_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(libbsd_CFLAGS) $(zlib_CFLAGS) $(libmd_CFLAGS) got-portable-0.101/libexec/got-read-gotconfig/got-read-gotconfig.c0000664000175100017510000003564214644144735020542 /* * Copyright (c) 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_repository.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_privsep.h" #include "gotconfig.h" /* parse.y */ static volatile sig_atomic_t sigint_received; static void catch_sigint(int signo) { sigint_received = 1; } static const struct got_error * make_fetch_url(char **url, struct gotconfig_remote_repo *repo) { const struct got_error *err = NULL; char *s = NULL, *p = NULL; const char *protocol, *server, *repo_path; int port; *url = NULL; if (repo->fetch_config && repo->fetch_config->protocol) protocol = repo->fetch_config->protocol; else protocol = repo->protocol; if (protocol == NULL) return got_error_fmt(GOT_ERR_PARSE_CONFIG, "fetch protocol required for remote repository \"%s\"", repo->name); if (asprintf(&s, "%s://", protocol) == -1) return got_error_from_errno("asprintf"); if (repo->fetch_config && repo->fetch_config->server) server = repo->fetch_config->server; else server = repo->server; if (server == NULL) return got_error_fmt(GOT_ERR_PARSE_CONFIG, "fetch server required for remote repository \"%s\"", repo->name); p = s; s = NULL; if (asprintf(&s, "%s%s", p, server) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(p); p = NULL; if (repo->fetch_config && repo->fetch_config->server) port = repo->fetch_config->port; else port = repo->port; if (port) { p = s; s = NULL; if (asprintf(&s, "%s:%d", p, repo->port) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(p); p = NULL; } if (repo->fetch_config && repo->fetch_config->repository) repo_path = repo->fetch_config->repository; else repo_path = repo->repository; if (repo_path == NULL) return got_error_fmt(GOT_ERR_PARSE_CONFIG, "fetch repository path required for remote " "repository \"%s\"", repo->name); while (repo_path[0] == '/') repo_path++; p = s; s = NULL; if (asprintf(&s, "%s/%s", p, repo_path) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(p); p = NULL; got_path_strip_trailing_slashes(s); done: if (err) { free(s); free(p); } else *url = s; return err; } static const struct got_error * make_send_url(char **url, struct gotconfig_remote_repo *repo) { const struct got_error *err = NULL; char *s = NULL, *p = NULL; const char *protocol, *server, *repo_path; int port; *url = NULL; if (repo->send_config && repo->send_config->protocol) protocol = repo->send_config->protocol; else protocol = repo->protocol; if (protocol == NULL) return got_error_fmt(GOT_ERR_PARSE_CONFIG, "send protocol required for remote repository \"%s\"", repo->name); if (asprintf(&s, "%s://", protocol) == -1) return got_error_from_errno("asprintf"); if (repo->send_config && repo->send_config->server) server = repo->send_config->server; else server = repo->server; if (server == NULL) return got_error_fmt(GOT_ERR_PARSE_CONFIG, "send server required for remote repository \"%s\"", repo->name); p = s; s = NULL; if (asprintf(&s, "%s%s", p, server) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(p); p = NULL; if (repo->send_config && repo->send_config->server) port = repo->send_config->port; else port = repo->port; if (port) { p = s; s = NULL; if (asprintf(&s, "%s:%d", p, repo->port) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(p); p = NULL; } if (repo->send_config && repo->send_config->repository) repo_path = repo->send_config->repository; else repo_path = repo->repository; if (repo_path == NULL) return got_error_fmt(GOT_ERR_PARSE_CONFIG, "send repository path required for remote " "repository \"%s\"", repo->name); while (repo_path[0] == '/') repo_path++; p = s; s = NULL; if (asprintf(&s, "%s/%s", p, repo_path) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(p); p = NULL; got_path_strip_trailing_slashes(s); done: if (err) { free(s); free(p); } else *url = s; return err; } static const struct got_error * send_gotconfig_str(struct imsgbuf *ibuf, const char *value) { size_t len = value ? strlen(value) : 0; if (imsg_compose(ibuf, GOT_IMSG_GOTCONFIG_STR_VAL, 0, 0, -1, value, len) == -1) return got_error_from_errno("imsg_compose GOTCONFIG_STR_VAL"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * send_gotconfig_remotes(struct imsgbuf *ibuf, struct gotconfig_remote_repo_list *remotes, int nremotes) { const struct got_error *err = NULL; struct got_imsg_remotes iremotes; struct gotconfig_remote_repo *repo; char *fetch_url = NULL, *send_url = NULL; iremotes.nremotes = nremotes; if (imsg_compose(ibuf, GOT_IMSG_GOTCONFIG_REMOTES, 0, 0, -1, &iremotes, sizeof(iremotes)) == -1) return got_error_from_errno("imsg_compose GOTCONFIG_REMOTES"); err = got_privsep_flush_imsg(ibuf); imsg_clear(ibuf); if (err) return err; TAILQ_FOREACH(repo, remotes, entry) { struct got_imsg_remote iremote; size_t len = sizeof(iremote); struct ibuf *wbuf; struct node_branch *branch; struct node_ref *ref; int nfetch_branches = 0, nsend_branches = 0, nfetch_refs = 0; if (repo->fetch_config && repo->fetch_config->branch) branch = repo->fetch_config->branch; else branch = repo->branch; while (branch) { branch = branch->next; nfetch_branches++; } if (repo->send_config && repo->send_config->branch) branch = repo->send_config->branch; else branch = repo->branch; while (branch) { branch = branch->next; nsend_branches++; } ref = repo->fetch_ref; while (ref) { ref = ref->next; nfetch_refs++; } iremote.nfetch_branches = nfetch_branches; iremote.nsend_branches = nsend_branches; iremote.nfetch_refs = nfetch_refs; iremote.mirror_references = repo->mirror_references; iremote.fetch_all_branches = repo->fetch_all_branches; iremote.name_len = strlen(repo->name); len += iremote.name_len; err = make_fetch_url(&fetch_url, repo); if (err) break; iremote.fetch_url_len = strlen(fetch_url); len += iremote.fetch_url_len; err = make_send_url(&send_url, repo); if (err) break; iremote.send_url_len = strlen(send_url); len += iremote.send_url_len; wbuf = imsg_create(ibuf, GOT_IMSG_GOTCONFIG_REMOTE, 0, 0, len); if (wbuf == NULL) { err = got_error_from_errno( "imsg_create GOTCONFIG_REMOTE"); break; } if (imsg_add(wbuf, &iremote, sizeof(iremote)) == -1) { err = got_error_from_errno( "imsg_add GOTCONFIG_REMOTE"); break; } if (imsg_add(wbuf, repo->name, iremote.name_len) == -1) { err = got_error_from_errno( "imsg_add GOTCONFIG_REMOTE"); break; } if (imsg_add(wbuf, fetch_url, iremote.fetch_url_len) == -1) { err = got_error_from_errno( "imsg_add GOTCONFIG_REMOTE"); break; } if (imsg_add(wbuf, send_url, iremote.send_url_len) == -1) { err = got_error_from_errno( "imsg_add GOTCONFIG_REMOTE"); break; } imsg_close(ibuf, wbuf); err = got_privsep_flush_imsg(ibuf); if (err) break; free(fetch_url); fetch_url = NULL; free(send_url); send_url = NULL; if (repo->fetch_config && repo->fetch_config->branch) branch = repo->fetch_config->branch; else branch = repo->branch; while (branch) { err = send_gotconfig_str(ibuf, branch->branch_name); if (err) break; branch = branch->next; } if (repo->send_config && repo->send_config->branch) branch = repo->send_config->branch; else branch = repo->branch; while (branch) { err = send_gotconfig_str(ibuf, branch->branch_name); if (err) break; branch = branch->next; } ref = repo->fetch_ref; while (ref) { err = send_gotconfig_str(ibuf, ref->ref_name); if (err) break; ref = ref->next; } } free(fetch_url); free(send_url); return err; } static const struct got_error * validate_protocol(const char *protocol, const char *repo_name) { static char msg[512]; if (strcmp(protocol, "ssh") != 0 && strcmp(protocol, "git+ssh") != 0 && strcmp(protocol, "git") != 0 && strcmp(protocol, "git+http") != 0 && strcmp(protocol, "http") != 0 && strcmp(protocol, "https") != 0 && strcmp(protocol, "git+https") != 0) { snprintf(msg, sizeof(msg),"unknown protocol \"%s\" " "for remote repository \"%s\"", protocol, repo_name); return got_error_msg(GOT_ERR_PARSE_CONFIG, msg); } return NULL; } static const struct got_error * validate_config(struct gotconfig *gotconfig) { const struct got_error *err; struct gotconfig_remote_repo *repo, *repo2; static char msg[512]; TAILQ_FOREACH(repo, &gotconfig->remotes, entry) { if (repo->name == NULL) { return got_error_msg(GOT_ERR_PARSE_CONFIG, "name required for remote repository"); } TAILQ_FOREACH(repo2, &gotconfig->remotes, entry) { if (repo == repo2 || strcmp(repo->name, repo2->name) != 0) continue; snprintf(msg, sizeof(msg), "duplicate remote repository name '%s'", repo->name); return got_error_msg(GOT_ERR_PARSE_CONFIG, msg); } if (repo->server == NULL && (repo->fetch_config == NULL || repo->fetch_config->server == NULL) && (repo->send_config == NULL || repo->send_config->server == NULL)) { snprintf(msg, sizeof(msg), "server required for remote repository \"%s\"", repo->name); return got_error_msg(GOT_ERR_PARSE_CONFIG, msg); } if (repo->protocol == NULL && (repo->fetch_config == NULL || repo->fetch_config->protocol == NULL) && (repo->send_config == NULL || repo->send_config->protocol == NULL)) { snprintf(msg, sizeof(msg), "protocol required for remote repository \"%s\"", repo->name); return got_error_msg(GOT_ERR_PARSE_CONFIG, msg); } if (repo->protocol) { err = validate_protocol(repo->protocol, repo->name); if (err) return err; } if (repo->fetch_config && repo->fetch_config->protocol) { err = validate_protocol(repo->fetch_config->protocol, repo->name); if (err) return err; } if (repo->send_config && repo->send_config->protocol) { err = validate_protocol(repo->send_config->protocol, repo->name); if (err) return err; } if (repo->repository == NULL && (repo->fetch_config == NULL || repo->fetch_config->repository == NULL) && (repo->send_config == NULL || repo->send_config->repository == NULL)) { snprintf(msg, sizeof(msg), "repository path required for remote " "repository \"%s\"", repo->name); return got_error_msg(GOT_ERR_PARSE_CONFIG, msg); } } return NULL; } int main(int argc, char *argv[]) { const struct got_error *err = NULL; struct imsgbuf ibuf; struct gotconfig *gotconfig = NULL; size_t datalen; const char *filename = "got.conf"; #if 0 static int attached; while (!attached) sleep(1); #endif signal(SIGINT, catch_sigint); imsg_init(&ibuf, GOT_IMSG_FD_CHILD); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif if (argc > 1) filename = argv[1]; for (;;) { struct imsg imsg; int fd = -1; memset(&imsg, 0, sizeof(imsg)); if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); break; } err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; break; } if (imsg.hdr.type == GOT_IMSG_STOP) break; switch (imsg.hdr.type) { case GOT_IMSG_GOTCONFIG_PARSE_REQUEST: datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); break; } fd = imsg_get_fd(&imsg); if (fd == -1){ err = got_error(GOT_ERR_PRIVSEP_NO_FD); break; } if (gotconfig) gotconfig_free(gotconfig); err = gotconfig_parse(&gotconfig, filename, &fd); if (err) break; err = validate_config(gotconfig); break; case GOT_IMSG_GOTCONFIG_AUTHOR_REQUEST: if (gotconfig == NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = send_gotconfig_str(&ibuf, gotconfig->author ? gotconfig->author : ""); break; case GOT_IMSG_GOTCONFIG_ALLOWEDSIGNERS_REQUEST: if (gotconfig == NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = send_gotconfig_str(&ibuf, gotconfig->allowed_signers_file ? gotconfig->allowed_signers_file : ""); break; case GOT_IMSG_GOTCONFIG_REVOKEDSIGNERS_REQUEST: if (gotconfig == NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = send_gotconfig_str(&ibuf, gotconfig->revoked_signers_file ? gotconfig->revoked_signers_file : ""); break; case GOT_IMSG_GOTCONFIG_SIGNERID_REQUEST: if (gotconfig == NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = send_gotconfig_str(&ibuf, gotconfig->signer_id ? gotconfig->signer_id : ""); break; case GOT_IMSG_GOTCONFIG_REMOTES_REQUEST: if (gotconfig == NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = send_gotconfig_remotes(&ibuf, &gotconfig->remotes, gotconfig->nremotes); break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); break; } if (fd != -1) { if (close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); } imsg_free(&imsg); if (err) break; } imsg_clear(&ibuf); if (err) { if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); } } if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL) err = got_error_from_errno("close"); return err ? 1 : 0; } got-portable-0.101/libexec/got-read-gotconfig/parse.c0000644000175100017510000021504514644145563016170 /* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. 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 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 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output, and Bison version. */ #define YYBISON 30802 /* Bison version string. */ #define YYBISON_VERSION "3.8.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* First part of user prologue. */ #line 24 "parse.y" #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "gotconfig.h" static struct file { FILE *stream; const char *name; size_t ungetpos; size_t ungetsize; u_char *ungetbuf; int eof_reached; int lineno; } *file; static const struct got_error* newfile(struct file**, const char *, int *); static void closefile(struct file *); int yyparse(void); int yylex(void); int yyerror(const char *, ...) __attribute__((__format__ (printf, 1, 2))) __attribute__((__nonnull__ (1))); int kw_cmp(const void *, const void *); int lookup(char *); int igetc(void); int lgetc(int); void lungetc(int); int findeol(void); static int parseport(char *, long long *); TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); struct sym { TAILQ_ENTRY(sym) entry; int used; int persist; char *nam; char *val; }; int symset(const char *, const char *, int); int cmdline_symset(char *); char *symget(const char *); static int atoul(char *, u_long *); static const struct got_error* gerror; static struct gotconfig_remote_repo *remote; static struct gotconfig gotconfig; static const struct got_error* new_remote(struct gotconfig_remote_repo **); static const struct got_error* new_fetch_config(struct fetch_config **); static const struct got_error* new_send_config(struct send_config **); typedef struct { union { long long number; char *string; struct node_branch *branch; struct node_ref *ref; } v; int lineno; } YYSTYPE; #if defined(__APPLE__) && !defined(YYSTYPE) #warning "Setting YYSTYPE - is GNU Bison installed?" #define YYSTYPE YYSTYPE #endif #line 153 "parse.c" # ifndef YY_CAST # ifdef __cplusplus # define YY_CAST(Type, Val) static_cast (Val) # define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) # else # define YY_CAST(Type, Val) ((Type) (Val)) # define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) # endif # endif # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # else # define YY_NULLPTR ((void*)0) # endif # endif /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yydebug; #endif /* Token kinds. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { YYEMPTY = -2, YYEOF = 0, /* "end of file" */ YYerror = 256, /* error */ YYUNDEF = 257, /* "invalid token" */ ERROR = 258, /* ERROR */ REMOTE = 259, /* REMOTE */ REPOSITORY = 260, /* REPOSITORY */ SERVER = 261, /* SERVER */ PORT = 262, /* PORT */ PROTOCOL = 263, /* PROTOCOL */ MIRROR_REFERENCES = 264, /* MIRROR_REFERENCES */ BRANCH = 265, /* BRANCH */ AUTHOR = 266, /* AUTHOR */ ALLOWED_SIGNERS = 267, /* ALLOWED_SIGNERS */ REVOKED_SIGNERS = 268, /* REVOKED_SIGNERS */ SIGNER_ID = 269, /* SIGNER_ID */ FETCH_ALL_BRANCHES = 270, /* FETCH_ALL_BRANCHES */ REFERENCE = 271, /* REFERENCE */ FETCH = 272, /* FETCH */ SEND = 273, /* SEND */ STRING = 274, /* STRING */ NUMBER = 275 /* NUMBER */ }; typedef enum yytokentype yytoken_kind_t; #endif /* Token kinds. */ #define YYEMPTY -2 #define YYEOF 0 #define YYerror 256 #define YYUNDEF 257 #define ERROR 258 #define REMOTE 259 #define REPOSITORY 260 #define SERVER 261 #define PORT 262 #define PROTOCOL 263 #define MIRROR_REFERENCES 264 #define BRANCH 265 #define AUTHOR 266 #define ALLOWED_SIGNERS 267 #define REVOKED_SIGNERS 268 #define SIGNER_ID 269 #define FETCH_ALL_BRANCHES 270 #define REFERENCE 271 #define FETCH 272 #define SEND 273 #define STRING 274 #define NUMBER 275 /* Value type. */ extern YYSTYPE yylval; int yyparse (void); /* Symbol kind. */ enum yysymbol_kind_t { YYSYMBOL_YYEMPTY = -2, YYSYMBOL_YYEOF = 0, /* "end of file" */ YYSYMBOL_YYerror = 1, /* error */ YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ YYSYMBOL_ERROR = 3, /* ERROR */ YYSYMBOL_REMOTE = 4, /* REMOTE */ YYSYMBOL_REPOSITORY = 5, /* REPOSITORY */ YYSYMBOL_SERVER = 6, /* SERVER */ YYSYMBOL_PORT = 7, /* PORT */ YYSYMBOL_PROTOCOL = 8, /* PROTOCOL */ YYSYMBOL_MIRROR_REFERENCES = 9, /* MIRROR_REFERENCES */ YYSYMBOL_BRANCH = 10, /* BRANCH */ YYSYMBOL_AUTHOR = 11, /* AUTHOR */ YYSYMBOL_ALLOWED_SIGNERS = 12, /* ALLOWED_SIGNERS */ YYSYMBOL_REVOKED_SIGNERS = 13, /* REVOKED_SIGNERS */ YYSYMBOL_SIGNER_ID = 14, /* SIGNER_ID */ YYSYMBOL_FETCH_ALL_BRANCHES = 15, /* FETCH_ALL_BRANCHES */ YYSYMBOL_REFERENCE = 16, /* REFERENCE */ YYSYMBOL_FETCH = 17, /* FETCH */ YYSYMBOL_SEND = 18, /* SEND */ YYSYMBOL_STRING = 19, /* STRING */ YYSYMBOL_NUMBER = 20, /* NUMBER */ YYSYMBOL_21_n_ = 21, /* '\n' */ YYSYMBOL_22_ = 22, /* '{' */ YYSYMBOL_23_ = 23, /* '}' */ YYSYMBOL_24_ = 24, /* ',' */ YYSYMBOL_YYACCEPT = 25, /* $accept */ YYSYMBOL_grammar = 26, /* grammar */ YYSYMBOL_boolean = 27, /* boolean */ YYSYMBOL_numberstring = 28, /* numberstring */ YYSYMBOL_portplain = 29, /* portplain */ YYSYMBOL_branch = 30, /* branch */ YYSYMBOL_xbranch = 31, /* xbranch */ YYSYMBOL_branch_list = 32, /* branch_list */ YYSYMBOL_ref = 33, /* ref */ YYSYMBOL_xref = 34, /* xref */ YYSYMBOL_ref_list = 35, /* ref_list */ YYSYMBOL_remoteopts2 = 36, /* remoteopts2 */ YYSYMBOL_remoteopts1 = 37, /* remoteopts1 */ YYSYMBOL_38_1 = 38, /* $@1 */ YYSYMBOL_39_2 = 39, /* $@2 */ YYSYMBOL_fetchempty = 40, /* fetchempty */ YYSYMBOL_fetchopts2 = 41, /* fetchopts2 */ YYSYMBOL_fetchopts1 = 42, /* fetchopts1 */ YYSYMBOL_sendempty = 43, /* sendempty */ YYSYMBOL_sendopts2 = 44, /* sendopts2 */ YYSYMBOL_sendopts1 = 45, /* sendopts1 */ YYSYMBOL_remote = 46, /* remote */ YYSYMBOL_47_3 = 47, /* $@3 */ YYSYMBOL_author = 48, /* author */ YYSYMBOL_allowed_signers = 49, /* allowed_signers */ YYSYMBOL_revoked_signers = 50, /* revoked_signers */ YYSYMBOL_signer_id = 51, /* signer_id */ YYSYMBOL_optnl = 52, /* optnl */ YYSYMBOL_nl = 53, /* nl */ YYSYMBOL_comma = 54 /* comma */ }; typedef enum yysymbol_kind_t yysymbol_kind_t; #ifdef short # undef short #endif /* On compilers that do not define __PTRDIFF_MAX__ etc., make sure and (if available) are included so that the code can choose integer types of a good width. */ #ifndef __PTRDIFF_MAX__ # include /* INFRINGES ON USER NAME SPACE */ # if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YY_STDINT_H # endif #endif /* Narrow types that promote to a signed type and that can represent a signed or unsigned integer of at least N bits. In tables they can save space and decrease cache pressure. Promoting to a signed type helps avoid bugs in integer arithmetic. */ #ifdef __INT_LEAST8_MAX__ typedef __INT_LEAST8_TYPE__ yytype_int8; #elif defined YY_STDINT_H typedef int_least8_t yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef __INT_LEAST16_MAX__ typedef __INT_LEAST16_TYPE__ yytype_int16; #elif defined YY_STDINT_H typedef int_least16_t yytype_int16; #else typedef short yytype_int16; #endif /* Work around bug in HP-UX 11.23, which defines these macros incorrectly for preprocessor constants. This workaround can likely be removed in 2023, as HPE has promised support for HP-UX 11.23 (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of . */ #ifdef __hpux # undef UINT_LEAST8_MAX # undef UINT_LEAST16_MAX # define UINT_LEAST8_MAX 255 # define UINT_LEAST16_MAX 65535 #endif #if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ typedef __UINT_LEAST8_TYPE__ yytype_uint8; #elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ && UINT_LEAST8_MAX <= INT_MAX) typedef uint_least8_t yytype_uint8; #elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX typedef unsigned char yytype_uint8; #else typedef short yytype_uint8; #endif #if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ typedef __UINT_LEAST16_TYPE__ yytype_uint16; #elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ && UINT_LEAST16_MAX <= INT_MAX) typedef uint_least16_t yytype_uint16; #elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX typedef unsigned short yytype_uint16; #else typedef int yytype_uint16; #endif #ifndef YYPTRDIFF_T # if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ # define YYPTRDIFF_T __PTRDIFF_TYPE__ # define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ # elif defined PTRDIFF_MAX # ifndef ptrdiff_t # include /* INFRINGES ON USER NAME SPACE */ # endif # define YYPTRDIFF_T ptrdiff_t # define YYPTRDIFF_MAXIMUM PTRDIFF_MAX # else # define YYPTRDIFF_T long # define YYPTRDIFF_MAXIMUM LONG_MAX # endif #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned # endif #endif #define YYSIZE_MAXIMUM \ YY_CAST (YYPTRDIFF_T, \ (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ ? YYPTRDIFF_MAXIMUM \ : YY_CAST (YYSIZE_T, -1))) #define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) /* Stored state numbers (used for stacks). */ typedef yytype_int8 yy_state_t; /* State numbers in computations. */ typedef int yy_state_fast_t; #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE_PURE # if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) # else # define YY_ATTRIBUTE_PURE # endif #endif #ifndef YY_ATTRIBUTE_UNUSED # if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) # else # define YY_ATTRIBUTE_UNUSED # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YY_USE(E) ((void) (E)) #else # define YY_USE(E) /* empty */ #endif /* Suppress an incorrect diagnostic about yylval being uninitialized. */ #if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ # if __GNUC__ * 100 + __GNUC_MINOR__ < 407 # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") # else # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # endif # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ # define YY_IGNORE_USELESS_CAST_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") # define YY_IGNORE_USELESS_CAST_END \ _Pragma ("GCC diagnostic pop") #endif #ifndef YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_END #endif #define YY_ASSERT(E) ((void) (0 && (E))) #if !defined yyoverflow /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* !defined yyoverflow */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yy_state_t yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYPTRDIFF_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / YYSIZEOF (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYPTRDIFF_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 105 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 25 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 30 /* YYNRULES -- Number of rules. */ #define YYNRULES 67 /* YYNSTATES -- Number of states. */ #define YYNSTATES 122 /* YYMAXUTOK -- Last valid token kind. */ #define YYMAXUTOK 275 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM as returned by yylex, with out-of-bounds checking. */ #define YYTRANSLATE(YYX) \ (0 <= (YYX) && (YYX) <= YYMAXUTOK \ ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ : YYSYMBOL_YYUNDEF) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex. */ static const yytype_int8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 24, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 2, 23, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { 0, 119, 119, 120, 121, 122, 123, 124, 125, 127, 142, 150, 152, 160, 161, 162, 164, 174, 175, 181, 182, 183, 185, 195, 196, 202, 203, 205, 208, 211, 214, 217, 220, 223, 226, 229, 229, 242, 242, 256, 257, 259, 260, 262, 265, 268, 271, 274, 278, 279, 281, 282, 284, 287, 290, 293, 296, 300, 300, 315, 319, 323, 327, 331, 332, 334, 336, 337 }; #endif /** Accessing symbol of state STATE. */ #define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) #if YYDEBUG || 0 /* The user-facing name of the symbol whose (internal) number is YYSYMBOL. No bounds checking. */ static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "\"end of file\"", "error", "\"invalid token\"", "ERROR", "REMOTE", "REPOSITORY", "SERVER", "PORT", "PROTOCOL", "MIRROR_REFERENCES", "BRANCH", "AUTHOR", "ALLOWED_SIGNERS", "REVOKED_SIGNERS", "SIGNER_ID", "FETCH_ALL_BRANCHES", "REFERENCE", "FETCH", "SEND", "STRING", "NUMBER", "'\\n'", "'{'", "'}'", "','", "$accept", "grammar", "boolean", "numberstring", "portplain", "branch", "xbranch", "branch_list", "ref", "xref", "ref_list", "remoteopts2", "remoteopts1", "$@1", "$@2", "fetchempty", "fetchopts2", "fetchopts1", "sendempty", "sendopts2", "sendopts1", "remote", "$@3", "author", "allowed_signers", "revoked_signers", "signer_id", "optnl", "nl", "comma", YY_NULLPTR }; static const char * yysymbol_name (yysymbol_kind_t yysymbol) { return yytname[yysymbol]; } #endif #define YYPACT_NINF (-102) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) #define YYTABLE_NINF (-1) #define yytable_value_is_error(Yyn) \ 0 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int8 yypact[] = { -102, 5, -102, -18, -11, 4, 10, 16, -102, 18, 22, 24, 35, 36, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, 25, 41, 41, 62, -102, 44, 45, 8, 57, 66, -9, 66, 2, -102, -102, 43, 41, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, 41, -102, -102, -102, -102, 41, -102, -102, 65, 67, -102, 69, -102, 72, 73, 41, 41, 41, -102, 41, 14, 41, 31, 26, 76, -102, -102, -102, -102, 72, -102, -102, 73, 74, 75, 8, 77, -9, 78, 26, 41, 79, 80, 8, 81, -9, 82, 76, 41, 41, 41, -102, -102, -102, -102, -102, -102, 69, -102, -102, -102, -102, -102, -102, -102, 69, -102, -102, -102, -102, -102 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_int8 yydefact[] = { 2, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 57, 59, 60, 61, 62, 5, 4, 6, 7, 8, 0, 64, 64, 0, 63, 0, 0, 0, 0, 0, 13, 0, 19, 35, 37, 0, 64, 27, 28, 11, 10, 12, 32, 29, 9, 30, 16, 64, 33, 14, 31, 22, 64, 34, 20, 0, 0, 58, 0, 26, 0, 0, 64, 64, 64, 25, 64, 67, 64, 67, 39, 48, 65, 17, 15, 66, 0, 23, 21, 0, 0, 0, 0, 0, 13, 0, 40, 64, 0, 0, 0, 0, 13, 0, 49, 64, 64, 64, 43, 44, 46, 45, 47, 36, 0, 42, 52, 53, 55, 54, 56, 38, 0, 51, 18, 24, 41, 50 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { -102, -102, 53, -102, -83, -84, -58, -102, -102, -63, -102, -102, 56, -102, -102, -102, -102, 7, -102, -102, 6, -102, -102, -102, -102, -102, -102, -26, -101, 29 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { 0, 1, 49, 45, 46, 52, 53, 71, 57, 58, 73, 39, 40, 59, 60, 89, 90, 91, 97, 98, 99, 9, 24, 10, 11, 12, 13, 27, 69, 80 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int8 yytable[] = { 28, 14, 72, 104, 106, 2, 70, 120, 15, 3, 50, 112, 114, 51, 63, 121, 4, 5, 6, 7, 101, 55, 100, 16, 56, 64, 8, 43, 44, 17, 65, 84, 85, 86, 87, 18, 88, 78, 79, 19, 74, 75, 76, 20, 77, 21, 81, 25, 29, 30, 31, 32, 33, 34, 82, 79, 22, 23, 35, 36, 37, 38, 26, 41, 42, 109, 61, 29, 30, 31, 32, 33, 34, 117, 118, 119, 47, 35, 36, 37, 38, 92, 93, 94, 95, 48, 96, 66, 54, 67, 68, 50, 55, 102, 103, 62, 105, 108, 110, 111, 113, 107, 83, 0, 116, 115 }; static const yytype_int8 yycheck[] = { 26, 19, 65, 86, 88, 0, 64, 108, 19, 4, 19, 94, 96, 22, 40, 116, 11, 12, 13, 14, 83, 19, 80, 19, 22, 51, 21, 19, 20, 19, 56, 5, 6, 7, 8, 19, 10, 23, 24, 21, 66, 67, 68, 21, 70, 21, 72, 22, 5, 6, 7, 8, 9, 10, 23, 24, 21, 21, 15, 16, 17, 18, 21, 19, 19, 91, 23, 5, 6, 7, 8, 9, 10, 99, 100, 101, 19, 15, 16, 17, 18, 5, 6, 7, 8, 19, 10, 22, 35, 22, 21, 19, 19, 19, 19, 39, 19, 90, 19, 19, 19, 23, 73, -1, 98, 23 }; /* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of state STATE-NUM. */ static const yytype_int8 yystos[] = { 0, 26, 0, 4, 11, 12, 13, 14, 21, 46, 48, 49, 50, 51, 19, 19, 19, 19, 19, 21, 21, 21, 21, 21, 47, 22, 21, 52, 52, 5, 6, 7, 8, 9, 10, 15, 16, 17, 18, 36, 37, 19, 19, 19, 20, 28, 29, 19, 19, 27, 19, 22, 30, 31, 27, 19, 22, 33, 34, 38, 39, 23, 37, 52, 52, 52, 22, 22, 21, 53, 31, 32, 34, 35, 52, 52, 52, 52, 23, 24, 54, 52, 23, 54, 5, 6, 7, 8, 10, 40, 41, 42, 5, 6, 7, 8, 10, 43, 44, 45, 31, 34, 19, 19, 29, 19, 30, 23, 42, 52, 19, 19, 29, 19, 30, 23, 45, 52, 52, 52, 53, 53 }; /* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ static const yytype_int8 yyr1[] = { 0, 25, 26, 26, 26, 26, 26, 26, 26, 27, 28, 28, 29, 30, 30, 30, 31, 32, 32, 33, 33, 33, 34, 35, 35, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 38, 37, 39, 37, 40, 40, 41, 41, 42, 42, 42, 42, 42, 43, 43, 44, 44, 45, 45, 45, 45, 45, 47, 46, 48, 49, 50, 51, 52, 52, 53, 54, 54 }; /* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ static const yytype_int8 yyr2[] = { 0, 2, 0, 2, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0, 1, 4, 1, 2, 4, 0, 1, 4, 1, 2, 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 6, 0, 6, 0, 1, 3, 2, 2, 2, 2, 2, 2, 0, 1, 3, 2, 2, 2, 2, 2, 2, 0, 7, 2, 2, 2, 2, 2, 0, 2, 1, 0 }; enum { YYENOMEM = -2 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYNOMEM goto yyexhaustedlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Backward compatibility with an undocumented macro. Use YYerror or YYUNDEF. */ #define YYERRCODE YYUNDEF /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Kind, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*-----------------------------------. | Print this symbol's value on YYO. | `-----------------------------------*/ static void yy_symbol_value_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) { FILE *yyoutput = yyo; YY_USE (yyoutput); if (!yyvaluep) return; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /*---------------------------. | Print this symbol on YYO. | `---------------------------*/ static void yy_symbol_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) { YYFPRINTF (yyo, "%s %s (", yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); yy_symbol_value_print (yyo, yykind, yyvaluep); YYFPRINTF (yyo, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, int yyrule) { int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), &yyvsp[(yyi + 1) - (yynrhs)]); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, Rule); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) ((void) 0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, yysymbol_kind_t yykind, YYSTYPE *yyvaluep) { YY_USE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /* Lookahead token kind. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*----------. | yyparse. | `----------*/ int yyparse (void) { yy_state_fast_t yystate = 0; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus = 0; /* Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* Their size. */ YYPTRDIFF_T yystacksize = YYINITDEPTH; /* The state stack: array, bottom, top. */ yy_state_t yyssa[YYINITDEPTH]; yy_state_t *yyss = yyssa; yy_state_t *yyssp = yyss; /* The semantic value stack: array, bottom, top. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; YYSTYPE *yyvsp = yyvs; int yyn; /* The return value of yyparse. */ int yyresult; /* Lookahead symbol kind. */ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; YYDPRINTF ((stderr, "Starting parse\n")); yychar = YYEMPTY; /* Cause a token to be read. */ goto yysetstate; /*------------------------------------------------------------. | yynewstate -- push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; /*--------------------------------------------------------------------. | yysetstate -- set current state (the top of the stack) to yystate. | `--------------------------------------------------------------------*/ yysetstate: YYDPRINTF ((stderr, "Entering state %d\n", yystate)); YY_ASSERT (0 <= yystate && yystate < YYNSTATES); YY_IGNORE_USELESS_CAST_BEGIN *yyssp = YY_CAST (yy_state_t, yystate); YY_IGNORE_USELESS_CAST_END YY_STACK_PRINT (yyss, yyssp); if (yyss + yystacksize - 1 <= yyssp) #if !defined yyoverflow && !defined YYSTACK_RELOCATE YYNOMEM; #else { /* Get the current used size of the three stacks, in elements. */ YYPTRDIFF_T yysize = yyssp - yyss + 1; # if defined yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ yy_state_t *yyss1 = yyss; YYSTYPE *yyvs1 = yyvs; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * YYSIZEOF (*yyssp), &yyvs1, yysize * YYSIZEOF (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } # else /* defined YYSTACK_RELOCATE */ /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) YYNOMEM; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yy_state_t *yyss1 = yyss; union yyalloc *yyptr = YY_CAST (union yyalloc *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); if (! yyptr) YYNOMEM; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YY_IGNORE_USELESS_CAST_BEGIN YYDPRINTF ((stderr, "Stack size increased to %ld\n", YY_CAST (long, yystacksize))); YY_IGNORE_USELESS_CAST_END if (yyss + yystacksize - 1 <= yyssp) YYABORT; } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token\n")); yychar = yylex (); } if (yychar <= YYEOF) { yychar = YYEOF; yytoken = YYSYMBOL_YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else if (yychar == YYerror) { /* The scanner already issued an error message, process directly to error recovery. But do not keep the error token as lookahead, it is too special and may lead us to an endless loop in error recovery. */ yychar = YYUNDEF; yytoken = YYSYMBOL_YYerror; goto yyerrlab1; } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Discard the shifted token. */ yychar = YYEMPTY; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 9: /* boolean: STRING */ #line 127 "parse.y" { if (strcasecmp((yyvsp[0].v.string), "true") == 0 || strcasecmp((yyvsp[0].v.string), "yes") == 0) (yyval.v.number) = 1; else if (strcasecmp((yyvsp[0].v.string), "false") == 0 || strcasecmp((yyvsp[0].v.string), "no") == 0) (yyval.v.number) = 0; else { yyerror("invalid boolean value '%s'", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1353 "parse.c" break; case 10: /* numberstring: NUMBER */ #line 142 "parse.y" { char *s; if (asprintf(&s, "%lld", (yyvsp[0].v.number)) == -1) { yyerror("string: asprintf"); YYERROR; } (yyval.v.string) = s; } #line 1366 "parse.c" break; case 12: /* portplain: numberstring */ #line 152 "parse.y" { if (parseport((yyvsp[0].v.string), &(yyval.v.number)) == -1) { free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1378 "parse.c" break; case 13: /* branch: %empty */ #line 160 "parse.y" { (yyval.v.branch) = NULL; } #line 1384 "parse.c" break; case 14: /* branch: xbranch */ #line 161 "parse.y" { (yyval.v.branch) = (yyvsp[0].v.branch); } #line 1390 "parse.c" break; case 15: /* branch: '{' optnl branch_list '}' */ #line 162 "parse.y" { (yyval.v.branch) = (yyvsp[-1].v.branch); } #line 1396 "parse.c" break; case 16: /* xbranch: STRING */ #line 164 "parse.y" { (yyval.v.branch) = calloc(1, sizeof(struct node_branch)); if ((yyval.v.branch) == NULL) { yyerror("calloc"); YYERROR; } (yyval.v.branch)->branch_name = (yyvsp[0].v.string); (yyval.v.branch)->tail = (yyval.v.branch); } #line 1410 "parse.c" break; case 17: /* branch_list: xbranch optnl */ #line 174 "parse.y" { (yyval.v.branch) = (yyvsp[-1].v.branch); } #line 1416 "parse.c" break; case 18: /* branch_list: branch_list comma xbranch optnl */ #line 175 "parse.y" { (yyvsp[-3].v.branch)->tail->next = (yyvsp[-1].v.branch); (yyvsp[-3].v.branch)->tail = (yyvsp[-1].v.branch); (yyval.v.branch) = (yyvsp[-3].v.branch); } #line 1426 "parse.c" break; case 19: /* ref: %empty */ #line 181 "parse.y" { (yyval.v.ref) = NULL; } #line 1432 "parse.c" break; case 20: /* ref: xref */ #line 182 "parse.y" { (yyval.v.ref) = (yyvsp[0].v.ref); } #line 1438 "parse.c" break; case 21: /* ref: '{' optnl ref_list '}' */ #line 183 "parse.y" { (yyval.v.ref) = (yyvsp[-1].v.ref); } #line 1444 "parse.c" break; case 22: /* xref: STRING */ #line 185 "parse.y" { (yyval.v.ref) = calloc(1, sizeof(struct node_ref)); if ((yyval.v.ref) == NULL) { yyerror("calloc"); YYERROR; } (yyval.v.ref)->ref_name = (yyvsp[0].v.string); (yyval.v.ref)->tail = (yyval.v.ref); } #line 1458 "parse.c" break; case 23: /* ref_list: xref optnl */ #line 195 "parse.y" { (yyval.v.ref) = (yyvsp[-1].v.ref); } #line 1464 "parse.c" break; case 24: /* ref_list: ref_list comma xref optnl */ #line 196 "parse.y" { (yyvsp[-3].v.ref)->tail->next = (yyvsp[-1].v.ref); (yyvsp[-3].v.ref)->tail = (yyvsp[-1].v.ref); (yyval.v.ref) = (yyvsp[-3].v.ref); } #line 1474 "parse.c" break; case 27: /* remoteopts1: REPOSITORY STRING */ #line 205 "parse.y" { remote->repository = (yyvsp[0].v.string); } #line 1482 "parse.c" break; case 28: /* remoteopts1: SERVER STRING */ #line 208 "parse.y" { remote->server = (yyvsp[0].v.string); } #line 1490 "parse.c" break; case 29: /* remoteopts1: PROTOCOL STRING */ #line 211 "parse.y" { remote->protocol = (yyvsp[0].v.string); } #line 1498 "parse.c" break; case 30: /* remoteopts1: MIRROR_REFERENCES boolean */ #line 214 "parse.y" { remote->mirror_references = (yyvsp[0].v.number); } #line 1506 "parse.c" break; case 31: /* remoteopts1: FETCH_ALL_BRANCHES boolean */ #line 217 "parse.y" { remote->fetch_all_branches = (yyvsp[0].v.number); } #line 1514 "parse.c" break; case 32: /* remoteopts1: PORT portplain */ #line 220 "parse.y" { remote->port = (yyvsp[0].v.number); } #line 1522 "parse.c" break; case 33: /* remoteopts1: BRANCH branch */ #line 223 "parse.y" { remote->branch = (yyvsp[0].v.branch); } #line 1530 "parse.c" break; case 34: /* remoteopts1: REFERENCE ref */ #line 226 "parse.y" { remote->fetch_ref = (yyvsp[0].v.ref); } #line 1538 "parse.c" break; case 35: /* $@1: %empty */ #line 229 "parse.y" { static const struct got_error* error; if (remote->fetch_config != NULL) { yyerror("fetch block already exists"); YYERROR; } error = new_fetch_config(&remote->fetch_config); if (error) { yyerror("%s", error->msg); YYERROR; } } #line 1556 "parse.c" break; case 37: /* $@2: %empty */ #line 242 "parse.y" { static const struct got_error* error; if (remote->send_config != NULL) { yyerror("send block already exists"); YYERROR; } error = new_send_config(&remote->send_config); if (error) { yyerror("%s", error->msg); YYERROR; } } #line 1574 "parse.c" break; case 43: /* fetchopts1: REPOSITORY STRING */ #line 262 "parse.y" { remote->fetch_config->repository = (yyvsp[0].v.string); } #line 1582 "parse.c" break; case 44: /* fetchopts1: SERVER STRING */ #line 265 "parse.y" { remote->fetch_config->server = (yyvsp[0].v.string); } #line 1590 "parse.c" break; case 45: /* fetchopts1: PROTOCOL STRING */ #line 268 "parse.y" { remote->fetch_config->protocol = (yyvsp[0].v.string); } #line 1598 "parse.c" break; case 46: /* fetchopts1: PORT portplain */ #line 271 "parse.y" { remote->fetch_config->port = (yyvsp[0].v.number); } #line 1606 "parse.c" break; case 47: /* fetchopts1: BRANCH branch */ #line 274 "parse.y" { remote->fetch_config->branch = (yyvsp[0].v.branch); } #line 1614 "parse.c" break; case 52: /* sendopts1: REPOSITORY STRING */ #line 284 "parse.y" { remote->send_config->repository = (yyvsp[0].v.string); } #line 1622 "parse.c" break; case 53: /* sendopts1: SERVER STRING */ #line 287 "parse.y" { remote->send_config->server = (yyvsp[0].v.string); } #line 1630 "parse.c" break; case 54: /* sendopts1: PROTOCOL STRING */ #line 290 "parse.y" { remote->send_config->protocol = (yyvsp[0].v.string); } #line 1638 "parse.c" break; case 55: /* sendopts1: PORT portplain */ #line 293 "parse.y" { remote->send_config->port = (yyvsp[0].v.number); } #line 1646 "parse.c" break; case 56: /* sendopts1: BRANCH branch */ #line 296 "parse.y" { remote->send_config->branch = (yyvsp[0].v.branch); } #line 1654 "parse.c" break; case 57: /* $@3: %empty */ #line 300 "parse.y" { static const struct got_error* error; error = new_remote(&remote); if (error) { free((yyvsp[0].v.string)); yyerror("%s", error->msg); YYERROR; } remote->name = (yyvsp[0].v.string); } #line 1670 "parse.c" break; case 58: /* remote: REMOTE STRING $@3 '{' optnl remoteopts2 '}' */ #line 310 "parse.y" { TAILQ_INSERT_TAIL(&gotconfig.remotes, remote, entry); gotconfig.nremotes++; } #line 1679 "parse.c" break; case 59: /* author: AUTHOR STRING */ #line 315 "parse.y" { gotconfig.author = (yyvsp[0].v.string); } #line 1687 "parse.c" break; case 60: /* allowed_signers: ALLOWED_SIGNERS STRING */ #line 319 "parse.y" { gotconfig.allowed_signers_file = (yyvsp[0].v.string); } #line 1695 "parse.c" break; case 61: /* revoked_signers: REVOKED_SIGNERS STRING */ #line 323 "parse.y" { gotconfig.revoked_signers_file = (yyvsp[0].v.string); } #line 1703 "parse.c" break; case 62: /* signer_id: SIGNER_ID STRING */ #line 327 "parse.y" { gotconfig.signer_id = (yyvsp[0].v.string); } #line 1711 "parse.c" break; #line 1715 "parse.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; *++yyvsp = yyval; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ { const int yylhs = yyr1[yyn] - YYNTOKENS; const int yyi = yypgoto[yylhs] + *yyssp; yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp ? yytable[yyi] : yydefgoto[yylhs]); } goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; yyerror (YY_("syntax error")); } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (0) YYERROR; ++yynerrs; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ /* Pop stack until we find a state that shifts the error token. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYSYMBOL_YYerror; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", YY_ACCESSING_SYMBOL (yystate), yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturnlab; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturnlab; /*-----------------------------------------------------------. | yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | `-----------------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; goto yyreturnlab; /*----------------------------------------------------------. | yyreturnlab -- parsing is finished, clean up and return. | `----------------------------------------------------------*/ yyreturnlab: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", YY_ACCESSING_SYMBOL (+*yyssp), yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif return yyresult; } #line 339 "parse.y" struct keywords { const char *k_name; int k_val; }; int yyerror(const char *fmt, ...) { va_list ap; char *msg; char *err = NULL; va_start(ap, fmt); if (vasprintf(&msg, fmt, ap) == -1) { gerror = got_error_from_errno("vasprintf"); return 0; } va_end(ap); if (asprintf(&err, "%s: line %d: %s", file->name, yylval.lineno, msg) == -1) { gerror = got_error_from_errno("asprintf"); return(0); } gerror = got_error_msg(GOT_ERR_PARSE_CONFIG, err); free(msg); return(0); } int kw_cmp(const void *k, const void *e) { return (strcmp(k, ((const struct keywords *)e)->k_name)); } int lookup(char *s) { /* This has to be sorted always. */ static const struct keywords keywords[] = { {"allowed_signers", ALLOWED_SIGNERS}, {"author", AUTHOR}, {"branch", BRANCH}, {"fetch", FETCH}, {"fetch-all-branches", FETCH_ALL_BRANCHES}, /* deprecated */ {"fetch_all_branches", FETCH_ALL_BRANCHES}, {"mirror-references", MIRROR_REFERENCES}, /* deprecated */ {"mirror_references", MIRROR_REFERENCES}, {"port", PORT}, {"protocol", PROTOCOL}, {"reference", REFERENCE}, {"remote", REMOTE}, {"repository", REPOSITORY}, {"revoked_signers", REVOKED_SIGNERS}, {"send", SEND}, {"server", SERVER}, {"signer_id", SIGNER_ID}, }; const struct keywords *p; p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), sizeof(keywords[0]), kw_cmp); if (p) return (p->k_val); else return (STRING); } #define START_EXPAND 1 #define DONE_EXPAND 2 static int expanding; int igetc(void) { int c; while (1) { if (file->ungetpos > 0) c = file->ungetbuf[--file->ungetpos]; else c = getc(file->stream); if (c == START_EXPAND) expanding = 1; else if (c == DONE_EXPAND) expanding = 0; else break; } return (c); } int lgetc(int quotec) { int c, next; if (quotec) { c = igetc(); if (c == EOF) { yyerror("reached end of file while parsing " "quoted string"); } return (c); } c = igetc(); while (c == '\\') { next = igetc(); if (next != '\n') { c = next; break; } yylval.lineno = file->lineno; file->lineno++; } return (c); } void lungetc(int c) { if (c == EOF) return; if (file->ungetpos >= file->ungetsize) { void *p = reallocarray(file->ungetbuf, file->ungetsize, 2); if (p == NULL) err(1, "%s", __func__); file->ungetbuf = p; file->ungetsize *= 2; } file->ungetbuf[file->ungetpos++] = c; } int findeol(void) { int c; /* Skip to either EOF or the first real EOL. */ while (1) { c = lgetc(0); if (c == '\n') { file->lineno++; break; } if (c == EOF) break; } return (ERROR); } static long long getservice(char *n) { struct servent *s; u_long ulval; if (atoul(n, &ulval) == 0) { if (ulval == 0 || ulval > 65535) { yyerror("illegal port value %lu", ulval); return (-1); } return ulval; } else { s = getservbyname(n, "tcp"); if (s == NULL) s = getservbyname(n, "udp"); if (s == NULL) { yyerror("unknown port %s", n); return (-1); } return (s->s_port); } } static int parseport(char *port, long long *pn) { if ((*pn = getservice(port)) == -1) { *pn = 0LL; return (-1); } return (0); } int yylex(void) { char buf[8096]; char *p, *val; int quotec, next, c; int token; top: p = buf; c = lgetc(0); while (c == ' ' || c == '\t') c = lgetc(0); /* nothing */ yylval.lineno = file->lineno; if (c == '#') { c = lgetc(0); while (c != '\n' && c != EOF) c = lgetc(0); /* nothing */ } if (c == '$' && !expanding) { while (1) { c = lgetc(0); if (c == EOF) return (0); if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } if (isalnum(c) || c == '_') { *p++ = c; continue; } *p = '\0'; lungetc(c); break; } val = symget(buf); if (val == NULL) { yyerror("macro '%s' not defined", buf); return (findeol()); } p = val + strlen(val) - 1; lungetc(DONE_EXPAND); while (p >= val) { lungetc((unsigned char)*p); p--; } lungetc(START_EXPAND); goto top; } switch (c) { case '\'': case '"': quotec = c; while (1) { c = lgetc(quotec); if (c == EOF) return (0); if (c == '\n') { file->lineno++; continue; } else if (c == '\\') { next = lgetc(quotec); if (next == EOF) return (0); if (next == quotec || c == ' ' || c == '\t') c = next; else if (next == '\n') { file->lineno++; continue; } else lungetc(next); } else if (c == quotec) { *p = '\0'; break; } else if (c == '\0') { yyerror("syntax error"); return (findeol()); } if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } *p++ = c; } yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "%s", __func__); return (STRING); } #define allowed_to_end_number(x) \ (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') if (c == '-' || isdigit(c)) { do { *p++ = c; if ((size_t)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && isdigit(c)); lungetc(c); if (p == buf + 1 && buf[0] == '-') goto nodigits; if (c == EOF || allowed_to_end_number(c)) { const char *errstr = NULL; *p = '\0'; yylval.v.number = strtonum(buf, LLONG_MIN, LLONG_MAX, &errstr); if (errstr) { yyerror("\"%s\" invalid number: %s", buf, errstr); return (findeol()); } return (NUMBER); } else { nodigits: while (p > buf + 1) lungetc((unsigned char)*--p); c = (unsigned char)*--p; if (c == '-') return (c); } } #define allowed_in_string(x) \ (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ x != '{' && x != '}' && \ x != '!' && x != '=' && x != '#' && \ x != ',')) if (isalnum(c) || c == ':' || c == '_') { do { *p++ = c; if ((size_t)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && (allowed_in_string(c))); lungetc(c); *p = '\0'; token = lookup(buf); if (token == STRING) { yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "%s", __func__); } return (token); } if (c == '\n') { yylval.lineno = file->lineno; file->lineno++; } if (c == EOF) return (0); return (c); } static const struct got_error* newfile(struct file **nfile, const char *filename, int *fd) { const struct got_error* error = NULL; (*nfile) = calloc(1, sizeof(struct file)); if ((*nfile) == NULL) return got_error_from_errno("calloc"); (*nfile)->stream = fdopen(*fd, "r"); if ((*nfile)->stream == NULL) { error = got_error_from_errno("fdopen"); free((*nfile)); return error; } *fd = -1; /* Stream owns the file descriptor now. */ (*nfile)->name = filename; (*nfile)->lineno = 1; (*nfile)->ungetsize = 16; (*nfile)->ungetbuf = malloc((*nfile)->ungetsize); if ((*nfile)->ungetbuf == NULL) { error = got_error_from_errno("malloc"); fclose((*nfile)->stream); free((*nfile)); return error; } return NULL; } static const struct got_error* new_remote(struct gotconfig_remote_repo **remote) { const struct got_error *error = NULL; *remote = calloc(1, sizeof(**remote)); if (*remote == NULL) error = got_error_from_errno("calloc"); return error; } static const struct got_error* new_fetch_config(struct fetch_config **fetch_config) { const struct got_error *error = NULL; *fetch_config = calloc(1, sizeof(**fetch_config)); if (*fetch_config == NULL) error = got_error_from_errno("calloc"); return error; } static const struct got_error* new_send_config(struct send_config **send_config) { const struct got_error *error = NULL; *send_config = calloc(1, sizeof(**send_config)); if (*send_config == NULL) error = got_error_from_errno("calloc"); return error; } static void closefile(struct file *file) { fclose(file->stream); free(file->ungetbuf); free(file); } const struct got_error * gotconfig_parse(struct gotconfig **conf, const char *filename, int *fd) { const struct got_error *err = NULL; struct sym *sym, *next; *conf = NULL; err = newfile(&file, filename, fd); if (err) return err; TAILQ_INIT(&gotconfig.remotes); yyparse(); closefile(file); /* Free macros and check which have not been used. */ TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { if (!sym->persist) { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } if (gerror == NULL) *conf = &gotconfig; return gerror; } static void free_fetch_config(struct fetch_config *fetch_config) { free(remote->fetch_config->repository); free(remote->fetch_config->server); free(remote->fetch_config->protocol); free(remote->fetch_config); } static void free_send_config(struct send_config *send_config) { free(remote->send_config->repository); free(remote->send_config->server); free(remote->send_config->protocol); free(remote->send_config); } void gotconfig_free(struct gotconfig *conf) { struct gotconfig_remote_repo *remote; free(conf->author); free(conf->allowed_signers_file); free(conf->revoked_signers_file); free(conf->signer_id); while (!TAILQ_EMPTY(&conf->remotes)) { remote = TAILQ_FIRST(&conf->remotes); TAILQ_REMOVE(&conf->remotes, remote, entry); if (remote->fetch_config != NULL) free_fetch_config(remote->fetch_config); if (remote->send_config != NULL) free_send_config(remote->send_config); free(remote->name); free(remote->repository); free(remote->server); free(remote->protocol); free(remote); } } int symset(const char *nam, const char *val, int persist) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) break; } if (sym != NULL) { if (sym->persist == 1) return (0); else { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } sym = calloc(1, sizeof(*sym)); if (sym == NULL) return (-1); sym->nam = strdup(nam); if (sym->nam == NULL) { free(sym); return (-1); } sym->val = strdup(val); if (sym->val == NULL) { free(sym->nam); free(sym); return (-1); } sym->used = 0; sym->persist = persist; TAILQ_INSERT_TAIL(&symhead, sym, entry); return (0); } int cmdline_symset(char *s) { char *sym, *val; int ret; size_t len; val = strrchr(s, '='); if (val == NULL) return (-1); len = strlen(s) - strlen(val) + 1; sym = malloc(len); if (sym == NULL) errx(1, "cmdline_symset: malloc"); strlcpy(sym, s, len); ret = symset(sym, val + 1, 1); free(sym); return (ret); } char * symget(const char *nam) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) { sym->used = 1; return (sym->val); } } return (NULL); } static int atoul(char *s, u_long *ulvalp) { u_long ulval; char *ep; errno = 0; ulval = strtoul(s, &ep, 0); if (s[0] == '\0' || *ep != '\0') return (-1); if (errno == ERANGE && ulval == ULONG_MAX) return (-1); *ulvalp = ulval; return (0); } got-portable-0.101/libexec/got-read-gotconfig/Makefile.in0000664000175100017510000006060214644145543016754 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-read-gotconfig$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-read-gotconfig ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_read_gotconfig_OBJECTS = $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) \ got-read-gotconfig.$(OBJEXT) parse.$(OBJEXT) got_read_gotconfig_OBJECTS = $(am_got_read_gotconfig_OBJECTS) got_read_gotconfig_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ ./$(DEPDIR)/got-read-gotconfig.Po ./$(DEPDIR)/parse.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \ -e s/c++$$/h++/ -e s/c$$/h/ YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS) AM_V_YACC = $(am__v_YACC_@AM_V@) am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@) am__v_YACC_0 = @echo " YACC " $@; am__v_YACC_1 = YLWRAP = $(top_srcdir)/etc/ylwrap SOURCES = $(got_read_gotconfig_SOURCES) DIST_SOURCES = $(got_read_gotconfig_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp \ $(top_srcdir)/etc/ylwrap parse.c DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(libbsd_CFLAGS) $(zlib_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_read_gotconfig_SOURCES = \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ got-read-gotconfig.c \ gotconfig.h \ parse.y got_read_gotconfig_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(libbsd_LIBS) \ $(zlib_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj .y $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-read-gotconfig/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-read-gotconfig/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files clean-libexecPROGRAMS: -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: > $(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: > $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-read-gotconfig$(EXEEXT): $(got_read_gotconfig_OBJECTS) $(got_read_gotconfig_DEPENDENCIES) $(EXTRA_got_read_gotconfig_DEPENDENCIES) @rm -f got-read-gotconfig$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_read_gotconfig_OBJECTS) $(got_read_gotconfig_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-read-gotconfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .y.c: $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -rm -f parse.c clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-gotconfig.Po -rm -f ./$(DEPDIR)/parse.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-gotconfig.Po -rm -f ./$(DEPDIR)/parse.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/libexec/got-read-gotconfig/gotconfig.h0000644000175100017510000000423714644143163017033 /* * Copyright (c) 2022 Josh Rickmar * Copyright (c) 2020, 2021 Tracey Emery * Copyright (c) 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * We maintain two different structures for fetch and send configuration * settings in case they diverge in the future. */ struct fetch_config { char *repository; char *server; char *protocol; int port; struct node_branch *branch; }; struct send_config { char *repository; char *server; char *protocol; int port; struct node_branch *branch; }; struct node_branch { char *branch_name; struct node_branch *next; struct node_branch *tail; }; struct node_ref { char *ref_name; struct node_ref *next; struct node_ref *tail; }; struct gotconfig_remote_repo { TAILQ_ENTRY(gotconfig_remote_repo) entry; char *name; char *repository; char *server; char *protocol; int port; int mirror_references; int fetch_all_branches; struct node_branch *branch; struct node_ref *fetch_ref; struct fetch_config *fetch_config; struct send_config *send_config; }; TAILQ_HEAD(gotconfig_remote_repo_list, gotconfig_remote_repo); struct gotconfig { char *author; struct gotconfig_remote_repo_list remotes; int nremotes; char *allowed_signers_file; char *revoked_signers_file; char *signer_id; }; /* * Parse individual gotconfig repository files */ const struct got_error *gotconfig_parse(struct gotconfig **, const char *, int *); void gotconfig_free(struct gotconfig *); got-portable-0.101/libexec/got-read-gotconfig/parse.y0000664000175100017510000004473014644144735016221 /* * Copyright (c) 2020, 2021 Tracey Emery * Copyright (c) 2020 Stefan Sperling * Copyright (c) 2004, 2005 Esben Norby * Copyright (c) 2004 Ryan McBride * Copyright (c) 2002, 2003, 2004 Henning Brauer * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. * Copyright (c) 2001 Theo de Raadt. All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ %{ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "gotconfig.h" static struct file { FILE *stream; const char *name; size_t ungetpos; size_t ungetsize; u_char *ungetbuf; int eof_reached; int lineno; } *file; static const struct got_error* newfile(struct file**, const char *, int *); static void closefile(struct file *); int yyparse(void); int yylex(void); int yyerror(const char *, ...) __attribute__((__format__ (printf, 1, 2))) __attribute__((__nonnull__ (1))); int kw_cmp(const void *, const void *); int lookup(char *); int igetc(void); int lgetc(int); void lungetc(int); int findeol(void); static int parseport(char *, long long *); TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); struct sym { TAILQ_ENTRY(sym) entry; int used; int persist; char *nam; char *val; }; int symset(const char *, const char *, int); int cmdline_symset(char *); char *symget(const char *); static int atoul(char *, u_long *); static const struct got_error* gerror; static struct gotconfig_remote_repo *remote; static struct gotconfig gotconfig; static const struct got_error* new_remote(struct gotconfig_remote_repo **); static const struct got_error* new_fetch_config(struct fetch_config **); static const struct got_error* new_send_config(struct send_config **); typedef struct { union { long long number; char *string; struct node_branch *branch; struct node_ref *ref; } v; int lineno; } YYSTYPE; #if defined(__APPLE__) && !defined(YYSTYPE) #warning "Setting YYSTYPE - is GNU Bison installed?" #define YYSTYPE YYSTYPE #endif %} %token ERROR %token REMOTE REPOSITORY SERVER PORT PROTOCOL MIRROR_REFERENCES BRANCH %token AUTHOR ALLOWED_SIGNERS REVOKED_SIGNERS SIGNER_ID FETCH_ALL_BRANCHES %token REFERENCE FETCH SEND %token STRING %token NUMBER %type boolean portplain %type numberstring %type branch xbranch branch_list %type ref xref ref_list %% grammar : /* empty */ | grammar '\n' | grammar author '\n' | grammar remote '\n' | grammar allowed_signers '\n' | grammar revoked_signers '\n' | grammar signer_id '\n' ; boolean : STRING { if (strcasecmp($1, "true") == 0 || strcasecmp($1, "yes") == 0) $$ = 1; else if (strcasecmp($1, "false") == 0 || strcasecmp($1, "no") == 0) $$ = 0; else { yyerror("invalid boolean value '%s'", $1); free($1); YYERROR; } free($1); } ; numberstring : NUMBER { char *s; if (asprintf(&s, "%lld", $1) == -1) { yyerror("string: asprintf"); YYERROR; } $$ = s; } | STRING ; portplain : numberstring { if (parseport($1, &$$) == -1) { free($1); YYERROR; } free($1); } ; branch : /* empty */ { $$ = NULL; } | xbranch { $$ = $1; } | '{' optnl branch_list '}' { $$ = $3; } ; xbranch : STRING { $$ = calloc(1, sizeof(struct node_branch)); if ($$ == NULL) { yyerror("calloc"); YYERROR; } $$->branch_name = $1; $$->tail = $$; } ; branch_list : xbranch optnl { $$ = $1; } | branch_list comma xbranch optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; } ; ref : /* empty */ { $$ = NULL; } | xref { $$ = $1; } | '{' optnl ref_list '}' { $$ = $3; } ; xref : STRING { $$ = calloc(1, sizeof(struct node_ref)); if ($$ == NULL) { yyerror("calloc"); YYERROR; } $$->ref_name = $1; $$->tail = $$; } ; ref_list : xref optnl { $$ = $1; } | ref_list comma xref optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; } ; remoteopts2 : remoteopts2 remoteopts1 nl | remoteopts1 optnl ; remoteopts1 : REPOSITORY STRING { remote->repository = $2; } | SERVER STRING { remote->server = $2; } | PROTOCOL STRING { remote->protocol = $2; } | MIRROR_REFERENCES boolean { remote->mirror_references = $2; } | FETCH_ALL_BRANCHES boolean { remote->fetch_all_branches = $2; } | PORT portplain { remote->port = $2; } | BRANCH branch { remote->branch = $2; } | REFERENCE ref { remote->fetch_ref = $2; } | FETCH { static const struct got_error* error; if (remote->fetch_config != NULL) { yyerror("fetch block already exists"); YYERROR; } error = new_fetch_config(&remote->fetch_config); if (error) { yyerror("%s", error->msg); YYERROR; } } '{' optnl fetchempty '}' | SEND { static const struct got_error* error; if (remote->send_config != NULL) { yyerror("send block already exists"); YYERROR; } error = new_send_config(&remote->send_config); if (error) { yyerror("%s", error->msg); YYERROR; } } '{' optnl sendempty '}' ; fetchempty : /* empty */ | fetchopts2 ; fetchopts2 : fetchopts2 fetchopts1 nl | fetchopts1 optnl ; fetchopts1 : REPOSITORY STRING { remote->fetch_config->repository = $2; } | SERVER STRING { remote->fetch_config->server = $2; } | PROTOCOL STRING { remote->fetch_config->protocol = $2; } | PORT portplain { remote->fetch_config->port = $2; } | BRANCH branch { remote->fetch_config->branch = $2; } ; sendempty : /* empty */ | sendopts2 ; sendopts2 : sendopts2 sendopts1 nl | sendopts1 optnl ; sendopts1 : REPOSITORY STRING { remote->send_config->repository = $2; } | SERVER STRING { remote->send_config->server = $2; } | PROTOCOL STRING { remote->send_config->protocol = $2; } | PORT portplain { remote->send_config->port = $2; } | BRANCH branch { remote->send_config->branch = $2; } ; remote : REMOTE STRING { static const struct got_error* error; error = new_remote(&remote); if (error) { free($2); yyerror("%s", error->msg); YYERROR; } remote->name = $2; } '{' optnl remoteopts2 '}' { TAILQ_INSERT_TAIL(&gotconfig.remotes, remote, entry); gotconfig.nremotes++; } ; author : AUTHOR STRING { gotconfig.author = $2; } ; allowed_signers : ALLOWED_SIGNERS STRING { gotconfig.allowed_signers_file = $2; } ; revoked_signers : REVOKED_SIGNERS STRING { gotconfig.revoked_signers_file = $2; } ; signer_id : SIGNER_ID STRING { gotconfig.signer_id = $2; } ; optnl : '\n' optnl | /* empty */ ; nl : '\n' optnl ; comma : ',' | /* empty */ ; %% struct keywords { const char *k_name; int k_val; }; int yyerror(const char *fmt, ...) { va_list ap; char *msg; char *err = NULL; va_start(ap, fmt); if (vasprintf(&msg, fmt, ap) == -1) { gerror = got_error_from_errno("vasprintf"); return 0; } va_end(ap); if (asprintf(&err, "%s: line %d: %s", file->name, yylval.lineno, msg) == -1) { gerror = got_error_from_errno("asprintf"); return(0); } gerror = got_error_msg(GOT_ERR_PARSE_CONFIG, err); free(msg); return(0); } int kw_cmp(const void *k, const void *e) { return (strcmp(k, ((const struct keywords *)e)->k_name)); } int lookup(char *s) { /* This has to be sorted always. */ static const struct keywords keywords[] = { {"allowed_signers", ALLOWED_SIGNERS}, {"author", AUTHOR}, {"branch", BRANCH}, {"fetch", FETCH}, {"fetch-all-branches", FETCH_ALL_BRANCHES}, /* deprecated */ {"fetch_all_branches", FETCH_ALL_BRANCHES}, {"mirror-references", MIRROR_REFERENCES}, /* deprecated */ {"mirror_references", MIRROR_REFERENCES}, {"port", PORT}, {"protocol", PROTOCOL}, {"reference", REFERENCE}, {"remote", REMOTE}, {"repository", REPOSITORY}, {"revoked_signers", REVOKED_SIGNERS}, {"send", SEND}, {"server", SERVER}, {"signer_id", SIGNER_ID}, }; const struct keywords *p; p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), sizeof(keywords[0]), kw_cmp); if (p) return (p->k_val); else return (STRING); } #define START_EXPAND 1 #define DONE_EXPAND 2 static int expanding; int igetc(void) { int c; while (1) { if (file->ungetpos > 0) c = file->ungetbuf[--file->ungetpos]; else c = getc(file->stream); if (c == START_EXPAND) expanding = 1; else if (c == DONE_EXPAND) expanding = 0; else break; } return (c); } int lgetc(int quotec) { int c, next; if (quotec) { c = igetc(); if (c == EOF) { yyerror("reached end of file while parsing " "quoted string"); } return (c); } c = igetc(); while (c == '\\') { next = igetc(); if (next != '\n') { c = next; break; } yylval.lineno = file->lineno; file->lineno++; } return (c); } void lungetc(int c) { if (c == EOF) return; if (file->ungetpos >= file->ungetsize) { void *p = reallocarray(file->ungetbuf, file->ungetsize, 2); if (p == NULL) err(1, "%s", __func__); file->ungetbuf = p; file->ungetsize *= 2; } file->ungetbuf[file->ungetpos++] = c; } int findeol(void) { int c; /* Skip to either EOF or the first real EOL. */ while (1) { c = lgetc(0); if (c == '\n') { file->lineno++; break; } if (c == EOF) break; } return (ERROR); } static long long getservice(char *n) { struct servent *s; u_long ulval; if (atoul(n, &ulval) == 0) { if (ulval == 0 || ulval > 65535) { yyerror("illegal port value %lu", ulval); return (-1); } return ulval; } else { s = getservbyname(n, "tcp"); if (s == NULL) s = getservbyname(n, "udp"); if (s == NULL) { yyerror("unknown port %s", n); return (-1); } return (s->s_port); } } static int parseport(char *port, long long *pn) { if ((*pn = getservice(port)) == -1) { *pn = 0LL; return (-1); } return (0); } int yylex(void) { char buf[8096]; char *p, *val; int quotec, next, c; int token; top: p = buf; c = lgetc(0); while (c == ' ' || c == '\t') c = lgetc(0); /* nothing */ yylval.lineno = file->lineno; if (c == '#') { c = lgetc(0); while (c != '\n' && c != EOF) c = lgetc(0); /* nothing */ } if (c == '$' && !expanding) { while (1) { c = lgetc(0); if (c == EOF) return (0); if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } if (isalnum(c) || c == '_') { *p++ = c; continue; } *p = '\0'; lungetc(c); break; } val = symget(buf); if (val == NULL) { yyerror("macro '%s' not defined", buf); return (findeol()); } p = val + strlen(val) - 1; lungetc(DONE_EXPAND); while (p >= val) { lungetc((unsigned char)*p); p--; } lungetc(START_EXPAND); goto top; } switch (c) { case '\'': case '"': quotec = c; while (1) { c = lgetc(quotec); if (c == EOF) return (0); if (c == '\n') { file->lineno++; continue; } else if (c == '\\') { next = lgetc(quotec); if (next == EOF) return (0); if (next == quotec || c == ' ' || c == '\t') c = next; else if (next == '\n') { file->lineno++; continue; } else lungetc(next); } else if (c == quotec) { *p = '\0'; break; } else if (c == '\0') { yyerror("syntax error"); return (findeol()); } if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } *p++ = c; } yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "%s", __func__); return (STRING); } #define allowed_to_end_number(x) \ (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') if (c == '-' || isdigit(c)) { do { *p++ = c; if ((size_t)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && isdigit(c)); lungetc(c); if (p == buf + 1 && buf[0] == '-') goto nodigits; if (c == EOF || allowed_to_end_number(c)) { const char *errstr = NULL; *p = '\0'; yylval.v.number = strtonum(buf, LLONG_MIN, LLONG_MAX, &errstr); if (errstr) { yyerror("\"%s\" invalid number: %s", buf, errstr); return (findeol()); } return (NUMBER); } else { nodigits: while (p > buf + 1) lungetc((unsigned char)*--p); c = (unsigned char)*--p; if (c == '-') return (c); } } #define allowed_in_string(x) \ (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ x != '{' && x != '}' && \ x != '!' && x != '=' && x != '#' && \ x != ',')) if (isalnum(c) || c == ':' || c == '_') { do { *p++ = c; if ((size_t)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && (allowed_in_string(c))); lungetc(c); *p = '\0'; token = lookup(buf); if (token == STRING) { yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "%s", __func__); } return (token); } if (c == '\n') { yylval.lineno = file->lineno; file->lineno++; } if (c == EOF) return (0); return (c); } static const struct got_error* newfile(struct file **nfile, const char *filename, int *fd) { const struct got_error* error = NULL; (*nfile) = calloc(1, sizeof(struct file)); if ((*nfile) == NULL) return got_error_from_errno("calloc"); (*nfile)->stream = fdopen(*fd, "r"); if ((*nfile)->stream == NULL) { error = got_error_from_errno("fdopen"); free((*nfile)); return error; } *fd = -1; /* Stream owns the file descriptor now. */ (*nfile)->name = filename; (*nfile)->lineno = 1; (*nfile)->ungetsize = 16; (*nfile)->ungetbuf = malloc((*nfile)->ungetsize); if ((*nfile)->ungetbuf == NULL) { error = got_error_from_errno("malloc"); fclose((*nfile)->stream); free((*nfile)); return error; } return NULL; } static const struct got_error* new_remote(struct gotconfig_remote_repo **remote) { const struct got_error *error = NULL; *remote = calloc(1, sizeof(**remote)); if (*remote == NULL) error = got_error_from_errno("calloc"); return error; } static const struct got_error* new_fetch_config(struct fetch_config **fetch_config) { const struct got_error *error = NULL; *fetch_config = calloc(1, sizeof(**fetch_config)); if (*fetch_config == NULL) error = got_error_from_errno("calloc"); return error; } static const struct got_error* new_send_config(struct send_config **send_config) { const struct got_error *error = NULL; *send_config = calloc(1, sizeof(**send_config)); if (*send_config == NULL) error = got_error_from_errno("calloc"); return error; } static void closefile(struct file *file) { fclose(file->stream); free(file->ungetbuf); free(file); } const struct got_error * gotconfig_parse(struct gotconfig **conf, const char *filename, int *fd) { const struct got_error *err = NULL; struct sym *sym, *next; *conf = NULL; err = newfile(&file, filename, fd); if (err) return err; TAILQ_INIT(&gotconfig.remotes); yyparse(); closefile(file); /* Free macros and check which have not been used. */ TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { if (!sym->persist) { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } if (gerror == NULL) *conf = &gotconfig; return gerror; } static void free_fetch_config(struct fetch_config *fetch_config) { free(remote->fetch_config->repository); free(remote->fetch_config->server); free(remote->fetch_config->protocol); free(remote->fetch_config); } static void free_send_config(struct send_config *send_config) { free(remote->send_config->repository); free(remote->send_config->server); free(remote->send_config->protocol); free(remote->send_config); } void gotconfig_free(struct gotconfig *conf) { struct gotconfig_remote_repo *remote; free(conf->author); free(conf->allowed_signers_file); free(conf->revoked_signers_file); free(conf->signer_id); while (!TAILQ_EMPTY(&conf->remotes)) { remote = TAILQ_FIRST(&conf->remotes); TAILQ_REMOVE(&conf->remotes, remote, entry); if (remote->fetch_config != NULL) free_fetch_config(remote->fetch_config); if (remote->send_config != NULL) free_send_config(remote->send_config); free(remote->name); free(remote->repository); free(remote->server); free(remote->protocol); free(remote); } } int symset(const char *nam, const char *val, int persist) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) break; } if (sym != NULL) { if (sym->persist == 1) return (0); else { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } sym = calloc(1, sizeof(*sym)); if (sym == NULL) return (-1); sym->nam = strdup(nam); if (sym->nam == NULL) { free(sym); return (-1); } sym->val = strdup(val); if (sym->val == NULL) { free(sym->nam); free(sym); return (-1); } sym->used = 0; sym->persist = persist; TAILQ_INSERT_TAIL(&symhead, sym, entry); return (0); } int cmdline_symset(char *s) { char *sym, *val; int ret; size_t len; val = strrchr(s, '='); if (val == NULL) return (-1); len = strlen(s) - strlen(val) + 1; sym = malloc(len); if (sym == NULL) errx(1, "cmdline_symset: malloc"); strlcpy(sym, s, len); ret = symset(sym, val + 1, 1); free(sym); return (ret); } char * symget(const char *nam) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) { sym->used = 1; return (sym->val); } } return (NULL); } static int atoul(char *s, u_long *ulvalp) { u_long ulval; char *ep; errno = 0; ulval = strtoul(s, &ep, 0); if (s[0] == '\0' || *ep != '\0') return (-1); if (errno == ERANGE && ulval == ULONG_MAX) return (-1); *ulvalp = ulval; return (0); } got-portable-0.101/libexec/got-read-pack/0000775000175100017510000000000014644145571013723 5got-portable-0.101/libexec/got-read-pack/Makefile.am0000664000175100017510000000152114644144735015677 libexec_PROGRAMS = got-read-pack include $(top_builddir)/Makefile.common got_read_pack_SOURCES = got-read-pack.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_pack_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.101/libexec/got-read-pack/Makefile.in0000664000175100017510000006442314644145544015721 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-read-pack$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-read-pack ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_read_pack_OBJECTS = got-read-pack.$(OBJEXT) \ $(top_builddir)/lib/delta.$(OBJEXT) \ $(top_builddir)/lib/delta_cache.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_cache.$(OBJEXT) \ $(top_builddir)/lib/object_idset.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/opentemp.$(OBJEXT) \ $(top_builddir)/lib/pack.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) got_read_pack_OBJECTS = $(am_got_read_pack_OBJECTS) got_read_pack_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/delta.Po \ $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/object_idset.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/opentemp.Po \ $(top_builddir)/lib/$(DEPDIR)/pack.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ ./$(DEPDIR)/got-read-pack.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_read_pack_SOURCES) DIST_SOURCES = $(got_read_pack_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_read_pack_SOURCES = got-read-pack.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_pack_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-read-pack/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-read-pack/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files clean-libexecPROGRAMS: -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: > $(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: > $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_idset.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/opentemp.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-read-pack$(EXEEXT): $(got_read_pack_OBJECTS) $(got_read_pack_DEPENDENCIES) $(EXTRA_got_read_pack_DEPENDENCIES) @rm -f got-read-pack$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_read_pack_OBJECTS) $(got_read_pack_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_idset.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/opentemp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-read-pack.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-pack.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-pack.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/libexec/got-read-pack/got-read-pack.c0000664000175100017510000014224014644144735016431 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_lib_delta.h" #include "got_lib_delta_cache.h" #include "got_lib_object.h" #include "got_lib_object_qid.h" #include "got_lib_object_cache.h" #include "got_lib_object_parse.h" #include "got_lib_object_idset.h" #include "got_lib_privsep.h" #include "got_lib_pack.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif static volatile sig_atomic_t sigint_received; static void catch_sigint(int signo) { sigint_received = 1; } static const struct got_error * open_object(struct got_object **obj, struct got_pack *pack, struct got_packidx *packidx, int idx, struct got_object_id *id, struct got_object_cache *objcache) { const struct got_error *err; err = got_packfile_open_object(obj, pack, packidx, idx, id); if (err) return err; (*obj)->refcnt++; err = got_object_cache_add(objcache, id, *obj); if (err) { if (err->code == GOT_ERR_OBJ_EXISTS || err->code == GOT_ERR_OBJ_TOO_LARGE) err = NULL; return err; } (*obj)->refcnt++; return NULL; } static const struct got_error * object_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx, struct got_object_cache *objcache) { const struct got_error *err = NULL; struct got_imsg_packed_object iobj; struct got_object *obj; struct got_object_id id; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(iobj)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iobj, imsg->data, sizeof(iobj)); memcpy(&id, &iobj.id, sizeof(id)); obj = got_object_cache_get(objcache, &id); if (obj) { obj->refcnt++; } else { err = open_object(&obj, pack, packidx, iobj.idx, &id, objcache); if (err) goto done; } err = got_privsep_send_obj(ibuf, obj); done: got_object_close(obj); return err; } static const struct got_error * open_commit(struct got_commit_object **commit, struct got_pack *pack, struct got_packidx *packidx, int obj_idx, struct got_object_id *id, struct got_object_cache *objcache) { const struct got_error *err = NULL; struct got_object *obj = NULL; uint8_t *buf = NULL; size_t len; *commit = NULL; obj = got_object_cache_get(objcache, id); if (obj) { obj->refcnt++; } else { err = open_object(&obj, pack, packidx, obj_idx, id, objcache); if (err) return err; } err = got_packfile_extract_object_to_mem(&buf, &len, obj, pack); if (err) goto done; obj->size = len; err = got_object_parse_commit(commit, buf, len); done: got_object_close(obj); free(buf); return err; } static const struct got_error * commit_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx, struct got_object_cache *objcache) { const struct got_error *err = NULL; struct got_imsg_packed_object iobj; struct got_commit_object *commit = NULL; struct got_object_id id; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(iobj)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iobj, imsg->data, sizeof(iobj)); memcpy(&id, &iobj.id, sizeof(id)); err = open_commit(&commit, pack, packidx, iobj.idx, &id, objcache); if (err) goto done; err = got_privsep_send_commit(ibuf, commit); done: if (commit) got_object_commit_close(commit); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; else got_privsep_send_error(ibuf, err); } return err; } static const struct got_error * open_tree(uint8_t **buf, size_t *len, struct got_pack *pack, struct got_packidx *packidx, int obj_idx, struct got_object_id *id, struct got_object_cache *objcache) { const struct got_error *err = NULL; struct got_object *obj = NULL; int cached = 0; *buf = NULL; *len = 0; obj = got_object_cache_get(objcache, id); if (obj) { obj->refcnt++; cached = 1; } else { err = open_object(&obj, pack, packidx, obj_idx, id, objcache); if (err) return err; } err = got_packfile_extract_object_to_mem(buf, len, obj, pack); if (err) goto done; if (!cached) obj->size = *len; done: got_object_close(obj); if (err) { free(*buf); *buf = NULL; } return err; } static const struct got_error * tree_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx, struct got_object_cache *objcache, struct got_parsed_tree_entry **entries, size_t *nentries, size_t *nentries_alloc) { const struct got_error *err = NULL; struct got_imsg_packed_object iobj; uint8_t *buf = NULL; size_t len = 0; struct got_object_id id; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(iobj)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iobj, imsg->data, sizeof(iobj)); memcpy(&id, &iobj.id, sizeof(id)); err = open_tree(&buf, &len, pack, packidx, iobj.idx, &id, objcache); if (err) return err; err = got_object_parse_tree(entries, nentries, nentries_alloc, buf, len); if (err) goto done; err = got_privsep_send_tree(ibuf, *entries, *nentries); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; else got_privsep_send_error(ibuf, err); } done: free(buf); return err; } static const struct got_error * receive_file(FILE **f, struct imsgbuf *ibuf, uint32_t imsg_code) { const struct got_error *err; struct imsg imsg; size_t datalen; int fd; err = got_privsep_recv_imsg(&imsg, ibuf, 0); if (err) return err; if (imsg.hdr.type != imsg_code) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } fd = imsg_get_fd(&imsg); if (fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } *f = fdopen(fd, "w+"); if (*f == NULL) { err = got_error_from_errno("fdopen"); close(fd); goto done; } done: imsg_free(&imsg); return err; } static const struct got_error * receive_tempfile(FILE **f, const char *mode, struct imsg *imsg, struct imsgbuf *ibuf) { const struct got_error *err; size_t datalen; int fd; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); fd = imsg_get_fd(imsg); if (fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); *f = fdopen(fd, mode); if (*f == NULL) { err = got_error_from_errno("fdopen"); close(fd); return err; } return NULL; } static const struct got_error * blob_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx, struct got_object_cache *objcache, FILE *basefile, FILE *accumfile) { const struct got_error *err = NULL; struct got_imsg_packed_object iobj; struct got_object *obj = NULL; FILE *outfile = NULL; struct got_object_id id; size_t datalen; uint64_t blob_size; uint8_t *buf = NULL; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(iobj)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iobj, imsg->data, sizeof(iobj)); memcpy(&id, &iobj.id, sizeof(id)); obj = got_object_cache_get(objcache, &id); if (obj) { obj->refcnt++; } else { err = open_object(&obj, pack, packidx, iobj.idx, &id, objcache); if (err) return err; } err = receive_file(&outfile, ibuf, GOT_IMSG_BLOB_OUTFD); if (err) goto done; if (obj->flags & GOT_OBJ_FLAG_DELTIFIED) { err = got_pack_get_max_delta_object_size(&blob_size, obj, pack); if (err) goto done; } else blob_size = obj->size; if (blob_size <= GOT_PRIVSEP_INLINE_BLOB_DATA_MAX) err = got_packfile_extract_object_to_mem(&buf, &obj->size, obj, pack); else err = got_packfile_extract_object(pack, obj, outfile, basefile, accumfile); if (err) goto done; err = got_privsep_send_blob(ibuf, obj->size, obj->hdrlen, buf); done: free(buf); if (outfile && fclose(outfile) == EOF && err == NULL) err = got_error_from_errno("fclose"); got_object_close(obj); if (err && err->code != GOT_ERR_PRIVSEP_PIPE) got_privsep_send_error(ibuf, err); return err; } static const struct got_error * tag_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx, struct got_object_cache *objcache) { const struct got_error *err = NULL; struct got_imsg_packed_object iobj; struct got_object *obj = NULL; struct got_tag_object *tag = NULL; uint8_t *buf = NULL; size_t len; struct got_object_id id; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(iobj)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iobj, imsg->data, sizeof(iobj)); memcpy(&id, &iobj.id, sizeof(id)); obj = got_object_cache_get(objcache, &id); if (obj) { obj->refcnt++; } else { err = open_object(&obj, pack, packidx, iobj.idx, &id, objcache); if (err) return err; } err = got_packfile_extract_object_to_mem(&buf, &len, obj, pack); if (err) goto done; obj->size = len; err = got_object_parse_tag(&tag, buf, len); if (err) goto done; err = got_privsep_send_tag(ibuf, tag); done: free(buf); got_object_close(obj); if (tag) got_object_tag_close(tag); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; else got_privsep_send_error(ibuf, err); } return err; } static const struct got_error * tree_path_changed(int *changed, uint8_t **buf1, size_t *len1, uint8_t **buf2, size_t *len2, const char *path, struct got_pack *pack, struct got_packidx *packidx, struct imsgbuf *ibuf, struct got_object_cache *objcache) { const struct got_error *err = NULL; struct got_parsed_tree_entry pte1, pte2; const char *seg, *s; size_t seglen; size_t remain1 = *len1, remain2 = *len2, elen; uint8_t *next_entry1 = *buf1; uint8_t *next_entry2 = *buf2; memset(&pte1, 0, sizeof(pte1)); memset(&pte2, 0, sizeof(pte2)); *changed = 0; /* We not do support comparing the root path. */ if (got_path_is_root_dir(path)) return got_error_path(path, GOT_ERR_BAD_PATH); s = path; while (*s == '/') s++; seg = s; seglen = 0; while (*s) { if (*s != '/') { s++; seglen++; if (*s) continue; } /* * As an optimization we compare entries in on-disk order * rather than in got_path_cmp() order. We only need to * find out if any entries differ. Parsing all entries and * sorting them slows us down significantly when tree objects * have thousands of entries. We can assume that on-disk entry * ordering is stable, as per got_object_tree_create() and * sort_tree_entries_the_way_git_likes_it(). Other orderings * are incompatible with Git and would yield false positives * here, too. */ while (remain1 > 0) { err = got_object_parse_tree_entry(&pte1, &elen, next_entry1, remain1); if (err) return err; next_entry1 += elen; remain1 -= elen; if (strncmp(pte1.name, seg, seglen) != 0 || pte1.name[seglen] != '\0') { memset(&pte1, 0, sizeof(pte1)); continue; } else break; } if (pte1.name == NULL) { err = got_error(GOT_ERR_NO_OBJ); break; } if (remain2 == 0) { *changed = 1; break; } while (remain2 > 0) { err = got_object_parse_tree_entry(&pte2, &elen, next_entry2, remain2); if (err) return err; next_entry2 += elen; remain2 -= elen; if (strncmp(pte2.name, seg, seglen) != 0 || pte2.name[seglen] != '\0') { memset(&pte2, 0, sizeof(pte2)); continue; } else break; } if (pte2.name == NULL) { *changed = 1; break; } if (pte1.mode != pte2.mode) { *changed = 1; break; } if (memcmp(pte1.id, pte2.id, SHA1_DIGEST_LENGTH) == 0) { *changed = 0; break; } if (*s == '\0') { /* final path element */ *changed = 1; break; } seg = s + 1; s++; seglen = 0; if (*s) { struct got_object_id id1, id2; int idx; memcpy(id1.sha1, pte1.id, SHA1_DIGEST_LENGTH); idx = got_packidx_get_object_idx(packidx, &id1); if (idx == -1) { err = got_error_no_obj(&id1); break; } free(*buf1); *buf1 = NULL; err = open_tree(buf1, len1, pack, packidx, idx, &id1, objcache); memset(&pte1, 0, sizeof(pte1)); if (err) break; next_entry1 = *buf1; remain1 = *len1; memcpy(id2.sha1, pte2.id, SHA1_DIGEST_LENGTH); idx = got_packidx_get_object_idx(packidx, &id2); if (idx == -1) { err = got_error_no_obj(&id2); break; } free(*buf2); *buf2 = NULL; err = open_tree(buf2, len2, pack, packidx, idx, &id2, objcache); memset(&pte2, 0, sizeof(pte2)); if (err) break; next_entry2 = *buf2; remain2 = *len2; } } return err; } static const struct got_error * send_traversed_commits(struct got_object_id *commit_ids, size_t ncommits, struct imsgbuf *ibuf) { struct ibuf *wbuf; size_t i; wbuf = imsg_create(ibuf, GOT_IMSG_TRAVERSED_COMMITS, 0, 0, sizeof(struct got_imsg_traversed_commits) + ncommits * sizeof(commit_ids[0])); if (wbuf == NULL) return got_error_from_errno("imsg_create TRAVERSED_COMMITS"); if (imsg_add(wbuf, &ncommits, sizeof(ncommits)) == -1) return got_error_from_errno("imsg_add TRAVERSED_COMMITS"); for (i = 0; i < ncommits; i++) { struct got_object_id *id = &commit_ids[i]; if (imsg_add(wbuf, id, sizeof(*id)) == -1) { return got_error_from_errno( "imsg_add TRAVERSED_COMMITS"); } } imsg_close(ibuf, wbuf); return got_privsep_flush_imsg(ibuf); } static const struct got_error * send_commit_traversal_done(struct imsgbuf *ibuf) { if (imsg_compose(ibuf, GOT_IMSG_COMMIT_TRAVERSAL_DONE, 0, 0, -1, NULL, 0) == -1) return got_error_from_errno("imsg_compose TRAVERSAL_DONE"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * commit_traversal_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx, struct got_object_cache *objcache) { const struct got_error *err = NULL; struct got_imsg_commit_traversal_request ctreq; struct got_object_qid *pid; struct got_commit_object *commit = NULL, *pcommit = NULL; struct got_object_id id; size_t datalen; char *path = NULL; const int min_alloc = 64; int changed = 0, ncommits = 0, nallocated = 0; struct got_object_id *commit_ids = NULL; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(ctreq)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ctreq, imsg->data, sizeof(ctreq)); memcpy(&id, &ctreq.iobj.id, sizeof(id)); if (datalen != sizeof(ctreq) + ctreq.path_len) return got_error(GOT_ERR_PRIVSEP_LEN); if (ctreq.path_len == 0) return got_error(GOT_ERR_PRIVSEP_LEN); path = strndup(imsg->data + sizeof(ctreq), ctreq.path_len); if (path == NULL) return got_error_from_errno("strndup"); nallocated = min_alloc; commit_ids = reallocarray(NULL, nallocated, sizeof(*commit_ids)); if (commit_ids == NULL) return got_error_from_errno("reallocarray"); do { const size_t max_datalen = MAX_IMSGSIZE - IMSG_HEADER_SIZE; int idx; if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); goto done; } if (commit == NULL) { idx = got_packidx_get_object_idx(packidx, &id); if (idx == -1) break; err = open_commit(&commit, pack, packidx, idx, &id, objcache); if (err) { if (err->code != GOT_ERR_NO_OBJ) goto done; err = NULL; break; } } if (sizeof(struct got_imsg_traversed_commits) + ncommits * sizeof(commit_ids[0]) >= max_datalen) { err = send_traversed_commits(commit_ids, ncommits, ibuf); if (err) goto done; ncommits = 0; } ncommits++; if (ncommits > nallocated) { struct got_object_id *new; nallocated += min_alloc; new = reallocarray(commit_ids, nallocated, sizeof(*commit_ids)); if (new == NULL) { err = got_error_from_errno("reallocarray"); goto done; } commit_ids = new; } memcpy(&commit_ids[ncommits - 1], &id, sizeof(id)); pid = STAILQ_FIRST(&commit->parent_ids); if (pid == NULL) break; idx = got_packidx_get_object_idx(packidx, &pid->id); if (idx == -1) break; err = open_commit(&pcommit, pack, packidx, idx, &pid->id, objcache); if (err) { if (err->code != GOT_ERR_NO_OBJ) goto done; err = NULL; break; } if (path[0] == '/' && path[1] == '\0') { if (got_object_id_cmp(pcommit->tree_id, commit->tree_id) != 0) { changed = 1; break; } } else { int pidx; uint8_t *buf = NULL, *pbuf = NULL; size_t len = 0, plen = 0; idx = got_packidx_get_object_idx(packidx, commit->tree_id); if (idx == -1) break; pidx = got_packidx_get_object_idx(packidx, pcommit->tree_id); if (pidx == -1) break; err = open_tree(&buf, &len, pack, packidx, idx, commit->tree_id, objcache); if (err) goto done; err = open_tree(&pbuf, &plen, pack, packidx, pidx, pcommit->tree_id, objcache); if (err) { free(buf); goto done; } err = tree_path_changed(&changed, &buf, &len, &pbuf, &plen, path, pack, packidx, ibuf, objcache); free(buf); free(pbuf); if (err) { if (err->code != GOT_ERR_NO_OBJ) goto done; err = NULL; break; } } if (!changed) { memcpy(&id, &pid->id, sizeof(id)); got_object_commit_close(commit); commit = pcommit; pcommit = NULL; } } while (!changed); if (ncommits > 0) { err = send_traversed_commits(commit_ids, ncommits, ibuf); if (err) goto done; if (changed) { err = got_privsep_send_commit(ibuf, commit); if (err) goto done; } } err = send_commit_traversal_done(ibuf); done: free(path); free(commit_ids); if (commit) got_object_commit_close(commit); if (pcommit) got_object_commit_close(pcommit); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; else got_privsep_send_error(ibuf, err); } return err; } static const struct got_error * raw_object_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx, struct got_object_cache *objcache, FILE *basefile, FILE *accumfile) { const struct got_error *err = NULL; uint8_t *buf = NULL; uint64_t size = 0; FILE *outfile = NULL; struct got_imsg_packed_object iobj; struct got_object *obj; struct got_object_id id; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(iobj)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iobj, imsg->data, sizeof(iobj)); memcpy(&id, &iobj.id, sizeof(id)); obj = got_object_cache_get(objcache, &id); if (obj) { obj->refcnt++; } else { err = open_object(&obj, pack, packidx, iobj.idx, &id, objcache); if (err) return err; } err = receive_file(&outfile, ibuf, GOT_IMSG_RAW_OBJECT_OUTFD); if (err) return err; if (obj->flags & GOT_OBJ_FLAG_DELTIFIED) { err = got_pack_get_max_delta_object_size(&size, obj, pack); if (err) goto done; } else size = obj->size; if (size <= GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX) err = got_packfile_extract_object_to_mem(&buf, &obj->size, obj, pack); else err = got_packfile_extract_object(pack, obj, outfile, basefile, accumfile); if (err) goto done; err = got_privsep_send_raw_obj(ibuf, obj->size, obj->hdrlen, buf); done: free(buf); if (outfile && fclose(outfile) == EOF && err == NULL) err = got_error_from_errno("fclose"); got_object_close(obj); if (err && err->code != GOT_ERR_PRIVSEP_PIPE) got_privsep_send_error(ibuf, err); return err; } static const struct got_error * get_base_object_id(struct got_object_id *base_id, struct got_packidx *packidx, off_t base_offset) { const struct got_error *err; int idx; err = got_packidx_get_offset_idx(&idx, packidx, base_offset); if (err) return err; if (idx == -1) return got_error(GOT_ERR_BAD_PACKIDX); return got_packidx_get_object_id(base_id, packidx, idx); } static const struct got_error * raw_delta_request(struct imsg *imsg, struct imsgbuf *ibuf, FILE *delta_outfile, struct got_pack *pack, struct got_packidx *packidx) { const struct got_error *err = NULL; struct got_imsg_raw_delta_request req; size_t datalen, delta_size, delta_compressed_size; off_t delta_offset, delta_data_offset; uint8_t *delta_buf = NULL; struct got_object_id id, base_id; off_t base_offset, delta_out_offset = 0; uint64_t base_size = 0, result_size = 0; size_t w; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(req)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&req, imsg->data, sizeof(req)); memcpy(&id, &req.id, sizeof(id)); err = got_packfile_extract_raw_delta(&delta_buf, &delta_size, &delta_compressed_size, &delta_offset, &delta_data_offset, &base_offset, &base_id, &base_size, &result_size, pack, packidx, req.idx); if (err) goto done; /* * If this is an offset delta we must determine the base * object ID ourselves. */ if (base_offset != 0) { err = get_base_object_id(&base_id, packidx, base_offset); if (err) goto done; } delta_out_offset = ftello(delta_outfile); w = fwrite(delta_buf, 1, delta_compressed_size, delta_outfile); if (w != delta_compressed_size) { err = got_ferror(delta_outfile, GOT_ERR_IO); goto done; } if (fflush(delta_outfile) == -1) { err = got_error_from_errno("fflush"); goto done; } err = got_privsep_send_raw_delta(ibuf, base_size, result_size, delta_size, delta_compressed_size, delta_offset, delta_out_offset, &base_id); done: free(delta_buf); return err; } struct search_deltas_arg { struct imsgbuf *ibuf; struct got_packidx *packidx; struct got_pack *pack; struct got_object_idset *idset; struct got_imsg_reused_delta deltas[GOT_IMSG_REUSED_DELTAS_MAX_NDELTAS]; size_t ndeltas; }; static const struct got_error * search_delta_for_object(struct got_object_id *id, void *data, void *arg) { const struct got_error *err; struct search_deltas_arg *a = arg; int obj_idx; uint8_t *delta_buf = NULL; uint64_t base_size, result_size; size_t delta_size, delta_compressed_size; off_t delta_offset, delta_data_offset, base_offset; struct got_object_id base_id; if (sigint_received) return got_error(GOT_ERR_CANCELLED); obj_idx = got_packidx_get_object_idx(a->packidx, id); if (obj_idx == -1) return NULL; /* object not present in our pack file */ err = got_packfile_extract_raw_delta(&delta_buf, &delta_size, &delta_compressed_size, &delta_offset, &delta_data_offset, &base_offset, &base_id, &base_size, &result_size, a->pack, a->packidx, obj_idx); if (err) { if (err->code == GOT_ERR_OBJ_TYPE) return NULL; /* object not stored as a delta */ return err; } /* * If this is an offset delta we must determine the base * object ID ourselves. */ if (base_offset != 0) { err = get_base_object_id(&base_id, a->packidx, base_offset); if (err) goto done; } if (got_object_idset_contains(a->idset, &base_id)) { struct got_imsg_reused_delta *delta; delta = &a->deltas[a->ndeltas++]; memcpy(&delta->id, id, sizeof(delta->id)); memcpy(&delta->base_id, &base_id, sizeof(delta->base_id)); delta->base_size = base_size; delta->result_size = result_size; delta->delta_size = delta_size; delta->delta_compressed_size = delta_compressed_size; delta->delta_offset = delta_data_offset; if (a->ndeltas >= GOT_IMSG_REUSED_DELTAS_MAX_NDELTAS) { err = got_privsep_send_reused_deltas(a->ibuf, a->deltas, a->ndeltas); if (err) goto done; a->ndeltas = 0; } } done: free(delta_buf); return err; } static const struct got_error * recv_object_ids(struct got_object_idset *idset, struct imsgbuf *ibuf) { const struct got_error *err = NULL; int done = 0; struct got_object_id *ids; size_t nids, i; for (;;) { err = got_privsep_recv_object_idlist(&done, &ids, &nids, ibuf); if (err || done) break; for (i = 0; i < nids; i++) { err = got_object_idset_add(idset, &ids[i], NULL); if (err) { free(ids); return err; } } free(ids); } return err; } static const struct got_error * recv_object_id_queue(struct got_object_id_queue *queue, struct got_object_idset *queued_ids, struct imsgbuf *ibuf) { const struct got_error *err = NULL; int done = 0; struct got_object_qid *qid; struct got_object_id *ids; size_t nids, i; for (;;) { err = got_privsep_recv_object_idlist(&done, &ids, &nids, ibuf); if (err || done) break; for (i = 0; i < nids; i++) { err = got_object_qid_alloc_partial(&qid); if (err) return err; memcpy(&qid->id, &ids[i], sizeof(qid->id)); STAILQ_INSERT_TAIL(queue, qid, entry); err = got_object_idset_add(queued_ids, &qid->id, NULL); if (err) return err; } } return err; } static const struct got_error * delta_reuse_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx) { const struct got_error *err = NULL; struct got_object_idset *idset; struct search_deltas_arg sda; idset = got_object_idset_alloc(); if (idset == NULL) return got_error_from_errno("got_object_idset_alloc"); err = recv_object_ids(idset, ibuf); if (err) return err; memset(&sda, 0, sizeof(sda)); sda.ibuf = ibuf; sda.idset = idset; sda.pack = pack; sda.packidx = packidx; err = got_object_idset_for_each(idset, search_delta_for_object, &sda); if (err) goto done; if (sda.ndeltas > 0) { err = got_privsep_send_reused_deltas(ibuf, sda.deltas, sda.ndeltas); if (err) goto done; } err = got_privsep_send_reused_deltas_done(ibuf); done: got_object_idset_free(idset); return err; } static const struct got_error * receive_packidx(struct got_packidx **packidx, struct imsgbuf *ibuf) { const struct got_error *err = NULL; struct imsg imsg; struct got_imsg_packidx ipackidx; size_t datalen; struct got_packidx *p; *packidx = NULL; err = got_privsep_recv_imsg(&imsg, ibuf, 0); if (err) return err; p = calloc(1, sizeof(*p)); if (p == NULL) { err = got_error_from_errno("calloc"); goto done; } if (imsg.hdr.type != GOT_IMSG_PACKIDX) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ipackidx)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&ipackidx, imsg.data, sizeof(ipackidx)); p->fd = imsg_get_fd(&imsg); p->len = ipackidx.len; if (p->fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } if (lseek(p->fd, 0, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } #ifndef GOT_PACK_NO_MMAP if (p->len > 0 && p->len <= SIZE_MAX) { p->map = mmap(NULL, p->len, PROT_READ, MAP_PRIVATE, p->fd, 0); if (p->map == MAP_FAILED) p->map = NULL; /* fall back to read(2) */ } #endif err = got_packidx_init_hdr(p, 1, ipackidx.packfile_size); done: if (err) { if (p != NULL) got_packidx_close(p); } else *packidx = p; imsg_free(&imsg); return err; } static const struct got_error * send_tree_enumeration_done(struct imsgbuf *ibuf) { if (imsg_compose(ibuf, GOT_IMSG_TREE_ENUMERATION_DONE, 0, 0, -1, NULL, 0) == -1) return got_error_from_errno("imsg_compose TREE_ENUMERATION_DONE"); return got_privsep_flush_imsg(ibuf); } struct enumerated_tree { struct got_object_id id; char *path; uint8_t *buf; struct got_parsed_tree_entry *entries; int nentries; }; static const struct got_error * enumerate_tree(int *have_all_entries, struct imsgbuf *ibuf, size_t *totlen, struct got_object_id *tree_id, const char *path, struct got_pack *pack, struct got_packidx *packidx, struct got_object_cache *objcache, struct got_object_idset *idset, struct enumerated_tree **trees, size_t *nalloc, size_t *ntrees) { const struct got_error *err = NULL; struct got_object_id_queue ids; struct got_object_qid *qid; uint8_t *buf = NULL; size_t len = 0; struct got_parsed_tree_entry *entries = NULL; size_t nentries = 0, nentries_alloc = 0, i; struct enumerated_tree *tree; *ntrees = 0; *have_all_entries = 1; STAILQ_INIT(&ids); err = got_object_qid_alloc_partial(&qid); if (err) return err; memcpy(&qid->id, tree_id, sizeof(*tree_id)); qid->data = strdup(path); if (qid->data == NULL) { err = got_error_from_errno("strdup"); goto done; } STAILQ_INSERT_TAIL(&ids, qid, entry); qid = NULL; /* Traverse the tree hierarchy, gather tree object IDs and paths. */ do { const char *path; int idx, i; if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); goto done; } qid = STAILQ_FIRST(&ids); STAILQ_REMOVE_HEAD(&ids, entry); path = qid->data; idx = got_packidx_get_object_idx(packidx, &qid->id); if (idx == -1) { *have_all_entries = 0; break; } err = open_tree(&buf, &len, pack, packidx, idx, &qid->id, objcache); if (err) { if (err->code != GOT_ERR_NO_OBJ) goto done; } err = got_object_parse_tree(&entries, &nentries, &nentries_alloc, buf, len); if (err) goto done; err = got_object_idset_add(idset, &qid->id, NULL); if (err) goto done; for (i = 0; i < nentries; i++) { struct got_object_qid *eqid = NULL; struct got_parsed_tree_entry *pte = &entries[i]; char *p; if (!S_ISDIR(pte->mode)) continue; err = got_object_qid_alloc_partial(&eqid); if (err) goto done; memcpy(eqid->id.sha1, pte->id, sizeof(eqid->id.sha1)); if (got_object_idset_contains(idset, &eqid->id)) { got_object_qid_free(eqid); continue; } if (asprintf(&p, "%s%s%s", path, got_path_is_root_dir(path) ? "" : "/", pte->name) == -1) { err = got_error_from_errno("asprintf"); got_object_qid_free(eqid); goto done; } eqid->data = p; STAILQ_INSERT_TAIL(&ids, eqid, entry); } if (*ntrees >= *nalloc) { struct enumerated_tree *new; new = recallocarray(*trees, *nalloc, *nalloc + 16, sizeof(*new)); if (new == NULL) { err = got_error_from_errno("malloc"); goto done; } *trees = new; *nalloc += 16; } tree = &(*trees)[*ntrees]; (*ntrees)++; memcpy(&tree->id, &qid->id, sizeof(tree->id)); tree->path = qid->data; tree->buf = buf; buf = NULL; tree->entries = entries; entries = NULL; nentries_alloc = 0; tree->nentries = nentries; nentries = 0; got_object_qid_free(qid); qid = NULL; } while (!STAILQ_EMPTY(&ids)); if (*have_all_entries) { int i; /* * We have managed to traverse all entries in the hierarchy. * Tell the main process what we have found. */ for (i = 0; i < *ntrees; i++) { tree = &(*trees)[i]; err = got_privsep_send_enumerated_tree(totlen, ibuf, &tree->id, tree->path, tree->entries, tree->nentries); if (err) goto done; free(tree->buf); tree->buf = NULL; free(tree->path); tree->path = NULL; free(tree->entries); tree->entries = NULL; } *ntrees = 0; /* don't loop again below to free memory */ err = send_tree_enumeration_done(ibuf); } else { /* * We can only load fully packed tree hierarchies on * behalf of the main process, otherwise the main process * gets a wrong idea about which tree objects have * already been traversed. * Indicate a missing entry for the root of this tree. * The main process should continue by loading this * entire tree the slow way. */ err = got_privsep_send_enumerated_tree(totlen, ibuf, tree_id, "/", NULL, -1); if (err) goto done; } done: free(buf); free(entries); for (i = 0; i < *ntrees; i++) { tree = &(*trees)[i]; free(tree->buf); tree->buf = NULL; free(tree->path); tree->path = NULL; free(tree->entries); tree->entries = NULL; } if (qid) free(qid->data); got_object_qid_free(qid); got_object_id_queue_free(&ids); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; else got_privsep_send_error(ibuf, err); } return err; } static const struct got_error * enumeration_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx, struct got_object_cache *objcache) { const struct got_error *err = NULL; struct got_object_id_queue commit_ids; const struct got_object_id_queue *parents = NULL; struct got_object_qid *qid = NULL; struct got_object *obj = NULL; struct got_commit_object *commit = NULL; struct got_object_id *tree_id = NULL; size_t totlen = 0; struct got_object_idset *idset, *queued_ids = NULL; int i, idx, have_all_entries = 1; struct enumerated_tree *trees = NULL; size_t ntrees = 0, nalloc = 16; STAILQ_INIT(&commit_ids); trees = calloc(nalloc, sizeof(*trees)); if (trees == NULL) return got_error_from_errno("calloc"); idset = got_object_idset_alloc(); if (idset == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } queued_ids = got_object_idset_alloc(); if (queued_ids == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } err = recv_object_id_queue(&commit_ids, queued_ids, ibuf); if (err) goto done; if (STAILQ_EMPTY(&commit_ids)) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } err = recv_object_ids(idset, ibuf); if (err) goto done; while (!STAILQ_EMPTY(&commit_ids)) { if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); goto done; } qid = STAILQ_FIRST(&commit_ids); STAILQ_REMOVE_HEAD(&commit_ids, entry); if (got_object_idset_contains(idset, &qid->id)) { got_object_qid_free(qid); qid = NULL; continue; } idx = got_packidx_get_object_idx(packidx, &qid->id); if (idx == -1) { have_all_entries = 0; break; } err = open_object(&obj, pack, packidx, idx, &qid->id, objcache); if (err) goto done; if (obj->type == GOT_OBJ_TYPE_TAG) { struct got_tag_object *tag; uint8_t *buf; size_t len; err = got_packfile_extract_object_to_mem(&buf, &len, obj, pack); if (err) goto done; obj->size = len; err = got_object_parse_tag(&tag, buf, len); if (err) { free(buf); goto done; } idx = got_packidx_get_object_idx(packidx, &tag->id); if (idx == -1) { have_all_entries = 0; break; } err = open_commit(&commit, pack, packidx, idx, &tag->id, objcache); got_object_tag_close(tag); free(buf); if (err) goto done; } else if (obj->type == GOT_OBJ_TYPE_COMMIT) { err = open_commit(&commit, pack, packidx, idx, &qid->id, objcache); if (err) goto done; } else { err = got_error(GOT_ERR_OBJ_TYPE); goto done; } got_object_close(obj); obj = NULL; err = got_privsep_send_enumerated_commit(ibuf, &qid->id, got_object_commit_get_committer_time(commit)); if (err) goto done; tree_id = got_object_commit_get_tree_id(commit); idx = got_packidx_get_object_idx(packidx, tree_id); if (idx == -1) { have_all_entries = 0; err = got_privsep_send_enumerated_tree(&totlen, ibuf, tree_id, "/", NULL, -1); if (err) goto done; break; } if (got_object_idset_contains(idset, tree_id)) { got_object_qid_free(qid); qid = NULL; err = send_tree_enumeration_done(ibuf); if (err) goto done; continue; } err = enumerate_tree(&have_all_entries, ibuf, &totlen, tree_id, "/", pack, packidx, objcache, idset, &trees, &nalloc, &ntrees); if (err) goto done; if (!have_all_entries) break; got_object_qid_free(qid); qid = NULL; parents = got_object_commit_get_parent_ids(commit); if (parents) { struct got_object_qid *pid; STAILQ_FOREACH(pid, parents, entry) { if (got_object_idset_contains(idset, &pid->id)) continue; if (got_object_idset_contains(queued_ids, &pid->id)) continue; err = got_object_qid_alloc_partial(&qid); if (err) goto done; memcpy(&qid->id, &pid->id, sizeof(qid->id)); STAILQ_INSERT_TAIL(&commit_ids, qid, entry); qid = NULL; } } got_object_commit_close(commit); commit = NULL; } if (have_all_entries) { err = got_privsep_send_object_enumeration_done(ibuf); if (err) goto done; } else { err = got_privsep_send_object_enumeration_incomplete(ibuf); if (err) goto done; } done: if (obj) got_object_close(obj); if (commit) got_object_commit_close(commit); got_object_qid_free(qid); got_object_id_queue_free(&commit_ids); if (idset) got_object_idset_free(idset); if (queued_ids) got_object_idset_free(queued_ids); for (i = 0; i < ntrees; i++) { struct enumerated_tree *tree = &trees[i]; free(tree->buf); free(tree->path); free(tree->entries); } free(trees); return err; } enum findtwixt_color { COLOR_KEEP = 0, COLOR_DROP, COLOR_SKIP, COLOR_MAX, }; static const struct got_error * paint_commit(struct got_object_qid *qid, intptr_t color) { if (color < 0 || color >= COLOR_MAX) return got_error(GOT_ERR_RANGE); qid->data = (void *)color; return NULL; } static const struct got_error * queue_commit_id(struct got_object_id_queue *ids, struct got_object_id *id, intptr_t color) { const struct got_error *err; struct got_object_qid *qid; err = got_object_qid_alloc_partial(&qid); if (err) return err; memcpy(&qid->id, id, sizeof(qid->id)); STAILQ_INSERT_TAIL(ids, qid, entry); return paint_commit(qid, color); } static const struct got_error * paint_commits(struct got_object_id_queue *ids, int *nids, struct got_object_idset *keep, struct got_object_idset *drop, struct got_object_idset *skip, struct got_pack *pack, struct got_packidx *packidx, struct imsgbuf *ibuf, struct got_object_cache *objcache) { const struct got_error *err = NULL; struct got_commit_object *commit = NULL; struct got_object_id_queue painted; const struct got_object_id_queue *parents; struct got_object_qid *qid = NULL; int nqueued = *nids, nskip = 0, npainted = 0; STAILQ_INIT(&painted); while (!STAILQ_EMPTY(ids) && nskip != nqueued) { int idx; intptr_t color; if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); goto done; } qid = STAILQ_FIRST(ids); idx = got_packidx_get_object_idx(packidx, &qid->id); if (idx == -1) { qid = NULL; break; } STAILQ_REMOVE_HEAD(ids, entry); nqueued--; color = (intptr_t)qid->data; if (color == COLOR_SKIP) nskip--; if (got_object_idset_contains(skip, &qid->id)) { got_object_qid_free(qid); qid = NULL; continue; } switch (color) { case COLOR_KEEP: if (got_object_idset_contains(keep, &qid->id)) { got_object_qid_free(qid); qid = NULL; continue; } if (got_object_idset_contains(drop, &qid->id)) { err = paint_commit(qid, COLOR_SKIP); if (err) goto done; } err = got_object_idset_add(keep, &qid->id, NULL); if (err) goto done; break; case COLOR_DROP: if (got_object_idset_contains(drop, &qid->id)) { got_object_qid_free(qid); qid = NULL; continue; } if (got_object_idset_contains(keep, &qid->id)) { err = paint_commit(qid, COLOR_SKIP); if (err) goto done; } err = got_object_idset_add(drop, &qid->id, NULL); if (err) goto done; break; case COLOR_SKIP: if (!got_object_idset_contains(skip, &qid->id)) { err = got_object_idset_add(skip, &qid->id, NULL); if (err) goto done; } break; default: /* should not happen */ err = got_error_fmt(GOT_ERR_NOT_IMPL, "%s invalid commit color %"PRIdPTR, __func__, color); goto done; } err = open_commit(&commit, pack, packidx, idx, &qid->id, objcache); if (err) goto done; parents = got_object_commit_get_parent_ids(commit); if (parents) { struct got_object_qid *pid; color = (intptr_t)qid->data; STAILQ_FOREACH(pid, parents, entry) { err = queue_commit_id(ids, &pid->id, color); if (err) goto done; nqueued++; if (color == COLOR_SKIP) nskip++; } } got_object_commit_close(commit); commit = NULL; STAILQ_INSERT_TAIL(&painted, qid, entry); qid = NULL; npainted++; err = got_privsep_send_painted_commits(ibuf, &painted, &npainted, 1, 0); if (err) goto done; } err = got_privsep_send_painted_commits(ibuf, &painted, &npainted, 1, 1); if (err) goto done; *nids = nqueued; done: if (commit) got_object_commit_close(commit); got_object_qid_free(qid); return err; } static void commit_painting_free(struct got_object_idset **keep, struct got_object_idset **drop, struct got_object_idset **skip) { if (*keep) { got_object_idset_free(*keep); *keep = NULL; } if (*drop) { got_object_idset_free(*drop); *drop = NULL; } if (*skip) { got_object_idset_free(*skip); *skip = NULL; } } static const struct got_error * commit_painting_init(struct imsgbuf *ibuf, struct got_object_idset **keep, struct got_object_idset **drop, struct got_object_idset **skip) { const struct got_error *err = NULL; *keep = got_object_idset_alloc(); if (*keep == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } *drop = got_object_idset_alloc(); if (*drop == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } *skip = got_object_idset_alloc(); if (*skip == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } err = recv_object_ids(*keep, ibuf); if (err) goto done; err = recv_object_ids(*drop, ibuf); if (err) goto done; err = recv_object_ids(*skip, ibuf); if (err) goto done; done: if (err) commit_painting_free(keep, drop, skip); return err; } static const struct got_error * commit_painting_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx, struct got_object_cache *objcache, struct got_object_idset *keep, struct got_object_idset *drop, struct got_object_idset *skip) { const struct got_error *err = NULL; struct got_imsg_commit_painting_request ireq; struct got_object_id id; size_t datalen; struct got_object_id_queue ids; int nids = 0; STAILQ_INIT(&ids); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ireq)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ireq, imsg->data, sizeof(ireq)); memcpy(&id, &ireq.id, sizeof(id)); err = queue_commit_id(&ids, &id, ireq.color); if (err) return err; nids = 1; err = paint_commits(&ids, &nids, keep, drop, skip, pack, packidx, ibuf, objcache); if (err) goto done; err = got_privsep_send_painted_commits(ibuf, &ids, &nids, 0, 1); if (err) goto done; err = got_privsep_send_painting_commits_done(ibuf); done: got_object_id_queue_free(&ids); return err; } static const struct got_error * receive_pack(struct got_pack **packp, struct imsgbuf *ibuf) { const struct got_error *err = NULL; struct imsg imsg; struct got_imsg_pack ipack; size_t datalen; struct got_pack *pack; *packp = NULL; err = got_privsep_recv_imsg(&imsg, ibuf, 0); if (err) return err; pack = calloc(1, sizeof(*pack)); if (pack == NULL) { err = got_error_from_errno("calloc"); goto done; } if (imsg.hdr.type != GOT_IMSG_PACK) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ipack)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&ipack, imsg.data, sizeof(ipack)); pack->filesize = ipack.filesize; pack->fd = imsg_get_fd(&imsg); if (pack->fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } if (lseek(pack->fd, 0, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } pack->path_packfile = strdup(ipack.path_packfile); if (pack->path_packfile == NULL) { err = got_error_from_errno("strdup"); goto done; } err = got_delta_cache_alloc(&pack->delta_cache); if (err) goto done; #ifndef GOT_PACK_NO_MMAP if (pack->filesize > 0 && pack->filesize <= SIZE_MAX) { pack->map = mmap(NULL, pack->filesize, PROT_READ, MAP_PRIVATE, pack->fd, 0); if (pack->map == MAP_FAILED) pack->map = NULL; /* fall back to read(2) */ } #endif done: if (err) { if (pack != NULL) got_pack_close(pack); } else *packp = pack; imsg_free(&imsg); return err; } int main(int argc, char *argv[]) { const struct got_error *err = NULL; struct imsgbuf ibuf; struct imsg imsg; struct got_packidx *packidx = NULL; struct got_pack *pack = NULL; struct got_object_cache objcache; FILE *basefile = NULL, *accumfile = NULL, *delta_outfile = NULL; struct got_object_idset *keep = NULL, *drop = NULL, *skip = NULL; struct got_parsed_tree_entry *entries = NULL; size_t nentries = 0, nentries_alloc = 0; //static int attached; //while (!attached) sleep(1); signal(SIGINT, catch_sigint); imsg_init(&ibuf, GOT_IMSG_FD_CHILD); err = got_object_cache_init(&objcache, GOT_OBJECT_CACHE_TYPE_OBJ); if (err) { err = got_error_from_errno("got_object_cache_init"); got_privsep_send_error(&ibuf, err); return 1; } #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif err = receive_packidx(&packidx, &ibuf); if (err) { got_privsep_send_error(&ibuf, err); return 1; } err = receive_pack(&pack, &ibuf); if (err) { got_privsep_send_error(&ibuf, err); return 1; } for (;;) { if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); break; } err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; break; } if (imsg.hdr.type == GOT_IMSG_STOP) { imsg_free(&imsg); break; } switch (imsg.hdr.type) { case GOT_IMSG_TMPFD: if (basefile == NULL) { err = receive_tempfile(&basefile, "w+", &imsg, &ibuf); } else if (accumfile == NULL) { err = receive_tempfile(&accumfile, "w+", &imsg, &ibuf); } else err = got_error(GOT_ERR_PRIVSEP_MSG); break; case GOT_IMSG_PACKED_OBJECT_REQUEST: err = object_request(&imsg, &ibuf, pack, packidx, &objcache); break; case GOT_IMSG_PACKED_RAW_OBJECT_REQUEST: if (basefile == NULL || accumfile == NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = raw_object_request(&imsg, &ibuf, pack, packidx, &objcache, basefile, accumfile); break; case GOT_IMSG_RAW_DELTA_OUTFD: if (delta_outfile != NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = receive_tempfile(&delta_outfile, "w", &imsg, &ibuf); break; case GOT_IMSG_RAW_DELTA_REQUEST: if (delta_outfile == NULL) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); break; } err = raw_delta_request(&imsg, &ibuf, delta_outfile, pack, packidx); break; case GOT_IMSG_DELTA_REUSE_REQUEST: err = delta_reuse_request(&imsg, &ibuf, pack, packidx); break; case GOT_IMSG_COMMIT_REQUEST: err = commit_request(&imsg, &ibuf, pack, packidx, &objcache); break; case GOT_IMSG_TREE_REQUEST: err = tree_request(&imsg, &ibuf, pack, packidx, &objcache, &entries, &nentries, &nentries_alloc); break; case GOT_IMSG_BLOB_REQUEST: if (basefile == NULL || accumfile == NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = blob_request(&imsg, &ibuf, pack, packidx, &objcache, basefile, accumfile); break; case GOT_IMSG_TAG_REQUEST: err = tag_request(&imsg, &ibuf, pack, packidx, &objcache); break; case GOT_IMSG_COMMIT_TRAVERSAL_REQUEST: err = commit_traversal_request(&imsg, &ibuf, pack, packidx, &objcache); break; case GOT_IMSG_OBJECT_ENUMERATION_REQUEST: err = enumeration_request(&imsg, &ibuf, pack, packidx, &objcache); break; case GOT_IMSG_COMMIT_PAINTING_INIT: commit_painting_free(&keep, &drop, &skip); err = commit_painting_init(&ibuf, &keep, &drop, &skip); break; case GOT_IMSG_COMMIT_PAINTING_REQUEST: if (keep == NULL || drop == NULL || skip == NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = commit_painting_request(&imsg, &ibuf, pack, packidx, &objcache, keep, drop, skip); break; case GOT_IMSG_COMMIT_PAINTING_DONE: commit_painting_free(&keep, &drop, &skip); break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); if (err) break; } free(entries); commit_painting_free(&keep, &drop, &skip); if (packidx) got_packidx_close(packidx); if (pack) got_pack_close(pack); got_object_cache_close(&objcache); imsg_clear(&ibuf); if (basefile && fclose(basefile) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (accumfile && fclose(accumfile) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (delta_outfile && fclose(delta_outfile) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (err) { if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); } } if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL) err = got_error_from_errno("close"); return err ? 1 : 0; } got-portable-0.101/libexec/got-index-pack/0000775000175100017510000000000014644145570014116 5got-portable-0.101/libexec/got-index-pack/Makefile.am0000664000175100017510000000152414644144735016076 libexec_PROGRAMS = got-index-pack include $(top_builddir)/Makefile.common got_index_pack_SOURCES = got-index-pack.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_index.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/hash.c got_index_pack_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(libbsd_LIBS) $(zlib_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(libbsd_CFLAGS) $(zlib_CFLAGS) $(libmd_CFLAGS) got-portable-0.101/libexec/got-index-pack/got-index-pack.c0000664000175100017510000001405414644144735017022 /* * Copyright (c) 2019 Ori Bernstein * Copyright (c) 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_lib_delta.h" #include "got_lib_delta_cache.h" #include "got_lib_hash.h" #include "got_lib_object.h" #include "got_lib_object_qid.h" #include "got_lib_privsep.h" #include "got_lib_ratelimit.h" #include "got_lib_pack.h" #include "got_lib_pack_index.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif static const struct got_error * send_index_pack_progress(void *arg, uint32_t nobj_total, uint32_t nobj_indexed, uint32_t nobj_loose, uint32_t nobj_resolved) { struct imsgbuf *ibuf = arg; struct got_imsg_index_pack_progress iprogress; iprogress.nobj_total = nobj_total; iprogress.nobj_indexed = nobj_indexed; iprogress.nobj_loose = nobj_loose; iprogress.nobj_resolved = nobj_resolved; if (imsg_compose(ibuf, GOT_IMSG_IDXPACK_PROGRESS, 0, 0, -1, &iprogress, sizeof(iprogress)) == -1) return got_error_from_errno("imsg_compose IDXPACK_PROGRESS"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * send_index_pack_done(struct imsgbuf *ibuf) { if (imsg_compose(ibuf, GOT_IMSG_IDXPACK_DONE, 0, 0, -1, NULL, 0) == -1) return got_error_from_errno("imsg_compose FETCH"); return got_privsep_flush_imsg(ibuf); } int main(int argc, char **argv) { const struct got_error *err = NULL, *close_err; struct imsgbuf ibuf; struct imsg imsg; size_t i; int idxfd = -1, tmpfd = -1; FILE *tmpfiles[3]; struct got_pack pack; uint8_t pack_hash[SHA1_DIGEST_LENGTH]; off_t packfile_size; struct got_ratelimit rl; #if 0 static int attached; while (!attached) sleep(1); #endif got_ratelimit_init(&rl, 0, 500); for (i = 0; i < nitems(tmpfiles); i++) tmpfiles[i] = NULL; memset(&pack, 0, sizeof(pack)); pack.fd = -1; err = got_delta_cache_alloc(&pack.delta_cache); if (err) goto done; imsg_init(&ibuf, GOT_IMSG_FD_CHILD); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) goto done; if (imsg.hdr.type == GOT_IMSG_STOP) goto done; if (imsg.hdr.type != GOT_IMSG_IDXPACK_REQUEST) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(pack_hash)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(pack_hash, imsg.data, sizeof(pack_hash)); pack.fd = imsg_get_fd(&imsg); err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) goto done; if (imsg.hdr.type == GOT_IMSG_STOP) goto done; if (imsg.hdr.type != GOT_IMSG_IDXPACK_OUTFD) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } if (imsg.hdr.len - IMSG_HEADER_SIZE != 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } idxfd = imsg_get_fd(&imsg); for (i = 0; i < nitems(tmpfiles); i++) { err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) goto done; if (imsg.hdr.type == GOT_IMSG_STOP) goto done; if (imsg.hdr.type != GOT_IMSG_TMPFD) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } if (imsg.hdr.len - IMSG_HEADER_SIZE != 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } tmpfd = imsg_get_fd(&imsg); tmpfiles[i] = fdopen(tmpfd, "w+"); if (tmpfiles[i] == NULL) { err = got_error_from_errno("fdopen"); goto done; } tmpfd = -1; } if (lseek(pack.fd, 0, SEEK_END) == -1) { err = got_error_from_errno("lseek"); goto done; } packfile_size = lseek(pack.fd, 0, SEEK_CUR); if (packfile_size == -1) { err = got_error_from_errno("lseek"); goto done; } pack.filesize = packfile_size; if (lseek(pack.fd, 0, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } #ifndef GOT_PACK_NO_MMAP if (pack.filesize > 0 && pack.filesize <= SIZE_MAX) { pack.map = mmap(NULL, pack.filesize, PROT_READ, MAP_PRIVATE, pack.fd, 0); if (pack.map == MAP_FAILED) pack.map = NULL; /* fall back to read(2) */ } #endif err = got_pack_index(&pack, idxfd, tmpfiles[0], tmpfiles[1], tmpfiles[2], pack_hash, send_index_pack_progress, &ibuf, &rl); done: close_err = got_pack_close(&pack); if (close_err && err == NULL) err = close_err; if (idxfd != -1 && close(idxfd) == -1 && err == NULL) err = got_error_from_errno("close"); if (tmpfd != -1 && close(tmpfd) == -1 && err == NULL) err = got_error_from_errno("close"); for (i = 0; i < nitems(tmpfiles); i++) { if (tmpfiles[i] != NULL && fclose(tmpfiles[i]) == EOF && err == NULL) err = got_error_from_errno("fclose"); } if (err == NULL) err = send_index_pack_done(&ibuf); if (err) { got_privsep_send_error(&ibuf, err); fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); exit(1); } exit(0); } got-portable-0.101/libexec/got-index-pack/Makefile.in0000664000175100017510000006444514644145543016120 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-index-pack$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-index-pack ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_index_pack_OBJECTS = got-index-pack.$(OBJEXT) \ $(top_builddir)/lib/delta.$(OBJEXT) \ $(top_builddir)/lib/delta_cache.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_idset.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/pack.$(OBJEXT) \ $(top_builddir)/lib/pack_index.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) \ $(top_builddir)/lib/ratelimit.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) got_index_pack_OBJECTS = $(am_got_index_pack_OBJECTS) got_index_pack_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/delta.Po \ $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_idset.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/pack.Po \ $(top_builddir)/lib/$(DEPDIR)/pack_index.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po \ ./$(DEPDIR)/got-index-pack.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_index_pack_SOURCES) DIST_SOURCES = $(got_index_pack_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(libbsd_CFLAGS) $(zlib_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_index_pack_SOURCES = got-index-pack.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_index.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/hash.c got_index_pack_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(libbsd_LIBS) \ $(zlib_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-index-pack/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-index-pack/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files clean-libexecPROGRAMS: -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: > $(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: > $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_idset.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack_index.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/ratelimit.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-index-pack$(EXEEXT): $(got_index_pack_OBJECTS) $(got_index_pack_DEPENDENCIES) $(EXTRA_got_index_pack_DEPENDENCIES) @rm -f got-index-pack$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_index_pack_OBJECTS) $(got_index_pack_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_idset.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack_index.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/ratelimit.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-index-pack.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_index.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f ./$(DEPDIR)/got-index-pack.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_index.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f ./$(DEPDIR)/got-index-pack.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/libexec/got-read-object/0000775000175100017510000000000014644145571014253 5got-portable-0.101/libexec/got-read-object/Makefile.am0000664000175100017510000000122514644144735016230 libexec_PROGRAMS = got-read-object include $(top_builddir)/Makefile.common got_read_object_SOURCES = got-read-object.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_object_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.101/libexec/got-read-object/Makefile.in0000664000175100017510000005714714644145543016255 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-read-object$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-read-object ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_read_object_OBJECTS = got-read-object.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) got_read_object_OBJECTS = $(am_got_read_object_OBJECTS) got_read_object_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ ./$(DEPDIR)/got-read-object.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_read_object_SOURCES) DIST_SOURCES = $(got_read_object_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_read_object_SOURCES = got-read-object.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_object_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-read-object/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-read-object/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files clean-libexecPROGRAMS: -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: > $(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: > $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-read-object$(EXEEXT): $(got_read_object_OBJECTS) $(got_read_object_DEPENDENCIES) $(EXTRA_got_read_object_DEPENDENCIES) @rm -f got-read-object$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_read_object_OBJECTS) $(got_read_object_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-read-object.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-object.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-object.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/libexec/got-read-object/got-read-object.c0000664000175100017510000001245314644144735017313 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_lib_delta.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_privsep.h" #include "got_lib_hash.h" #ifndef nitems #define nitems(_a) (sizeof(_a) / sizeof((_a)[0])) #endif #define GOT_OBJ_TAG_COMMIT "commit" #define GOT_OBJ_TAG_TREE "tree" #define GOT_OBJ_TAG_BLOB "blob" #define GOT_OBJ_TAG_TAG "tag" static volatile sig_atomic_t sigint_received; static void catch_sigint(int signo) { sigint_received = 1; } static const struct got_error * send_raw_obj(struct imsgbuf *ibuf, struct got_object *obj, struct got_object_id *expected_id, int fd, int outfd) { const struct got_error *err = NULL; uint8_t *data = NULL; off_t size; size_t hdrlen; if (lseek(fd, SEEK_SET, 0) == -1) { err = got_error_from_errno("lseek"); goto done; } err = got_object_read_raw(&data, &size, &hdrlen, GOT_PRIVSEP_INLINE_BLOB_DATA_MAX, outfd, expected_id, fd); if (err) goto done; err = got_privsep_send_raw_obj(ibuf, size, hdrlen, data); done: free(data); if (close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); return err; } int main(int argc, char *argv[]) { const struct got_error *err = NULL; struct got_object *obj = NULL; struct imsg imsg; struct imsgbuf ibuf; size_t datalen; struct got_object_id expected_id; signal(SIGINT, catch_sigint); imsg_init(&ibuf, GOT_IMSG_FD_CHILD); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif for (;;) { int fd = -1, outfd = -1; if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); break; } err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; break; } if (imsg.hdr.type == GOT_IMSG_STOP) break; if (imsg.hdr.type != GOT_IMSG_OBJECT_REQUEST && imsg.hdr.type != GOT_IMSG_RAW_OBJECT_REQUEST) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(expected_id)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&expected_id, imsg.data, sizeof(expected_id)); fd = imsg_get_fd(&imsg); if (fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } err = got_object_read_header(&obj, fd); if (err) goto done; if (imsg.hdr.type == GOT_IMSG_RAW_OBJECT_REQUEST) { struct imsg imsg_outfd; err = got_privsep_recv_imsg(&imsg_outfd, &ibuf, 0); if (err) { if (imsg_outfd.hdr.len == 0) err = NULL; goto done; } if (imsg_outfd.hdr.type == GOT_IMSG_STOP) { imsg_free(&imsg_outfd); goto done; } if (imsg_outfd.hdr.type != GOT_IMSG_RAW_OBJECT_OUTFD) { err = got_error(GOT_ERR_PRIVSEP_MSG); imsg_free(&imsg_outfd); goto done; } datalen = imsg_outfd.hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); imsg_free(&imsg_outfd); goto done; } outfd = imsg_get_fd(&imsg_outfd); if (outfd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); imsg_free(&imsg_outfd); goto done; } err = send_raw_obj(&ibuf, obj, &expected_id, fd, outfd); fd = -1; /* fd is owned by send_raw_obj() */ if (close(outfd) == -1 && err == NULL) err = got_error_from_errno("close"); imsg_free(&imsg_outfd); if (err) goto done; } else err = got_privsep_send_obj(&ibuf, obj); done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); imsg_free(&imsg); if (obj) got_object_close(obj); if (err) break; } imsg_clear(&ibuf); if (err) { if(!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); } } if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL) err = got_error_from_errno("close"); return err ? 1 : 0; } got-portable-0.101/libexec/got-read-tag/0000775000175100017510000000000014644145571013560 5got-portable-0.101/libexec/got-read-tag/Makefile.am0000664000175100017510000000121114644144735015530 libexec_PROGRAMS = got-read-tag include $(top_builddir)/Makefile.common got_read_tag_SOURCES = got-read-tag.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_tag_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.101/libexec/got-read-tag/got-read-tag.c0000664000175100017510000000662614644144735016132 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_lib_delta.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_privsep.h" #include "got_lib_hash.h" static volatile sig_atomic_t sigint_received; static void catch_sigint(int signo) { sigint_received = 1; } int main(int argc, char *argv[]) { const struct got_error *err = NULL; struct imsgbuf ibuf; size_t datalen; signal(SIGINT, catch_sigint); imsg_init(&ibuf, GOT_IMSG_FD_CHILD); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif for (;;) { struct imsg imsg; struct got_tag_object *tag = NULL; struct got_object_id expected_id; int fd = -1; if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); break; } err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; break; } if (imsg.hdr.type == GOT_IMSG_STOP) break; if (imsg.hdr.type != GOT_IMSG_TAG_REQUEST) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(expected_id)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&expected_id, imsg.data, sizeof(expected_id)); fd = imsg_get_fd(&imsg); if (fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } /* Always assume file offset zero. */ err = got_object_read_tag(&tag, fd, &expected_id, 0); if (err) goto done; err = got_privsep_send_tag(&ibuf, tag); done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); imsg_free(&imsg); if (err) break; } imsg_clear(&ibuf); if (err) { if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); } } if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL) err = got_error_from_errno("close"); return err ? 1 : 0; } got-portable-0.101/libexec/got-read-tag/Makefile.in0000664000175100017510000005703414644145544015556 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-read-tag$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-read-tag ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_read_tag_OBJECTS = got-read-tag.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) got_read_tag_OBJECTS = $(am_got_read_tag_OBJECTS) got_read_tag_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ ./$(DEPDIR)/got-read-tag.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_read_tag_SOURCES) DIST_SOURCES = $(got_read_tag_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_read_tag_SOURCES = got-read-tag.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_tag_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-read-tag/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-read-tag/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files clean-libexecPROGRAMS: -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: > $(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: > $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-read-tag$(EXEEXT): $(got_read_tag_OBJECTS) $(got_read_tag_DEPENDENCIES) $(EXTRA_got_read_tag_DEPENDENCIES) @rm -f got-read-tag$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_read_tag_OBJECTS) $(got_read_tag_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-read-tag.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-tag.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-tag.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/libexec/Makefile.in0000664000175100017510000004604714644145543013304 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = libexec ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ SUBDIRS = got-fetch-http \ got-fetch-pack \ got-index-pack \ got-read-blob \ got-read-commit \ got-read-gitconfig \ got-read-gotconfig \ got-read-object \ got-read-pack \ got-read-patch \ got-read-tag \ got-read-tree \ got-send-pack all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic cscopelist-am ctags ctags-am \ distclean distclean-generic distclean-tags distdir dvi dvi-am \ html html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags tags-am uninstall uninstall-am .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/libexec/got-read-commit/0000775000175100017510000000000014644145570014274 5got-portable-0.101/libexec/got-read-commit/Makefile.am0000664000175100017510000000122514644144735016252 libexec_PROGRAMS = got-read-commit include $(top_builddir)/Makefile.common got_read_commit_SOURCES = got-read-commit.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_commit_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.101/libexec/got-read-commit/Makefile.in0000664000175100017510000005714714644145543016277 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-read-commit$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-read-commit ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_read_commit_OBJECTS = got-read-commit.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) got_read_commit_OBJECTS = $(am_got_read_commit_OBJECTS) got_read_commit_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ ./$(DEPDIR)/got-read-commit.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_read_commit_SOURCES) DIST_SOURCES = $(got_read_commit_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_read_commit_SOURCES = got-read-commit.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_commit_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-read-commit/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-read-commit/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files clean-libexecPROGRAMS: -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: > $(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: > $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-read-commit$(EXEEXT): $(got_read_commit_OBJECTS) $(got_read_commit_DEPENDENCIES) $(EXTRA_got_read_commit_DEPENDENCIES) @rm -f got-read-commit$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_read_commit_OBJECTS) $(got_read_commit_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-read-commit.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-commit.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-commit.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/libexec/got-read-commit/got-read-commit.c0000664000175100017510000000672214644144735017361 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_lib_delta.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_object_qid.h" #include "got_lib_privsep.h" #include "got_lib_hash.h" static volatile sig_atomic_t sigint_received; static void catch_sigint(int signo) { sigint_received = 1; } int main(int argc, char *argv[]) { const struct got_error *err = NULL; struct imsgbuf ibuf; size_t datalen; signal(SIGINT, catch_sigint); imsg_init(&ibuf, GOT_IMSG_FD_CHILD); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif for (;;) { struct imsg imsg; struct got_commit_object *commit = NULL; struct got_object_id expected_id; int fd = -1; if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); break; } err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; break; } if (imsg.hdr.type == GOT_IMSG_STOP) break; if (imsg.hdr.type != GOT_IMSG_COMMIT_REQUEST) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(expected_id)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&expected_id, imsg.data, sizeof(expected_id)); fd = imsg_get_fd(&imsg); if (fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } err = got_object_read_commit(&commit, fd, &expected_id, 0); if (err) goto done; err = got_privsep_send_commit(&ibuf, commit); got_object_commit_close(commit); done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); imsg_free(&imsg); if (err) break; } imsg_clear(&ibuf); if (err) { if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); } } if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL) err = got_error_from_errno("close"); return err ? 1 : 0; } got-portable-0.101/libexec/got-read-gitconfig/0000775000175100017510000000000014644145571014756 5got-portable-0.101/libexec/got-read-gitconfig/got-read-gitconfig.c0000664000175100017510000002702514644144735020522 /* * Copyright (c) 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_repository.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_privsep.h" #include "got_lib_gitconfig.h" static volatile sig_atomic_t sigint_received; static void catch_sigint(int signo) { sigint_received = 1; } static const struct got_error * send_gitconfig_int(struct imsgbuf *ibuf, int value) { if (imsg_compose(ibuf, GOT_IMSG_GITCONFIG_INT_VAL, 0, 0, -1, &value, sizeof(value)) == -1) return got_error_from_errno("imsg_compose GITCONFIG_INT_VAL"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * gitconfig_num_request(struct imsgbuf *ibuf, struct got_gitconfig *gitconfig, const char *section, const char *tag, int def) { int value; if (gitconfig == NULL) return got_error(GOT_ERR_PRIVSEP_MSG); value = got_gitconfig_get_num(gitconfig, section, tag, def); return send_gitconfig_int(ibuf, value); } static const struct got_error * send_gitconfig_str(struct imsgbuf *ibuf, const char *value) { size_t len = value ? strlen(value) : 0; if (imsg_compose(ibuf, GOT_IMSG_GITCONFIG_STR_VAL, 0, 0, -1, value, len) == -1) return got_error_from_errno("imsg_compose GITCONFIG_STR_VAL"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * send_gitconfig_pair(struct imsgbuf *ibuf, const char *key, const char *val) { struct ibuf *wbuf; size_t klen = key ? strlen(key) : 0; size_t vlen = val ? strlen(val) : 0; size_t tot = sizeof(klen) + sizeof(vlen) + klen + vlen; if (tot > MAX_IMSGSIZE - IMSG_HEADER_SIZE) return got_error(GOT_ERR_NO_SPACE); wbuf = imsg_create(ibuf, GOT_IMSG_GITCONFIG_PAIR, 0, 0, tot); if (wbuf == NULL) return got_error_from_errno("imsg_create GITCONFIG_PAIR"); /* Keep in sync with got_imsg_gitconfig_pair */ if (imsg_add(wbuf, &klen, sizeof(klen)) == -1) return got_error_from_errno("imsg_add GITCONFIG_PAIR"); if (imsg_add(wbuf, &vlen, sizeof(vlen)) == -1) return got_error_from_errno("imsg_add GITCONFIG_PAIR"); if (imsg_add(wbuf, key, klen) == -1) return got_error_from_errno("imsg_add GITCONFIG_PAIR"); if (imsg_add(wbuf, val, vlen) == -1) return got_error_from_errno("imsg_add GITCONFIG_PAIR"); imsg_close(ibuf, wbuf); return got_privsep_flush_imsg(ibuf); } static const struct got_error * gitconfig_str_request(struct imsgbuf *ibuf, struct got_gitconfig *gitconfig, const char *section, const char *tag) { char *value; if (gitconfig == NULL) return got_error(GOT_ERR_PRIVSEP_MSG); value = got_gitconfig_get_str(gitconfig, section, tag); return send_gitconfig_str(ibuf, value); } static const struct got_error * send_gitconfig_remotes(struct imsgbuf *ibuf, struct got_remote_repo *remotes, int nremotes) { const struct got_error *err = NULL; struct got_imsg_remotes iremotes; int i; iremotes.nremotes = nremotes; if (imsg_compose(ibuf, GOT_IMSG_GITCONFIG_REMOTES, 0, 0, -1, &iremotes, sizeof(iremotes)) == -1) return got_error_from_errno("imsg_compose GITCONFIG_REMOTES"); err = got_privsep_flush_imsg(ibuf); imsg_clear(ibuf); if (err) return err; for (i = 0; i < nremotes; i++) { struct got_imsg_remote iremote; size_t len = sizeof(iremote); struct ibuf *wbuf; iremote.mirror_references = remotes[i].mirror_references; iremote.name_len = strlen(remotes[i].name); len += iremote.name_len; iremote.fetch_url_len = strlen(remotes[i].fetch_url); len += iremote.fetch_url_len; iremote.send_url_len = strlen(remotes[i].send_url); len += iremote.send_url_len; wbuf = imsg_create(ibuf, GOT_IMSG_GITCONFIG_REMOTE, 0, 0, len); if (wbuf == NULL) return got_error_from_errno( "imsg_create GITCONFIG_REMOTE"); if (imsg_add(wbuf, &iremote, sizeof(iremote)) == -1) return got_error_from_errno( "imsg_add GITCONFIG_REMOTE"); if (imsg_add(wbuf, remotes[i].name, iremote.name_len) == -1) return got_error_from_errno( "imsg_add GITCONFIG_REMOTE"); if (imsg_add(wbuf, remotes[i].fetch_url, iremote.fetch_url_len) == -1) return got_error_from_errno( "imsg_add GITCONFIG_REMOTE"); if (imsg_add(wbuf, remotes[i].send_url, iremote.send_url_len) == -1) return got_error_from_errno( "imsg_add GITCONFIG_REMOTE"); imsg_close(ibuf, wbuf); err = got_privsep_flush_imsg(ibuf); if (err) return err; } return NULL; } static int get_boolean_val(char *val) { return (strcasecmp(val, "true") == 0 || strcasecmp(val, "on") == 0 || strcasecmp(val, "yes") == 0 || strcmp(val, "1") == 0); } static int skip_node(struct got_gitconfig *gitconfig, struct got_gitconfig_list_node *node) { /* * Skip config nodes which do not describe remotes, and remotes * which do not have a fetch URL defined (as used by git-annex). */ return (strncasecmp("remote \"", node->field, 8) != 0 || got_gitconfig_get_str(gitconfig, node->field, "url") == NULL); } static const struct got_error * gitconfig_remotes_request(struct imsgbuf *ibuf, struct got_gitconfig *gitconfig) { const struct got_error *err = NULL; struct got_gitconfig_list *sections; struct got_gitconfig_list_node *node; struct got_remote_repo *remotes = NULL; int nremotes = 0, i; if (gitconfig == NULL) return got_error(GOT_ERR_PRIVSEP_MSG); err = got_gitconfig_get_section_list(§ions, gitconfig); if (err) return err; TAILQ_FOREACH(node, §ions->fields, link) { if (skip_node(gitconfig, node)) continue; nremotes++; } if (nremotes == 0) { err = send_gitconfig_remotes(ibuf, NULL, 0); goto done; } remotes = recallocarray(NULL, 0, nremotes, sizeof(*remotes)); if (remotes == NULL) { err = got_error_from_errno("recallocarray"); goto done; } i = 0; TAILQ_FOREACH(node, §ions->fields, link) { char *name, *end, *mirror; if (skip_node(gitconfig, node)) continue; name = strdup(node->field + 8); if (name == NULL) { err = got_error_from_errno("strdup"); goto done; } end = strrchr(name, '"'); if (end) *end = '\0'; remotes[i].name = name; remotes[i].fetch_url = got_gitconfig_get_str(gitconfig, node->field, "url"); remotes[i].send_url = got_gitconfig_get_str(gitconfig, node->field, "pushurl"); if (remotes[i].send_url == NULL) remotes[i].send_url = remotes[i].fetch_url; remotes[i].mirror_references = 0; mirror = got_gitconfig_get_str(gitconfig, node->field, "mirror"); if (mirror != NULL && get_boolean_val(mirror)) remotes[i].mirror_references = 1; i++; } err = send_gitconfig_remotes(ibuf, remotes, nremotes); done: for (i = 0; i < nremotes; i++) free(remotes[i].name); free(remotes); got_gitconfig_free_list(sections); return err; } static const struct got_error * gitconfig_owner_request(struct imsgbuf *ibuf, struct got_gitconfig *gitconfig) { char *value; if (gitconfig == NULL) return got_error(GOT_ERR_PRIVSEP_MSG); value = got_gitconfig_get_str(gitconfig, "gotweb", "owner"); if (value) return send_gitconfig_str(ibuf, value); value = got_gitconfig_get_str(gitconfig, "gitweb", "owner"); return send_gitconfig_str(ibuf, value); } static const struct got_error * gitconfig_extensions_request(struct imsgbuf *ibuf, struct got_gitconfig *gitconfig) { const struct got_error *err = NULL; struct got_gitconfig_list *tags; struct got_gitconfig_list_node *node; int nextensions = 0; char *val; if (gitconfig == NULL) return got_error(GOT_ERR_PRIVSEP_MSG); tags = got_gitconfig_get_tag_list(gitconfig, "extensions"); if (tags == NULL) return send_gitconfig_int(ibuf, 0); TAILQ_FOREACH(node, &tags->fields, link) nextensions++; err = send_gitconfig_int(ibuf, nextensions); if (err) goto done; TAILQ_FOREACH(node, &tags->fields, link) { val = got_gitconfig_get_str(gitconfig, "extensions", node->field); err = send_gitconfig_pair(ibuf, node->field, val); if (err) goto done; } done: got_gitconfig_free_list(tags); return err; } int main(int argc, char *argv[]) { const struct got_error *err = NULL; struct imsgbuf ibuf; size_t datalen; struct got_gitconfig *gitconfig = NULL; #if 0 static int attached; while (!attached) sleep(1); #endif signal(SIGINT, catch_sigint); imsg_init(&ibuf, GOT_IMSG_FD_CHILD); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif for (;;) { struct imsg imsg; int fd = -1; memset(&imsg, 0, sizeof(imsg)); if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); break; } err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; break; } if (imsg.hdr.type == GOT_IMSG_STOP) break; switch (imsg.hdr.type) { case GOT_IMSG_GITCONFIG_PARSE_REQUEST: datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); break; } fd = imsg_get_fd(&imsg); if (fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); break; } if (gitconfig) got_gitconfig_close(gitconfig); err = got_gitconfig_open(&gitconfig, fd); break; case GOT_IMSG_GITCONFIG_REPOSITORY_FORMAT_VERSION_REQUEST: err = gitconfig_num_request(&ibuf, gitconfig, "core", "repositoryformatversion", 0); break; case GOT_IMSG_GITCONFIG_REPOSITORY_EXTENSIONS_REQUEST: err = gitconfig_extensions_request(&ibuf, gitconfig); break; case GOT_IMSG_GITCONFIG_AUTHOR_NAME_REQUEST: err = gitconfig_str_request(&ibuf, gitconfig, "user", "name"); break; case GOT_IMSG_GITCONFIG_AUTHOR_EMAIL_REQUEST: err = gitconfig_str_request(&ibuf, gitconfig, "user", "email"); break; case GOT_IMSG_GITCONFIG_REMOTES_REQUEST: err = gitconfig_remotes_request(&ibuf, gitconfig); break; case GOT_IMSG_GITCONFIG_OWNER_REQUEST: err = gitconfig_owner_request(&ibuf, gitconfig); break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); break; } if (fd != -1) { if (close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); } imsg_free(&imsg); if (err) break; } imsg_clear(&ibuf); if (err) { if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); } } if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL) err = got_error_from_errno("close"); return err ? 1 : 0; } got-portable-0.101/libexec/got-read-gitconfig/Makefile.am0000664000175100017510000000130214644144735016727 libexec_PROGRAMS = got-read-gitconfig include $(top_builddir)/Makefile.common got_read_gitconfig_SOURCES = got-read-gitconfig.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gitconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_gitconfig_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.101/libexec/got-read-gitconfig/Makefile.in0000664000175100017510000006020414644145543016744 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-read-gitconfig$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-read-gitconfig ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_read_gitconfig_OBJECTS = got-read-gitconfig.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/gitconfig.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) got_read_gitconfig_OBJECTS = $(am_got_read_gitconfig_OBJECTS) got_read_gitconfig_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/gitconfig.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ ./$(DEPDIR)/got-read-gitconfig.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_read_gitconfig_SOURCES) DIST_SOURCES = $(got_read_gitconfig_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_read_gitconfig_SOURCES = got-read-gitconfig.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gitconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_gitconfig_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-read-gitconfig/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-read-gitconfig/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files clean-libexecPROGRAMS: -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: > $(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: > $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gitconfig.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-read-gitconfig$(EXEEXT): $(got_read_gitconfig_OBJECTS) $(got_read_gitconfig_DEPENDENCIES) $(EXTRA_got_read_gitconfig_DEPENDENCIES) @rm -f got-read-gitconfig$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_read_gitconfig_OBJECTS) $(got_read_gitconfig_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gitconfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-read-gitconfig.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gitconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-gitconfig.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gitconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-gitconfig.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/libexec/got-read-patch/0000775000175100017510000000000014644145571014104 5got-portable-0.101/libexec/got-read-patch/Makefile.am0000664000175100017510000000122114644144735016055 libexec_PROGRAMS = got-read-patch include $(top_builddir)/Makefile.common got_read_patch_SOURCES = got-read-patch.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_patch_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.101/libexec/got-read-patch/got-read-patch.c0000664000175100017510000003716514644144735017004 /* * Copyright 1986, Larry Wall * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following condition is met: * 1. Redistributions of source code must retain the above copyright notice, * this condition and the following disclaimer. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Copyright (c) 2022 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_privsep.h" #include "got_lib_hash.h" struct imsgbuf ibuf; static const struct got_error * send_patch(const char *oldname, const char *newname, const char *commitid, const char *blob, const int xbit, int git) { struct got_imsg_patch p; memset(&p, 0, sizeof(p)); if (oldname != NULL) strlcpy(p.old, oldname, sizeof(p.old)); if (newname != NULL) strlcpy(p.new, newname, sizeof(p.new)); if (commitid != NULL) strlcpy(p.cid, commitid, sizeof(p.cid)); if (blob != NULL) strlcpy(p.blob, blob, sizeof(p.blob)); p.xbit = xbit; p.git = git; if (imsg_compose(&ibuf, GOT_IMSG_PATCH, 0, 0, -1, &p, sizeof(p)) == -1) return got_error_from_errno("imsg_compose GOT_IMSG_PATCH"); return NULL; } static const struct got_error * send_patch_done(void) { if (imsg_compose(&ibuf, GOT_IMSG_PATCH_DONE, 0, 0, -1, NULL, 0) == -1) return got_error_from_errno("imsg_compose GOT_IMSG_PATCH_EOF"); return got_privsep_flush_imsg(&ibuf); } /* based on fetchname from usr.bin/patch/util.c */ static const struct got_error * filename(const char *at, char **name) { char *tmp, *t; *name = NULL; if (*at == '\0') return NULL; while (isspace((unsigned char)*at)) at++; /* files can be created or removed by diffing against /dev/null */ if (!strncmp(at, _PATH_DEVNULL, sizeof(_PATH_DEVNULL) - 1)) return NULL; tmp = strdup(at); if (tmp == NULL) return got_error_from_errno("strdup"); if ((t = strchr(tmp, '\t')) != NULL) *t = '\0'; if ((t = strchr(tmp, '\n')) != NULL) *t = '\0'; *name = strdup(tmp); free(tmp); if (*name == NULL) return got_error_from_errno("strdup"); return NULL; } static int binary_deleted(const char *line) { const char *prefix = "Binary files "; const char *suffix = " and /dev/null differ\n"; size_t len, d; if (strncmp(line, prefix, strlen(prefix)) != 0) return 0; line += strlen(prefix); len = strlen(line); if (len <= strlen(suffix)) return 0; d = len - strlen(suffix); return (strcmp(line + d, suffix) == 0); } static const struct got_error * binaryfilename(const char *at, char **name) { const char *suffix = " and /dev/null differ\n"; size_t len, d; *name = NULL; len = strlen(at); if (len <= strlen(suffix)) return NULL; d = len - strlen(suffix); if (strcmp(at + d, suffix) != 0) return NULL; *name = strndup(at, d); if (*name == NULL) return got_error_from_errno("strndup"); return NULL; } static int filexbit(const char *line) { char *m; m = strchr(line, '('); if (m && !strncmp(m + 1, "mode ", 5)) return strncmp(m + 6, "755", 3) == 0; return 0; } static const struct got_error * blobid(const char *line, char **blob, int git) { uint8_t digest[SHA1_DIGEST_LENGTH]; size_t len; *blob = NULL; len = strspn(line, "0123456789abcdefABCDEF"); if ((*blob = strndup(line, len)) == NULL) return got_error_from_errno("strndup"); if (!git && !got_parse_hash_digest(digest, *blob, GOT_HASH_SHA1)) { /* silently ignore invalid blob ids */ free(*blob); *blob = NULL; } return NULL; } static const struct got_error * patch_start(int *git, char **cid, FILE *fp) { const struct got_error *err = NULL; char *line = NULL; size_t linesize = 0; ssize_t linelen; *git = 0; while ((linelen = getline(&line, &linesize, fp)) != -1) { if (!strncmp(line, "diff --git ", 11)) { *git = 1; free(*cid); *cid = NULL; break; } else if (!strncmp(line, "diff ", 5)) { *git = 0; free(*cid); *cid = NULL; } else if (!strncmp(line, "commit - ", 9)) { free(*cid); err = blobid(line + 9, cid, *git); if (err) break; } else if (!strncmp(line, "--- ", 4) || !strncmp(line, "+++ ", 4) || !strncmp(line, "blob - ", 7) || binary_deleted(line)) { /* rewind to previous line */ if (fseeko(fp, -linelen, SEEK_CUR) == -1) err = got_error_from_errno("fseeko"); break; } } free(line); if (ferror(fp) && err == NULL) err = got_error_from_errno("getline"); if (feof(fp) && err == NULL) err = got_error(GOT_ERR_NO_PATCH); return err; } static const struct got_error * find_diff(int *done, int *next, FILE *fp, int git, const char *commitid) { const struct got_error *err = NULL; char *old = NULL, *new = NULL; char *blob = NULL; char *line = NULL; size_t linesize = 0; ssize_t linelen; int create, delete_binary = 0, rename = 0, xbit = 0; *done = 0; *next = 0; while ((linelen = getline(&line, &linesize, fp)) != -1) { /* * Ignore the Index name like GNU and larry' patch, * we don't have to follow POSIX. */ if (!strncmp(line, "--- ", 4)) { free(old); err = filename(line+4, &old); } else if (rename && !strncmp(line, "rename from ", 12)) { free(old); err = filename(line+12, &old); } else if (!strncmp(line, "+++ ", 4)) { free(new); err = filename(line+4, &new); } else if (!strncmp(line, "blob + ", 7) || !strncmp(line, "file + ", 7)) { xbit = filexbit(line); } else if (!git && !strncmp(line, "blob - ", 7)) { free(blob); err = blobid(line + 7, &blob, git); } else if (!strncmp(line, "Binary files ", 13)) { delete_binary = 1; free(old); err = binaryfilename(line + 13, &old); } else if (rename && !strncmp(line, "rename to ", 10)) { free(new); err = filename(line + 10, &new); } else if (git && !strncmp(line, "similarity index 100%", 21)) rename = 1; else if (git && !strncmp(line, "new file mode 100", 17)) xbit = strncmp(line + 17, "755", 3) == 0; else if (git && !strncmp(line, "index ", 6)) { free(blob); err = blobid(line + 6, &blob, git); } else if (!strncmp(line, "diff ", 5)) { /* rewind to previous line */ if (fseeko(fp, -linelen, SEEK_CUR) == -1) err = got_error_from_errno("fseeko"); *next = 1; break; } if (err) break; /* * Git-style diffs with "similarity index 100%" don't * have any hunks and ends with the "rename to foobar" * line. */ if (rename && old != NULL && new != NULL) { *done = 1; err = send_patch(old, new, commitid, blob, xbit, git); break; } /* * Diffs that remove binary files have no hunks. */ if (delete_binary && old != NULL) { *done = 1; err = send_patch(old, new, commitid, blob, xbit, git); break; } if (!strncmp(line, "@@ -", 4)) { create = !strncmp(line+4, "0,0", 3); if ((old == NULL && new == NULL) || (!create && old == NULL)) err = got_error(GOT_ERR_PATCH_MALFORMED); else err = send_patch(old, new, commitid, blob, xbit, git); if (err) break; /* rewind to previous line */ if (fseeko(fp, -linelen, SEEK_CUR) == -1) err = got_error_from_errno("fseeko"); break; } } free(old); free(new); free(blob); free(line); if (ferror(fp) && err == NULL) err = got_error_from_errno("getline"); if (feof(fp) && err == NULL) err = got_error(GOT_ERR_NO_PATCH); return err; } static const struct got_error * strtolnum(char **str, int *n) { char *p, c; const char *errstr; for (p = *str; isdigit((unsigned char)*p); ++p) /* nop */; c = *p; *p = '\0'; *n = strtonum(*str, 0, INT_MAX, &errstr); if (errstr != NULL) return got_error(GOT_ERR_PATCH_MALFORMED); *p = c; *str = p; return NULL; } static const struct got_error * parse_hdr(char *s, int *done, struct got_imsg_patch_hunk *hdr) { static const struct got_error *err = NULL; if (strncmp(s, "@@ -", 4)) { *done = 1; return NULL; } s += 4; if (!*s) return NULL; err = strtolnum(&s, &hdr->oldfrom); if (err) return err; if (*s == ',') { s++; err = strtolnum(&s, &hdr->oldlines); if (err) return err; } else hdr->oldlines = 1; if (*s == ' ') s++; if (*s != '+' || !*++s) return got_error(GOT_ERR_PATCH_MALFORMED); err = strtolnum(&s, &hdr->newfrom); if (err) return err; if (*s == ',') { s++; err = strtolnum(&s, &hdr->newlines); if (err) return err; } else hdr->newlines = 1; if (*s == ' ') s++; if (*s != '@') return got_error(GOT_ERR_PATCH_MALFORMED); if (hdr->oldfrom >= INT_MAX - hdr->oldlines || hdr->newfrom >= INT_MAX - hdr->newlines || /* not so sure about this one */ hdr->oldlines >= INT_MAX - hdr->newlines - 1 || (hdr->oldlines == 0 && hdr->newlines == 0)) return got_error(GOT_ERR_PATCH_MALFORMED); if (hdr->oldlines == 0) { /* larry says to "do append rather than insert"; I don't * quite get it, but i trust him. */ hdr->oldfrom++; } if (imsg_compose(&ibuf, GOT_IMSG_PATCH_HUNK, 0, 0, -1, hdr, sizeof(*hdr)) == -1) return got_error_from_errno( "imsg_compose GOT_IMSG_PATCH_HUNK"); return NULL; } static const struct got_error * send_line(const char *line, size_t len) { static const struct got_error *err = NULL; struct iovec iov[2]; int iovcnt = 0; memset(&iov, 0, sizeof(iov)); if (*line != '+' && *line != '-' && *line != ' ' && *line != '\\') { iov[iovcnt].iov_base = (void *)" "; iov[iovcnt].iov_len = 1; iovcnt++; } iov[iovcnt].iov_base = (void *)line; iov[iovcnt].iov_len = len; iovcnt++; if (imsg_composev(&ibuf, GOT_IMSG_PATCH_LINE, 0, 0, -1, iov, iovcnt) == -1) err = got_error_from_errno( "imsg_compose GOT_IMSG_PATCH_LINE"); return err; } static const struct got_error * peek_special_line(FILE *fp) { const struct got_error *err; int ch; ch = fgetc(fp); if (ch != EOF && ch != '\\') { ungetc(ch, fp); return NULL; } if (ch == '\\') { err = send_line("\\", 2); if (err) return err; } while (ch != EOF && ch != '\n') ch = fgetc(fp); if (ch != EOF || feof(fp)) return NULL; return got_error(GOT_ERR_IO); } static const struct got_error * parse_hunk(FILE *fp, int *done) { static const struct got_error *err = NULL; struct got_imsg_patch_hunk hdr; char *line = NULL, ch; size_t linesize = 0; ssize_t linelen; int leftold, leftnew; linelen = getline(&line, &linesize, fp); if (linelen == -1) { *done = 1; goto done; } err = parse_hdr(line, done, &hdr); if (err) goto done; if (*done) { if (fseeko(fp, -linelen, SEEK_CUR) == -1) err = got_error_from_errno("fseeko"); goto done; } leftold = hdr.oldlines; leftnew = hdr.newlines; while (leftold > 0 || leftnew > 0) { linelen = getline(&line, &linesize, fp); if (linelen == -1) { if (ferror(fp)) { err = got_error_from_errno("getline"); goto done; } /* trailing newlines may be chopped */ if (leftold < 3 && leftnew < 3) { *done = 1; break; } err = got_error(GOT_ERR_PATCH_TRUNCATED); goto done; } if (line[linelen - 1] == '\n') line[linelen - 1] = '\0'; /* usr.bin/patch allows '=' as context char */ if (*line == '=') *line = ' '; ch = *line; if (ch == '\t' || ch == '\0') ch = ' '; /* the space got eaten */ switch (ch) { case '-': leftold--; break; case ' ': leftold--; leftnew--; break; case '+': leftnew--; break; default: err = got_error(GOT_ERR_PATCH_MALFORMED); goto done; } if (leftold < 0 || leftnew < 0) { err = got_error(GOT_ERR_PATCH_MALFORMED); goto done; } err = send_line(line, linelen); if (err) goto done; if ((ch == '-' && leftold == 0) || (ch == '+' && leftnew == 0)) { err = peek_special_line(fp); if (err) goto done; } } done: free(line); return err; } static const struct got_error * read_patch(struct imsgbuf *ibuf, FILE *fp) { const struct got_error *err = NULL; int git, patch_found = 0; char *cid = NULL; while ((err = patch_start(&git, &cid, fp)) == NULL) { int done, next; err = find_diff(&done, &next, fp, git, cid); if (err) goto done; if (next) continue; patch_found = 1; while (!done) { err = parse_hunk(fp, &done); if (err) goto done; } err = send_patch_done(); if (err) goto done; } done: free(cid); /* ignore trailing gibberish */ if (err != NULL && err->code == GOT_ERR_NO_PATCH && patch_found) err = NULL; return err; } int main(int argc, char **argv) { const struct got_error *err = NULL; struct imsg imsg; FILE *fp = NULL; int fd = -1; #if 0 static int attached; while (!attached) sleep(1); #endif imsg_init(&ibuf, GOT_IMSG_FD_CHILD); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) goto done; if (imsg.hdr.type != GOT_IMSG_PATCH_FILE) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } fd = imsg_get_fd(&imsg); if (fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } fp = fdopen(fd, "r"); if (fp == NULL) { err = got_error_from_errno("fdopen"); goto done; } fd = -1; err = read_patch(&ibuf, fp); if (err) goto done; if (imsg_compose(&ibuf, GOT_IMSG_PATCH_EOF, 0, 0, -1, NULL, 0) == -1) { err = got_error_from_errno("imsg_compose GOT_IMSG_PATCH_EOF"); goto done; } err = got_privsep_flush_imsg(&ibuf); imsg_free(&imsg); done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (fp != NULL && fclose(fp) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (err != NULL) { got_privsep_send_error(&ibuf, err); err = NULL; } if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL) err = got_error_from_errno("close"); if (err && err->code != GOT_ERR_PRIVSEP_PIPE) fprintf(stderr, "%s: %s\n", getprogname(), err->msg); return err ? 1 : 0; } got-portable-0.101/libexec/got-read-patch/Makefile.in0000664000175100017510000005711614644145544016103 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-read-patch$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-read-patch ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_read_patch_OBJECTS = got-read-patch.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) got_read_patch_OBJECTS = $(am_got_read_patch_OBJECTS) got_read_patch_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ ./$(DEPDIR)/got-read-patch.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_read_patch_SOURCES) DIST_SOURCES = $(got_read_patch_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_read_patch_SOURCES = got-read-patch.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_patch_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-read-patch/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-read-patch/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files clean-libexecPROGRAMS: -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: > $(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: > $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-read-patch$(EXEEXT): $(got_read_patch_OBJECTS) $(got_read_patch_DEPENDENCIES) $(EXTRA_got_read_patch_DEPENDENCIES) @rm -f got-read-patch$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_read_patch_OBJECTS) $(got_read_patch_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-read-patch.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-patch.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-patch.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/libexec/got-fetch-pack/0000775000175100017510000000000014644145570014100 5got-portable-0.101/libexec/got-fetch-pack/Makefile.am0000664000175100017510000000136014644144735016056 libexec_PROGRAMS = got-fetch-pack include $(top_builddir)/Makefile.common got_fetch_pack_SOURCES = \ got-fetch-pack.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gitproto.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pkt.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c got_fetch_pack_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.101/libexec/got-fetch-pack/got-fetch-pack.c0000664000175100017510000007115414644144735016772 /* * Copyright (c) 2019 Ori Bernstein * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_version.h" #include "got_fetch.h" #include "got_reference.h" #include "got_lib_hash.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_privsep.h" #include "got_lib_pack.h" #include "got_lib_pkt.h" #include "got_lib_poll.h" #include "got_lib_gitproto.h" #include "got_lib_ratelimit.h" #ifndef MIN #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) #endif #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif struct got_object *indexed; static int chattygot; static const struct got_capability got_capabilities[] = { { GOT_CAPA_AGENT, "got/" GOT_VERSION_STR }, { GOT_CAPA_OFS_DELTA, NULL }, { GOT_CAPA_SIDE_BAND_64K, NULL }, }; static void match_remote_ref(struct got_pathlist_head *have_refs, struct got_object_id *my_id, const char *refname) { struct got_pathlist_entry *pe; /* XXX zero-hash signifies we don't have this ref; * we should use a flag instead */ memset(my_id, 0, sizeof(*my_id)); TAILQ_FOREACH(pe, have_refs, entry) { struct got_object_id *id = pe->data; if (strcmp(pe->path, refname) == 0) { memcpy(my_id, id, sizeof(*my_id)); break; } } } static int match_branch(const char *branch, const char *wanted_branch) { if (strncmp(branch, "refs/heads/", 11) != 0) return 0; if (strncmp(wanted_branch, "refs/heads/", 11) == 0) wanted_branch += 11; return (strcmp(branch + 11, wanted_branch) == 0); } static int match_wanted_ref(const char *refname, const char *wanted_ref) { if (strncmp(refname, "refs/", 5) != 0) return 0; refname += 5; /* * Prevent fetching of references that won't make any * sense outside of the remote repository's context. */ if (strncmp(refname, "got/", 4) == 0) return 0; if (strncmp(refname, "remotes/", 8) == 0) return 0; if (strncmp(wanted_ref, "refs/", 5) == 0) wanted_ref += 5; /* Allow prefix match. */ if (got_path_is_child(refname, wanted_ref, strlen(wanted_ref))) return 1; /* Allow exact match. */ return (strcmp(refname, wanted_ref) == 0); } static const struct got_error * send_fetch_server_progress(struct imsgbuf *ibuf, const char *msg, size_t msglen) { if (msglen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) return got_error(GOT_ERR_NO_SPACE); if (msglen == 0) return NULL; if (imsg_compose(ibuf, GOT_IMSG_FETCH_SERVER_PROGRESS, 0, 0, -1, msg, msglen) == -1) return got_error_from_errno( "imsg_compose FETCH_SERVER_PROGRESS"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * send_fetch_download_progress(struct imsgbuf *ibuf, off_t bytes, struct got_ratelimit *rl) { const struct got_error *err; int elapsed = 0; if (rl) { err = got_ratelimit_check(&elapsed, rl); if (err || !elapsed) return err; } if (imsg_compose(ibuf, GOT_IMSG_FETCH_DOWNLOAD_PROGRESS, 0, 0, -1, &bytes, sizeof(bytes)) == -1) return got_error_from_errno( "imsg_compose FETCH_DOWNLOAD_PROGRESS"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * send_fetch_done(struct imsgbuf *ibuf, uint8_t *pack_sha1) { if (imsg_compose(ibuf, GOT_IMSG_FETCH_DONE, 0, 0, -1, pack_sha1, SHA1_DIGEST_LENGTH) == -1) return got_error_from_errno("imsg_compose FETCH"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * fetch_progress(struct imsgbuf *ibuf, const char *buf, size_t len) { size_t i; if (len == 0) return NULL; /* * Truncate messages which exceed the maximum imsg payload size. * Server may send up to 64k. */ if (len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) len = MAX_IMSGSIZE - IMSG_HEADER_SIZE; /* Only allow printable ASCII. */ for (i = 0; i < len; i++) { if (isprint((unsigned char)buf[i]) || isspace((unsigned char)buf[i])) continue; return got_error_msg(GOT_ERR_BAD_PACKET, "non-printable progress message received from server"); } return send_fetch_server_progress(ibuf, buf, len); } static const struct got_error * fetch_error(const char *buf, size_t len) { static char msg[1024]; size_t i; for (i = 0; i < len && i < sizeof(msg) - 1; i++) { if (!isprint((unsigned char)buf[i])) return got_error_msg(GOT_ERR_BAD_PACKET, "non-printable error message received from server"); msg[i] = buf[i]; } msg[i] = '\0'; return got_error_msg(GOT_ERR_FETCH_FAILED, msg); } static const struct got_error * send_fetch_symrefs(struct imsgbuf *ibuf, struct got_pathlist_head *symrefs) { struct ibuf *wbuf; size_t len, nsymrefs = 0; struct got_pathlist_entry *pe; len = sizeof(struct got_imsg_fetch_symrefs); TAILQ_FOREACH(pe, symrefs, entry) { const char *target = pe->data; len += sizeof(struct got_imsg_fetch_symref) + pe->path_len + strlen(target); nsymrefs++; } if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE) return got_error(GOT_ERR_NO_SPACE); wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_SYMREFS, 0, 0, len); if (wbuf == NULL) return got_error_from_errno("imsg_create FETCH_SYMREFS"); /* Keep in sync with struct got_imsg_fetch_symrefs definition! */ if (imsg_add(wbuf, &nsymrefs, sizeof(nsymrefs)) == -1) return got_error_from_errno("imsg_add FETCH_SYMREFS"); TAILQ_FOREACH(pe, symrefs, entry) { const char *name = pe->path; size_t name_len = pe->path_len; const char *target = pe->data; size_t target_len = strlen(target); /* Keep in sync with struct got_imsg_fetch_symref definition! */ if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1) return got_error_from_errno("imsg_add FETCH_SYMREFS"); if (imsg_add(wbuf, &target_len, sizeof(target_len)) == -1) return got_error_from_errno("imsg_add FETCH_SYMREFS"); if (imsg_add(wbuf, name, name_len) == -1) return got_error_from_errno("imsg_add FETCH_SYMREFS"); if (imsg_add(wbuf, target, target_len) == -1) return got_error_from_errno("imsg_add FETCH_SYMREFS"); } imsg_close(ibuf, wbuf); return got_privsep_flush_imsg(ibuf); } static const struct got_error * send_fetch_ref(struct imsgbuf *ibuf, struct got_object_id *refid, const char *refname) { struct ibuf *wbuf; size_t len, reflen = strlen(refname); len = sizeof(struct got_imsg_fetch_ref) + reflen; if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE) return got_error(GOT_ERR_NO_SPACE); wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_REF, 0, 0, len); if (wbuf == NULL) return got_error_from_errno("imsg_create FETCH_REF"); /* Keep in sync with struct got_imsg_fetch_ref definition! */ if (imsg_add(wbuf, refid, sizeof(*refid)) == -1) return got_error_from_errno("imsg_add FETCH_REF"); if (imsg_add(wbuf, refname, reflen) == -1) return got_error_from_errno("imsg_add FETCH_REF"); imsg_close(ibuf, wbuf); return got_privsep_flush_imsg(ibuf); } static const struct got_error * fetch_ref(struct imsgbuf *ibuf, struct got_pathlist_head *have_refs, struct got_object_id *have, struct got_object_id *want, const char *refname, const char *id_str) { const struct got_error *err; char *theirs = NULL, *mine = NULL; if (!got_parse_object_id(want, id_str, GOT_HASH_SHA1)) { err = got_error(GOT_ERR_BAD_OBJ_ID_STR); goto done; } match_remote_ref(have_refs, have, refname); err = send_fetch_ref(ibuf, want, refname); if (err) goto done; if (chattygot) fprintf(stderr, "%s: %s will be fetched\n", getprogname(), refname); if (chattygot > 1) { err = got_object_id_str(&theirs, want); if (err) goto done; err = got_object_id_str(&mine, have); if (err) goto done; fprintf(stderr, "%s: remote: %s\n%s: local: %s\n", getprogname(), theirs, getprogname(), mine); } done: free(theirs); free(mine); return err; } static const struct got_error * fetch_pack(int fd, int packfd, uint8_t *pack_sha1, struct got_pathlist_head *have_refs, int fetch_all_branches, struct got_pathlist_head *wanted_branches, struct got_pathlist_head *wanted_refs, int list_refs_only, const char *worktree_branch, const char *remote_head, int no_head, struct imsgbuf *ibuf) { const struct got_error *err = NULL; char buf[GOT_PKT_MAX]; char hashstr[SHA1_DIGEST_STRING_LENGTH]; struct got_object_id *have, *want; int is_firstpkt = 1, nref = 0, refsz = 16; int i, n, nwant = 0, nhave = 0, acked = 0, eof = 0; off_t packsz = 0, last_reported_packsz = 0; char *id_str = NULL, *default_id_str = NULL, *refname = NULL; char *server_capabilities = NULL, *my_capabilities = NULL; const char *default_branch = NULL; struct got_pathlist_head symrefs; struct got_pathlist_entry *pe; int sent_my_capabilites = 0, have_sidebands = 0; int found_branch = 0; struct got_hash ctx; uint8_t sha1_buf[SHA1_DIGEST_LENGTH]; size_t sha1_buf_len = 0; ssize_t w; struct got_ratelimit rl; TAILQ_INIT(&symrefs); got_hash_init(&ctx, GOT_HASH_SHA1); got_ratelimit_init(&rl, 0, 500); have = malloc(refsz * sizeof(have[0])); if (have == NULL) return got_error_from_errno("malloc"); want = malloc(refsz * sizeof(want[0])); if (want == NULL) { err = got_error_from_errno("malloc"); goto done; } while (1) { err = got_pkt_readpkt(&n, fd, buf, sizeof(buf), chattygot, INFTIM); if (err) goto done; if (n == 0) break; if (n >= 4 && strncmp(buf, "ERR ", 4) == 0) { err = fetch_error(&buf[4], n - 4); goto done; } free(id_str); free(refname); err = got_gitproto_parse_refline(&id_str, &refname, &server_capabilities, buf, n); if (err) goto done; if (refsz == nref + 1) { struct got_object_id *h, *w; refsz *= 2; h = reallocarray(have, refsz, sizeof(have[0])); if (h == NULL) { err = got_error_from_errno("reallocarray"); goto done; } have = h; w = reallocarray(want, refsz, sizeof(want[0])); if (w == NULL) { err = got_error_from_errno("reallocarray"); goto done; } want = w; } if (is_firstpkt) { if (chattygot && server_capabilities[0] != '\0') fprintf(stderr, "%s: server capabilities: %s\n", getprogname(), server_capabilities); err = got_gitproto_match_capabilities(&my_capabilities, &symrefs, server_capabilities, got_capabilities, nitems(got_capabilities)); if (err) goto done; if (chattygot) fprintf(stderr, "%s: my capabilities:%s\n", getprogname(), my_capabilities != NULL ? my_capabilities : ""); err = send_fetch_symrefs(ibuf, &symrefs); if (err) goto done; is_firstpkt = 0; if (!fetch_all_branches) { TAILQ_FOREACH(pe, &symrefs, entry) { const char *name = pe->path; const char *symref_target = pe->data; if (strcmp(name, GOT_REF_HEAD) != 0) continue; default_branch = symref_target; break; } } if (default_branch) continue; } if (strstr(refname, "^{}")) { if (chattygot) { fprintf(stderr, "%s: ignoring %s\n", getprogname(), refname); } continue; } if (default_branch && default_id_str == NULL && strcmp(refname, default_branch) == 0) { default_id_str = strdup(id_str); if (default_id_str == NULL) { err = got_error_from_errno("strdup"); goto done; } } if (list_refs_only || strncmp(refname, "refs/tags/", 10) == 0) { err = fetch_ref(ibuf, have_refs, &have[nref], &want[nref], refname, id_str); if (err) goto done; nref++; } else if (strncmp(refname, "refs/heads/", 11) == 0) { if (fetch_all_branches) { err = fetch_ref(ibuf, have_refs, &have[nref], &want[nref], refname, id_str); if (err) goto done; nref++; found_branch = 1; continue; } TAILQ_FOREACH(pe, wanted_branches, entry) { if (match_branch(refname, pe->path)) break; } if (pe != NULL || (worktree_branch != NULL && match_branch(refname, worktree_branch))) { err = fetch_ref(ibuf, have_refs, &have[nref], &want[nref], refname, id_str); if (err) goto done; nref++; found_branch = 1; } else if (chattygot) { fprintf(stderr, "%s: ignoring %s\n", getprogname(), refname); } } else { TAILQ_FOREACH(pe, wanted_refs, entry) { if (match_wanted_ref(refname, pe->path)) break; } if (pe != NULL) { err = fetch_ref(ibuf, have_refs, &have[nref], &want[nref], refname, id_str); if (err) goto done; nref++; } else if (chattygot) { fprintf(stderr, "%s: ignoring %s\n", getprogname(), refname); } } } if (list_refs_only) goto done; /* * If -b was not used and either none of the requested branches * (got.conf, worktree) were found or the client already has the * remote HEAD symref but its target changed, fetch remote's HEAD. */ if (!no_head && default_branch && default_id_str && strncmp(default_branch, "refs/heads/", 11) == 0) { int remote_head_changed = 0; if (remote_head) { if (strcmp(remote_head, default_branch + 11) != 0) remote_head_changed = 1; } if (!found_branch || remote_head_changed) { err = fetch_ref(ibuf, have_refs, &have[nref], &want[nref], default_branch, default_id_str); if (err) goto done; nref++; } } /* Abort if we haven't found anything to fetch. */ if (nref == 0) { struct got_pathlist_entry *pe; static char msg[PATH_MAX + 33]; pe = TAILQ_FIRST(wanted_branches); if (pe) { snprintf(msg, sizeof(msg), "branch \"%s\" not found on server", pe->path); err = got_error_msg(GOT_ERR_FETCH_NO_BRANCH, msg); goto done; } pe = TAILQ_FIRST(wanted_refs); if (pe) { snprintf(msg, sizeof(msg), "reference \"%s\" not found on server", pe->path); err = got_error_msg(GOT_ERR_FETCH_NO_BRANCH, msg); goto done; } err = got_error(GOT_ERR_FETCH_NO_BRANCH); goto done; } for (i = 0; i < nref; i++) { if (got_object_id_cmp(&have[i], &want[i]) == 0) continue; got_object_id_hex(&want[i], hashstr, sizeof(hashstr)); n = snprintf(buf, sizeof(buf), "want %s%s\n", hashstr, sent_my_capabilites || my_capabilities == NULL ? "" : my_capabilities); if (n < 0 || (size_t)n >= sizeof(buf)) { err = got_error(GOT_ERR_NO_SPACE); goto done; } err = got_pkt_writepkt(fd, buf, n, chattygot); if (err) goto done; sent_my_capabilites = 1; nwant++; } err = got_pkt_flushpkt(fd, chattygot); if (err) goto done; if (nwant == 0) goto done; TAILQ_FOREACH(pe, have_refs, entry) { struct got_object_id *id = pe->data; got_object_id_hex(id, hashstr, sizeof(hashstr)); n = snprintf(buf, sizeof(buf), "have %s\n", hashstr); if (n < 0 || (size_t)n >= sizeof(buf)) { err = got_error(GOT_ERR_NO_SPACE); goto done; } err = got_pkt_writepkt(fd, buf, n, chattygot); if (err) goto done; nhave++; } n = strlcpy(buf, "done\n", sizeof(buf)); err = got_pkt_writepkt(fd, buf, n, chattygot); if (err) goto done; while (nhave > 0 && !acked) { struct got_object_id common_id; /* The server should ACK the object IDs we need. */ err = got_pkt_readpkt(&n, fd, buf, sizeof(buf), chattygot, INFTIM); if (err) goto done; if (n >= 4 && strncmp(buf, "ERR ", 4) == 0) { err = fetch_error(&buf[4], n - 4); goto done; } if (n >= 4 && strncmp(buf, "NAK\n", 4) == 0) { /* * Server could not find a common ancestor. * Perhaps it is an out-of-date mirror, or there * is a repository with unrelated history. */ break; } if (n < 4 + SHA1_DIGEST_STRING_LENGTH || strncmp(buf, "ACK ", 4) != 0) { err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected message from server"); goto done; } if (!got_parse_object_id(&common_id, buf + 4, GOT_HASH_SHA1)) { err = got_error_msg(GOT_ERR_BAD_PACKET, "bad object ID in ACK packet from server"); goto done; } acked++; } if (nhave == 0) { err = got_pkt_readpkt(&n, fd, buf, sizeof(buf), chattygot, INFTIM); if (err) goto done; if (n != 4 || strncmp(buf, "NAK\n", n) != 0) { err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected message from server"); goto done; } } if (chattygot) fprintf(stderr, "%s: fetching...\n", getprogname()); if (my_capabilities != NULL && strstr(my_capabilities, GOT_CAPA_SIDE_BAND_64K) != NULL) have_sidebands = 1; while (!eof) { ssize_t r = 0; int datalen = -1; if (have_sidebands) { err = got_pkt_readhdr(&datalen, fd, chattygot, INFTIM); if (err) goto done; if (datalen <= 0) break; /* Read sideband channel ID (one byte). */ r = read(fd, buf, 1); if (r == -1) { err = got_error_from_errno("read"); goto done; } if (r != 1) { err = got_error_msg(GOT_ERR_BAD_PACKET, "short packet"); goto done; } if (datalen > sizeof(buf) - 5) { err = got_error_msg(GOT_ERR_BAD_PACKET, "bad packet length"); goto done; } datalen--; /* sideband ID has been read */ if (buf[0] == GOT_SIDEBAND_PACKFILE_DATA) { /* Read packfile data. */ err = got_pkt_readn(&r, fd, buf, datalen, INFTIM); if (err) goto done; if (r != datalen) { err = got_error_msg(GOT_ERR_BAD_PACKET, "packet too short"); goto done; } } else if (buf[0] == GOT_SIDEBAND_PROGRESS_INFO) { err = got_pkt_readn(&r, fd, buf, datalen, INFTIM); if (err) goto done; if (r != datalen) { err = got_error_msg(GOT_ERR_BAD_PACKET, "packet too short"); goto done; } err = fetch_progress(ibuf, buf, r); if (err) goto done; continue; } else if (buf[0] == GOT_SIDEBAND_ERROR_INFO) { err = got_pkt_readn(&r, fd, buf, datalen, INFTIM); if (err) goto done; if (r != datalen) { err = got_error_msg(GOT_ERR_BAD_PACKET, "packet too short"); goto done; } err = fetch_error(buf, r); goto done; } else if (buf[0] == 'A') { err = got_pkt_readn(&r, fd, buf, datalen, INFTIM); if (err) goto done; if (r != datalen) { err = got_error_msg(GOT_ERR_BAD_PACKET, "packet too short"); goto done; } /* * Git server responds with ACK after 'done' * even though multi_ack is disabled?!? */ buf[r] = '\0'; if (strncmp(buf, "CK ", 3) == 0) continue; /* ignore */ err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected message from server"); goto done; } else { err = got_error_msg(GOT_ERR_BAD_PACKET, "unknown side-band received from server"); goto done; } } else { /* No sideband channel. Every byte is packfile data. */ size_t n = 0; err = got_poll_read_full_timeout(fd, &n, buf, sizeof buf, 1, INFTIM); if (err) { if (err->code != GOT_ERR_EOF) goto done; r = 0; eof = 1; } else r = n; } /* * An expected SHA1 checksum sits at the end of the pack file. * Since we don't know the file size ahead of time we have to * keep SHA1_DIGEST_LENGTH bytes buffered and avoid mixing * those bytes into our SHA1 checksum computation until we * know for sure that additional pack file data bytes follow. */ if (r < SHA1_DIGEST_LENGTH) { if (sha1_buf_len < SHA1_DIGEST_LENGTH) { /* * If there's enough buffered + read data to * fill up the buffer then shift a sufficient * amount of bytes out at the front to make * room, mixing those bytes into the checksum. */ if (sha1_buf_len > 0 && sha1_buf_len + r > SHA1_DIGEST_LENGTH) { size_t nshift = MIN(sha1_buf_len + r - SHA1_DIGEST_LENGTH, sha1_buf_len); got_hash_update(&ctx, sha1_buf, nshift); memmove(sha1_buf, sha1_buf + nshift, sha1_buf_len - nshift); sha1_buf_len -= nshift; } /* Buffer potential checksum bytes. */ memcpy(sha1_buf + sha1_buf_len, buf, r); sha1_buf_len += r; } else if (r > 0) { /* * Mix in previously buffered bytes which * are not part of the checksum after all. */ got_hash_update(&ctx, sha1_buf, r); /* Update potential checksum buffer. */ memmove(sha1_buf, sha1_buf + r, sha1_buf_len - r); memcpy(sha1_buf + sha1_buf_len - r, buf, r); } } else { /* Mix in any previously buffered bytes. */ got_hash_update(&ctx, sha1_buf, sha1_buf_len); /* Mix in bytes read minus potential checksum bytes. */ got_hash_update(&ctx, buf, r - SHA1_DIGEST_LENGTH); /* Buffer potential checksum bytes. */ memcpy(sha1_buf, buf + r - SHA1_DIGEST_LENGTH, SHA1_DIGEST_LENGTH); sha1_buf_len = SHA1_DIGEST_LENGTH; } /* Write packfile data to temporary pack file. */ w = write(packfd, buf, r); if (w == -1) { err = got_error_from_errno("write"); goto done; } if (w != r) { err = got_error(GOT_ERR_IO); goto done; } packsz += w; /* Don't send too many progress privsep messages. */ if (packsz > last_reported_packsz + 1024) { err = send_fetch_download_progress(ibuf, packsz, &rl); if (err) goto done; last_reported_packsz = packsz; } } err = send_fetch_download_progress(ibuf, packsz, NULL); if (err) goto done; got_hash_final(&ctx, pack_sha1); if (sha1_buf_len != SHA1_DIGEST_LENGTH || memcmp(pack_sha1, sha1_buf, sha1_buf_len) != 0) { err = got_error_msg(GOT_ERR_BAD_PACKFILE, "pack file checksum mismatch"); } done: got_pathlist_free(&symrefs, GOT_PATHLIST_FREE_ALL); free(have); free(want); free(id_str); free(default_id_str); free(refname); free(server_capabilities); return err; } int main(int argc, char **argv) { const struct got_error *err = NULL; int fetchfd = -1, packfd = -1; uint8_t pack_sha1[SHA1_DIGEST_LENGTH]; struct imsgbuf ibuf; struct imsg imsg; struct got_pathlist_head have_refs; struct got_pathlist_head wanted_branches; struct got_pathlist_head wanted_refs; struct got_imsg_fetch_request fetch_req; struct got_imsg_fetch_have_ref href; struct got_imsg_fetch_wanted_branch wbranch; struct got_imsg_fetch_wanted_ref wref; size_t datalen, i; char *remote_head = NULL, *worktree_branch = NULL; #if 0 static int attached; while (!attached) sleep (1); #endif TAILQ_INIT(&have_refs); TAILQ_INIT(&wanted_branches); TAILQ_INIT(&wanted_refs); imsg_init(&ibuf, GOT_IMSG_FD_CHILD); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; goto done; } if (imsg.hdr.type == GOT_IMSG_STOP) goto done; if (imsg.hdr.type != GOT_IMSG_FETCH_REQUEST) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(fetch_req)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&fetch_req, imsg.data, sizeof(fetch_req)); fetchfd = imsg_get_fd(&imsg); if (datalen != sizeof(fetch_req) + fetch_req.worktree_branch_len + fetch_req.remote_head_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } if (fetch_req.worktree_branch_len != 0) { worktree_branch = strndup(imsg.data + sizeof(fetch_req), fetch_req.worktree_branch_len); if (worktree_branch == NULL) { err = got_error_from_errno("strndup"); goto done; } } if (fetch_req.remote_head_len != 0) { remote_head = strndup(imsg.data + sizeof(fetch_req) + fetch_req.worktree_branch_len, fetch_req.remote_head_len); if (remote_head == NULL) { err = got_error_from_errno("strndup"); goto done; } } imsg_free(&imsg); if (fetch_req.verbosity > 0) chattygot += fetch_req.verbosity; for (i = 0; i < fetch_req.n_have_refs; i++) { struct got_object_id *id; char *refname; err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; goto done; } if (imsg.hdr.type == GOT_IMSG_STOP) goto done; if (imsg.hdr.type != GOT_IMSG_FETCH_HAVE_REF) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(href)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&href, imsg.data, sizeof(href)); if (datalen - sizeof(href) < href.name_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } refname = strndup(imsg.data + sizeof(href), href.name_len); if (refname == NULL) { err = got_error_from_errno("strndup"); goto done; } id = malloc(sizeof(*id)); if (id == NULL) { free(refname); err = got_error_from_errno("malloc"); goto done; } memcpy(id, &href.id, sizeof(*id)); err = got_pathlist_append(&have_refs, refname, id); if (err) { free(refname); free(id); goto done; } imsg_free(&imsg); } for (i = 0; i < fetch_req.n_wanted_branches; i++) { char *refname; err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; goto done; } if (imsg.hdr.type == GOT_IMSG_STOP) goto done; if (imsg.hdr.type != GOT_IMSG_FETCH_WANTED_BRANCH) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(wbranch)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&wbranch, imsg.data, sizeof(wbranch)); if (datalen - sizeof(wbranch) < wbranch.name_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } refname = strndup(imsg.data + sizeof(wbranch), wbranch.name_len); if (refname == NULL) { err = got_error_from_errno("strndup"); goto done; } err = got_pathlist_append(&wanted_branches, refname, NULL); if (err) { free(refname); goto done; } imsg_free(&imsg); } for (i = 0; i < fetch_req.n_wanted_refs; i++) { char *refname; err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; goto done; } if (imsg.hdr.type == GOT_IMSG_STOP) goto done; if (imsg.hdr.type != GOT_IMSG_FETCH_WANTED_REF) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(wref)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&wref, imsg.data, sizeof(wref)); if (datalen - sizeof(wref) < wref.name_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } refname = strndup(imsg.data + sizeof(wref), wref.name_len); if (refname == NULL) { err = got_error_from_errno("strndup"); goto done; } err = got_pathlist_append(&wanted_refs, refname, NULL); if (err) { free(refname); goto done; } imsg_free(&imsg); } err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; goto done; } if (imsg.hdr.type == GOT_IMSG_STOP) goto done; if (imsg.hdr.type != GOT_IMSG_FETCH_OUTFD) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } if (imsg.hdr.len - IMSG_HEADER_SIZE != 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } packfd = imsg_get_fd(&imsg); err = fetch_pack(fetchfd, packfd, pack_sha1, &have_refs, fetch_req.fetch_all_branches, &wanted_branches, &wanted_refs, fetch_req.list_refs_only, worktree_branch, remote_head, fetch_req.no_head, &ibuf); done: free(worktree_branch); free(remote_head); got_pathlist_free(&have_refs, GOT_PATHLIST_FREE_ALL); got_pathlist_free(&wanted_branches, GOT_PATHLIST_FREE_PATH); if (fetchfd != -1 && close(fetchfd) == -1 && err == NULL) err = got_error_from_errno("close"); if (packfd != -1 && close(packfd) == -1 && err == NULL) err = got_error_from_errno("close"); if (err != NULL) got_privsep_send_error(&ibuf, err); else err = send_fetch_done(&ibuf, pack_sha1); if (err != NULL) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); } exit(0); } got-portable-0.101/libexec/got-fetch-pack/Makefile.in0000664000175100017510000006162614644145543016100 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-fetch-pack$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-fetch-pack ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_fetch_pack_OBJECTS = got-fetch-pack.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/gitproto.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pkt.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) \ $(top_builddir)/lib/ratelimit.$(OBJEXT) got_fetch_pack_OBJECTS = $(am_got_fetch_pack_OBJECTS) got_fetch_pack_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/gitproto.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pkt.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po \ ./$(DEPDIR)/got-fetch-pack.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_fetch_pack_SOURCES) DIST_SOURCES = $(got_fetch_pack_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_fetch_pack_SOURCES = \ got-fetch-pack.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gitproto.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pkt.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c got_fetch_pack_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-fetch-pack/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-fetch-pack/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files clean-libexecPROGRAMS: -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: > $(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: > $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gitproto.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pkt.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/ratelimit.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-fetch-pack$(EXEEXT): $(got_fetch_pack_OBJECTS) $(got_fetch_pack_DEPENDENCIES) $(EXTRA_got_fetch_pack_DEPENDENCIES) @rm -f got-fetch-pack$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_fetch_pack_OBJECTS) $(got_fetch_pack_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gitproto.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pkt.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/ratelimit.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-fetch-pack.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gitproto.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pkt.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f ./$(DEPDIR)/got-fetch-pack.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gitproto.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pkt.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f ./$(DEPDIR)/got-fetch-pack.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/libexec/got-fetch-http/0000775000175100017510000000000014644145570014141 5got-portable-0.101/libexec/got-fetch-http/Makefile.am0000664000175100017510000000141714644144735016122 libexec_PROGRAMS = got-fetch-http include $(top_builddir)/Makefile.common got_fetch_http_SOURCES = got-fetch-http.c \ $(top_srcdir)/lib/bufio.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pkt.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/object_parse.c got_fetch_http_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(libtls_LIBS) if HOST_FREEBSD LDADD += -lmd endif if HOST_OPENBSD LDADD += -ltls endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) $(libtls_CFLAGS) got-portable-0.101/libexec/got-fetch-http/Makefile.in0000664000175100017510000006100714644145543016132 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-fetch-http$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd @HOST_OPENBSD_TRUE@am__append_2 = -ltls subdir = libexec/got-fetch-http ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_fetch_http_OBJECTS = got-fetch-http.$(OBJEXT) \ $(top_builddir)/lib/bufio.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pkt.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) got_fetch_http_OBJECTS = $(am_got_fetch_http_OBJECTS) got_fetch_http_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/bufio.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pkt.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ ./$(DEPDIR)/got-fetch-http.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_fetch_http_SOURCES) DIST_SOURCES = $(got_fetch_http_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) $(libtls_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_fetch_http_SOURCES = got-fetch-http.c \ $(top_srcdir)/lib/bufio.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pkt.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/object_parse.c got_fetch_http_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(libtls_LIBS) \ $(am__append_1) $(am__append_2) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-fetch-http/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-fetch-http/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files clean-libexecPROGRAMS: -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: > $(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: > $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/bufio.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pkt.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-fetch-http$(EXEEXT): $(got_fetch_http_OBJECTS) $(got_fetch_http_DEPENDENCIES) $(EXTRA_got_fetch_http_DEPENDENCIES) @rm -f got-fetch-http$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_fetch_http_OBJECTS) $(got_fetch_http_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/bufio.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pkt.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-fetch-http.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/bufio.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pkt.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-fetch-http.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/bufio.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pkt.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-fetch-http.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/libexec/got-fetch-http/got-fetch-http.c0000664000175100017510000003032514644144735017067 /* * Copyright (c) 2024 Tobias Heider * Copyright (c) 2022 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_path.h" #include "got_version.h" #include "got_lib_pkt.h" #include "bufio.h" #define UPLOAD_PACK_ADV "application/x-git-upload-pack-advertisement" #define UPLOAD_PACK_REQ "application/x-git-upload-pack-request" #define UPLOAD_PACK_RES "application/x-git-upload-pack-result" #define GOT_USERAGENT "got/" GOT_VERSION_STR #define MINIMUM(a, b) ((a) < (b) ? (a) : (b)) #define hasprfx(str, p) (strncasecmp(str, p, strlen(p)) == 0) FILE *tmp; static int verbose; static char * bufio_getdelim_sync(struct bufio *bio, const char *nl, size_t *len) { int r; do { r = bufio_read(bio); if (r == -1 && errno != EAGAIN) errx(1, "bufio_read: %s", bufio_io_err(bio)); } while (r == -1 && errno == EAGAIN); return buf_getdelim(&bio->rbuf, nl, len); } static size_t bufio_drain_sync(struct bufio *bio, void *d, size_t len) { int r; do { r = bufio_read(bio); if (r == -1 && errno != EAGAIN) errx(1, "bufio_read: %s", bufio_io_err(bio)); } while (r == -1 && errno == EAGAIN); return bufio_drain(bio, d, len); } static void bufio_close_sync(struct bufio *bio) { int r; do { r = bufio_close(bio); if (r == -1 && errno != EAGAIN) errx(1, "bufio_close: %s", bufio_io_err(bio)); } while (r == -1 && errno == EAGAIN); } static long long hexstrtonum(const char *str, long long min, long long max, const char **errstr) { long long lval; char *cp; errno = 0; lval = strtoll(str, &cp, 16); if (*str == '\0' || *cp != '\0') { *errstr = "not a number"; return 0; } if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) || lval < min || lval > max) { *errstr = "out of range"; return 0; } *errstr = NULL; return lval; } static int dial(int https, const char *host, const char *port) { struct addrinfo hints, *res, *res0; int error, saved_errno, fd = -1; const char *cause = NULL; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; error = getaddrinfo(host, port, &hints, &res0); if (error) { warnx("%s", gai_strerror(error)); return -1; } for (res = res0; res; res = res->ai_next) { fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (fd == -1) { cause = "socket"; continue; } if (connect(fd, res->ai_addr, res->ai_addrlen) == 0) break; cause = "connect"; saved_errno = errno; close(fd); fd = -1; errno = saved_errno; } freeaddrinfo(res0); if (fd == -1) { warn("%s", cause); return -1; } return fd; } static int http_open(struct bufio *bio, int https, const char *method, const char *host, const char *port, const char *path, const char *path_sufx, const char *query, const char *ctype) { const char *chdr = NULL, *te = ""; char *p, *req; int r; if (strcmp(method, "POST") == 0) te = "\r\nTransfer-Encoding: chunked\r\n"; if (ctype) chdr = "Content-Type: "; r = asprintf(&p, "%s%s/%s%s%s", got_path_is_absolute(path) ? "" :"/", path, path_sufx, query ? "?" : "", query ? query : ""); if (r == -1) err(1, "asprintf"); r = asprintf(&req, "%s %s HTTP/1.1\r\n" "Host: %s\r\n" "Connection: close\r\n" "User-agent: %s\r\n" "%s%s%s\r\n", method, p, host, GOT_USERAGENT, chdr ? chdr : "", ctype ? ctype : "", te); if (r == -1) err(1, "asprintf"); free(p); if (verbose > 0) fprintf(stderr, "%s: request: %s\n", getprogname(), req); r = bufio_compose(bio, req, r); if (r == -1) err(1, "bufio_compose_fmt"); free(req); do { r = bufio_write(bio); if (r == -1 && errno != EAGAIN) errx(1, "bufio_write: %s", bufio_io_err(bio)); } while (bio->wbuf.len != 0); return 0; } static int http_parse_reply(struct bufio *bio, int *chunked, const char *expected_ctype) { char *cp, *line; size_t linelen; *chunked = 0; line = bufio_getdelim_sync(bio, "\r\n", &linelen); if (line == NULL) { warnx("%s: bufio_getdelim_sync()", __func__); return -1; } if (verbose > 0) fprintf(stderr, "%s: response: %s\n", getprogname(), line); if ((cp = strchr(line, ' ')) == NULL) { warnx("malformed HTTP response"); return -1; } cp++; if (strncmp(cp, "200 ", 4) != 0) { warnx("malformed HTTP response"); return -1; } buf_drain(&bio->rbuf, linelen); while(1) { line = bufio_getdelim_sync(bio, "\r\n", &linelen); if (line == NULL) { warnx("%s: bufio_getdelim_sync()", __func__); return -1; } if (*line == '\0') { buf_drain(&bio->rbuf, linelen); break; } if (hasprfx(line, "content-type:")) { cp = strchr(line, ':') + 1; cp += strspn(cp, " \t"); cp[strcspn(cp, " \t")] = '\0'; if (strcmp(cp, expected_ctype) != 0) { warnx("server not using the \"smart\" " "HTTP protocol."); return -1; } } if (hasprfx(line, "transfer-encoding:")) { cp = strchr(line, ':') + 1; cp += strspn(cp, " \t"); cp[strcspn(cp, " \t")] = '\0'; if (strcmp(cp, "chunked") != 0) { warnx("unknown transfer-encoding"); return -1; } *chunked = 1; } buf_drain(&bio->rbuf, linelen); } return 0; } static ssize_t http_read(struct bufio *bio, int chunked, size_t *chunksz, char *buf, size_t bufsz) { const char *errstr; char *line = NULL; size_t r; ssize_t ret = 0, linelen; if (!chunked) return bufio_drain_sync(bio, buf, bufsz); while (bufsz > 0) { if (*chunksz == 0) { again: line = bufio_getdelim_sync(bio, "\r\n", &linelen); if (line == NULL) { buf_drain(&bio->rbuf, linelen); break; } if (*line == '\0') { buf_drain(&bio->rbuf, linelen); goto again; /* was the CRLF after the chunk */ } *chunksz = hexstrtonum(line, 0, INT_MAX, &errstr); if (errstr != NULL) { warnx("invalid HTTP chunk: size is %s (%s)", errstr, line); ret = -1; break; } if (*chunksz == 0) { buf_drain(&bio->rbuf, linelen); break; } buf_drain(&bio->rbuf, linelen); } r = bufio_drain_sync(bio, buf, MINIMUM(*chunksz, bufsz)); if (r == 0) { break; } ret += r; buf += r; bufsz -= r; *chunksz -= r; } return ret; } static int http_chunk(struct bufio *bio, const void *buf, size_t len) { int r; if (bufio_compose_fmt(bio, "%zx\r\n", len) == -1 || bufio_compose(bio, buf, len) == -1 || bufio_compose(bio, "\r\n", 2) == -1) return 1; do { r = bufio_write(bio); if (r == -1 && errno != EAGAIN) errx(1, "bufio_read: %s", bufio_io_err(bio)); } while (bio->wbuf.len != 0); return 0; } static int get_refs(int https, const char *host, const char *port, const char *path) { struct bufio bio; char buf[GOT_PKT_MAX]; const struct got_error *e; size_t chunksz = 0; ssize_t r; int skip; int chunked; int sock; int ret = -1; if ((sock = dial(https, host, port)) == -1) return -1; if (bufio_init(&bio)) { warnx("bufio_init"); goto err; } bufio_set_fd(&bio, sock); if (https && bufio_starttls(&bio, host, 0, NULL, 0, NULL, 0) == -1) { warnx("bufio_starttls"); goto err; } if (http_open(&bio, https, "GET", host, port, path, "info/refs", "service=git-upload-pack", NULL) == -1) goto err; /* Fetch the initial reference announcement from the server. */ if (http_parse_reply(&bio, &chunked, UPLOAD_PACK_ADV) == -1) goto err; /* skip first pack; why git over http is like this? */ r = http_read(&bio, chunked, &chunksz, buf, 4); if (r <= 0) goto err; e = got_pkt_readlen(&skip, buf, verbose); if (e) { warnx("%s", e->msg); goto err; } /* TODO: validate it's # service=git-upload-pack\n */ while (skip > 0) { r = http_read(&bio, chunked, &chunksz, buf, MINIMUM(skip, sizeof(buf))); if (r <= 0) goto err; skip -= r; } for (;;) { r = http_read(&bio, chunked, &chunksz, buf, sizeof(buf)); if (r == -1) goto err; if (r == 0) break; fwrite(buf, 1, r, stdout); } fflush(stdout); ret = 0; err: bufio_close_sync(&bio); bufio_free(&bio); return ret; } static int upload_request(int https, const char *host, const char *port, const char *path, FILE *in) { struct bufio bio; char buf[GOT_PKT_MAX]; const struct got_error *e; ssize_t r; size_t chunksz = 0; int t; int chunked; int sock; int ret = -1; if ((sock = dial(https, host, port)) == -1) return -1; if (bufio_init(&bio)) { warnx("bufio_init"); goto err; } bufio_set_fd(&bio, sock); if (https && bufio_starttls(&bio, host, 0, NULL, 0, NULL, 0) == -1) { warnx("bufio_starttls"); goto err; } #ifndef PROFILE /* TODO: can we push this upwards such that get_refs() is covered? */ if (pledge("stdio", NULL) == -1) err(1, "pledge"); #endif if (http_open(&bio, https, "POST", host, port, path, "git-upload-pack", NULL, UPLOAD_PACK_REQ) == -1) goto err; /* * Read have/want lines generated by got-fetch-pack and forward * them to the server in the POST request body. */ for (;;) { r = fread(buf, 1, 4, in); if (r != 4) goto err; e = got_pkt_readlen(&t, buf, verbose); if (e) { warnx("%s", e->msg); goto err; } if (t == 0) { const char *flushpkt = "0000"; if (http_chunk(&bio, flushpkt, strlen(flushpkt))) goto err; continue; /* got-fetch-pack will send "done" */ } if (t < 6) { warnx("pktline len is too small"); goto err; } r = fread(buf + 4, 1, t - 4, in); if (r != t - 4) goto err; if (http_chunk(&bio, buf, t)) goto err; /* * Once got-fetch-pack is done the server will * send pack file data. */ if (t == 9 && strncmp(buf + 4, "done\n", 5) == 0) { if (http_chunk(&bio, NULL, 0)) goto err; break; } } if (http_parse_reply(&bio, &chunked, UPLOAD_PACK_RES) == -1) goto err; /* Fetch pack file data from server. */ for (;;) { r = http_read(&bio, chunked, &chunksz, buf, sizeof(buf)); if (r == -1) goto err; if (r == 0) break; fwrite(buf, 1, r, stdout); } ret = 0; err: bufio_close_sync(&bio); bufio_free(&bio); return ret; } static __dead void usage(void) { fprintf(stderr, "usage: %s [-qv] proto host port path\n", getprogname()); exit(1); } int main(int argc, char **argv) { struct pollfd pfd; const char *host, *port; char *path; int https = 0; int ch; #ifndef PROFILE if (pledge("stdio rpath inet dns unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "qv")) != -1) { switch (ch) { case 'q': verbose = -1; break; case 'v': verbose++; break; default: usage(); } } argc -= optind; argv += optind; if (argc != 4) usage(); https = strcmp(argv[0], "https") == 0; #ifndef PROFILE if (https) { if (unveil("/etc/ssl/cert.pem", "r") == -1) err(1, "unveil /etc/ssl/cert.pem"); } else { /* drop "rpath" */ if (pledge("stdio inet dns unveil", NULL) == -1) err(1, "pledge"); } #else if (unveil("gmon.out", "rwc") != 0) err(1, "unveil gmon.out"); #endif if (unveil(NULL, NULL) == -1) err(1, "unveil NULL"); host = argv[1]; port = argv[2]; path = argv[3]; got_path_strip_trailing_slashes(path); if (get_refs(https, host, port, path) == -1) errx(1, "failed to get refs"); pfd.fd = 0; pfd.events = POLLIN; if (poll(&pfd, 1, INFTIM) == -1) err(1, "poll"); if ((ch = fgetc(stdin)) == EOF) return 0; ungetc(ch, stdin); if (upload_request(https, host, port, path, stdin) == -1) { fflush(tmp); errx(1, "failed to upload request"); } return 0; } got-portable-0.101/libexec/got-read-tree/0000775000175100017510000000000014644145571013744 5got-portable-0.101/libexec/got-read-tree/Makefile.am0000664000175100017510000000121514644144735015720 libexec_PROGRAMS = got-read-tree include $(top_builddir)/Makefile.common got_read_tree_SOURCES = got-read-tree.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_tree_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.101/libexec/got-read-tree/Makefile.in0000664000175100017510000005706514644145544015746 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-read-tree$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-read-tree ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_read_tree_OBJECTS = got-read-tree.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) got_read_tree_OBJECTS = $(am_got_read_tree_OBJECTS) got_read_tree_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ ./$(DEPDIR)/got-read-tree.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_read_tree_SOURCES) DIST_SOURCES = $(got_read_tree_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_read_tree_SOURCES = got-read-tree.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_tree_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-read-tree/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-read-tree/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files clean-libexecPROGRAMS: -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: > $(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: > $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-read-tree$(EXEEXT): $(got_read_tree_OBJECTS) $(got_read_tree_DEPENDENCIES) $(EXTRA_got_read_tree_DEPENDENCIES) @rm -f got-read-tree$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_read_tree_OBJECTS) $(got_read_tree_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-read-tree.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-tree.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-tree.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/libexec/got-read-tree/got-read-tree.c0000664000175100017510000000713214644144735016473 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_lib_delta.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_privsep.h" #include "got_lib_hash.h" static volatile sig_atomic_t sigint_received; static void catch_sigint(int signo) { sigint_received = 1; } int main(int argc, char *argv[]) { const struct got_error *err = NULL; struct imsgbuf ibuf; size_t datalen; struct got_parsed_tree_entry *entries = NULL; size_t nentries = 0, nentries_alloc = 0; signal(SIGINT, catch_sigint); imsg_init(&ibuf, GOT_IMSG_FD_CHILD); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif for (;;) { struct imsg imsg; uint8_t *buf = NULL; struct got_object_id expected_id; int fd = -1; if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); break; } err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; break; } if (imsg.hdr.type == GOT_IMSG_STOP) break; if (imsg.hdr.type != GOT_IMSG_TREE_REQUEST) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(expected_id)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&expected_id, imsg.data, sizeof(expected_id)); fd = imsg_get_fd(&imsg); if (fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } /* Always assume file offset zero. */ err = got_object_read_tree(&entries, &nentries, &nentries_alloc, &buf, fd, &expected_id); if (err) goto done; err = got_privsep_send_tree(&ibuf, entries, nentries); done: free(buf); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); imsg_free(&imsg); if (err) break; } free(entries); imsg_clear(&ibuf); if (err) { if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); } } if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL) err = got_error_from_errno("close"); return err ? 1 : 0; } got-portable-0.101/libexec/got-read-blob/0000775000175100017510000000000014644145570013722 5got-portable-0.101/libexec/got-read-blob/Makefile.am0000664000175100017510000000121514644144735015677 libexec_PROGRAMS = got-read-blob include $(top_builddir)/Makefile.common got_read_blob_SOURCES = got-read-blob.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_blob_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.101/libexec/got-read-blob/Makefile.in0000664000175100017510000005706514644145543015724 # Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-read-blob$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-read-blob ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_read_blob_OBJECTS = got-read-blob.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) got_read_blob_OBJECTS = $(am_got_read_blob_OBJECTS) got_read_blob_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ ./$(DEPDIR)/got-read-blob.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_read_blob_SOURCES) DIST_SOURCES = $(got_read_blob_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_read_blob_SOURCES = got-read-blob.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_blob_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-read-blob/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-read-blob/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files clean-libexecPROGRAMS: -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: > $(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: > $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-read-blob$(EXEEXT): $(got_read_blob_OBJECTS) $(got_read_blob_DEPENDENCIES) $(EXTRA_got_read_blob_DEPENDENCIES) @rm -f got-read-blob$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_read_blob_OBJECTS) $(got_read_blob_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-read-blob.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -test -z "$(top_builddir)/lib/$(am__dirstamp)" || rm -f $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-blob.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-blob.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: got-portable-0.101/libexec/got-read-blob/got-read-blob.c0000664000175100017510000001226214644144735016431 /* * Copyright (c) 2018, 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_lib_delta.h" #include "got_lib_hash.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_privsep.h" static volatile sig_atomic_t sigint_received; static void catch_sigint(int signo) { sigint_received = 1; } int main(int argc, char *argv[]) { const struct got_error *err = NULL; struct imsgbuf ibuf; size_t datalen; signal(SIGINT, catch_sigint); imsg_init(&ibuf, GOT_IMSG_FD_CHILD); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif for (;;) { struct imsg imsg, imsg_outfd; FILE *f = NULL; int fd = -1, outfd = -1; size_t size; struct got_object *obj = NULL; uint8_t *buf = NULL; struct got_object_id id; struct got_object_id expected_id; struct got_inflate_checksum csum; struct got_hash ctx; got_hash_init(&ctx, GOT_HASH_SHA1); memset(&csum, 0, sizeof(csum)); csum.output_ctx = &ctx; memset(&imsg, 0, sizeof(imsg)); memset(&imsg_outfd, 0, sizeof(imsg_outfd)); if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); break; } err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; break; } if (imsg.hdr.type == GOT_IMSG_STOP) break; if (imsg.hdr.type != GOT_IMSG_BLOB_REQUEST) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(expected_id)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&expected_id, imsg.data, sizeof(expected_id)); fd = imsg_get_fd(&imsg); if (fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } err = got_privsep_recv_imsg(&imsg_outfd, &ibuf, 0); if (err) { if (imsg.hdr.len == 0) err = NULL; break; } if (imsg_outfd.hdr.type == GOT_IMSG_STOP) break; if (imsg_outfd.hdr.type != GOT_IMSG_BLOB_OUTFD) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg_outfd.hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } outfd = imsg_get_fd(&imsg_outfd); if (outfd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } err = got_object_read_header(&obj, fd); if (err) goto done; if (lseek(fd, SEEK_SET, 0) == -1) { err = got_error_from_errno("lseek"); goto done; } f = fdopen(fd, "rb"); if (f == NULL) { err = got_error_from_errno("fdopen"); goto done; } fd = -1; if (obj->size + obj->hdrlen <= GOT_PRIVSEP_INLINE_BLOB_DATA_MAX) { err = got_inflate_to_mem(&buf, &size, NULL, &csum, f); if (err) goto done; } else { err = got_inflate_to_fd(&size, f, &csum, outfd); if (err) goto done; } got_hash_final_object_id(&ctx, &id); if (got_object_id_cmp(&expected_id, &id) != 0) { err = got_error_checksum(&expected_id); goto done; } if (size < obj->hdrlen) { err = got_error(GOT_ERR_BAD_OBJ_HDR); goto done; } err = got_privsep_send_blob(&ibuf, size, obj->hdrlen, buf); done: free(buf); if (f && fclose(f) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (outfd != -1 && close(outfd) == -1 && err == NULL) err = got_error_from_errno("close"); imsg_free(&imsg); imsg_free(&imsg_outfd); if (obj) got_object_close(obj); if (err) break; } imsg_clear(&ibuf); if (err) { if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); } } if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL) err = got_error_from_errno("close"); return err ? 1 : 0; } got-portable-0.101/lib/0000775000175100017510000000000014644145570010437 5got-portable-0.101/lib/diff_patience.c0000644000175100017510000004547014644143163013307 /* Implementation of the Patience Diff algorithm invented by Bram Cohen: * Divide a diff problem into smaller chunks by an LCS (Longest Common Sequence) * of common-unique lines. */ /* * Copyright (c) 2020 Neels Hofmeyr * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include "diff_internal.h" #include "diff_debug.h" /* Algorithm to find unique lines: * 0: stupidly iterate atoms * 1: qsort * 2: mergesort */ #define UNIQUE_STRATEGY 1 /* Per-atom state for the Patience Diff algorithm */ struct atom_patience { #if UNIQUE_STRATEGY == 0 bool unique_here; #endif bool unique_in_both; struct diff_atom *pos_in_other; struct diff_atom *prev_stack; struct diff_range identical_lines; }; /* A diff_atom has a backpointer to the root diff_data. That points to the * current diff_data, a possibly smaller section of the root. That current * diff_data->algo_data is a pointer to an array of struct atom_patience. The * atom's index in current diff_data gives the index in the atom_patience array. */ #define PATIENCE(ATOM) \ (((struct atom_patience*)((ATOM)->root->current->algo_data))\ [diff_atom_idx((ATOM)->root->current, ATOM)]) #if UNIQUE_STRATEGY == 0 /* Stupid iteration and comparison of all atoms */ static int diff_atoms_mark_unique(struct diff_data *d, unsigned int *unique_count) { struct diff_atom *i; unsigned int count = 0; diff_data_foreach_atom(i, d) { PATIENCE(i).unique_here = true; PATIENCE(i).unique_in_both = true; count++; } diff_data_foreach_atom(i, d) { struct diff_atom *j; if (!PATIENCE(i).unique_here) continue; diff_data_foreach_atom_from(i + 1, j, d) { bool same; int r = diff_atom_same(&same, i, j); if (r) return r; if (!same) continue; if (PATIENCE(i).unique_here) { PATIENCE(i).unique_here = false; PATIENCE(i).unique_in_both = false; count--; } PATIENCE(j).unique_here = false; PATIENCE(j).unique_in_both = false; count--; } } if (unique_count) *unique_count = count; return 0; } /* Mark those lines as PATIENCE(atom).unique_in_both = true that appear exactly * once in each side. */ static int diff_atoms_mark_unique_in_both(struct diff_data *left, struct diff_data *right, unsigned int *unique_in_both_count) { /* Derive the final unique_in_both count without needing an explicit * iteration. So this is just some optimiziation to save one iteration * in the end. */ unsigned int unique_in_both; int r; r = diff_atoms_mark_unique(left, &unique_in_both); if (r) return r; r = diff_atoms_mark_unique(right, NULL); if (r) return r; debug("unique_in_both %u\n", unique_in_both); struct diff_atom *i; diff_data_foreach_atom(i, left) { if (!PATIENCE(i).unique_here) continue; struct diff_atom *j; int found_in_b = 0; diff_data_foreach_atom(j, right) { bool same; int r = diff_atom_same(&same, i, j); if (r) return r; if (!same) continue; if (!PATIENCE(j).unique_here) { found_in_b = 2; /* or more */ break; } else { found_in_b = 1; PATIENCE(j).pos_in_other = i; PATIENCE(i).pos_in_other = j; } } if (found_in_b == 0 || found_in_b > 1) { PATIENCE(i).unique_in_both = false; unique_in_both--; debug("unique_in_both %u (%d) ", unique_in_both, found_in_b); debug_dump_atom(left, NULL, i); } } /* Still need to unmark right[*]->patience.unique_in_both for atoms that * don't exist in left */ diff_data_foreach_atom(i, right) { if (!PATIENCE(i).unique_here || !PATIENCE(i).unique_in_both) continue; struct diff_atom *j; bool found_in_a = false; diff_data_foreach_atom(j, left) { bool same; int r; if (!PATIENCE(j).unique_in_both) continue; r = diff_atom_same(&same, i, j); if (r) return r; if (!same) continue; found_in_a = true; break; } if (!found_in_a) PATIENCE(i).unique_in_both = false; } if (unique_in_both_count) *unique_in_both_count = unique_in_both; return 0; } #else /* UNIQUE_STRATEGY != 0 */ /* Use an optimized sorting algorithm (qsort, mergesort) to find unique lines */ static int diff_atoms_compar(const void *_a, const void *_b) { const struct diff_atom *a = *(struct diff_atom**)_a; const struct diff_atom *b = *(struct diff_atom**)_b; int cmp; int rc = 0; /* If there's been an error (e.g. I/O error) in a previous compar, we * have no way to abort the sort but just report the rc and stop * comparing. Make sure to catch errors on either side. If atoms are * from more than one diff_data, make sure the error, if any, spreads * to all of them, so we can cut short all future comparisons. */ if (a->root->err) rc = a->root->err; if (b->root->err) rc = b->root->err; if (rc) { a->root->err = rc; b->root->err = rc; /* just return 'equal' to not swap more positions */ return 0; } /* Sort by the simplistic hash */ if (a->hash < b->hash) return -1; if (a->hash > b->hash) return 1; /* If hashes are the same, the lines may still differ. Do a full cmp. */ rc = diff_atom_cmp(&cmp, a, b); if (rc) { /* Mark the I/O error so that the caller can find out about it. * For the case atoms are from more than one diff_data, mark in * both. */ a->root->err = rc; if (a->root != b->root) b->root->err = rc; return 0; } return cmp; } /* Sort an array of struct diff_atom* in-place. */ static int diff_atoms_sort(struct diff_atom *atoms[], size_t atoms_count) { #if UNIQUE_STRATEGY == 1 qsort(atoms, atoms_count, sizeof(struct diff_atom*), diff_atoms_compar); #else mergesort(atoms, atoms_count, sizeof(struct diff_atom*), diff_atoms_compar); #endif return atoms[0]->root->err; } static int diff_atoms_mark_unique_in_both(struct diff_data *left, struct diff_data *right, unsigned int *unique_in_both_count_p) { struct diff_atom *a; struct diff_atom *b; struct diff_atom **all_atoms; unsigned int len = 0; unsigned int i; unsigned int unique_in_both_count = 0; int rc; all_atoms = calloc(left->atoms.len + right->atoms.len, sizeof(struct diff_atom *)); if (all_atoms == NULL) return ENOMEM; left->err = 0; right->err = 0; left->root->err = 0; right->root->err = 0; diff_data_foreach_atom(a, left) { all_atoms[len++] = a; } diff_data_foreach_atom(b, right) { all_atoms[len++] = b; } rc = diff_atoms_sort(all_atoms, len); if (rc) goto free_and_exit; /* Now we have a sorted array of atom pointers. All similar lines are * adjacent. Walk through the array and mark those that are unique on * each side, but exist once in both sources. */ for (i = 0; i < len; i++) { bool same; unsigned int next_differing_i; unsigned int last_identical_i; unsigned int j; unsigned int count_first_side = 1; unsigned int count_other_side = 0; a = all_atoms[i]; debug("a: "); debug_dump_atom(a->root, NULL, a); /* Do as few diff_atom_cmp() as possible: first walk forward * only using the cheap hash as indicator for differing atoms; * then walk backwards until hitting an identical atom. */ for (next_differing_i = i + 1; next_differing_i < len; next_differing_i++) { b = all_atoms[next_differing_i]; if (a->hash != b->hash) break; } for (last_identical_i = next_differing_i - 1; last_identical_i > i; last_identical_i--) { b = all_atoms[last_identical_i]; rc = diff_atom_same(&same, a, b); if (rc) goto free_and_exit; if (same) break; } next_differing_i = last_identical_i + 1; for (j = i+1; j < next_differing_i; j++) { b = all_atoms[j]; /* A following atom is the same. See on which side the * repetition counts. */ if (a->root == b->root) count_first_side ++; else count_other_side ++; debug("b: "); debug_dump_atom(b->root, NULL, b); debug(" count_first_side=%d count_other_side=%d\n", count_first_side, count_other_side); } /* Counted a section of similar atoms, put the results back to * the atoms. */ if ((count_first_side == 1) && (count_other_side == 1)) { b = all_atoms[i+1]; PATIENCE(a).unique_in_both = true; PATIENCE(a).pos_in_other = b; PATIENCE(b).unique_in_both = true; PATIENCE(b).pos_in_other = a; unique_in_both_count++; } /* j now points at the first atom after 'a' that is not * identical to 'a'. j is always > i. */ i = j - 1; } *unique_in_both_count_p = unique_in_both_count; rc = 0; free_and_exit: free(all_atoms); return rc; } #endif /* UNIQUE_STRATEGY != 0 */ /* binary search to find the stack to put this atom "card" on. */ static int find_target_stack(struct diff_atom *atom, struct diff_atom **patience_stacks, unsigned int patience_stacks_count) { unsigned int lo = 0; unsigned int hi = patience_stacks_count; while (lo < hi) { unsigned int mid = (lo + hi) >> 1; if (PATIENCE(patience_stacks[mid]).pos_in_other < PATIENCE(atom).pos_in_other) lo = mid + 1; else hi = mid; } return lo; } /* Among the lines that appear exactly once in each side, find the longest * streak that appear in both files in the same order (with other stuff allowed * to interleave). Use patience sort for that, as in the Patience Diff * algorithm. * See https://bramcohen.livejournal.com/73318.html and, for a much more * detailed explanation, * https://blog.jcoglan.com/2017/09/19/the-patience-diff-algorithm/ */ int diff_algo_patience(const struct diff_algo_config *algo_config, struct diff_state *state) { int rc; struct diff_data *left = &state->left; struct diff_data *right = &state->right; struct atom_patience *atom_patience_left = calloc(left->atoms.len, sizeof(struct atom_patience)); struct atom_patience *atom_patience_right = calloc(right->atoms.len, sizeof(struct atom_patience)); unsigned int unique_in_both_count; struct diff_atom **lcs = NULL; debug("\n** %s\n", __func__); left->root->current = left; right->root->current = right; left->algo_data = atom_patience_left; right->algo_data = atom_patience_right; /* Find those lines that appear exactly once in 'left' and exactly once * in 'right'. */ rc = diff_atoms_mark_unique_in_both(left, right, &unique_in_both_count); if (rc) goto free_and_exit; debug("unique_in_both_count %u\n", unique_in_both_count); debug("left:\n"); debug_dump(left); debug("right:\n"); debug_dump(right); if (!unique_in_both_count) { /* Cannot apply Patience, tell the caller to use fallback_algo * instead. */ rc = DIFF_RC_USE_DIFF_ALGO_FALLBACK; goto free_and_exit; } rc = ENOMEM; /* An array of Longest Common Sequence is the result of the below * subscope: */ unsigned int lcs_count = 0; struct diff_atom *lcs_tail = NULL; { /* This subscope marks the lifetime of the atom_pointers * allocation */ /* One chunk of storage for atom pointers */ struct diff_atom **atom_pointers; atom_pointers = recallocarray(NULL, 0, unique_in_both_count * 2, sizeof(struct diff_atom*)); if (atom_pointers == NULL) return ENOMEM; /* Half for the list of atoms that still need to be put on * stacks */ struct diff_atom **uniques = atom_pointers; /* Half for the patience sort state's "card stacks" -- we * remember only each stack's topmost "card" */ struct diff_atom **patience_stacks; patience_stacks = atom_pointers + unique_in_both_count; unsigned int patience_stacks_count = 0; /* Take all common, unique items from 'left' ... */ struct diff_atom *atom; struct diff_atom **uniques_end = uniques; diff_data_foreach_atom(atom, left) { if (!PATIENCE(atom).unique_in_both) continue; *uniques_end = atom; uniques_end++; } /* ...and sort them to the order found in 'right'. * The idea is to find the leftmost stack that has a higher line * number and add it to the stack's top. * If there is no such stack, open a new one on the right. The * line number is derived from the atom*, which are array items * and hence reflect the relative position in the source file. * So we got the common-uniques from 'left' and sort them * according to PATIENCE(atom).pos_in_other. */ unsigned int i; for (i = 0; i < unique_in_both_count; i++) { atom = uniques[i]; unsigned int target_stack; target_stack = find_target_stack(atom, patience_stacks, patience_stacks_count); assert(target_stack <= patience_stacks_count); patience_stacks[target_stack] = atom; if (target_stack == patience_stacks_count) patience_stacks_count++; /* Record a back reference to the next stack on the * left, which will form the final longest sequence * later. */ PATIENCE(atom).prev_stack = target_stack ? patience_stacks[target_stack - 1] : NULL; { int xx; for (xx = 0; xx < patience_stacks_count; xx++) { debug(" %s%d", (xx == target_stack) ? ">" : "", diff_atom_idx(right, PATIENCE(patience_stacks[xx]).pos_in_other)); } debug("\n"); } } /* backtrace through prev_stack references to form the final * longest common sequence */ lcs_tail = patience_stacks[patience_stacks_count - 1]; lcs_count = patience_stacks_count; /* uniques and patience_stacks are no longer needed. * Backpointers are in PATIENCE(atom).prev_stack */ free(atom_pointers); } lcs = recallocarray(NULL, 0, lcs_count, sizeof(struct diff_atom*)); struct diff_atom **lcs_backtrace_pos = &lcs[lcs_count - 1]; struct diff_atom *atom; for (atom = lcs_tail; atom; atom = PATIENCE(atom).prev_stack, lcs_backtrace_pos--) { assert(lcs_backtrace_pos >= lcs); *lcs_backtrace_pos = atom; } unsigned int i; if (DEBUG) { debug("\npatience LCS:\n"); for (i = 0; i < lcs_count; i++) { debug("\n L "); debug_dump_atom(left, right, lcs[i]); debug(" R "); debug_dump_atom(right, left, PATIENCE(lcs[i]).pos_in_other); } } /* TODO: For each common-unique line found (now listed in lcs), swallow * lines upwards and downwards that are identical on each side. Requires * a way to represent atoms being glued to adjacent atoms. */ debug("\ntraverse LCS, possibly recursing:\n"); /* Now we have pinned positions in both files at which it makes sense to * divide the diff problem into smaller chunks. Go into the next round: * look at each section in turn, trying to again find common-unique * lines in those smaller sections. As soon as no more are found, the * remaining smaller sections are solved by Myers. */ /* left_pos and right_pos are indexes in left/right->atoms.head until * which the atoms are already handled (added to result chunks). */ unsigned int left_pos = 0; unsigned int right_pos = 0; for (i = 0; i <= lcs_count; i++) { struct diff_atom *atom; struct diff_atom *atom_r; /* left_idx and right_idx are indexes of the start of this * section of identical lines on both sides. * left_pos marks the index of the first still unhandled line, * left_idx is the start of an identical section some way * further down, and this loop adds an unsolved chunk of * [left_pos..left_idx[ and a solved chunk of * [left_idx..identical_lines.end[. */ unsigned int left_idx; unsigned int right_idx; debug("iteration %u of %u left_pos %u right_pos %u\n", i, lcs_count, left_pos, right_pos); if (i < lcs_count) { atom = lcs[i]; atom_r = PATIENCE(atom).pos_in_other; debug("lcs[%u] = left[%u] = right[%u]\n", i, diff_atom_idx(left, atom), diff_atom_idx(right, atom_r)); left_idx = diff_atom_idx(left, atom); right_idx = diff_atom_idx(right, atom_r); } else { /* There are no more identical lines until the end of * left and right. */ atom = NULL; atom_r = NULL; left_idx = left->atoms.len; right_idx = right->atoms.len; } /* 'atom' (if not NULL) now marks an atom that matches on both * sides according to patience-diff (a common-unique identical * atom in both files). * Handle the section before and the atom itself; the section * after will be handled by the next loop iteration -- note that * i loops to last element + 1 ("i <= lcs_count"), so that there * will be another final iteration to pick up the last remaining * items after the last LCS atom. */ debug("iteration %u left_pos %u left_idx %u" " right_pos %u right_idx %u\n", i, left_pos, left_idx, right_pos, right_idx); /* Section before the matching atom */ struct diff_atom *left_atom = &left->atoms.head[left_pos]; unsigned int left_section_len = left_idx - left_pos; struct diff_atom *right_atom = &(right->atoms.head[right_pos]); unsigned int right_section_len = right_idx - right_pos; if (left_section_len && right_section_len) { /* Record an unsolved chunk, the caller will apply * inner_algo() on this chunk. */ if (!diff_state_add_chunk(state, false, left_atom, left_section_len, right_atom, right_section_len)) goto free_and_exit; } else if (left_section_len && !right_section_len) { /* Only left atoms and none on the right, they form a * "minus" chunk, then. */ if (!diff_state_add_chunk(state, true, left_atom, left_section_len, right_atom, 0)) goto free_and_exit; } else if (!left_section_len && right_section_len) { /* No left atoms, only atoms on the right, they form a * "plus" chunk, then. */ if (!diff_state_add_chunk(state, true, left_atom, 0, right_atom, right_section_len)) goto free_and_exit; } /* else: left_section_len == 0 and right_section_len == 0, i.e. * nothing here. */ /* The atom found to match on both sides forms a chunk of equals * on each side. In the very last iteration of this loop, there * is no matching atom, we were just cleaning out the remaining * lines. */ if (atom) { void *ok; ok = diff_state_add_chunk(state, true, atom, 1, PATIENCE(atom).pos_in_other, 1); if (!ok) goto free_and_exit; } left_pos = left_idx + 1; right_pos = right_idx + 1; debug("end of iteration %u left_pos %u left_idx %u" " right_pos %u right_idx %u\n", i, left_pos, left_idx, right_pos, right_idx); } debug("** END %s\n", __func__); rc = DIFF_RC_OK; free_and_exit: left->root->current = NULL; right->root->current = NULL; free(atom_patience_left); free(atom_patience_right); if (lcs) free(lcs); return rc; } got-portable-0.101/lib/got_lib_fileindex.h0000644000175100017510000001706714644143163014203 /* * Copyright (c) 2018, 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * State information for a tracked file in a work tree. * When written to disk, multi-byte fields are written in big-endian. * Some fields are based on results from stat(2). These are only used in * order to detect modifications made to on-disk files, they are never * applied back to the filesystem. */ struct got_fileindex_entry { RB_ENTRY(got_fileindex_entry) entry; uint64_t ctime_sec; uint64_t ctime_nsec; uint64_t mtime_sec; uint64_t mtime_nsec; uint32_t uid; uint32_t gid; /* * On-disk size is truncated to the lower 32 bits. * The value is only used to check for modifications anyway. */ uint32_t size; uint16_t mode; #define GOT_FILEIDX_MODE_FILE_TYPE 0x000f #define GOT_FILEIDX_MODE_FILE_TYPE_ONDISK 0x0003 #define GOT_FILEIDX_MODE_FILE_TYPE_STAGED 0x000c #define GOT_FILEIDX_MODE_FILE_TYPE_STAGED_SHIFT 2 #define GOT_FILEIDX_MODE_REGULAR_FILE 1 #define GOT_FILEIDX_MODE_SYMLINK 2 #define GOT_FILEIDX_MODE_BAD_SYMLINK 3 #define GOT_FILEIDX_MODE_PERMS 0xfff0 #define GOT_FILEIDX_MODE_PERMS_SHIFT 4 /* SHA1 of corresponding blob in repository. */ uint8_t blob_sha1[SHA1_DIGEST_LENGTH]; /* SHA1 of corresponding base commit in repository. */ uint8_t commit_sha1[SHA1_DIGEST_LENGTH]; uint32_t flags; /* * UNIX-style path, relative to work tree root. * Variable length, and NUL-padded to a multiple of 8 on disk. */ char *path; /* * (since GOT_FILE_INDEX_VERSION 2) * SHA1 of staged blob in repository if stage equals either * GOT_FILEIDX_STAGE_MODIFY or GOT_FILEIDX_STAGE_ADD. * Otherwise, this field is not written to disk. */ uint8_t staged_blob_sha1[SHA1_DIGEST_LENGTH]; }; /* Modifications explicitly staged for commit. */ #define GOT_FILEIDX_STAGE_NONE 0 #define GOT_FILEIDX_STAGE_MODIFY 1 #define GOT_FILEIDX_STAGE_ADD 2 #define GOT_FILEIDX_STAGE_DELETE 3 struct got_fileindex; RB_HEAD(got_fileindex_tree, got_fileindex_entry); size_t got_fileindex_entry_path_len(const struct got_fileindex_entry *); static inline int got_fileindex_cmp(const struct got_fileindex_entry *e1, const struct got_fileindex_entry *e2) { return got_path_cmp(e1->path, e2->path, got_fileindex_entry_path_len(e1), got_fileindex_entry_path_len(e2)); } RB_PROTOTYPE(got_fileindex_tree, got_fileindex_entry, entry, got_fileindex_cmp); /* On-disk file index header structure. */ struct got_fileindex_hdr { uint32_t signature; /* big-endian */ #define GOT_FILE_INDEX_SIGNATURE 0x676f7449 /* 'g', 'o', 't', 'I' */ uint32_t version; /* big-endian */ #define GOT_FILE_INDEX_VERSION 2 uint32_t nentries; /* big-endian */ /* list of concatenated fileindex entries */ uint8_t sha1[SHA1_DIGEST_LENGTH]; /* checksum of above on-disk data */ }; mode_t got_fileindex_entry_perms_get(struct got_fileindex_entry *); uint16_t got_fileindex_perms_from_st(struct stat *); mode_t got_fileindex_perms_to_st(struct got_fileindex_entry *); const struct got_error *got_fileindex_entry_update(struct got_fileindex_entry *, int, const char *, uint8_t *, uint8_t *, int); void got_fileindex_entry_mark_skipped(struct got_fileindex_entry *); const struct got_error *got_fileindex_entry_alloc(struct got_fileindex_entry **, const char *); void got_fileindex_entry_free(struct got_fileindex_entry *); struct got_fileindex *got_fileindex_alloc(void); void got_fileindex_free(struct got_fileindex *); const struct got_error *got_fileindex_write(struct got_fileindex *, FILE *); const struct got_error *got_fileindex_entry_add(struct got_fileindex *, struct got_fileindex_entry *); void got_fileindex_entry_remove(struct got_fileindex *, struct got_fileindex_entry *); struct got_fileindex_entry *got_fileindex_entry_get(struct got_fileindex *, const char *, size_t); const struct got_error *got_fileindex_read(struct got_fileindex *, FILE *); typedef const struct got_error *(*got_fileindex_cb)(void *, struct got_fileindex_entry *); const struct got_error *got_fileindex_for_each_entry_safe( struct got_fileindex *, got_fileindex_cb cb, void *); typedef const struct got_error *(*got_fileindex_diff_tree_old_new_cb)(void *, struct got_fileindex_entry *, struct got_tree_entry *, const char *); typedef const struct got_error *(*got_fileindex_diff_tree_old_cb)(void *, struct got_fileindex_entry *, const char *); typedef const struct got_error *(*got_fileindex_diff_tree_new_cb)(void *, struct got_tree_entry *, const char *); struct got_fileindex_diff_tree_cb { got_fileindex_diff_tree_old_new_cb diff_old_new; got_fileindex_diff_tree_old_cb diff_old; got_fileindex_diff_tree_new_cb diff_new; }; const struct got_error *got_fileindex_diff_tree(struct got_fileindex *, struct got_tree_object *, const char *, const char *, struct got_repository *, struct got_fileindex_diff_tree_cb *, void *); typedef const struct got_error *(*got_fileindex_diff_dir_old_new_cb)(void *, struct got_fileindex_entry *, struct dirent *, const char *, int); typedef const struct got_error *(*got_fileindex_diff_dir_old_cb)(void *, struct got_fileindex_entry *, const char *); typedef const struct got_error *(*got_fileindex_diff_dir_new_cb)(int *, void *, struct dirent *, const char *, int); typedef const struct got_error *(*got_fileindex_diff_dir_traverse)(void *, const char *, int); struct got_fileindex_diff_dir_cb { got_fileindex_diff_dir_old_new_cb diff_old_new; got_fileindex_diff_dir_old_cb diff_old; got_fileindex_diff_dir_new_cb diff_new; got_fileindex_diff_dir_traverse diff_traverse; }; const struct got_error *got_fileindex_diff_dir(struct got_fileindex *, int, const char *, const char *, struct got_repository *, struct got_fileindex_diff_dir_cb *, void *); int got_fileindex_entry_has_blob(struct got_fileindex_entry *); int got_fileindex_entry_has_commit(struct got_fileindex_entry *); int got_fileindex_entry_has_file_on_disk(struct got_fileindex_entry *); int got_fileindex_entry_was_skipped(struct got_fileindex_entry *); uint32_t got_fileindex_entry_stage_get(const struct got_fileindex_entry *); void got_fileindex_entry_stage_set(struct got_fileindex_entry *ie, uint32_t); int got_fileindex_entry_filetype_get(struct got_fileindex_entry *); void got_fileindex_entry_filetype_set(struct got_fileindex_entry *, int); void got_fileindex_entry_staged_filetype_set(struct got_fileindex_entry *, int); int got_fileindex_entry_staged_filetype_get(struct got_fileindex_entry *); void got_fileindex_entry_mark_deleted_from_disk(struct got_fileindex_entry *); /* * Retrieve staged, blob or commit id from a fileindex entry, and return * the given object id. */ struct got_object_id *got_fileindex_entry_get_staged_blob_id( struct got_object_id *, struct got_fileindex_entry *); struct got_object_id *got_fileindex_entry_get_blob_id(struct got_object_id *, struct got_fileindex_entry *); struct got_object_id *got_fileindex_entry_get_commit_id(struct got_object_id *, struct got_fileindex_entry *); got-portable-0.101/lib/diff_myers.c0000664000175100017510000013003514644144735012656 /* Myers diff algorithm implementation, invented by Eugene W. Myers [1]. * Implementations of both the Myers Divide Et Impera (using linear space) * and the canonical Myers algorithm (using quadratic space). */ /* * Copyright (c) 2020 Neels Hofmeyr * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include "diff_internal.h" #include "diff_debug.h" /* Myers' diff algorithm [1] is nicely explained in [2]. * [1] http://www.xmailserver.org/diff2.pdf * [2] https://blog.jcoglan.com/2017/02/12/the-myers-diff-algorithm-part-1/ ff. * * Myers approaches finding the smallest diff as a graph problem. * The crux is that the original algorithm requires quadratic amount of memory: * both sides' lengths added, and that squared. So if we're diffing lines of * text, two files with 1000 lines each would blow up to a matrix of about * 2000 * 2000 ints of state, about 16 Mb of RAM to figure out 2 kb of text. * The solution is using Myers' "divide and conquer" extension algorithm, which * does the original traversal from both ends of the files to reach a middle * where these "snakes" touch, hence does not need to backtrace the traversal, * and so gets away with only keeping a single column of that huge state matrix * in memory. */ struct diff_box { unsigned int left_start; unsigned int left_end; unsigned int right_start; unsigned int right_end; }; /* If the two contents of a file are A B C D E and X B C Y, * the Myers diff graph looks like: * * k0 k1 * \ \ * k-1 0 1 2 3 4 5 * \ A B C D E * 0 o-o-o-o-o-o * X | | | | | | * 1 o-o-o-o-o-o * B | |\| | | | * 2 o-o-o-o-o-o * C | | |\| | | * 3 o-o-o-o-o-o * Y | | | | | |\ * 4 o-o-o-o-o-o c1 * \ \ * c-1 c0 * * Moving right means delete an atom from the left-hand-side, * Moving down means add an atom from the right-hand-side. * Diagonals indicate identical atoms on both sides, the challenge is to use as * many diagonals as possible. * * The original Myers algorithm walks all the way from the top left to the * bottom right, remembers all steps, and then backtraces to find the shortest * path. However, that requires keeping the entire graph in memory, which needs * quadratic space. * * Myers adds a variant that uses linear space -- note, not linear time, only * linear space: walk forward and backward, find a meeting point in the middle, * and recurse on the two separate sections. This is called "divide and * conquer". * * d: the step number, starting with 0, a.k.a. the distance from the starting * point. * k: relative index in the state array for the forward scan, indicating on * which diagonal through the diff graph we currently are. * c: relative index in the state array for the backward scan, indicating the * diagonal number from the bottom up. * * The "divide and conquer" traversal through the Myers graph looks like this: * * | d= 0 1 2 3 2 1 0 * ----+-------------------------------------------- * k= | c= * 4 | 3 * | * 3 | 3,0 5,2 2 * | / \ * 2 | 2,0 5,3 1 * | / \ * 1 | 1,0 4,3 >= 4,3 5,4<-- 0 * | / / \ / * 0 | -->0,0 3,3 4,4 -1 * | \ / / * -1 | 0,1 1,2 3,4 -2 * | \ / * -2 | 0,2 -3 * | \ * | 0,3 * | forward-> <-backward * * x,y pairs here are the coordinates in the Myers graph: * x = atom index in left-side source, y = atom index in the right-side source. * * Only one forward column and one backward column are kept in mem, each need at * most left.len + 1 + right.len items. Note that each d step occupies either * the even or the odd items of a column: if e.g. the previous column is in the * odd items, the next column is formed in the even items, without overwriting * the previous column's results. * * Also note that from the diagonal index k and the x coordinate, the y * coordinate can be derived: * y = x - k * Hence the state array only needs to keep the x coordinate, i.e. the position * in the left-hand file, and the y coordinate, i.e. position in the right-hand * file, is derived from the index in the state array. * * The two traces meet at 4,3, the first step (here found in the forward * traversal) where a forward position is on or past a backward traced position * on the same diagonal. * * This divides the problem space into: * * 0 1 2 3 4 5 * A B C D E * 0 o-o-o-o-o * X | | | | | * 1 o-o-o-o-o * B | |\| | | * 2 o-o-o-o-o * C | | |\| | * 3 o-o-o-o-*-o *: forward and backward meet here * Y | | * 4 o-o * * Doing the same on each section lead to: * * 0 1 2 3 4 5 * A B C D E * 0 o-o * X | | * 1 o-b b: backward d=1 first reaches here (sliding up the snake) * B \ f: then forward d=2 reaches here (sliding down the snake) * 2 o As result, the box from b to f is found to be identical; * C \ leaving a top box from 0,0 to 1,1 and a bottom trivial * 3 f-o tail 3,3 to 4,3. * * 3 o-* * Y | * 4 o *: forward and backward meet here * * and solving the last top left box gives: * * 0 1 2 3 4 5 * A B C D E -A * 0 o-o +X * X | B * 1 o C * B \ -D * 2 o -E * C \ +Y * 3 o-o-o * Y | * 4 o * */ #define xk_to_y(X, K) ((X) - (K)) #define xc_to_y(X, C, DELTA) ((X) - (C) + (DELTA)) #define k_to_c(K, DELTA) ((K) + (DELTA)) #define c_to_k(C, DELTA) ((C) - (DELTA)) /* Do one forwards step in the "divide and conquer" graph traversal. * left: the left side to diff. * right: the right side to diff against. * kd_forward: the traversal state for forwards traversal, modified by this * function. * This is carried over between invocations with increasing d. * kd_forward points at the center of the state array, allowing * negative indexes. * kd_backward: the traversal state for backwards traversal, to find a meeting * point. * Since forwards is done first, kd_backward will be valid for d - * 1, not d. * kd_backward points at the center of the state array, allowing * negative indexes. * d: Step or distance counter, indicating for what value of d the kd_forward * should be populated. * For d == 0, kd_forward[0] is initialized, i.e. the first invocation should * be for d == 0. * meeting_snake: resulting meeting point, if any. * Return true when a meeting point has been identified. */ static int diff_divide_myers_forward(bool *found_midpoint, struct diff_data *left, struct diff_data *right, int *kd_forward, int *kd_backward, int d, struct diff_box *meeting_snake) { int delta = (int)right->atoms.len - (int)left->atoms.len; int k; int x; int prev_x; int prev_y; int x_before_slide; *found_midpoint = false; for (k = d; k >= -d; k -= 2) { if (k < -(int)right->atoms.len || k > (int)left->atoms.len) { /* This diagonal is completely outside of the Myers * graph, don't calculate it. */ if (k < 0) { /* We are traversing negatively, and already * below the entire graph, nothing will come of * this. */ debug(" break\n"); break; } debug(" continue\n"); continue; } if (d == 0) { /* This is the initializing step. There is no prev_k * yet, get the initial x from the top left of the Myers * graph. */ x = 0; prev_x = x; prev_y = xk_to_y(x, k); } /* Favoring "-" lines first means favoring moving rightwards in * the Myers graph. * For this, all k should derive from k - 1, only the bottom * most k derive from k + 1: * * | d= 0 1 2 * ----+---------------- * k= | * 2 | 2,0 <-- from prev_k = 2 - 1 = 1 * | / * 1 | 1,0 * | / * 0 | -->0,0 3,3 * | \\ / * -1 | 0,1 <-- bottom most for d=1 from * | \\ prev_k = -1 + 1 = 0 * -2 | 0,2 <-- bottom most for d=2 from * prev_k = -2 + 1 = -1 * * Except when a k + 1 from a previous run already means a * further advancement in the graph. * If k == d, there is no k + 1 and k - 1 is the only option. * If k < d, use k + 1 in case that yields a larger x. Also use * k + 1 if k - 1 is outside the graph. */ else if (k > -d && (k == d || (k - 1 >= -(int)right->atoms.len && kd_forward[k - 1] >= kd_forward[k + 1]))) { /* Advance from k - 1. * From position prev_k, step to the right in the Myers * graph: x += 1. */ int prev_k = k - 1; prev_x = kd_forward[prev_k]; prev_y = xk_to_y(prev_x, prev_k); x = prev_x + 1; } else { /* The bottom most one. * From position prev_k, step to the bottom in the Myers * graph: y += 1. * Incrementing y is achieved by decrementing k while * keeping the same x. * (since we're deriving y from y = x - k). */ int prev_k = k + 1; prev_x = kd_forward[prev_k]; prev_y = xk_to_y(prev_x, prev_k); x = prev_x; } x_before_slide = x; /* Slide down any snake that we might find here. */ while (x < left->atoms.len && xk_to_y(x, k) < right->atoms.len) { bool same; int r = diff_atom_same(&same, &left->atoms.head[x], &right->atoms.head[ xk_to_y(x, k)]); if (r) return r; if (!same) break; x++; } kd_forward[k] = x; #if 0 if (x_before_slide != x) { debug(" down %d similar lines\n", x - x_before_slide); } #if DEBUG { int fi; for (fi = d; fi >= k; fi--) { debug("kd_forward[%d] = (%d, %d)\n", fi, kd_forward[fi], kd_forward[fi] - fi); } } #endif #endif if (x < 0 || x > left->atoms.len || xk_to_y(x, k) < 0 || xk_to_y(x, k) > right->atoms.len) continue; /* Figured out a new forwards traversal, see if this has gone * onto or even past a preceding backwards traversal. * * If the delta in length is odd, then d and backwards_d hit the * same state indexes: * | d= 0 1 2 1 0 * ----+---------------- ---------------- * k= | c= * 4 | 3 * | * 3 | 2 * | same * 2 | 2,0====5,3 1 * | / \ * 1 | 1,0 5,4<-- 0 * | / / * 0 | -->0,0 3,3====4,4 -1 * | \ / * -1 | 0,1 -2 * | \ * -2 | 0,2 -3 * | * * If the delta is even, they end up off-by-one, i.e. on * different diagonals: * * | d= 0 1 2 1 0 * ----+---------------- ---------------- * | c= * 3 | 3 * | * 2 | 2,0 off 2 * | / \\ * 1 | 1,0 4,3 1 * | / // \ * 0 | -->0,0 3,3 4,4<-- 0 * | \ / / * -1 | 0,1 3,4 -1 * | \ // * -2 | 0,2 -2 * | * * So in the forward path, we can only match up diagonals when * the delta is odd. */ if ((delta & 1) == 0) continue; /* Forwards is done first, so the backwards one was still at * d - 1. Can't do this for d == 0. */ int backwards_d = d - 1; if (backwards_d < 0) continue; /* If both sides have the same length, forward and backward * start on the same diagonal, meaning the backwards state index * c == k. * As soon as the lengths are not the same, the backwards * traversal starts on a different diagonal, and c = k shifted * by the difference in length. */ int c = k_to_c(k, delta); /* When the file sizes are very different, the traversal trees * start on far distant diagonals. * They don't necessarily meet straight on. See whether this * forward value is on a diagonal that is also valid in * kd_backward[], and match them if so. */ if (c >= -backwards_d && c <= backwards_d) { /* Current k is on a diagonal that exists in * kd_backward[]. If the two x positions have met or * passed (forward walked onto or past backward), then * we've found a midpoint / a mid-box. * * When forwards and backwards traversals meet, the * endpoints of the mid-snake are not the two points in * kd_forward and kd_backward, but rather the section * that was slid (if any) of the current * forward/backward traversal only. * * For example: * * o * \ * o * \ * o * \ * o * \ * X o o * | | | * o-o-o o * \| * M * \ * o * \ * A o * | | * o-o-o * * The forward traversal reached M from the top and slid * downwards to A. The backward traversal already * reached X, which is not a straight line from M * anymore, so picking a mid-snake from M to X would * yield a mistake. * * The correct mid-snake is between M and A. M is where * the forward traversal hit the diagonal that the * backward traversal has already passed, and A is what * it reaches when sliding down identical lines. */ int backward_x = kd_backward[c]; if (x >= backward_x) { if (x_before_slide != x) { /* met after sliding up a mid-snake */ *meeting_snake = (struct diff_box){ .left_start = x_before_slide, .left_end = x, .right_start = xc_to_y(x_before_slide, c, delta), .right_end = xk_to_y(x, k), }; } else { /* met after a side step, non-identical * line. Mark that as box divider * instead. This makes sure that * myers_divide never returns the same * box that came as input, avoiding * "infinite" looping. */ *meeting_snake = (struct diff_box){ .left_start = prev_x, .left_end = x, .right_start = prev_y, .right_end = xk_to_y(x, k), }; } debug("HIT x=(%u,%u) - y=(%u,%u)\n", meeting_snake->left_start, meeting_snake->right_start, meeting_snake->left_end, meeting_snake->right_end); debug_dump_myers_graph(left, right, NULL, kd_forward, d, kd_backward, d-1); *found_midpoint = true; return 0; } } } return 0; } /* Do one backwards step in the "divide and conquer" graph traversal. * left: the left side to diff. * right: the right side to diff against. * kd_forward: the traversal state for forwards traversal, to find a meeting * point. * Since forwards is done first, after this, both kd_forward and * kd_backward will be valid for d. * kd_forward points at the center of the state array, allowing * negative indexes. * kd_backward: the traversal state for backwards traversal, to find a meeting * point. * This is carried over between invocations with increasing d. * kd_backward points at the center of the state array, allowing * negative indexes. * d: Step or distance counter, indicating for what value of d the kd_backward * should be populated. * Before the first invocation, kd_backward[0] shall point at the bottom * right of the Myers graph (left.len, right.len). * The first invocation will be for d == 1. * meeting_snake: resulting meeting point, if any. * Return true when a meeting point has been identified. */ static int diff_divide_myers_backward(bool *found_midpoint, struct diff_data *left, struct diff_data *right, int *kd_forward, int *kd_backward, int d, struct diff_box *meeting_snake) { int delta = (int)right->atoms.len - (int)left->atoms.len; int c; int x; int prev_x; int prev_y; int x_before_slide; *found_midpoint = false; for (c = d; c >= -d; c -= 2) { if (c < -(int)left->atoms.len || c > (int)right->atoms.len) { /* This diagonal is completely outside of the Myers * graph, don't calculate it. */ if (c < 0) { /* We are traversing negatively, and already * below the entire graph, nothing will come of * this. */ break; } continue; } if (d == 0) { /* This is the initializing step. There is no prev_c * yet, get the initial x from the bottom right of the * Myers graph. */ x = left->atoms.len; prev_x = x; prev_y = xc_to_y(x, c, delta); } /* Favoring "-" lines first means favoring moving rightwards in * the Myers graph. * For this, all c should derive from c - 1, only the bottom * most c derive from c + 1: * * 2 1 0 * --------------------------------------------------- * c= * 3 * * from prev_c = c - 1 --> 5,2 2 * \ * 5,3 1 * \ * 4,3 5,4<-- 0 * \ / * bottom most for d=1 from c + 1 --> 4,4 -1 * / * bottom most for d=2 --> 3,4 -2 * * Except when a c + 1 from a previous run already means a * further advancement in the graph. * If c == d, there is no c + 1 and c - 1 is the only option. * If c < d, use c + 1 in case that yields a larger x. * Also use c + 1 if c - 1 is outside the graph. */ else if (c > -d && (c == d || (c - 1 >= -(int)right->atoms.len && kd_backward[c - 1] <= kd_backward[c + 1]))) { /* A top one. * From position prev_c, step upwards in the Myers * graph: y -= 1. * Decrementing y is achieved by incrementing c while * keeping the same x. (since we're deriving y from * y = x - c + delta). */ int prev_c = c - 1; prev_x = kd_backward[prev_c]; prev_y = xc_to_y(prev_x, prev_c, delta); x = prev_x; } else { /* The bottom most one. * From position prev_c, step to the left in the Myers * graph: x -= 1. */ int prev_c = c + 1; prev_x = kd_backward[prev_c]; prev_y = xc_to_y(prev_x, prev_c, delta); x = prev_x - 1; } /* Slide up any snake that we might find here (sections of * identical lines on both sides). */ #if 0 debug("c=%d x-1=%d Yb-1=%d-1=%d\n", c, x-1, xc_to_y(x, c, delta), xc_to_y(x, c, delta)-1); if (x > 0) { debug(" l="); debug_dump_atom(left, right, &left->atoms.head[x-1]); } if (xc_to_y(x, c, delta) > 0) { debug(" r="); debug_dump_atom(right, left, &right->atoms.head[xc_to_y(x, c, delta)-1]); } #endif x_before_slide = x; while (x > 0 && xc_to_y(x, c, delta) > 0) { bool same; int r = diff_atom_same(&same, &left->atoms.head[x-1], &right->atoms.head[ xc_to_y(x, c, delta)-1]); if (r) return r; if (!same) break; x--; } kd_backward[c] = x; #if 0 if (x_before_slide != x) { debug(" up %d similar lines\n", x_before_slide - x); } if (DEBUG) { int fi; for (fi = d; fi >= c; fi--) { debug("kd_backward[%d] = (%d, %d)\n", fi, kd_backward[fi], kd_backward[fi] - fi + delta); } } #endif if (x < 0 || x > left->atoms.len || xc_to_y(x, c, delta) < 0 || xc_to_y(x, c, delta) > right->atoms.len) continue; /* Figured out a new backwards traversal, see if this has gone * onto or even past a preceding forwards traversal. * * If the delta in length is even, then d and backwards_d hit * the same state indexes -- note how this is different from in * the forwards traversal, because now both d are the same: * * | d= 0 1 2 2 1 0 * ----+---------------- -------------------- * k= | c= * 4 | * | * 3 | 3 * | same * 2 | 2,0====5,2 2 * | / \ * 1 | 1,0 5,3 1 * | / / \ * 0 | -->0,0 3,3====4,3 5,4<-- 0 * | \ / / * -1 | 0,1 4,4 -1 * | \ * -2 | 0,2 -2 * | * -3 * If the delta is odd, they end up off-by-one, i.e. on * different diagonals. * So in the backward path, we can only match up diagonals when * the delta is even. */ if ((delta & 1) != 0) continue; /* Forwards was done first, now both d are the same. */ int forwards_d = d; /* As soon as the lengths are not the same, the * backwards traversal starts on a different diagonal, * and c = k shifted by the difference in length. */ int k = c_to_k(c, delta); /* When the file sizes are very different, the traversal trees * start on far distant diagonals. * They don't necessarily meet straight on. See whether this * backward value is also on a valid diagonal in kd_forward[], * and match them if so. */ if (k >= -forwards_d && k <= forwards_d) { /* Current c is on a diagonal that exists in * kd_forward[]. If the two x positions have met or * passed (backward walked onto or past forward), then * we've found a midpoint / a mid-box. * * When forwards and backwards traversals meet, the * endpoints of the mid-snake are not the two points in * kd_forward and kd_backward, but rather the section * that was slid (if any) of the current * forward/backward traversal only. * * For example: * * o-o-o * | | * o A * | \ * o o * \ * M * |\ * o o-o-o * | | | * o o X * \ * o * \ * o * \ * o * * The backward traversal reached M from the bottom and * slid upwards. The forward traversal already reached * X, which is not a straight line from M anymore, so * picking a mid-snake from M to X would yield a * mistake. * * The correct mid-snake is between M and A. M is where * the backward traversal hit the diagonal that the * forwards traversal has already passed, and A is what * it reaches when sliding up identical lines. */ int forward_x = kd_forward[k]; if (forward_x >= x) { if (x_before_slide != x) { /* met after sliding down a mid-snake */ *meeting_snake = (struct diff_box){ .left_start = x, .left_end = x_before_slide, .right_start = xc_to_y(x, c, delta), .right_end = xk_to_y(x_before_slide, k), }; } else { /* met after a side step, non-identical * line. Mark that as box divider * instead. This makes sure that * myers_divide never returns the same * box that came as input, avoiding * "infinite" looping. */ *meeting_snake = (struct diff_box){ .left_start = x, .left_end = prev_x, .right_start = xc_to_y(x, c, delta), .right_end = prev_y, }; } debug("HIT x=%u,%u - y=%u,%u\n", meeting_snake->left_start, meeting_snake->right_start, meeting_snake->left_end, meeting_snake->right_end); debug_dump_myers_graph(left, right, NULL, kd_forward, d, kd_backward, d); *found_midpoint = true; return 0; } } } return 0; } /* Integer square root approximation */ static int shift_sqrt(int val) { int i; for (i = 1; val > 0; val >>= 2) i <<= 1; return i; } #define DIFF_EFFORT_MIN 1024 /* Myers "Divide et Impera": tracing forwards from the start and backwards from * the end to find a midpoint that divides the problem into smaller chunks. * Requires only linear amounts of memory. */ int diff_algo_myers_divide(const struct diff_algo_config *algo_config, struct diff_state *state) { int rc = ENOMEM; struct diff_data *left = &state->left; struct diff_data *right = &state->right; int *kd_buf; debug("\n** %s\n", __func__); debug("left:\n"); debug_dump(left); debug("right:\n"); debug_dump(right); /* Allocate two columns of a Myers graph, one for the forward and one * for the backward traversal. */ unsigned int max = left->atoms.len + right->atoms.len; size_t kd_len = max + 1; size_t kd_buf_size = kd_len << 1; if (state->kd_buf_size < kd_buf_size) { kd_buf = reallocarray(state->kd_buf, kd_buf_size, sizeof(int)); if (!kd_buf) return ENOMEM; state->kd_buf = kd_buf; state->kd_buf_size = kd_buf_size; } else kd_buf = state->kd_buf; int i; for (i = 0; i < kd_buf_size; i++) kd_buf[i] = -1; int *kd_forward = kd_buf; int *kd_backward = kd_buf + kd_len; int max_effort = shift_sqrt(max/2); if (max_effort < DIFF_EFFORT_MIN) max_effort = DIFF_EFFORT_MIN; /* The 'k' axis in Myers spans positive and negative indexes, so point * the kd to the middle. * It is then possible to index from -max/2 .. max/2. */ kd_forward += max/2; kd_backward += max/2; int d; struct diff_box mid_snake = {}; bool found_midpoint = false; for (d = 0; d <= (max/2); d++) { int r; r = diff_divide_myers_forward(&found_midpoint, left, right, kd_forward, kd_backward, d, &mid_snake); if (r) return r; if (found_midpoint) break; r = diff_divide_myers_backward(&found_midpoint, left, right, kd_forward, kd_backward, d, &mid_snake); if (r) return r; if (found_midpoint) break; /* Limit the effort spent looking for a mid snake. If files have * very few lines in common, the effort spent to find nice mid * snakes is just not worth it, the diff result will still be * essentially minus everything on the left, plus everything on * the right, with a few useless matches here and there. */ if (d > max_effort) { /* pick the furthest reaching point from * kd_forward and kd_backward, and use that as a * midpoint, to not step into another diff algo * recursion with unchanged box. */ int delta = (int)right->atoms.len - (int)left->atoms.len; int x = 0; int y; int i; int best_forward_i = 0; int best_forward_distance = 0; int best_backward_i = 0; int best_backward_distance = 0; int distance; int best_forward_x; int best_forward_y; int best_backward_x; int best_backward_y; debug("~~~ HIT d = %d > max_effort = %d\n", d, max_effort); debug_dump_myers_graph(left, right, NULL, kd_forward, d, kd_backward, d); for (i = d; i >= -d; i -= 2) { if (i >= -(int)right->atoms.len && i <= (int)left->atoms.len) { x = kd_forward[i]; y = xk_to_y(x, i); distance = x + y; if (distance > best_forward_distance) { best_forward_distance = distance; best_forward_i = i; } } if (i >= -(int)left->atoms.len && i <= (int)right->atoms.len) { x = kd_backward[i]; y = xc_to_y(x, i, delta); distance = (right->atoms.len - x) + (left->atoms.len - y); if (distance >= best_backward_distance) { best_backward_distance = distance; best_backward_i = i; } } } /* The myers-divide didn't meet in the middle. We just * figured out the places where the forward path * advanced the most, and the backward path advanced the * most. Just divide at whichever one of those two is better. * * o-o * | * o * \ * o * \ * F <-- cut here * * * * or here --> B * \ * o * \ * o * | * o-o */ best_forward_x = kd_forward[best_forward_i]; best_forward_y = xk_to_y(best_forward_x, best_forward_i); best_backward_x = kd_backward[best_backward_i]; best_backward_y = xc_to_y(best_backward_x, best_backward_i, delta); if (best_forward_distance >= best_backward_distance) { x = best_forward_x; y = best_forward_y; } else { x = best_backward_x; y = best_backward_y; } debug("max_effort cut at x=%d y=%d\n", x, y); if (x < 0 || y < 0 || x > left->atoms.len || y > right->atoms.len) break; found_midpoint = true; mid_snake = (struct diff_box){ .left_start = x, .left_end = x, .right_start = y, .right_end = y, }; break; } } if (!found_midpoint) { /* Divide and conquer failed to find a meeting point. Use the * fallback_algo defined in the algo_config (leave this to the * caller). This is just paranoia/sanity, we normally should * always find a midpoint. */ debug(" no midpoint \n"); rc = DIFF_RC_USE_DIFF_ALGO_FALLBACK; goto return_rc; } else { debug(" mid snake L: %u to %u of %u R: %u to %u of %u\n", mid_snake.left_start, mid_snake.left_end, left->atoms.len, mid_snake.right_start, mid_snake.right_end, right->atoms.len); /* Section before the mid-snake. */ debug("Section before the mid-snake\n"); struct diff_atom *left_atom = &left->atoms.head[0]; unsigned int left_section_len = mid_snake.left_start; struct diff_atom *right_atom = &right->atoms.head[0]; unsigned int right_section_len = mid_snake.right_start; if (left_section_len && right_section_len) { /* Record an unsolved chunk, the caller will apply * inner_algo() on this chunk. */ if (!diff_state_add_chunk(state, false, left_atom, left_section_len, right_atom, right_section_len)) goto return_rc; } else if (left_section_len && !right_section_len) { /* Only left atoms and none on the right, they form a * "minus" chunk, then. */ if (!diff_state_add_chunk(state, true, left_atom, left_section_len, right_atom, 0)) goto return_rc; } else if (!left_section_len && right_section_len) { /* No left atoms, only atoms on the right, they form a * "plus" chunk, then. */ if (!diff_state_add_chunk(state, true, left_atom, 0, right_atom, right_section_len)) goto return_rc; } /* else: left_section_len == 0 and right_section_len == 0, i.e. * nothing before the mid-snake. */ if (mid_snake.left_end > mid_snake.left_start || mid_snake.right_end > mid_snake.right_start) { /* The midpoint is a section of identical data on both * sides, or a certain differing line: that section * immediately becomes a solved chunk. */ debug("the mid-snake\n"); if (!diff_state_add_chunk(state, true, &left->atoms.head[mid_snake.left_start], mid_snake.left_end - mid_snake.left_start, &right->atoms.head[mid_snake.right_start], mid_snake.right_end - mid_snake.right_start)) goto return_rc; } /* Section after the mid-snake. */ debug("Section after the mid-snake\n"); debug(" left_end %u right_end %u\n", mid_snake.left_end, mid_snake.right_end); debug(" left_count %u right_count %u\n", left->atoms.len, right->atoms.len); left_atom = &left->atoms.head[mid_snake.left_end]; left_section_len = left->atoms.len - mid_snake.left_end; right_atom = &right->atoms.head[mid_snake.right_end]; right_section_len = right->atoms.len - mid_snake.right_end; if (left_section_len && right_section_len) { /* Record an unsolved chunk, the caller will apply * inner_algo() on this chunk. */ if (!diff_state_add_chunk(state, false, left_atom, left_section_len, right_atom, right_section_len)) goto return_rc; } else if (left_section_len && !right_section_len) { /* Only left atoms and none on the right, they form a * "minus" chunk, then. */ if (!diff_state_add_chunk(state, true, left_atom, left_section_len, right_atom, 0)) goto return_rc; } else if (!left_section_len && right_section_len) { /* No left atoms, only atoms on the right, they form a * "plus" chunk, then. */ if (!diff_state_add_chunk(state, true, left_atom, 0, right_atom, right_section_len)) goto return_rc; } /* else: left_section_len == 0 and right_section_len == 0, i.e. * nothing after the mid-snake. */ } rc = DIFF_RC_OK; return_rc: debug("** END %s\n", __func__); return rc; } /* Myers Diff tracing from the start all the way through to the end, requiring * quadratic amounts of memory. This can fail if the required space surpasses * algo_config->permitted_state_size. */ int diff_algo_myers(const struct diff_algo_config *algo_config, struct diff_state *state) { /* do a diff_divide_myers_forward() without a _backward(), so that it * walks forward across the entire files to reach the end. Keep each * run's state, and do a final backtrace. */ int rc = ENOMEM; struct diff_data *left = &state->left; struct diff_data *right = &state->right; int *kd_buf; debug("\n** %s\n", __func__); debug("left:\n"); debug_dump(left); debug("right:\n"); debug_dump(right); debug_dump_myers_graph(left, right, NULL, NULL, 0, NULL, 0); /* Allocate two columns of a Myers graph, one for the forward and one * for the backward traversal. */ unsigned int max = left->atoms.len + right->atoms.len; size_t kd_len = max + 1 + max; size_t kd_buf_size = kd_len * kd_len; size_t kd_state_size = kd_buf_size * sizeof(int); debug("state size: %zu\n", kd_state_size); if (kd_buf_size < kd_len /* overflow? */ || (SIZE_MAX / kd_len ) < kd_len || kd_state_size > algo_config->permitted_state_size) { debug("state size %zu > permitted_state_size %zu, use fallback_algo\n", kd_state_size, algo_config->permitted_state_size); return DIFF_RC_USE_DIFF_ALGO_FALLBACK; } if (state->kd_buf_size < kd_buf_size) { kd_buf = reallocarray(state->kd_buf, kd_buf_size, sizeof(int)); if (!kd_buf) return ENOMEM; state->kd_buf = kd_buf; state->kd_buf_size = kd_buf_size; } else kd_buf = state->kd_buf; int i; for (i = 0; i < kd_buf_size; i++) kd_buf[i] = -1; /* The 'k' axis in Myers spans positive and negative indexes, so point * the kd to the middle. * It is then possible to index from -max .. max. */ int *kd_origin = kd_buf + max; int *kd_column = kd_origin; int d; int backtrack_d = -1; int backtrack_k = 0; int k; int x, y; for (d = 0; d <= max; d++, kd_column += kd_len) { debug("-- %s d=%d\n", __func__, d); for (k = d; k >= -d; k -= 2) { if (k < -(int)right->atoms.len || k > (int)left->atoms.len) { /* This diagonal is completely outside of the * Myers graph, don't calculate it. */ if (k < -(int)right->atoms.len) debug(" %d k <" " -(int)right->atoms.len %d\n", k, -(int)right->atoms.len); else debug(" %d k > left->atoms.len %d\n", k, left->atoms.len); if (k < 0) { /* We are traversing negatively, and * already below the entire graph, * nothing will come of this. */ debug(" break\n"); break; } debug(" continue\n"); continue; } if (d == 0) { /* This is the initializing step. There is no * prev_k yet, get the initial x from the top * left of the Myers graph. */ x = 0; } else { int *kd_prev_column = kd_column - kd_len; /* Favoring "-" lines first means favoring * moving rightwards in the Myers graph. * For this, all k should derive from k - 1, * only the bottom most k derive from k + 1: * * | d= 0 1 2 * ----+---------------- * k= | * 2 | 2,0 <-- from * | / prev_k = 2 - 1 = 1 * 1 | 1,0 * | / * 0 | -->0,0 3,3 * | \\ / * -1 | 0,1 <-- bottom most for d=1 * | \\ from prev_k = -1+1 = 0 * -2 | 0,2 <-- bottom most for * d=2 from * prev_k = -2+1 = -1 * * Except when a k + 1 from a previous run * already means a further advancement in the * graph. * If k == d, there is no k + 1 and k - 1 is the * only option. * If k < d, use k + 1 in case that yields a * larger x. Also use k + 1 if k - 1 is outside * the graph. */ if (k > -d && (k == d || (k - 1 >= -(int)right->atoms.len && kd_prev_column[k - 1] >= kd_prev_column[k + 1]))) { /* Advance from k - 1. * From position prev_k, step to the * right in the Myers graph: x += 1. */ int prev_k = k - 1; int prev_x = kd_prev_column[prev_k]; x = prev_x + 1; } else { /* The bottom most one. * From position prev_k, step to the * bottom in the Myers graph: y += 1. * Incrementing y is achieved by * decrementing k while keeping the same * x. (since we're deriving y from y = * x - k). */ int prev_k = k + 1; int prev_x = kd_prev_column[prev_k]; x = prev_x; } } /* Slide down any snake that we might find here. */ while (x < left->atoms.len && xk_to_y(x, k) < right->atoms.len) { bool same; int r = diff_atom_same(&same, &left->atoms.head[x], &right->atoms.head[ xk_to_y(x, k)]); if (r) return r; if (!same) break; x++; } kd_column[k] = x; if (x == left->atoms.len && xk_to_y(x, k) == right->atoms.len) { /* Found a path */ backtrack_d = d; backtrack_k = k; debug("Reached the end at d = %d, k = %d\n", backtrack_d, backtrack_k); break; } } if (backtrack_d >= 0) break; } debug_dump_myers_graph(left, right, kd_origin, NULL, 0, NULL, 0); /* backtrack. A matrix spanning from start to end of the file is ready: * * | d= 0 1 2 3 4 * ----+--------------------------------- * k= | * 3 | * | * 2 | 2,0 * | / * 1 | 1,0 4,3 * | / / \ * 0 | -->0,0 3,3 4,4 --> backtrack_d = 4, backtrack_k = 0 * | \ / \ * -1 | 0,1 3,4 * | \ * -2 | 0,2 * | * * From (4,4) backwards, find the previous position that is the largest, and remember it. * */ for (d = backtrack_d, k = backtrack_k; d >= 0; d--) { x = kd_column[k]; y = xk_to_y(x, k); /* When the best position is identified, remember it for that * kd_column. * That kd_column is no longer needed otherwise, so just * re-purpose kd_column[0] = x and kd_column[1] = y, * so that there is no need to allocate more memory. */ kd_column[0] = x; kd_column[1] = y; debug("Backtrack d=%d: xy=(%d, %d)\n", d, kd_column[0], kd_column[1]); /* Don't access memory before kd_buf */ if (d == 0) break; int *kd_prev_column = kd_column - kd_len; /* When y == 0, backtracking downwards (k-1) is the only way. * When x == 0, backtracking upwards (k+1) is the only way. * * | d= 0 1 2 3 4 * ----+--------------------------------- * k= | * 3 | * | ..y == 0 * 2 | 2,0 * | / * 1 | 1,0 4,3 * | / / \ * 0 | -->0,0 3,3 4,4 --> backtrack_d = 4, * | \ / \ backtrack_k = 0 * -1 | 0,1 3,4 * | \ * -2 | 0,2__ * | x == 0 */ if (y == 0 || (x > 0 && kd_prev_column[k - 1] >= kd_prev_column[k + 1])) { k = k - 1; debug("prev k=k-1=%d x=%d y=%d\n", k, kd_prev_column[k], xk_to_y(kd_prev_column[k], k)); } else { k = k + 1; debug("prev k=k+1=%d x=%d y=%d\n", k, kd_prev_column[k], xk_to_y(kd_prev_column[k], k)); } kd_column = kd_prev_column; } /* Forwards again, this time recording the diff chunks. * Definitely start from 0,0. kd_column[0] may actually point to the * bottom of a snake starting at 0,0 */ x = 0; y = 0; kd_column = kd_origin; for (d = 0; d <= backtrack_d; d++, kd_column += kd_len) { int next_x = kd_column[0]; int next_y = kd_column[1]; debug("Forward track from xy(%d,%d) to xy(%d,%d)\n", x, y, next_x, next_y); struct diff_atom *left_atom = &left->atoms.head[x]; int left_section_len = next_x - x; struct diff_atom *right_atom = &right->atoms.head[y]; int right_section_len = next_y - y; rc = ENOMEM; if (left_section_len && right_section_len) { /* This must be a snake slide. * Snake slides have a straight line leading into them * (except when starting at (0,0)). Find out whether the * lead-in is horizontal or vertical: * * left * ----------> * | * r| o-o o * i| \ | * g| o o * h| \ \ * t| o o * v * * If left_section_len > right_section_len, the lead-in * is horizontal, meaning first remove one atom from the * left before sliding down the snake. * If right_section_len > left_section_len, the lead-in * is vetical, so add one atom from the right before * sliding down the snake. */ if (left_section_len == right_section_len + 1) { if (!diff_state_add_chunk(state, true, left_atom, 1, right_atom, 0)) goto return_rc; left_atom++; left_section_len--; } else if (right_section_len == left_section_len + 1) { if (!diff_state_add_chunk(state, true, left_atom, 0, right_atom, 1)) goto return_rc; right_atom++; right_section_len--; } else if (left_section_len != right_section_len) { /* The numbers are making no sense. Should never * happen. */ rc = DIFF_RC_USE_DIFF_ALGO_FALLBACK; goto return_rc; } if (!diff_state_add_chunk(state, true, left_atom, left_section_len, right_atom, right_section_len)) goto return_rc; } else if (left_section_len && !right_section_len) { /* Only left atoms and none on the right, they form a * "minus" chunk, then. */ if (!diff_state_add_chunk(state, true, left_atom, left_section_len, right_atom, 0)) goto return_rc; } else if (!left_section_len && right_section_len) { /* No left atoms, only atoms on the right, they form a * "plus" chunk, then. */ if (!diff_state_add_chunk(state, true, left_atom, 0, right_atom, right_section_len)) goto return_rc; } x = next_x; y = next_y; } rc = DIFF_RC_OK; return_rc: debug("** END %s rc=%d\n", __func__, rc); return rc; } got-portable-0.101/lib/object.c0000664000175100017510000005206014644144735011776 /* * Copyright (c) 2018, 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_repository.h" #include "got_opentemp.h" #include "got_path.h" #include "got_lib_hash.h" #include "got_lib_delta.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_idcache.h" #include "got_lib_object_cache.h" #include "got_lib_object_parse.h" #include "got_lib_pack.h" #include "got_lib_repository.h" #ifndef MIN #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) #endif #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif struct got_object_id * got_object_get_id(struct got_object *obj) { return &obj->id; } const struct got_error * got_object_get_id_str(char **outbuf, struct got_object *obj) { return got_object_id_str(outbuf, &obj->id); } const struct got_error * got_object_get_type(int *type, struct got_repository *repo, struct got_object_id *id) { const struct got_error *err = NULL; struct got_object *obj; err = got_object_open(&obj, repo, id); if (err) return err; switch (obj->type) { case GOT_OBJ_TYPE_COMMIT: case GOT_OBJ_TYPE_TREE: case GOT_OBJ_TYPE_BLOB: case GOT_OBJ_TYPE_TAG: *type = obj->type; break; default: err = got_error(GOT_ERR_OBJ_TYPE); break; } got_object_close(obj); return err; } const struct got_error * got_object_get_path(char **path, struct got_object_id *id, struct got_repository *repo) { const struct got_error *err = NULL; char *hex = NULL; char *path_objects; *path = NULL; path_objects = got_repo_get_path_objects(repo); if (path_objects == NULL) return got_error_from_errno("got_repo_get_path_objects"); err = got_object_id_str(&hex, id); if (err) goto done; if (asprintf(path, "%s/%.2x/%s", path_objects, id->sha1[0], hex + 2) == -1) err = got_error_from_errno("asprintf"); done: free(hex); free(path_objects); return err; } const struct got_error * got_object_open_loose_fd(int *fd, struct got_object_id *id, struct got_repository *repo) { const struct got_error *err = NULL; char *path; err = got_object_get_path(&path, id, repo); if (err) return err; *fd = open(path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (*fd == -1) { err = got_error_from_errno2("open", path); goto done; } done: free(path); return err; } const struct got_error * got_object_open_by_id_str(struct got_object **obj, struct got_repository *repo, const char *id_str) { struct got_object_id id; if (!got_parse_object_id(&id, id_str, GOT_HASH_SHA1)) return got_error_path(id_str, GOT_ERR_BAD_OBJ_ID_STR); return got_object_open(obj, repo, &id); } const struct got_error * got_object_resolve_id_str(struct got_object_id **id, struct got_repository *repo, const char *id_str) { const struct got_error *err = NULL; struct got_object *obj; err = got_object_open_by_id_str(&obj, repo, id_str); if (err) return err; *id = got_object_id_dup(got_object_get_id(obj)); got_object_close(obj); if (*id == NULL) return got_error_from_errno("got_object_id_dup"); return NULL; } int got_object_tree_get_nentries(struct got_tree_object *tree) { return tree->nentries; } struct got_tree_entry * got_object_tree_get_first_entry(struct got_tree_object *tree) { return got_object_tree_get_entry(tree, 0); } struct got_tree_entry * got_object_tree_get_last_entry(struct got_tree_object *tree) { return got_object_tree_get_entry(tree, tree->nentries - 1); } struct got_tree_entry * got_object_tree_get_entry(struct got_tree_object *tree, int i) { if (i < 0 || i >= tree->nentries) return NULL; return &tree->entries[i]; } mode_t got_tree_entry_get_mode(struct got_tree_entry *te) { return te->mode; } const char * got_tree_entry_get_name(struct got_tree_entry *te) { return &te->name[0]; } struct got_object_id * got_tree_entry_get_id(struct got_tree_entry *te) { return &te->id; } const struct got_error * got_object_blob_read_to_str(char **s, struct got_blob_object *blob) { const struct got_error *err = NULL; size_t len, totlen, hdrlen, offset; *s = NULL; hdrlen = got_object_blob_get_hdrlen(blob); totlen = 0; offset = 0; do { char *p; err = got_object_blob_read_block(&len, blob); if (err) return err; if (len == 0) break; totlen += len - hdrlen; p = realloc(*s, totlen + 1); if (p == NULL) { err = got_error_from_errno("realloc"); free(*s); *s = NULL; return err; } *s = p; /* Skip blob object header first time around. */ memcpy(*s + offset, got_object_blob_get_read_buf(blob) + hdrlen, len - hdrlen); hdrlen = 0; offset = totlen; } while (len > 0); (*s)[totlen] = '\0'; return NULL; } const struct got_error * got_tree_entry_get_symlink_target(char **link_target, struct got_tree_entry *te, struct got_repository *repo) { const struct got_error *err = NULL; struct got_blob_object *blob = NULL; int fd = -1; *link_target = NULL; if (!got_object_tree_entry_is_symlink(te)) return got_error(GOT_ERR_TREE_ENTRY_TYPE); fd = got_opentempfd(); if (fd == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } err = got_object_open_as_blob(&blob, repo, got_tree_entry_get_id(te), PATH_MAX, fd); if (err) goto done; err = got_object_blob_read_to_str(link_target, blob); done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob) got_object_blob_close(blob); if (err) { free(*link_target); *link_target = NULL; } return err; } int got_tree_entry_get_index(struct got_tree_entry *te) { return te->idx; } struct got_tree_entry * got_tree_entry_get_next(struct got_tree_object *tree, struct got_tree_entry *te) { return got_object_tree_get_entry(tree, te->idx + 1); } struct got_tree_entry * got_tree_entry_get_prev(struct got_tree_object *tree, struct got_tree_entry *te) { return got_object_tree_get_entry(tree, te->idx - 1); } const struct got_error * got_object_blob_close(struct got_blob_object *blob) { const struct got_error *err = NULL; free(blob->read_buf); if (blob->f && fclose(blob->f) == EOF) err = got_error_from_errno("fclose"); free(blob->data); free(blob); return err; } void got_object_blob_rewind(struct got_blob_object *blob) { if (blob->f) rewind(blob->f); } char * got_object_blob_id_str(struct got_blob_object *blob, char *buf, size_t size) { return got_object_id_hex(&blob->id, buf, size); } size_t got_object_blob_get_hdrlen(struct got_blob_object *blob) { return blob->hdrlen; } const uint8_t * got_object_blob_get_read_buf(struct got_blob_object *blob) { return blob->read_buf; } const struct got_error * got_object_blob_read_block(size_t *outlenp, struct got_blob_object *blob) { size_t n; n = fread(blob->read_buf, 1, blob->blocksize, blob->f); if (n == 0 && ferror(blob->f)) return got_ferror(blob->f, GOT_ERR_IO); *outlenp = n; return NULL; } const struct got_error * got_object_blob_is_binary(int *binary, struct got_blob_object *blob) { const struct got_error *err; size_t hdrlen, len; *binary = 0; hdrlen = got_object_blob_get_hdrlen(blob); if (fseeko(blob->f, hdrlen, SEEK_SET) == -1) return got_error_from_errno("fseeko"); err = got_object_blob_read_block(&len, blob); if (err) return err; *binary = memchr(blob->read_buf, '\0', len) != NULL; if (fseeko(blob->f, hdrlen, SEEK_SET) == -1) return got_error_from_errno("fseeko"); return NULL; } const struct got_error * got_object_blob_getline(char **line, ssize_t *linelen, size_t *linesize, struct got_blob_object *blob) { *linelen = getline(line, linesize, blob->f); if (*linelen == -1 && !feof(blob->f)) return got_error_from_errno("getline"); return NULL; } const struct got_error * got_object_blob_dump_to_file(off_t *filesize, int *nlines, off_t **line_offsets, FILE *outfile, struct got_blob_object *blob) { const struct got_error *err = NULL; size_t n, len, hdrlen; const uint8_t *buf; int i; const int alloc_chunksz = 512; size_t nalloc = 0; off_t off = 0, total_len = 0; if (line_offsets) *line_offsets = NULL; if (filesize) *filesize = 0; if (nlines) *nlines = 0; hdrlen = got_object_blob_get_hdrlen(blob); do { err = got_object_blob_read_block(&len, blob); if (err) return err; if (len == 0) break; buf = got_object_blob_get_read_buf(blob); i = hdrlen; if (nlines) { if (line_offsets && *line_offsets == NULL) { /* Have some data but perhaps no '\n'. */ *nlines = 1; nalloc = alloc_chunksz; *line_offsets = calloc(nalloc, sizeof(**line_offsets)); if (*line_offsets == NULL) return got_error_from_errno("calloc"); /* Skip forward over end of first line. */ while (i < len) { if (buf[i] == '\n') break; i++; } } /* Scan '\n' offsets in remaining chunk of data. */ while (i < len) { if (buf[i] != '\n') { i++; continue; } (*nlines)++; if (line_offsets && nalloc < *nlines) { size_t n = *nlines + alloc_chunksz; off_t *o = recallocarray(*line_offsets, nalloc, n, sizeof(**line_offsets)); if (o == NULL) { free(*line_offsets); *line_offsets = NULL; return got_error_from_errno( "recallocarray"); } *line_offsets = o; nalloc = n; } if (line_offsets) { off = total_len + i - hdrlen + 1; (*line_offsets)[*nlines - 1] = off; } i++; } } /* Skip blob object header first time around. */ n = fwrite(buf + hdrlen, 1, len - hdrlen, outfile); if (n != len - hdrlen) return got_ferror(outfile, GOT_ERR_IO); total_len += len - hdrlen; hdrlen = 0; } while (len != 0); if (fflush(outfile) != 0) return got_error_from_errno("fflush"); rewind(outfile); if (filesize) *filesize = total_len; return NULL; } const char * got_object_tag_get_name(struct got_tag_object *tag) { return tag->tag; } int got_object_tag_get_object_type(struct got_tag_object *tag) { return tag->obj_type; } struct got_object_id * got_object_tag_get_object_id(struct got_tag_object *tag) { return &tag->id; } time_t got_object_tag_get_tagger_time(struct got_tag_object *tag) { return tag->tagger_time; } time_t got_object_tag_get_tagger_gmtoff(struct got_tag_object *tag) { return tag->tagger_gmtoff; } const char * got_object_tag_get_tagger(struct got_tag_object *tag) { return tag->tagger; } const char * got_object_tag_get_message(struct got_tag_object *tag) { return tag->tagmsg; } static struct got_tree_entry * find_entry_by_name(struct got_tree_object *tree, const char *name, size_t len) { int i; /* Note that tree entries are sorted in strncmp() order. */ for (i = 0; i < tree->nentries; i++) { struct got_tree_entry *te = &tree->entries[i]; int cmp = strncmp(te->name, name, len); if (cmp < 0) continue; if (cmp > 0) break; if (te->name[len] == '\0') return te; } return NULL; } struct got_tree_entry * got_object_tree_find_entry(struct got_tree_object *tree, const char *name) { return find_entry_by_name(tree, name, strlen(name)); } const struct got_error * got_object_tree_find_path(struct got_object_id **id, mode_t *mode, struct got_repository *repo, struct got_tree_object *tree, const char *path) { const struct got_error *err = NULL; struct got_tree_object *subtree = NULL; struct got_tree_entry *te = NULL; const char *seg, *s; size_t seglen; *id = NULL; s = path; while (s[0] == '/') s++; seg = s; seglen = 0; subtree = tree; while (*s) { struct got_tree_object *next_tree; if (*s != '/') { s++; seglen++; if (*s) continue; } te = find_entry_by_name(subtree, seg, seglen); if (te == NULL) { err = got_error_path(path, GOT_ERR_NO_TREE_ENTRY); goto done; } if (*s == '\0') break; seg = s + 1; seglen = 0; s++; if (*s) { err = got_object_open_as_tree(&next_tree, repo, &te->id); te = NULL; if (err) goto done; if (subtree != tree) got_object_tree_close(subtree); subtree = next_tree; } } if (te) { *id = got_object_id_dup(&te->id); if (*id == NULL) return got_error_from_errno("got_object_id_dup"); if (mode) *mode = te->mode; } else err = got_error_path(path, GOT_ERR_NO_TREE_ENTRY); done: if (subtree && subtree != tree) got_object_tree_close(subtree); return err; } const struct got_error * got_object_id_by_path(struct got_object_id **id, struct got_repository *repo, struct got_commit_object *commit, const char *path) { const struct got_error *err = NULL; struct got_tree_object *tree = NULL; *id = NULL; /* Handle opening of root of commit's tree. */ if (got_path_is_root_dir(path)) { *id = got_object_id_dup(commit->tree_id); if (*id == NULL) err = got_error_from_errno("got_object_id_dup"); } else { err = got_object_open_as_tree(&tree, repo, commit->tree_id); if (err) goto done; err = got_object_tree_find_path(id, NULL, repo, tree, path); } done: if (tree) got_object_tree_close(tree); return err; } /* * Normalize file mode bits to avoid false positive tree entry differences * in case tree entries have unexpected mode bits set. */ static mode_t normalize_mode_for_comparison(mode_t mode) { /* * For directories, the only relevant bit is the IFDIR bit. * This allows us to detect paths changing from a directory * to a file and vice versa. */ if (S_ISDIR(mode)) return mode & S_IFDIR; /* * For symlinks, the only relevant bit is the IFLNK bit. * This allows us to detect paths changing from a symlinks * to a file or directory and vice versa. */ if (S_ISLNK(mode)) return mode & S_IFLNK; /* For files, the only change we care about is the executable bit. */ return mode & S_IXUSR; } const struct got_error * got_object_tree_path_changed(int *changed, struct got_tree_object *tree01, struct got_tree_object *tree02, const char *path, struct got_repository *repo) { const struct got_error *err = NULL; struct got_tree_object *tree1 = NULL, *tree2 = NULL; struct got_tree_entry *te1 = NULL, *te2 = NULL; const char *seg, *s; size_t seglen; *changed = 0; /* We not do support comparing the root path. */ if (got_path_is_root_dir(path)) return got_error_path(path, GOT_ERR_BAD_PATH); tree1 = tree01; tree2 = tree02; s = path; while (*s == '/') s++; seg = s; seglen = 0; while (*s) { struct got_tree_object *next_tree1, *next_tree2; mode_t mode1, mode2; if (*s != '/') { s++; seglen++; if (*s) continue; } te1 = find_entry_by_name(tree1, seg, seglen); if (te1 == NULL) { err = got_error(GOT_ERR_NO_OBJ); goto done; } if (tree2) te2 = find_entry_by_name(tree2, seg, seglen); if (te2) { mode1 = normalize_mode_for_comparison(te1->mode); mode2 = normalize_mode_for_comparison(te2->mode); if (mode1 != mode2) { *changed = 1; goto done; } if (got_object_id_cmp(&te1->id, &te2->id) == 0) { *changed = 0; goto done; } } if (*s == '\0') { /* final path element */ *changed = 1; goto done; } seg = s + 1; s++; seglen = 0; if (*s) { err = got_object_open_as_tree(&next_tree1, repo, &te1->id); te1 = NULL; if (err) goto done; if (tree1 != tree01) got_object_tree_close(tree1); tree1 = next_tree1; if (te2) { err = got_object_open_as_tree(&next_tree2, repo, &te2->id); te2 = NULL; if (err) goto done; if (tree2 != tree02) got_object_tree_close(tree2); tree2 = next_tree2; } else if (tree2) { if (tree2 != tree02) got_object_tree_close(tree2); tree2 = NULL; } } } done: if (tree1 && tree1 != tree01) got_object_tree_close(tree1); if (tree2 && tree2 != tree02) got_object_tree_close(tree2); return err; } const struct got_error * got_object_tree_entry_dup(struct got_tree_entry **new_te, struct got_tree_entry *te) { const struct got_error *err = NULL; *new_te = calloc(1, sizeof(**new_te)); if (*new_te == NULL) return got_error_from_errno("calloc"); (*new_te)->mode = te->mode; memcpy((*new_te)->name, te->name, sizeof((*new_te)->name)); memcpy(&(*new_te)->id, &te->id, sizeof((*new_te)->id)); return err; } int got_object_tree_entry_is_submodule(struct got_tree_entry *te) { return (te->mode & S_IFMT) == (S_IFDIR | S_IFLNK); } int got_object_tree_entry_is_symlink(struct got_tree_entry *te) { /* S_IFDIR check avoids confusing symlinks with submodules. */ return ((te->mode & (S_IFDIR | S_IFLNK)) == S_IFLNK); } static const struct got_error * resolve_symlink(char **link_target, const char *path, struct got_commit_object *commit, struct got_repository *repo) { const struct got_error *err = NULL; char buf[PATH_MAX]; char *name, *parent_path = NULL; struct got_object_id *tree_obj_id = NULL; struct got_tree_object *tree = NULL; struct got_tree_entry *te = NULL; *link_target = NULL; if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) return got_error(GOT_ERR_NO_SPACE); name = basename(buf); if (name == NULL) return got_error_from_errno2("basename", path); err = got_path_dirname(&parent_path, path); if (err) return err; err = got_object_id_by_path(&tree_obj_id, repo, commit, parent_path); if (err) { if (err->code == GOT_ERR_NO_TREE_ENTRY) { /* Display the complete path in error message. */ err = got_error_path(path, err->code); } goto done; } err = got_object_open_as_tree(&tree, repo, tree_obj_id); if (err) goto done; te = got_object_tree_find_entry(tree, name); if (te == NULL) { err = got_error_path(path, GOT_ERR_NO_TREE_ENTRY); goto done; } if (got_object_tree_entry_is_symlink(te)) { err = got_tree_entry_get_symlink_target(link_target, te, repo); if (err) goto done; if (!got_path_is_absolute(*link_target)) { char *abspath; if (asprintf(&abspath, "%s/%s", parent_path, *link_target) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(*link_target); *link_target = malloc(PATH_MAX); if (*link_target == NULL) { err = got_error_from_errno("malloc"); goto done; } err = got_canonpath(abspath, *link_target, PATH_MAX); free(abspath); if (err) goto done; } } done: free(parent_path); free(tree_obj_id); if (tree) got_object_tree_close(tree); if (err) { free(*link_target); *link_target = NULL; } return err; } const struct got_error * got_object_resolve_symlinks(char **link_target, const char *path, struct got_commit_object *commit, struct got_repository *repo) { const struct got_error *err = NULL; char *next_target = NULL; int max_recursion = 40; /* matches Git */ *link_target = NULL; do { err = resolve_symlink(&next_target, *link_target ? *link_target : path, commit, repo); if (err) break; if (next_target) { free(*link_target); if (--max_recursion == 0) { err = got_error_path(path, GOT_ERR_RECURSION); *link_target = NULL; break; } *link_target = next_target; } } while (next_target); return err; } void got_object_commit_retain(struct got_commit_object *commit) { commit->refcnt++; } const struct got_error * got_object_raw_alloc(struct got_raw_object **obj, uint8_t *outbuf, int *outfd, size_t max_in_mem_size, size_t hdrlen, off_t size) { const struct got_error *err = NULL; off_t tot; tot = hdrlen + size; *obj = calloc(1, sizeof(**obj)); if (*obj == NULL) { err = got_error_from_errno("calloc"); goto done; } (*obj)->fd = -1; (*obj)->tempfile_idx = -1; if (outbuf) { (*obj)->data = outbuf; } else { struct stat sb; if (fstat(*outfd, &sb) == -1) { err = got_error_from_errno("fstat"); goto done; } if (sb.st_size != tot) { err = got_error_msg(GOT_ERR_BAD_OBJ_HDR, "raw object has unexpected size"); goto done; } #ifndef GOT_PACK_NO_MMAP if (tot > 0 && tot <= max_in_mem_size) { (*obj)->data = mmap(NULL, tot, PROT_READ, MAP_PRIVATE, *outfd, 0); if ((*obj)->data == MAP_FAILED) { if (errno != ENOMEM) { err = got_error_from_errno("mmap"); goto done; } (*obj)->data = NULL; } else { (*obj)->fd = *outfd; *outfd = -1; } } #endif if (*outfd != -1) { (*obj)->f = fdopen(*outfd, "r"); if ((*obj)->f == NULL) { err = got_error_from_errno("fdopen"); goto done; } *outfd = -1; } } (*obj)->hdrlen = hdrlen; (*obj)->size = size; done: if (err) { if (*obj) { got_object_raw_close(*obj); *obj = NULL; } } else (*obj)->refcnt++; return err; } got-portable-0.101/lib/object_qid.c0000664000175100017510000000445114644144735012634 /* * Copyright (c) 2018, 2019, 2020, 2023 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include "got_object.h" #include "got_error.h" #include "got_lib_object_qid.h" #include "got_lib_hash.h" const struct got_error * got_object_qid_alloc_partial(struct got_object_qid **qid) { *qid = calloc(1, sizeof(**qid)); if (*qid == NULL) return got_error_from_errno("malloc"); (*qid)->data = NULL; return NULL; } const struct got_error * got_object_qid_alloc(struct got_object_qid **qid, struct got_object_id *id) { *qid = calloc(1, sizeof(**qid)); if (*qid == NULL) return got_error_from_errno("calloc"); memcpy(&(*qid)->id, id, sizeof((*qid)->id)); return NULL; } void got_object_qid_free(struct got_object_qid *qid) { free(qid); } void got_object_id_queue_free(struct got_object_id_queue *ids) { struct got_object_qid *qid; while (!STAILQ_EMPTY(ids)) { qid = STAILQ_FIRST(ids); STAILQ_REMOVE_HEAD(ids, entry); got_object_qid_free(qid); } } const struct got_error * got_object_id_queue_copy(const struct got_object_id_queue *src, struct got_object_id_queue *dest) { const struct got_error *err; struct got_object_qid *qid; STAILQ_FOREACH(qid, src, entry) { struct got_object_qid *new; /* * Deep-copy the object ID only. Let the caller deal * with setting up the new->data pointer if needed. */ err = got_object_qid_alloc(&new, &qid->id); if (err) { got_object_id_queue_free(dest); return err; } STAILQ_INSERT_TAIL(dest, new, entry); } return NULL; } got-portable-0.101/lib/got_lib_object_qid.h0000644000175100017510000000157414644143163014333 /* * Copyright (c) 2018, 2019, 2020, 2023 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ const struct got_error *got_object_qid_alloc_partial(struct got_object_qid **); got-portable-0.101/lib/ratelimit.c0000664000175100017510000000313014644144735012514 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include "got_lib_ratelimit.h" #include "got_compat.h" #include "got_error.h" void got_ratelimit_init(struct got_ratelimit *rl, time_t interval_sec, unsigned int interval_msec) { memset(rl, 0, sizeof(*rl)); rl->interval.tv_sec = interval_sec; rl->interval.tv_nsec = interval_msec * 1000000UL; } const struct got_error * got_ratelimit_check(int *elapsed, struct got_ratelimit *rl) { struct timespec now, delta; if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) return got_error_from_errno("clock_gettime"); if (timespecisset(&rl->last)) { timespecsub(&now, &rl->last, &delta); *elapsed = timespeccmp(&delta, &rl->interval, >=) ? 1 : 0; } else *elapsed = 1; if (*elapsed) rl->last = now; return NULL; } got-portable-0.101/lib/blame.c0000664000175100017510000003744114644144735011616 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * Copyright (c) 2020 Neels Hofmeyr * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_cancel.h" #include "got_commit_graph.h" #include "got_opentemp.h" #include "got_diff.h" #include "got_blame.h" #include "got_lib_inflate.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_diff.h" #ifndef MAX #define MAX(_a,_b) ((_a) > (_b) ? (_a) : (_b)) #endif struct got_blame_line { int annotated; struct got_object_id id; }; struct got_blame { struct diff_config *cfg; int nlines; /* number of lines in file being blamed */ int nannotated; /* number of lines already annotated */ struct got_blame_line *lines; /* one per line */ int ncommits; /* * These change with every traversed commit. After diffing * commits N:N-1, in preparation for diffing commits N-1:N-2, * data for commit N is retained and flipped into data for N-1. * */ FILE *f1; /* older version from commit N-1. */ FILE *f2; /* newer version from commit N. */ int fd; unsigned char *map1; unsigned char *map2; off_t size1; off_t size2; int nlines1; int nlines2; off_t *line_offsets1; off_t *line_offsets2; /* * Map line numbers of an older version of the file to valid line * numbers in the version of the file being blamed. This map is * updated with each commit we traverse throughout the file's history. * Lines mapped to -1 do not correspond to any line in the version * being blamed. */ int *linemap1; int *linemap2; struct diff_data *data1; struct diff_data *data2; }; static const struct got_error * annotate_line(struct got_blame *blame, int lineno, struct got_commit_object *commit, struct got_object_id *id, got_blame_cb cb, void *arg) { const struct got_error *err = NULL; struct got_blame_line *line; if (lineno < 0 || lineno >= blame->nlines) return NULL; line = &blame->lines[lineno]; if (line->annotated) return NULL; memcpy(&line->id, id, sizeof(line->id)); line->annotated = 1; blame->nannotated++; if (cb) err = cb(arg, blame->nlines, lineno + 1, commit, id); return err; } static const struct got_error * blame_changes(struct got_blame *blame, struct diff_result *diff_result, struct got_commit_object *commit, struct got_object_id *commit_id, got_blame_cb cb, void *arg) { const struct got_error *err = NULL; int i; int idx1 = 0, idx2 = 0; for (i = 0; i < diff_result->chunks.len && blame->nannotated < blame->nlines; i++) { struct diff_chunk *c = diff_chunk_get(diff_result, i); unsigned int left_count, right_count; int j; /* * We do not need to worry about idx1/idx2 growing out * of bounds because the diff implementation ensures * that chunk ranges never exceed the number of lines * in the left/right input files. */ left_count = diff_chunk_get_left_count(c); right_count = diff_chunk_get_right_count(c); if (left_count == right_count) { for (j = 0; j < left_count; j++) { blame->linemap1[idx1++] = blame->linemap2[idx2++]; } continue; } if (right_count == 0) { for (j = 0; j < left_count; j++) { blame->linemap1[idx1++] = -1; } continue; } for (j = 0; j < right_count; j++) { int ln = blame->linemap2[idx2++]; err = annotate_line(blame, ln, commit, commit_id, cb, arg); if (err) return err; if (blame->nlines == blame->nannotated) break; } } return NULL; } static const struct got_error * blame_prepare_file(FILE *f, unsigned char **p, off_t *size, int *nlines, off_t **line_offsets, struct diff_data *diff_data, const struct diff_config *cfg, struct got_blob_object *blob) { const struct got_error *err = NULL; int diff_flags = 0, rc; err = got_object_blob_dump_to_file(size, nlines, line_offsets, f, blob); if (err) return err; #ifndef GOT_DIFF_NO_MMAP *p = mmap(NULL, *size, PROT_READ, MAP_PRIVATE, fileno(f), 0); if (*p == MAP_FAILED) #endif *p = NULL; /* fall back on file I/O */ /* Allow blaming lines in binary files even though it's useless. */ diff_flags |= DIFF_FLAG_FORCE_TEXT_DATA; rc = diff_atomize_file(diff_data, cfg, f, *p, *size, diff_flags); if (rc) return got_error_set_errno(rc, "diff_atomize_file"); return NULL; } static const struct got_error * blame_commit(struct got_blame *blame, struct got_object_id *id, const char *path, struct got_repository *repo, got_blame_cb cb, void *arg) { const struct got_error *err = NULL; struct got_commit_object *commit = NULL, *pcommit = NULL; struct got_object_qid *pid = NULL; struct got_object_id *pblob_id = NULL; struct got_blob_object *pblob = NULL; struct diff_result *diff_result = NULL; err = got_object_open_as_commit(&commit, repo, id); if (err) return err; pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); if (pid == NULL) { got_object_commit_close(commit); return NULL; } err = got_object_open_as_commit(&pcommit, repo, &pid->id); if (err) goto done; err = got_object_id_by_path(&pblob_id, repo, pcommit, path); if (err) { if (err->code == GOT_ERR_NO_TREE_ENTRY) err = NULL; goto done; } err = got_object_open_as_blob(&pblob, repo, pblob_id, 8192, blame->fd); if (err) goto done; err = blame_prepare_file(blame->f1, &blame->map1, &blame->size1, &blame->nlines1, &blame->line_offsets1, blame->data1, blame->cfg, pblob); if (err) goto done; diff_result = diff_main(blame->cfg, blame->data1, blame->data2); if (diff_result == NULL) { err = got_error_set_errno(ENOMEM, "malloc"); goto done; } if (diff_result->rc != DIFF_RC_OK) { err = got_error_set_errno(diff_result->rc, "diff"); goto done; } if (diff_result->chunks.len > 0) { if (blame->nlines1 > 0) { blame->linemap1 = calloc(blame->nlines1, sizeof(*blame->linemap1)); if (blame->linemap1 == NULL) { err = got_error_from_errno("malloc"); goto done; } } err = blame_changes(blame, diff_result, commit, id, cb, arg); if (err) goto done; } else if (cb) err = cb(arg, blame->nlines, -1, commit, id); done: if (diff_result) diff_result_free(diff_result); if (commit) got_object_commit_close(commit); if (pcommit) got_object_commit_close(pcommit); free(pblob_id); if (pblob) got_object_blob_close(pblob); return err; } static const struct got_error * blame_close(struct got_blame *blame) { const struct got_error *err = NULL; diff_data_free(blame->data1); free(blame->data1); diff_data_free(blame->data2); free(blame->data2); if (blame->map1) { if (munmap(blame->map1, blame->size1) == -1 && err == NULL) err = got_error_from_errno("munmap"); } if (blame->map2) { if (munmap(blame->map2, blame->size2) == -1 && err == NULL) err = got_error_from_errno("munmap"); } free(blame->lines); free(blame->line_offsets1); free(blame->line_offsets2); free(blame->linemap1); free(blame->linemap2); free(blame->cfg); free(blame); return err; } static int atomize_file(struct diff_data *d, FILE *f, off_t filesize, int nlines, off_t *line_offsets) { int i, rc = DIFF_RC_OK; int embedded_nul = 0; ARRAYLIST_INIT(d->atoms, nlines); for (i = 0; i < nlines; i++) { struct diff_atom *atom; off_t len, pos = line_offsets[i]; unsigned int hash = 0; int j; ARRAYLIST_ADD(atom, d->atoms); if (atom == NULL) { rc = errno; break; } if (i < nlines - 1) len = line_offsets[i + 1] - pos; else len = filesize - pos; if (fseeko(f, pos, SEEK_SET) == -1) { rc = errno; break; } for (j = 0; j < len; j++) { int c = fgetc(f); if (c == EOF) { if (feof(f)) rc = EIO; /* unexpected EOF */ else rc = errno; goto done; } hash = diff_atom_hash_update(hash, (unsigned char)c); if (c == '\0') embedded_nul = 1; } *atom = (struct diff_atom){ .root = d, .pos = pos, .at = NULL, /* atom data is not memory-mapped */ .len = len, .hash = hash, }; } /* File are considered binary if they contain embedded '\0' bytes. */ if (embedded_nul) d->atomizer_flags |= DIFF_ATOMIZER_FOUND_BINARY_DATA; done: if (rc) ARRAYLIST_FREE(d->atoms); return rc; } static int atomize_file_mmap(struct diff_data *d, unsigned char *p, off_t filesize, int nlines, off_t *line_offsets) { int i, rc = DIFF_RC_OK; int embedded_nul = 0; ARRAYLIST_INIT(d->atoms, nlines); for (i = 0; i < nlines; i++) { struct diff_atom *atom; off_t len, pos = line_offsets[i]; unsigned int hash = 0; int j; ARRAYLIST_ADD(atom, d->atoms); if (atom == NULL) { rc = errno; break; } if (i < nlines - 1) len = line_offsets[i + 1] - pos; else len = filesize - pos; for (j = 0; j < len; j++) hash = diff_atom_hash_update(hash, p[pos + j]); if (!embedded_nul && memchr(&p[pos], '\0', len) != NULL) embedded_nul = 1; *atom = (struct diff_atom){ .root = d, .pos = pos, .at = &p[pos], .len = len, .hash = hash, }; } /* File are considered binary if they contain embedded '\0' bytes. */ if (embedded_nul) d->atomizer_flags |= DIFF_ATOMIZER_FOUND_BINARY_DATA; if (rc) ARRAYLIST_FREE(d->atoms); return rc; } /* Implements diff_atomize_func_t */ static int blame_atomize_file(void *arg, struct diff_data *d) { struct got_blame *blame = arg; if (d->f == blame->f1) { if (blame->map1) return atomize_file_mmap(d, blame->map1, blame->size1, blame->nlines1, blame->line_offsets1); else return atomize_file(d, blame->f1, blame->size1, blame->nlines1, blame->line_offsets1); } else if (d->f == blame->f2) { if (d->atoms.len > 0) { /* Re-use data from previous commit. */ return DIFF_RC_OK; } if (blame->map2) return atomize_file_mmap(d, blame->map2, blame->size2, blame->nlines2, blame->line_offsets2); else return atomize_file(d, blame->f2, blame->size2, blame->nlines2, blame->line_offsets2); } return DIFF_RC_OK; } static const struct got_error * flip_files(struct got_blame *blame) { const struct got_error *err = NULL; struct diff_data *d; FILE *tmp; free(blame->line_offsets2); blame->line_offsets2 = blame->line_offsets1; blame->line_offsets1 = NULL; free(blame->linemap2); blame->linemap2 = blame->linemap1; blame->linemap1 = NULL; if (blame->map2) { if (munmap(blame->map2, blame->size2) == -1) return got_error_from_errno("munmap"); blame->map2 = blame->map1; blame->map1 = NULL; } blame->size2 = blame->size1; err = got_opentemp_truncate(blame->f2); if (err) return err; tmp = blame->f2; blame->f2 = blame->f1; blame->f1 = tmp; blame->size1 = 0; blame->nlines2 = blame->nlines1; blame->nlines1 = 0; diff_data_free(blame->data2); /* does not free pointer itself */ memset(blame->data2, 0, sizeof(*blame->data2)); d = blame->data2; blame->data2 = blame->data1; blame->data1 = d; return NULL; } static const struct got_error * blame_open(struct got_blame **blamep, const char *path, struct got_object_id *start_commit_id, struct got_repository *repo, enum got_diff_algorithm diff_algo, got_blame_cb cb, void *arg, got_cancel_cb cancel_cb, void *cancel_arg, int fd1, int fd2, FILE *f1, FILE *f2) { const struct got_error *err = NULL; struct got_commit_object *start_commit = NULL, *last_commit = NULL; struct got_object_id *obj_id = NULL; struct got_blob_object *blob = NULL; struct got_blame *blame = NULL; struct got_object_id id; int lineno, have_id = 0; struct got_commit_graph *graph = NULL; *blamep = NULL; err = got_object_open_as_commit(&start_commit, repo, start_commit_id); if (err) goto done; err = got_object_id_by_path(&obj_id, repo, start_commit, path); if (err) goto done; err = got_object_open_as_blob(&blob, repo, obj_id, 8192, fd1); if (err) goto done; blame = calloc(1, sizeof(*blame)); if (blame == NULL) { err = got_error_from_errno("calloc"); goto done; } blame->data1 = calloc(1, sizeof(*blame->data1)); if (blame->data1 == NULL) { err = got_error_from_errno("calloc"); goto done; } blame->data2 = calloc(1, sizeof(*blame->data2)); if (blame->data2 == NULL) { err = got_error_from_errno("calloc"); goto done; } blame->f1 = f1; blame->f2 = f2; blame->fd = fd2; err = got_diff_get_config(&blame->cfg, diff_algo, blame_atomize_file, blame); if (err) goto done; err = blame_prepare_file(blame->f2, &blame->map2, &blame->size2, &blame->nlines2, &blame->line_offsets2, blame->data2, blame->cfg, blob); blame->nlines = blame->nlines2; if (err || blame->nlines == 0) goto done; got_object_blob_close(blob); blob = NULL; /* Don't include \n at EOF in the blame line count. */ if (blame->line_offsets2[blame->nlines - 1] == blame->size2) blame->nlines--; blame->lines = calloc(blame->nlines, sizeof(*blame->lines)); if (blame->lines == NULL) { err = got_error_from_errno("calloc"); goto done; } blame->linemap2 = calloc(blame->nlines2, sizeof(*blame->linemap2)); if (blame->linemap2 == NULL) { err = got_error_from_errno("calloc"); goto done; } for (lineno = 0; lineno < blame->nlines2; lineno++) blame->linemap2[lineno] = lineno; err = got_commit_graph_open(&graph, path, 1); if (err) goto done; err = got_commit_graph_bfsort(graph, start_commit_id, repo, cancel_cb, cancel_arg); if (err) goto done; for (;;) { err = got_commit_graph_iter_next(&id, graph, repo, cancel_cb, cancel_arg); if (err) { if (err->code == GOT_ERR_ITER_COMPLETED) { err = NULL; break; } goto done; } have_id = 1; err = blame_commit(blame, &id, path, repo, cb, arg); if (err) { if (err->code == GOT_ERR_ITER_COMPLETED) err = NULL; goto done; } if (blame->nannotated == blame->nlines) break; err = flip_files(blame); if (err) goto done; } if (have_id && blame->nannotated < blame->nlines) { /* Annotate remaining non-annotated lines with last commit. */ err = got_object_open_as_commit(&last_commit, repo, &id); if (err) goto done; for (lineno = 0; lineno < blame->nlines; lineno++) { err = annotate_line(blame, lineno, last_commit, &id, cb, arg); if (err) goto done; } } done: if (graph) got_commit_graph_close(graph); free(obj_id); if (blob) got_object_blob_close(blob); if (start_commit) got_object_commit_close(start_commit); if (last_commit) got_object_commit_close(last_commit); if (err) { if (blame) blame_close(blame); } else *blamep = blame; return err; } const struct got_error * got_blame(const char *path, struct got_object_id *commit_id, struct got_repository *repo, enum got_diff_algorithm diff_algo, got_blame_cb cb, void *arg, got_cancel_cb cancel_cb, void* cancel_arg, int fd1, int fd2, FILE *f1, FILE *f2) { const struct got_error *err = NULL, *close_err = NULL; struct got_blame *blame; char *abspath; if (asprintf(&abspath, "%s%s", path[0] == '/' ? "" : "/", path) == -1) return got_error_from_errno2("asprintf", path); err = blame_open(&blame, abspath, commit_id, repo, diff_algo, cb, arg, cancel_cb, cancel_arg, fd1, fd2, f1, f2); free(abspath); if (blame) close_err = blame_close(blame); return err ? err : close_err; } got-portable-0.101/lib/reference.c0000664000175100017510000011514714644144735012474 /* * Copyright (c) 2018, 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_repository.h" #include "got_reference.h" #include "got_opentemp.h" #include "got_path.h" #include "got_lib_hash.h" #include "got_lib_delta.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_idset.h" #include "got_lib_lockfile.h" #ifndef nitems #define nitems(_a) (sizeof(_a) / sizeof((_a)[0])) #endif #define GOT_REF_HEADS "heads" #define GOT_REF_TAGS "tags" #define GOT_REF_REMOTES "remotes" /* * We do not resolve tags yet, and don't yet care about sorting refs either, * so packed-refs files we write contain a minimal header which disables all * packed-refs "traits" supported by Git. */ #define GOT_PACKED_REFS_HEADER "# pack-refs with:" /* A symbolic reference. */ struct got_symref { char *name; char *ref; }; #define GOT_REF_RECURSE_MAX 20 /* A non-symbolic reference (there is no better designation). */ struct got_ref { char *name; struct got_object_id id; }; /* A reference which points to an arbitrary object. */ struct got_reference { unsigned int flags; #define GOT_REF_IS_SYMBOLIC 0x01 #define GOT_REF_IS_PACKED 0x02 union { struct got_ref ref; struct got_symref symref; } ref; struct got_lockfile *lf; time_t mtime; /* * Cached timestamp for got_ref_cmp_by_commit_timestamp_descending() * and got_ref_cmp_tags(). */ time_t committer_time; }; static const struct got_error * alloc_ref(struct got_reference **ref, const char *name, struct got_object_id *id, int flags, time_t mtime) { const struct got_error *err = NULL; *ref = calloc(1, sizeof(**ref)); if (*ref == NULL) return got_error_from_errno("calloc"); memcpy(&(*ref)->ref.ref.id, id, sizeof((*ref)->ref.ref.id)); (*ref)->flags = flags; (*ref)->ref.ref.name = strdup(name); (*ref)->mtime = mtime; if ((*ref)->ref.ref.name == NULL) { err = got_error_from_errno("strdup"); got_ref_close(*ref); *ref = NULL; } return err; } static const struct got_error * alloc_symref(struct got_reference **ref, const char *name, const char *target_ref, int flags) { const struct got_error *err = NULL; *ref = calloc(1, sizeof(**ref)); if (*ref == NULL) return got_error_from_errno("calloc"); (*ref)->flags = GOT_REF_IS_SYMBOLIC | flags; (*ref)->ref.symref.name = strdup(name); if ((*ref)->ref.symref.name == NULL) { err = got_error_from_errno("strdup"); got_ref_close(*ref); *ref = NULL; return err; } (*ref)->ref.symref.ref = strdup(target_ref); if ((*ref)->ref.symref.ref == NULL) { err = got_error_from_errno("strdup"); got_ref_close(*ref); *ref = NULL; } return err; } static const struct got_error * parse_symref(struct got_reference **ref, const char *name, const char *line) { if (line[0] == '\0') return got_error(GOT_ERR_BAD_REF_DATA); return alloc_symref(ref, name, line, 0); } static const struct got_error * parse_ref_line(struct got_reference **ref, const char *name, const char *line, time_t mtime, enum got_hash_algorithm algo) { struct got_object_id id; if (strncmp(line, "ref: ", 5) == 0) { line += 5; return parse_symref(ref, name, line); } if (!got_parse_object_id(&id, line, algo)) return got_error(GOT_ERR_BAD_REF_DATA); return alloc_ref(ref, name, &id, 0, mtime); } static const struct got_error * parse_ref_file(struct got_reference **ref, const char *name, const char *absname, const char *abspath, int lock, enum got_hash_algorithm algo) { const struct got_error *err = NULL; FILE *f; char *line = NULL; size_t linesize = 0; ssize_t linelen; struct got_lockfile *lf = NULL; struct stat sb; if (lock) { err = got_lockfile_lock(&lf, abspath, -1); if (err) { if (err->code == GOT_ERR_ERRNO && errno == ENOENT) err = got_error_not_ref(name); return err; } } f = fopen(abspath, "rbe"); if (f == NULL) { if (errno != ENOTDIR && errno != ENOENT) err = got_error_from_errno2("fopen", abspath); else err = got_error_not_ref(name); if (lock) got_lockfile_unlock(lf, -1); return err; } if (fstat(fileno(f), &sb) == -1) { err = got_error_from_errno2("fstat", abspath); goto done; } linelen = getline(&line, &linesize, f); if (linelen == -1) { if (feof(f)) err = NULL; /* ignore empty files (could be locks) */ else { if (errno == EISDIR) err = got_error(GOT_ERR_NOT_REF); else if (ferror(f)) err = got_ferror(f, GOT_ERR_IO); else err = got_error_from_errno2("getline", abspath); } if (lock) got_lockfile_unlock(lf, -1); goto done; } while (linelen > 0 && line[linelen - 1] == '\n') { line[linelen - 1] = '\0'; linelen--; } err = parse_ref_line(ref, absname, line, sb.st_mtime, algo); if (lock) { if (err) got_lockfile_unlock(lf, -1); else { if (*ref) (*ref)->lf = lf; else got_lockfile_unlock(lf, -1); } } done: free(line); if (fclose(f) == EOF && err == NULL) { err = got_error_from_errno("fclose"); if (*ref) { if (lock) got_ref_unlock(*ref); got_ref_close(*ref); *ref = NULL; } } return err; } static int is_well_known_ref(const char *refname) { return (strcmp(refname, GOT_REF_HEAD) == 0 || strcmp(refname, GOT_REF_ORIG_HEAD) == 0 || strcmp(refname, GOT_REF_MERGE_HEAD) == 0 || strcmp(refname, GOT_REF_FETCH_HEAD) == 0); } static char * get_refs_dir_path(struct got_repository *repo, const char *refname) { if (is_well_known_ref(refname) || strncmp(refname, "refs/", 5) == 0) return strdup(got_repo_get_path_git_dir(repo)); return got_repo_get_path_refs(repo); } const struct got_error * got_ref_alloc(struct got_reference **ref, const char *name, struct got_object_id *id) { if (!got_ref_name_is_valid(name)) return got_error_path(name, GOT_ERR_BAD_REF_NAME); return alloc_ref(ref, name, id, 0, 0); } const struct got_error * got_ref_alloc_symref(struct got_reference **ref, const char *name, struct got_reference *target_ref) { if (!got_ref_name_is_valid(name)) return got_error_path(name, GOT_ERR_BAD_REF_NAME); return alloc_symref(ref, name, got_ref_get_name(target_ref), 0); } static const struct got_error * parse_packed_ref_line(struct got_reference **ref, const char *abs_refname, const char *line, time_t mtime, enum got_hash_algorithm algo) { struct got_object_id id; const char *name; *ref = NULL; if (line[0] == '#' || line[0] == '^') return NULL; if (!got_parse_object_id(&id, line, algo)) return got_error(GOT_ERR_BAD_REF_DATA); if (abs_refname) { if (strcmp(line + SHA1_DIGEST_STRING_LENGTH, abs_refname) != 0) return NULL; name = abs_refname; } else name = line + SHA1_DIGEST_STRING_LENGTH; return alloc_ref(ref, name, &id, GOT_REF_IS_PACKED, mtime); } static const struct got_error * open_packed_ref(struct got_reference **ref, FILE *f, const char **subdirs, int nsubdirs, const char *refname, time_t mtime, enum got_hash_algorithm algo) { const struct got_error *err = NULL; char *abs_refname; char *line = NULL; size_t linesize = 0; ssize_t linelen; int i, ref_is_absolute = (strncmp(refname, "refs/", 5) == 0); *ref = NULL; if (ref_is_absolute) abs_refname = (char *)refname; do { linelen = getline(&line, &linesize, f); if (linelen == -1) { if (feof(f)) break; err = got_ferror(f, GOT_ERR_BAD_REF_DATA); break; } if (linelen > 0 && line[linelen - 1] == '\n') line[linelen - 1] = '\0'; for (i = 0; i < nsubdirs; i++) { if (!ref_is_absolute && asprintf(&abs_refname, "refs/%s/%s", subdirs[i], refname) == -1) return got_error_from_errno("asprintf"); err = parse_packed_ref_line(ref, abs_refname, line, mtime, algo); if (!ref_is_absolute) free(abs_refname); if (err || *ref != NULL) break; } if (err) break; } while (*ref == NULL); free(line); return err; } static const struct got_error * open_ref(struct got_reference **ref, const char *path_refs, const char *subdir, const char *name, int lock, enum got_hash_algorithm algo) { const struct got_error *err = NULL; char *path = NULL; char *absname = NULL; int ref_is_absolute = (strncmp(name, "refs/", 5) == 0); int ref_is_well_known = (subdir[0] == '\0' && is_well_known_ref(name)); *ref = NULL; if (!got_ref_name_is_valid(name)) return got_error_path(name, GOT_ERR_BAD_REF_NAME); if (ref_is_absolute || ref_is_well_known) { if (asprintf(&path, "%s/%s", path_refs, name) == -1) return got_error_from_errno("asprintf"); absname = (char *)name; } else { if (asprintf(&path, "%s/%s%s%s", path_refs, subdir, subdir[0] ? "/" : "", name) == -1) return got_error_from_errno("asprintf"); if (asprintf(&absname, "refs/%s%s%s", subdir, subdir[0] ? "/" : "", name) == -1) { err = got_error_from_errno("asprintf"); goto done; } } err = parse_ref_file(ref, name, absname, path, lock, algo); done: if (!ref_is_absolute && !ref_is_well_known) free(absname); free(path); return err; } const struct got_error * got_ref_open(struct got_reference **ref, struct got_repository *repo, const char *refname, int lock) { const struct got_error *err = NULL; char *packed_refs_path = NULL, *path_refs = NULL; const char *subdirs[] = { GOT_REF_HEADS, GOT_REF_TAGS, GOT_REF_REMOTES }; size_t i; int well_known = is_well_known_ref(refname); struct got_lockfile *lf = NULL; *ref = NULL; path_refs = get_refs_dir_path(repo, refname); if (path_refs == NULL) { err = got_error_from_errno2("get_refs_dir_path", refname); goto done; } if (well_known) { err = open_ref(ref, path_refs, "", refname, lock, got_repo_get_object_format(repo)); } else { FILE *f; /* Search on-disk refs before packed refs! */ for (i = 0; i < nitems(subdirs); i++) { err = open_ref(ref, path_refs, subdirs[i], refname, lock, got_repo_get_object_format(repo)); if ((err && err->code != GOT_ERR_NOT_REF) || *ref) goto done; } packed_refs_path = got_repo_get_path_packed_refs(repo); if (packed_refs_path == NULL) { err = got_error_from_errno( "got_repo_get_path_packed_refs"); goto done; } if (lock) { err = got_lockfile_lock(&lf, packed_refs_path, -1); if (err) goto done; } f = fopen(packed_refs_path, "rbe"); if (f != NULL) { struct stat sb; if (fstat(fileno(f), &sb) == -1) { err = got_error_from_errno2("fstat", packed_refs_path); goto done; } err = open_packed_ref(ref, f, subdirs, nitems(subdirs), refname, sb.st_mtime, got_repo_get_object_format(repo)); if (!err) { if (fclose(f) == EOF) { err = got_error_from_errno("fclose"); got_ref_close(*ref); *ref = NULL; } else if (*ref) (*ref)->lf = lf; } } } done: if (!err && *ref == NULL) err = got_error_not_ref(refname); if (err && lf) got_lockfile_unlock(lf, -1); free(packed_refs_path); free(path_refs); return err; } void got_ref_close(struct got_reference *ref) { if (ref->flags & GOT_REF_IS_SYMBOLIC) { free(ref->ref.symref.name); free(ref->ref.symref.ref); } else free(ref->ref.ref.name); free(ref); } struct got_reference * got_ref_dup(struct got_reference *ref) { struct got_reference *ret; ret = calloc(1, sizeof(*ret)); if (ret == NULL) return NULL; ret->flags = ref->flags; if (ref->flags & GOT_REF_IS_SYMBOLIC) { ret->ref.symref.name = strdup(ref->ref.symref.name); if (ret->ref.symref.name == NULL) { free(ret); return NULL; } ret->ref.symref.ref = strdup(ref->ref.symref.ref); if (ret->ref.symref.ref == NULL) { free(ret->ref.symref.name); free(ret); return NULL; } } else { ret->ref.ref.name = strdup(ref->ref.ref.name); if (ret->ref.ref.name == NULL) { free(ret); return NULL; } memcpy(&ret->ref.ref.id, &ref->ref.ref.id, sizeof(ret->ref.ref.id)); } return ret; } const struct got_error * got_reflist_entry_dup(struct got_reflist_entry **newp, struct got_reflist_entry *re) { const struct got_error *err = NULL; struct got_reflist_entry *new; *newp = NULL; new = malloc(sizeof(*new)); if (new == NULL) return got_error_from_errno("malloc"); new->ref = got_ref_dup(re->ref); if (new->ref == NULL) { err = got_error_from_errno("got_ref_dup"); free(new); return err; } *newp = new; return NULL; } const struct got_error * got_ref_resolve_symbolic(struct got_reference **resolved, struct got_repository *repo, struct got_reference *ref) { struct got_reference *nextref; const struct got_error *err; err = got_ref_open(&nextref, repo, ref->ref.symref.ref, 0); if (err) return err; if (nextref->flags & GOT_REF_IS_SYMBOLIC) err = got_ref_resolve_symbolic(resolved, repo, nextref); else *resolved = got_ref_dup(nextref); got_ref_close(nextref); return err; } static const struct got_error * ref_resolve(struct got_object_id **id, struct got_repository *repo, struct got_reference *ref, int recursion) { const struct got_error *err; if (recursion <= 0) return got_error_msg(GOT_ERR_RECURSION, "reference recursion limit reached"); if (ref->flags & GOT_REF_IS_SYMBOLIC) { struct got_reference *resolved = NULL; err = got_ref_resolve_symbolic(&resolved, repo, ref); if (err == NULL) err = ref_resolve(id, repo, resolved, --recursion); if (resolved) got_ref_close(resolved); return err; } *id = calloc(1, sizeof(**id)); if (*id == NULL) return got_error_from_errno("calloc"); memcpy(*id, &ref->ref.ref.id, sizeof(**id)); return NULL; } const struct got_error * got_ref_resolve(struct got_object_id **id, struct got_repository *repo, struct got_reference *ref) { return ref_resolve(id, repo, ref, GOT_REF_RECURSE_MAX); } char * got_ref_to_str(struct got_reference *ref) { char *str; if (ref->flags & GOT_REF_IS_SYMBOLIC) return strdup(ref->ref.symref.ref); if (got_object_id_str(&str, &ref->ref.ref.id) != NULL) return NULL; return str; } const char * got_ref_get_name(struct got_reference *ref) { if (ref->flags & GOT_REF_IS_SYMBOLIC) return ref->ref.symref.name; return ref->ref.ref.name; } const char * got_ref_get_symref_target(struct got_reference *ref) { if (ref->flags & GOT_REF_IS_SYMBOLIC) return ref->ref.symref.ref; return NULL; } time_t got_ref_get_mtime(struct got_reference *ref) { return ref->mtime; } const struct got_error * got_ref_cmp_by_name(void *arg, int *cmp, struct got_reference *re1, struct got_reference* re2) { const char *name1 = got_ref_get_name(re1); const char *name2 = got_ref_get_name(re2); *cmp = got_path_cmp(name1, name2, strlen(name1), strlen(name2)); return NULL; } static const struct got_error * get_committer_time(struct got_reference *ref, struct got_repository *repo) { const struct got_error *err = NULL; int obj_type; struct got_commit_object *commit = NULL; struct got_tag_object *tag = NULL; struct got_object_id *id = NULL; err = got_ref_resolve(&id, repo, ref); if (err) return err; err = got_object_get_type(&obj_type, repo, id); if (err) goto done; switch (obj_type) { case GOT_OBJ_TYPE_COMMIT: err = got_object_open_as_commit(&commit, repo, id); if (err) goto done; ref->committer_time = got_object_commit_get_committer_time(commit); break; case GOT_OBJ_TYPE_TAG: err = got_object_open_as_tag(&tag, repo, id); if (err) goto done; ref->committer_time = got_object_tag_get_tagger_time(tag); break; default: /* best effort for other object types */ ref->committer_time = got_ref_get_mtime(ref); break; } done: free(id); if (commit) got_object_commit_close(commit); if (tag) got_object_tag_close(tag); return err; } const struct got_error * got_ref_cmp_tags(void *arg, int *cmp, struct got_reference *ref1, struct got_reference *ref2) { const struct got_error *err = NULL; struct got_repository *repo = arg; *cmp = 0; if (ref1->committer_time == 0) { err = get_committer_time(ref1, repo); if (err) return err; } if (ref2->committer_time == 0) { err = get_committer_time(ref2, repo); if (err) return err; } /* Put latest tags first. */ if (ref1->committer_time < ref2->committer_time) *cmp = 1; else if (ref1->committer_time > ref2->committer_time) *cmp = -1; else err = got_ref_cmp_by_name(NULL, cmp, ref2, ref1); return err; } const struct got_error * got_ref_cmp_by_commit_timestamp_descending(void *arg, int *cmp, struct got_reference *ref1, struct got_reference *ref2) { const struct got_error *err = NULL; struct got_repository *repo = arg; *cmp = 0; if (ref1->committer_time == 0) { err = get_committer_time(ref1, repo); if (err) return err; } if (ref2->committer_time == 0) { err = get_committer_time(ref2, repo); if (err) return err; } if (ref1->committer_time < ref2->committer_time) *cmp = 1; else if (ref2->committer_time < ref1->committer_time) *cmp = -1; else return got_ref_cmp_by_name(arg, cmp, ref1, ref2); return err; } const struct got_error * got_reflist_insert(struct got_reflist_entry **newp, struct got_reflist_head *refs, struct got_reference *ref, got_ref_cmp_cb cmp_cb, void *cmp_arg) { const struct got_error *err; struct got_reflist_entry *new, *re; int cmp; *newp = NULL; if (cmp_cb != got_ref_cmp_by_name && (ref->flags & GOT_REF_IS_PACKED)) { /* * If we are not sorting elements by name then we must still * detect collisions between a packed ref and an on-disk ref * using the same name. On-disk refs take precedence and are * already present on the list before packed refs get added. */ TAILQ_FOREACH(re, refs, entry) { err = got_ref_cmp_by_name(NULL, &cmp, re->ref, ref); if (err) return err; if (cmp == 0) return NULL; } } new = malloc(sizeof(*new)); if (new == NULL) return got_error_from_errno("malloc"); new->ref = ref; *newp = new; /* * We must de-duplicate entries on insert because packed-refs may * contain redundant entries. On-disk refs take precedence. * This code assumes that on-disk revs are read before packed-refs. * We're iterating the list anyway, so insert elements sorted by name. * * Many callers will provide paths in a somewhat sorted order. * Iterating backwards from the tail of the list should be more * efficient than traversing through the entire list each time * an element is inserted. */ re = TAILQ_LAST(refs, got_reflist_head); while (re) { err = (*cmp_cb)(cmp_arg, &cmp, re->ref, new->ref); if (err) return err; if (cmp == 0) { /* duplicate */ free(new); *newp = NULL; return NULL; } else if (cmp < 0) { TAILQ_INSERT_AFTER(refs, re, new, entry); return NULL; } re = TAILQ_PREV(re, got_reflist_head, entry); } TAILQ_INSERT_HEAD(refs, new, entry); return NULL; } const struct got_error * got_reflist_sort(struct got_reflist_head *refs, got_ref_cmp_cb cmp_cb, void *cmp_arg) { const struct got_error *err = NULL; struct got_reflist_entry *re, *tmp, *new; struct got_reflist_head sorted; TAILQ_INIT(&sorted); TAILQ_FOREACH_SAFE(re, refs, entry, tmp) { struct got_reference *ref = re->ref; TAILQ_REMOVE(refs, re, entry); free(re); err = got_reflist_insert(&new, &sorted, ref, cmp_cb, cmp_arg); if (err || new == NULL /* duplicate */) got_ref_close(ref); if (err) return err; } TAILQ_CONCAT(refs, &sorted, entry); return NULL; } static const struct got_error * gather_on_disk_refs(struct got_reflist_head *refs, const char *path_refs, const char *subdir, struct got_repository *repo, got_ref_cmp_cb cmp_cb, void *cmp_arg) { const struct got_error *err = NULL; DIR *d = NULL; char *path_subdir; struct got_reference *ref; struct got_reflist_entry *new; while (subdir[0] == '/') subdir++; if (asprintf(&path_subdir, "%s/%s", path_refs, subdir) == -1) return got_error_from_errno("asprintf"); d = opendir(path_subdir); if (d == NULL) { char *refname; if (errno != ENOTDIR) goto done; /* This could be a regular on-disk reference file. */ free(path_subdir); err = got_path_dirname(&path_subdir, subdir); if (err) return err; err = got_path_basename(&refname, subdir); if (err) { free(path_subdir); return err; } err = open_ref(&ref, path_refs, path_subdir, refname, 0, got_repo_get_object_format(repo)); free(path_subdir); free(refname); if (err) { if (err->code == GOT_ERR_NOT_REF) return NULL; return err; } err = got_reflist_insert(&new, refs, ref, cmp_cb, cmp_arg); if (err || new == NULL /* duplicate */) got_ref_close(ref); return err; } for (;;) { struct dirent *dent; char *child; int type; dent = readdir(d); if (dent == NULL) break; if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) continue; err = got_path_dirent_type(&type, path_subdir, dent); if (err) break; switch (type) { case DT_REG: err = open_ref(&ref, path_refs, subdir, dent->d_name, 0, got_repo_get_object_format(repo)); if (err && err->code == GOT_ERR_BAD_REF_NAME) break; if (err) goto done; if (ref) { err = got_reflist_insert(&new, refs, ref, cmp_cb, cmp_arg); if (err || new == NULL /* duplicate */) got_ref_close(ref); if (err) goto done; } break; case DT_DIR: if (asprintf(&child, "%s%s%s", subdir, subdir[0] == '\0' ? "" : "/", dent->d_name) == -1) { err = got_error_from_errno("asprintf"); break; } err = gather_on_disk_refs(refs, path_refs, child, repo, cmp_cb, cmp_arg); free(child); break; default: break; } } done: if (d) closedir(d); free(path_subdir); return err; } static int match_packed_ref(struct got_reference *ref, const char *ref_namespace) { const char *name = got_ref_get_name(ref); int namespace_is_absolute = (strncmp(ref_namespace, "refs/", 5) == 0); if (namespace_is_absolute) { return (strcmp(name, ref_namespace) == 0 || got_path_is_child(name, ref_namespace, strlen(ref_namespace))); } /* Match all "subdirectories" as we do with on-disk refs. */ while (*name != '\0') { while (*name == '/') name++; if (strcmp(name, ref_namespace) == 0 || got_path_is_child(name, ref_namespace, strlen(ref_namespace))) return 1; while (*name != '\0' && *name != '/') name++; } return 0; } const struct got_error * got_ref_list(struct got_reflist_head *refs, struct got_repository *repo, const char *ref_namespace, got_ref_cmp_cb cmp_cb, void *cmp_arg) { const struct got_error *err; char *packed_refs_path = NULL, *path_refs = NULL; char *abs_namespace = NULL, *buf = NULL; const char *ondisk_ref_namespace = NULL; char *line = NULL; FILE *f = NULL; struct got_reference *ref; struct got_reflist_entry *new; if (ref_namespace == NULL || ref_namespace[0] == '\0') { path_refs = get_refs_dir_path(repo, GOT_REF_HEAD); if (path_refs == NULL) { err = got_error_from_errno("get_refs_dir_path"); goto done; } err = open_ref(&ref, path_refs, "", GOT_REF_HEAD, 0, got_repo_get_object_format(repo)); if (err) goto done; err = got_reflist_insert(&new, refs, ref, cmp_cb, cmp_arg); if (err || new == NULL /* duplicate */) got_ref_close(ref); if (err && err->code != GOT_ERR_NOT_REF) goto done; } else { /* Try listing a single reference. */ err = got_ref_open(&ref, repo, ref_namespace, 0); if (err) { if (err->code != GOT_ERR_NOT_REF) goto done; /* Try to look up references in a given namespace. */ } else { err = got_reflist_insert(&new, refs, ref, cmp_cb, cmp_arg); if (err || new == NULL /* duplicate */) got_ref_close(ref); return err; } } if (ref_namespace) { size_t len; /* Canonicalize the path to eliminate double-slashes if any. */ if (asprintf(&abs_namespace, "/%s", ref_namespace) == -1) { err = got_error_from_errno("asprintf"); goto done; } len = strlen(abs_namespace) + 1; buf = malloc(len); if (buf == NULL) { err = got_error_from_errno("malloc"); goto done; } err = got_canonpath(abs_namespace, buf, len); if (err) goto done; ondisk_ref_namespace = buf; while (ondisk_ref_namespace[0] == '/') ondisk_ref_namespace++; if (strncmp(ondisk_ref_namespace, "refs/", 5) == 0) ondisk_ref_namespace += 5; else if (strcmp(ondisk_ref_namespace, "refs") == 0) ondisk_ref_namespace = ""; } /* Gather on-disk refs before parsing packed-refs. */ free(path_refs); path_refs = get_refs_dir_path(repo, ""); if (path_refs == NULL) { err = got_error_from_errno("get_refs_dir_path"); goto done; } err = gather_on_disk_refs(refs, path_refs, ondisk_ref_namespace ? ondisk_ref_namespace : "", repo, cmp_cb, cmp_arg); if (err) goto done; /* * The packed-refs file may contain redundant entries, in which * case on-disk refs take precedence. */ packed_refs_path = got_repo_get_path_packed_refs(repo); if (packed_refs_path == NULL) { err = got_error_from_errno("got_repo_get_path_packed_refs"); goto done; } f = fopen(packed_refs_path, "re"); if (f) { size_t linesize = 0; ssize_t linelen; struct stat sb; if (fstat(fileno(f), &sb) == -1) { err = got_error_from_errno2("fstat", packed_refs_path); goto done; } for (;;) { linelen = getline(&line, &linesize, f); if (linelen == -1) { if (feof(f)) break; err = got_ferror(f, GOT_ERR_BAD_REF_DATA); goto done; } if (linelen > 0 && line[linelen - 1] == '\n') line[linelen - 1] = '\0'; err = parse_packed_ref_line(&ref, NULL, line, sb.st_mtime, got_repo_get_object_format(repo)); if (err) goto done; if (ref) { if (ref_namespace && !match_packed_ref(ref, ref_namespace)) { got_ref_close(ref); continue; } err = got_reflist_insert(&new, refs, ref, cmp_cb, cmp_arg); if (err || new == NULL /* duplicate */) got_ref_close(ref); if (err) goto done; } } } done: free(packed_refs_path); free(abs_namespace); free(buf); free(line); free(path_refs); if (f && fclose(f) == EOF && err == NULL) err = got_error_from_errno("fclose"); return err; } void got_ref_list_free(struct got_reflist_head *refs) { struct got_reflist_entry *re; while ((re = TAILQ_FIRST(refs))) { TAILQ_REMOVE(refs, re, entry); got_ref_close(re->ref); free(re); } } int got_ref_is_symbolic(struct got_reference *ref) { return (ref->flags & GOT_REF_IS_SYMBOLIC); } const struct got_error * got_ref_change_ref(struct got_reference *ref, struct got_object_id *id) { if (ref->flags & GOT_REF_IS_SYMBOLIC) return got_error(GOT_ERR_BAD_REF_TYPE); memcpy(&ref->ref.ref.id, id, sizeof(ref->ref.ref.id)); return NULL; } const struct got_error * got_ref_change_symref(struct got_reference *ref, const char *refname) { char *new_name; if ((ref->flags & GOT_REF_IS_SYMBOLIC) == 0) return got_error(GOT_ERR_BAD_REF_TYPE); new_name = strdup(refname); if (new_name == NULL) return got_error_from_errno("strdup"); free(ref->ref.symref.ref); ref->ref.symref.ref = new_name; return NULL; } const struct got_error * got_ref_change_symref_to_ref(struct got_reference *symref, struct got_object_id *id) { if ((symref->flags & GOT_REF_IS_SYMBOLIC) == 0) return got_error(GOT_ERR_BAD_REF_TYPE); symref->ref.ref.name = symref->ref.symref.name; memcpy(&symref->ref.ref.id, id, sizeof(symref->ref.ref.id)); symref->flags &= ~GOT_REF_IS_SYMBOLIC; return NULL; } const struct got_error * got_ref_write(struct got_reference *ref, struct got_repository *repo) { const struct got_error *err = NULL, *unlock_err = NULL; const char *name = got_ref_get_name(ref); char *path_refs = NULL, *path = NULL, *tmppath = NULL; struct got_lockfile *lf = NULL; FILE *f = NULL; size_t n; struct stat sb; path_refs = get_refs_dir_path(repo, name); if (path_refs == NULL) { err = got_error_from_errno2("get_refs_dir_path", name); goto done; } if (asprintf(&path, "%s/%s", path_refs, name) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_opentemp_named(&tmppath, &f, path, ""); if (err) { char *parent; if (err->code == GOT_ERR_ERRNO && errno == ENOTDIR) { err = got_error_fmt(GOT_ERR_BAD_REF_NAME, "collision with an existing reference: %s", got_ref_get_name(ref)); goto done; } if (!(err->code == GOT_ERR_ERRNO && errno == ENOENT)) goto done; err = got_path_dirname(&parent, path); if (err) goto done; err = got_path_mkdir(parent); free(parent); if (err) goto done; err = got_opentemp_named(&tmppath, &f, path, ""); if (err) goto done; } if (ref->flags & GOT_REF_IS_SYMBOLIC) { n = fprintf(f, "ref: %s\n", ref->ref.symref.ref); if (n != strlen(ref->ref.symref.ref) + 6) { err = got_ferror(f, GOT_ERR_IO); goto done; } } else { char *hex; size_t len; err = got_object_id_str(&hex, &ref->ref.ref.id); if (err) goto done; len = strlen(hex); n = fprintf(f, "%s\n", hex); free(hex); if (n != len + 1) { err = got_ferror(f, GOT_ERR_IO); goto done; } } if (ref->lf == NULL) { err = got_lockfile_lock(&lf, path, -1); if (err) goto done; } /* XXX: check if old content matches our expectations? */ if (stat(path, &sb) != 0) { if (errno != ENOENT) { err = got_error_from_errno2("stat", path); goto done; } sb.st_mode = GOT_DEFAULT_FILE_MODE; } if (fchmod(fileno(f), sb.st_mode) != 0) { err = got_error_from_errno2("fchmod", tmppath); goto done; } if (rename(tmppath, path) != 0) { err = got_error_from_errno3("rename", tmppath, path); goto done; } free(tmppath); tmppath = NULL; if (stat(path, &sb) == -1) { err = got_error_from_errno2("stat", path); goto done; } ref->mtime = sb.st_mtime; done: if (ref->lf == NULL && lf) unlock_err = got_lockfile_unlock(lf, -1); if (f) { if (fclose(f) == EOF && err == NULL) err = got_error_from_errno("fclose"); } free(path_refs); free(path); if (tmppath) { if (unlink(tmppath) == -1 && err == NULL) err = got_error_from_errno2("unlink", tmppath); free(tmppath); } return err ? err : unlock_err; } static const struct got_error * delete_packed_ref(struct got_reference *delref, struct got_repository *repo) { const struct got_error *err = NULL, *unlock_err = NULL; struct got_lockfile *lf = NULL; FILE *f = NULL, *tmpf = NULL; char *line = NULL, *packed_refs_path, *tmppath = NULL; size_t linesize = 0; struct got_reflist_head refs; int found_delref = 0; /* The packed-refs file does not cotain symbolic references. */ if (delref->flags & GOT_REF_IS_SYMBOLIC) return got_error(GOT_ERR_BAD_REF_DATA); TAILQ_INIT(&refs); packed_refs_path = got_repo_get_path_packed_refs(repo); if (packed_refs_path == NULL) return got_error_from_errno("got_repo_get_path_packed_refs"); err = got_opentemp_named(&tmppath, &tmpf, packed_refs_path, ""); if (err) goto done; if (delref->lf == NULL) { err = got_lockfile_lock(&lf, packed_refs_path, -1); if (err) goto done; } f = fopen(packed_refs_path, "re"); if (f == NULL) { err = got_error_from_errno2("fopen", packed_refs_path); goto done; } for (;;) { ssize_t linelen; struct got_reference *ref; struct got_reflist_entry *new; linelen = getline(&line, &linesize, f); if (linelen == -1) { if (feof(f)) break; err = got_ferror(f, GOT_ERR_BAD_REF_DATA); goto done; } if (linelen > 0 && line[linelen - 1] == '\n') line[linelen - 1] = '\0'; err = parse_packed_ref_line(&ref, NULL, line, 0, got_repo_get_object_format(repo)); if (err) goto done; if (ref == NULL) continue; if (strcmp(ref->ref.ref.name, delref->ref.ref.name) == 0 && got_object_id_cmp(&ref->ref.ref.id, &delref->ref.ref.id) == 0) { found_delref = 1; got_ref_close(ref); continue; } err = got_reflist_insert(&new, &refs, ref, got_ref_cmp_by_name, NULL); if (err || new == NULL /* duplicate */) got_ref_close(ref); if (err) goto done; } if (found_delref) { struct got_reflist_entry *re; size_t n; struct stat sb; n = fprintf(tmpf, "%s\n", GOT_PACKED_REFS_HEADER); if (n != sizeof(GOT_PACKED_REFS_HEADER)) { err = got_ferror(f, GOT_ERR_IO); goto done; } TAILQ_FOREACH(re, &refs, entry) { char *hex; size_t len; err = got_object_id_str(&hex, &re->ref->ref.ref.id); if (err) goto done; len = strlen(hex); n = fprintf(tmpf, "%s ", hex); free(hex); if (n != len + 1) { err = got_ferror(f, GOT_ERR_IO); goto done; } n = fprintf(tmpf, "%s\n", re->ref->ref.ref.name); if (n != strlen(re->ref->ref.ref.name) + 1) { err = got_ferror(f, GOT_ERR_IO); goto done; } } if (fflush(tmpf) != 0) { err = got_error_from_errno("fflush"); goto done; } if (fstat(fileno(f), &sb) != 0) { if (errno != ENOENT) { err = got_error_from_errno2("fstat", packed_refs_path); goto done; } sb.st_mode = GOT_DEFAULT_FILE_MODE; } if (fchmod(fileno(tmpf), sb.st_mode) != 0) { err = got_error_from_errno2("fchmod", tmppath); goto done; } if (rename(tmppath, packed_refs_path) != 0) { err = got_error_from_errno3("rename", tmppath, packed_refs_path); goto done; } free(tmppath); tmppath = NULL; } done: if (delref->lf == NULL && lf) unlock_err = got_lockfile_unlock(lf, -1); if (f) { if (fclose(f) == EOF && err == NULL) err = got_error_from_errno("fclose"); } if (tmppath && unlink(tmppath) == -1 && err == NULL) err = got_error_from_errno2("unlink", tmppath); if (tmpf && fclose(tmpf) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(tmppath); free(packed_refs_path); free(line); got_ref_list_free(&refs); return err ? err : unlock_err; } static const struct got_error * delete_loose_ref(struct got_reference *ref, struct got_repository *repo) { const struct got_error *err = NULL, *unlock_err = NULL; const char *name = got_ref_get_name(ref); char *path_refs = NULL, *path = NULL; struct got_lockfile *lf = NULL; path_refs = get_refs_dir_path(repo, name); if (path_refs == NULL) { err = got_error_from_errno2("get_refs_dir_path", name); goto done; } if (asprintf(&path, "%s/%s", path_refs, name) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (ref->lf == NULL) { err = got_lockfile_lock(&lf, path, -1); if (err) goto done; } /* XXX: check if old content matches our expectations? */ if (unlink(path) == -1) err = got_error_from_errno2("unlink", path); done: if (ref->lf == NULL && lf) unlock_err = got_lockfile_unlock(lf, -1); free(path_refs); free(path); return err ? err : unlock_err; } const struct got_error * got_ref_delete(struct got_reference *ref, struct got_repository *repo) { const struct got_error *err = NULL; struct got_reference *ref2; if (ref->flags & GOT_REF_IS_PACKED) { err = delete_packed_ref(ref, repo); if (err) return err; err = got_ref_open(&ref2, repo, got_ref_get_name(ref), 0); if (err) { if (err->code == GOT_ERR_NOT_REF) return NULL; return err; } err = delete_loose_ref(ref2, repo); got_ref_close(ref2); return err; } else { err = delete_loose_ref(ref, repo); if (err) return err; err = got_ref_open(&ref2, repo, got_ref_get_name(ref), 0); if (err) { if (err->code == GOT_ERR_NOT_REF) return NULL; return err; } err = delete_packed_ref(ref2, repo); got_ref_close(ref2); return err; } } const struct got_error * got_ref_unlock(struct got_reference *ref) { const struct got_error *err; err = got_lockfile_unlock(ref->lf, -1); ref->lf = NULL; return err; } struct got_reflist_object_id_map { struct got_object_idset *idset; }; struct got_reflist_object_id_map_entry { struct got_reflist_head refs; }; static const struct got_error * add_object_id_map_entry(struct got_object_idset *idset, struct got_object_id *id, struct got_reflist_entry *re) { const struct got_error *err = NULL; struct got_reflist_object_id_map_entry *ent; struct got_reflist_entry *new; ent = got_object_idset_get(idset, id); if (ent == NULL) { ent = malloc(sizeof(*ent)); if (ent == NULL) return got_error_from_errno("malloc"); TAILQ_INIT(&ent->refs); err = got_object_idset_add(idset, id, ent); if (err) { free(ent); return err; } } err = got_reflist_entry_dup(&new, re); if (err) return err; TAILQ_INSERT_TAIL(&ent->refs, new, entry); return NULL; } const struct got_error * got_reflist_object_id_map_create(struct got_reflist_object_id_map **map, struct got_reflist_head *refs, struct got_repository *repo) { const struct got_error *err = NULL; struct got_object_idset *idset; struct got_object_id *id = NULL; struct got_reflist_entry *re; idset = got_object_idset_alloc(); if (idset == NULL) return got_error_from_errno("got_object_idset_alloc"); *map = malloc(sizeof(**map)); if (*map == NULL) { got_object_idset_free(idset); return got_error_from_errno("malloc"); } (*map)->idset = idset; TAILQ_FOREACH(re, refs, entry) { struct got_tag_object *tag = NULL; err = got_ref_resolve(&id, repo, re->ref); if (err) goto done; err = add_object_id_map_entry(idset, id, re); if (err) goto done; if (strstr(got_ref_get_name(re->ref), "/tags/") == NULL) { free(id); id = NULL; continue; } err = got_object_open_as_tag(&tag, repo, id); if (err) { if (err->code != GOT_ERR_OBJ_TYPE) goto done; /* Ref points at something other than a tag. */ err = NULL; tag = NULL; free(id); id = NULL; continue; } err = add_object_id_map_entry(idset, got_object_tag_get_object_id(tag), re); got_object_tag_close(tag); if (err) goto done; free(id); id = NULL; } done: free(id); if (err) { got_reflist_object_id_map_free(*map); *map = NULL; } return err; } struct got_reflist_head * got_reflist_object_id_map_lookup(struct got_reflist_object_id_map *map, struct got_object_id *id) { struct got_reflist_object_id_map_entry *ent; ent = got_object_idset_get(map->idset, id); if (ent) return &ent->refs; return NULL; } static const struct got_error * free_id_map_entry(struct got_object_id *id, void *data, void *arg) { struct got_reflist_object_id_map_entry *ent = data; got_ref_list_free(&ent->refs); free(ent); return NULL; } void got_reflist_object_id_map_free(struct got_reflist_object_id_map *map) { got_object_idset_for_each(map->idset, free_id_map_entry, NULL); got_object_idset_free(map->idset); free(map); } got-portable-0.101/lib/repository_admin.c0000664000175100017510000011366514644144735014130 /* * Copyright (c) 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_cancel.h" #include "got_object.h" #include "got_reference.h" #include "got_repository.h" #include "got_repository_admin.h" #include "got_opentemp.h" #include "got_path.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_object_idset.h" #include "got_lib_object_cache.h" #include "got_lib_pack.h" #include "got_lib_privsep.h" #include "got_lib_repository.h" #include "got_lib_ratelimit.h" #include "got_lib_pack_create.h" #include "got_lib_hash.h" #include "got_lib_lockfile.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif static const struct got_error * get_reflist_object_ids(struct got_object_id ***ids, int *nobjects, unsigned int wanted_obj_type_mask, struct got_reflist_head *refs, struct got_repository *repo, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; const size_t alloc_chunksz = 256; size_t nalloc; struct got_reflist_entry *re; int i; *ids = NULL; *nobjects = 0; err = got_reflist_sort(refs, got_ref_cmp_by_commit_timestamp_descending, repo); if (err) return err; *ids = reallocarray(NULL, alloc_chunksz, sizeof(struct got_object_id *)); if (*ids == NULL) return got_error_from_errno("reallocarray"); nalloc = alloc_chunksz; TAILQ_FOREACH(re, refs, entry) { struct got_object_id *id; if (cancel_cb) { err = cancel_cb(cancel_arg); if (err) goto done; } err = got_ref_resolve(&id, repo, re->ref); if (err) goto done; if (wanted_obj_type_mask != GOT_OBJ_TYPE_ANY) { int obj_type; err = got_object_get_type(&obj_type, repo, id); if (err) goto done; if ((wanted_obj_type_mask & (1 << obj_type)) == 0) { free(id); id = NULL; continue; } } if (nalloc <= *nobjects) { struct got_object_id **new; new = recallocarray(*ids, nalloc, nalloc + alloc_chunksz, sizeof(struct got_object_id *)); if (new == NULL) { err = got_error_from_errno( "recallocarray"); goto done; } *ids = new; nalloc += alloc_chunksz; } (*ids)[*nobjects] = id; if ((*ids)[*nobjects] == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } (*nobjects)++; } done: if (err) { for (i = 0; i < *nobjects; i++) free((*ids)[i]); free(*ids); *ids = NULL; *nobjects = 0; } return err; } const struct got_error * got_repo_pack_objects(FILE **packfile, struct got_object_id **pack_hash, struct got_reflist_head *include_refs, struct got_reflist_head *exclude_refs, struct got_repository *repo, int loose_obj_only, int force_refdelta, got_pack_progress_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; struct got_object_id **ours = NULL, **theirs = NULL; int nours = 0, ntheirs = 0, packfd = -1, i; char *tmpfile_path = NULL, *path = NULL, *packfile_path = NULL; char *sha1_str = NULL; FILE *delta_cache = NULL; struct got_ratelimit rl; *packfile = NULL; *pack_hash = NULL; got_ratelimit_init(&rl, 0, 500); if (asprintf(&path, "%s/%s/packing.pack", got_repo_get_path_git_dir(repo), GOT_OBJECTS_PACK_DIR) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_opentemp_named_fd(&tmpfile_path, &packfd, path, ""); if (err) goto done; if (fchmod(packfd, GOT_DEFAULT_PACK_MODE) == -1) { err = got_error_from_errno2("fchmod", tmpfile_path); goto done; } delta_cache = got_opentemp(); if (delta_cache == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } err = get_reflist_object_ids(&ours, &nours, (1 << GOT_OBJ_TYPE_COMMIT) | (1 << GOT_OBJ_TYPE_TAG), include_refs, repo, cancel_cb, cancel_arg); if (err) goto done; if (nours == 0) { err = got_error(GOT_ERR_CANNOT_PACK); goto done; } if (!TAILQ_EMPTY(exclude_refs)) { err = get_reflist_object_ids(&theirs, &ntheirs, (1 << GOT_OBJ_TYPE_COMMIT) | (1 << GOT_OBJ_TYPE_TAG), exclude_refs, repo, cancel_cb, cancel_arg); if (err) goto done; } *pack_hash = calloc(1, sizeof(**pack_hash)); if (*pack_hash == NULL) { err = got_error_from_errno("calloc"); goto done; } err = got_pack_create((*pack_hash)->sha1, packfd, delta_cache, theirs, ntheirs, ours, nours, repo, loose_obj_only, 0, force_refdelta, progress_cb, progress_arg, &rl, cancel_cb, cancel_arg); if (err) goto done; err = got_object_id_str(&sha1_str, *pack_hash); if (err) goto done; if (asprintf(&packfile_path, "%s/%s/pack-%s.pack", got_repo_get_path_git_dir(repo), GOT_OBJECTS_PACK_DIR, sha1_str) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (lseek(packfd, 0L, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } if (rename(tmpfile_path, packfile_path) == -1) { err = got_error_from_errno3("rename", tmpfile_path, packfile_path); goto done; } free(tmpfile_path); tmpfile_path = NULL; *packfile = fdopen(packfd, "w"); if (*packfile == NULL) { err = got_error_from_errno2("fdopen", tmpfile_path); goto done; } packfd = -1; done: for (i = 0; i < nours; i++) free(ours[i]); free(ours); for (i = 0; i < ntheirs; i++) free(theirs[i]); free(theirs); if (packfd != -1 && close(packfd) == -1 && err == NULL) err = got_error_from_errno2("close", packfile_path); if (delta_cache && fclose(delta_cache) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (tmpfile_path && unlink(tmpfile_path) == -1 && err == NULL) err = got_error_from_errno2("unlink", tmpfile_path); free(tmpfile_path); free(packfile_path); free(sha1_str); free(path); if (err) { free(*pack_hash); *pack_hash = NULL; if (*packfile) fclose(*packfile); *packfile = NULL; } return err; } const struct got_error * got_repo_index_pack(FILE *packfile, struct got_object_id *pack_hash, struct got_repository *repo, got_pack_index_progress_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg) { size_t i; char *path; int imsg_idxfds[2]; int npackfd = -1, idxfd = -1, nidxfd = -1; int tmpfds[3]; int idxstatus, done = 0; const struct got_error *err; struct imsgbuf idxibuf; pid_t idxpid; char *tmpidxpath = NULL; char *packfile_path = NULL, *idxpath = NULL, *id_str = NULL; const char *repo_path = got_repo_get_path_git_dir(repo); struct stat sb; for (i = 0; i < nitems(tmpfds); i++) tmpfds[i] = -1; if (asprintf(&path, "%s/%s/indexing.idx", repo_path, GOT_OBJECTS_PACK_DIR) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_opentemp_named_fd(&tmpidxpath, &idxfd, path, ""); free(path); if (err) goto done; if (fchmod(idxfd, GOT_DEFAULT_PACK_MODE) == -1) { err = got_error_from_errno2("fchmod", tmpidxpath); goto done; } nidxfd = dup(idxfd); if (nidxfd == -1) { err = got_error_from_errno("dup"); goto done; } for (i = 0; i < nitems(tmpfds); i++) { tmpfds[i] = got_opentempfd(); if (tmpfds[i] == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } } err = got_object_id_str(&id_str, pack_hash); if (err) goto done; if (asprintf(&packfile_path, "%s/%s/pack-%s.pack", repo_path, GOT_OBJECTS_PACK_DIR, id_str) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (fstat(fileno(packfile), &sb) == -1) { err = got_error_from_errno2("fstat", packfile_path); goto done; } if (asprintf(&idxpath, "%s/%s/pack-%s.idx", repo_path, GOT_OBJECTS_PACK_DIR, id_str) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_idxfds) == -1) { err = got_error_from_errno("socketpair"); goto done; } idxpid = fork(); if (idxpid == -1) { err= got_error_from_errno("fork"); goto done; } else if (idxpid == 0) got_privsep_exec_child(imsg_idxfds, GOT_PATH_PROG_INDEX_PACK, packfile_path); if (close(imsg_idxfds[1]) == -1) { err = got_error_from_errno("close"); goto done; } imsg_init(&idxibuf, imsg_idxfds[0]); npackfd = dup(fileno(packfile)); if (npackfd == -1) { err = got_error_from_errno("dup"); goto done; } err = got_privsep_send_index_pack_req(&idxibuf, pack_hash->sha1, npackfd); if (err != NULL) goto done; npackfd = -1; err = got_privsep_send_index_pack_outfd(&idxibuf, nidxfd); if (err != NULL) goto done; nidxfd = -1; for (i = 0; i < nitems(tmpfds); i++) { err = got_privsep_send_tmpfd(&idxibuf, tmpfds[i]); if (err != NULL) goto done; tmpfds[i] = -1; } done = 0; while (!done) { int nobj_total, nobj_indexed, nobj_loose, nobj_resolved; if (cancel_cb) { err = cancel_cb(cancel_arg); if (err) goto done; } err = got_privsep_recv_index_progress(&done, &nobj_total, &nobj_indexed, &nobj_loose, &nobj_resolved, &idxibuf); if (err != NULL) goto done; if (nobj_indexed != 0) { err = progress_cb(progress_arg, sb.st_size, nobj_total, nobj_indexed, nobj_loose, nobj_resolved); if (err) break; } } if (close(imsg_idxfds[0]) == -1) { err = got_error_from_errno("close"); goto done; } if (waitpid(idxpid, &idxstatus, 0) == -1) { err = got_error_from_errno("waitpid"); goto done; } if (rename(tmpidxpath, idxpath) == -1) { err = got_error_from_errno3("rename", tmpidxpath, idxpath); goto done; } free(tmpidxpath); tmpidxpath = NULL; done: if (tmpidxpath && unlink(tmpidxpath) == -1 && err == NULL) err = got_error_from_errno2("unlink", tmpidxpath); if (npackfd != -1 && close(npackfd) == -1 && err == NULL) err = got_error_from_errno("close"); if (idxfd != -1 && close(idxfd) == -1 && err == NULL) err = got_error_from_errno("close"); for (i = 0; i < nitems(tmpfds); i++) { if (tmpfds[i] != -1 && close(tmpfds[i]) == -1 && err == NULL) err = got_error_from_errno("close"); } free(tmpidxpath); free(idxpath); free(packfile_path); return err; } const struct got_error * got_repo_find_pack(FILE **packfile, struct got_object_id **pack_hash, struct got_repository *repo, const char *packfile_path) { const struct got_error *err = NULL; const char *packdir_path = NULL; char *packfile_name = NULL, *p, *dot; struct got_object_id id; int packfd = -1; *packfile = NULL; *pack_hash = NULL; packdir_path = got_repo_get_path_objects_pack(repo); if (packdir_path == NULL) return got_error_from_errno("got_repo_get_path_objects_pack"); if (!got_path_is_child(packfile_path, packdir_path, strlen(packdir_path))) { err = got_error_path(packfile_path, GOT_ERR_BAD_PATH); goto done; } err = got_path_basename(&packfile_name, packfile_path); if (err) goto done; p = packfile_name; if (strncmp(p, "pack-", 5) != 0) { err = got_error_fmt(GOT_ERR_BAD_PATH, "'%s' is not a valid pack file name", packfile_name); goto done; } p += 5; dot = strchr(p, '.'); if (dot == NULL) { err = got_error_fmt(GOT_ERR_BAD_PATH, "'%s' is not a valid pack file name", packfile_name); goto done; } if (strcmp(dot + 1, "pack") != 0) { err = got_error_fmt(GOT_ERR_BAD_PATH, "'%s' is not a valid pack file name", packfile_name); goto done; } *dot = '\0'; if (!got_parse_object_id(&id, p, repo->algo)) { err = got_error_fmt(GOT_ERR_BAD_PATH, "'%s' is not a valid pack file name", packfile_name); goto done; } *pack_hash = got_object_id_dup(&id); if (*pack_hash == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } packfd = open(packfile_path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (packfd == -1) { err = got_error_from_errno2("open", packfile_path); goto done; } *packfile = fdopen(packfd, "r"); if (*packfile == NULL) { err = got_error_from_errno2("fdopen", packfile_path); goto done; } packfd = -1; done: if (packfd != -1 && close(packfd) == -1 && err == NULL) err = got_error_from_errno2("close", packfile_path); free(packfile_name); if (err) { free(*pack_hash); *pack_hash = NULL; } return err; } const struct got_error * got_repo_list_pack(FILE *packfile, struct got_object_id *pack_hash, struct got_repository *repo, got_pack_list_cb list_cb, void *list_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; char *id_str = NULL, *idxpath = NULL, *packpath = NULL; struct got_packidx *packidx = NULL; struct got_pack *pack = NULL; uint32_t nobj, i; err = got_object_id_str(&id_str, pack_hash); if (err) goto done; if (asprintf(&packpath, "%s/pack-%s.pack", GOT_OBJECTS_PACK_DIR, id_str) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (asprintf(&idxpath, "%s/pack-%s.idx", GOT_OBJECTS_PACK_DIR, id_str) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_packidx_open(&packidx, got_repo_get_fd(repo), idxpath, 1); if (err) goto done; err = got_repo_cache_pack(&pack, repo, packpath, packidx); if (err) goto done; nobj = be32toh(packidx->hdr.fanout_table[0xff]); for (i = 0; i < nobj; i++) { struct got_packidx_object_id *oid; struct got_object_id id, base_id; off_t offset, base_offset = 0; uint8_t type; uint64_t size; size_t tslen, len; if (cancel_cb) { err = cancel_cb(cancel_arg); if (err) break; } oid = &packidx->hdr.sorted_ids[i]; memcpy(id.sha1, oid->sha1, SHA1_DIGEST_LENGTH); offset = got_packidx_get_object_offset(packidx, i); if (offset == -1) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } err = got_pack_parse_object_type_and_size(&type, &size, &tslen, pack, offset); if (err) goto done; switch (type) { case GOT_OBJ_TYPE_OFFSET_DELTA: err = got_pack_parse_offset_delta(&base_offset, &len, pack, offset, tslen); if (err) goto done; break; case GOT_OBJ_TYPE_REF_DELTA: err = got_pack_parse_ref_delta(&base_id, pack, offset, tslen); if (err) goto done; break; } err = (*list_cb)(list_arg, &id, type, offset, size, base_offset, &base_id); if (err) goto done; } done: free(id_str); free(idxpath); free(packpath); if (packidx) got_packidx_close(packidx); return err; } static const struct got_error * repo_cleanup_lock(struct got_repository *repo, struct got_lockfile **lk) { const struct got_error *err; char myname[_POSIX_HOST_NAME_MAX + 1]; if (gethostname(myname, sizeof(myname)) == -1) return got_error_from_errno("gethostname"); err = got_lockfile_lock(lk, "gc.pid", got_repo_get_fd(repo)); if (err) return err; /* * Git uses these info to provide some verbiage when finds a * lock during `git gc --force' so don't try too hard to avoid * short writes and don't care if a race happens between the * lockfile creation and the write itself. */ if (dprintf((*lk)->fd, "%d %s", getpid(), myname) < 0) return got_error_from_errno("dprintf"); return NULL; } static const struct got_error * report_cleanup_progress(got_cleanup_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl, int ncommits, int nloose, int npurged, int nredundant) { const struct got_error *err; int elapsed; if (progress_cb == NULL) return NULL; err = got_ratelimit_check(&elapsed, rl); if (err || !elapsed) return err; return progress_cb(progress_arg, ncommits, nloose, npurged, nredundant); } static const struct got_error * get_loose_object_ids(struct got_object_idset **loose_ids, off_t *ondisk_size, int ncommits, got_cleanup_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl, struct got_repository *repo) { const struct got_error *err = NULL; char *path_objects = NULL, *path = NULL; DIR *dir = NULL; struct got_object *obj = NULL; struct got_object_id id; int i, fd = -1; struct stat sb; *ondisk_size = 0; *loose_ids = got_object_idset_alloc(); if (*loose_ids == NULL) return got_error_from_errno("got_object_idset_alloc"); path_objects = got_repo_get_path_objects(repo); if (path_objects == NULL) { err = got_error_from_errno("got_repo_get_path_objects"); goto done; } for (i = 0; i <= 0xff; i++) { struct dirent *dent; if (asprintf(&path, "%s/%.2x", path_objects, i) == -1) { err = got_error_from_errno("asprintf"); break; } dir = opendir(path); if (dir == NULL) { if (errno == ENOENT) { err = NULL; continue; } err = got_error_from_errno2("opendir", path); break; } while ((dent = readdir(dir)) != NULL) { char *id_str; if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) continue; if (asprintf(&id_str, "%.2x%s", i, dent->d_name) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (!got_parse_object_id(&id, id_str, repo->algo)) { free(id_str); continue; } free(id_str); err = got_object_open_loose_fd(&fd, &id, repo); if (err) goto done; if (fstat(fd, &sb) == -1) { err = got_error_from_errno("fstat"); goto done; } err = got_object_read_header_privsep(&obj, &id, repo, fd); if (err) goto done; fd = -1; /* already closed */ switch (obj->type) { case GOT_OBJ_TYPE_COMMIT: case GOT_OBJ_TYPE_TREE: case GOT_OBJ_TYPE_BLOB: case GOT_OBJ_TYPE_TAG: break; default: err = got_error_fmt(GOT_ERR_OBJ_TYPE, "%d", obj->type); goto done; } got_object_close(obj); obj = NULL; (*ondisk_size) += sb.st_size; err = got_object_idset_add(*loose_ids, &id, NULL); if (err) goto done; err = report_cleanup_progress(progress_cb, progress_arg, rl, ncommits, got_object_idset_num_elements(*loose_ids), -1, -1); if (err) goto done; } if (closedir(dir) != 0) { err = got_error_from_errno("closedir"); goto done; } dir = NULL; free(path); path = NULL; } done: if (dir && closedir(dir) != 0 && err == NULL) err = got_error_from_errno("closedir"); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (err) { got_object_idset_free(*loose_ids); *loose_ids = NULL; } if (obj) got_object_close(obj); free(path_objects); free(path); return err; } static const struct got_error * load_tree_entries(struct got_object_id_queue *ids, struct got_object_idset *traversed_ids, struct got_object_id *tree_id, const char *dpath, struct got_repository *repo, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err; struct got_tree_object *tree; char *p = NULL; int i; err = got_object_open_as_tree(&tree, repo, tree_id); if (err) return err; for (i = 0; i < got_object_tree_get_nentries(tree); i++) { struct got_tree_entry *e = got_object_tree_get_entry(tree, i); struct got_object_id *id = got_tree_entry_get_id(e); mode_t mode = got_tree_entry_get_mode(e); if (cancel_cb) { err = (*cancel_cb)(cancel_arg); if (err) break; } if (got_object_tree_entry_is_symlink(e) || got_object_tree_entry_is_submodule(e) || got_object_idset_contains(traversed_ids, id)) continue; if (asprintf(&p, "%s%s%s", dpath, dpath[0] != '\0' ? "/" : "", got_tree_entry_get_name(e)) == -1) { err = got_error_from_errno("asprintf"); break; } if (S_ISDIR(mode)) { struct got_object_qid *qid; err = got_object_qid_alloc(&qid, id); if (err) break; STAILQ_INSERT_TAIL(ids, qid, entry); } else if (S_ISREG(mode)) { /* This blob is referenced. */ err = got_object_idset_add(traversed_ids, id, NULL); if (err) break; } free(p); p = NULL; } got_object_tree_close(tree); free(p); return err; } static const struct got_error * load_tree(struct got_object_idset *traversed_ids, struct got_object_id *tree_id, const char *dpath, struct got_repository *repo, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; struct got_object_id_queue tree_ids; struct got_object_qid *qid; err = got_object_qid_alloc(&qid, tree_id); if (err) return err; STAILQ_INIT(&tree_ids); STAILQ_INSERT_TAIL(&tree_ids, qid, entry); while (!STAILQ_EMPTY(&tree_ids)) { if (cancel_cb) { err = (*cancel_cb)(cancel_arg); if (err) break; } qid = STAILQ_FIRST(&tree_ids); STAILQ_REMOVE_HEAD(&tree_ids, entry); if (got_object_idset_contains(traversed_ids, &qid->id)) { got_object_qid_free(qid); continue; } err = got_object_idset_add(traversed_ids, &qid->id, NULL); if (err) { got_object_qid_free(qid); break; } err = load_tree_entries(&tree_ids, traversed_ids, &qid->id, dpath, repo, cancel_cb, cancel_arg); got_object_qid_free(qid); if (err) break; } got_object_id_queue_free(&tree_ids); return err; } static const struct got_error * load_commit_or_tag(int *ncommits, struct got_object_idset *traversed_ids, struct got_object_id *id, struct got_repository *repo, got_cleanup_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err; struct got_commit_object *commit = NULL; struct got_tag_object *tag = NULL; struct got_object_id *tree_id = NULL; struct got_object_id_queue ids; struct got_object_qid *qid; int obj_type; err = got_object_qid_alloc(&qid, id); if (err) return err; STAILQ_INIT(&ids); STAILQ_INSERT_TAIL(&ids, qid, entry); while (!STAILQ_EMPTY(&ids)) { if (cancel_cb) { err = (*cancel_cb)(cancel_arg); if (err) break; } qid = STAILQ_FIRST(&ids); STAILQ_REMOVE_HEAD(&ids, entry); if (got_object_idset_contains(traversed_ids, &qid->id)) { got_object_qid_free(qid); qid = NULL; continue; } err = got_object_idset_add(traversed_ids, &qid->id, NULL); if (err) break; err = got_object_get_type(&obj_type, repo, &qid->id); if (err) break; switch (obj_type) { case GOT_OBJ_TYPE_COMMIT: err = got_object_open_as_commit(&commit, repo, &qid->id); if (err) goto done; break; case GOT_OBJ_TYPE_TAG: err = got_object_open_as_tag(&tag, repo, &qid->id); if (err) goto done; break; default: /* should not happen */ err = got_error(GOT_ERR_OBJ_TYPE); goto done; } /* Find a tree object to scan. */ if (commit) { tree_id = got_object_commit_get_tree_id(commit); } else if (tag) { obj_type = got_object_tag_get_object_type(tag); switch (obj_type) { case GOT_OBJ_TYPE_COMMIT: err = got_object_open_as_commit(&commit, repo, got_object_tag_get_object_id(tag)); if (err) goto done; tree_id = got_object_commit_get_tree_id(commit); break; case GOT_OBJ_TYPE_TREE: tree_id = got_object_tag_get_object_id(tag); break; default: /* * Tag points at something other than a * commit or tree. Leave this weird tag object * and the object it points to. */ if (got_object_idset_contains(traversed_ids, got_object_tag_get_object_id(tag))) break; err = got_object_idset_add(traversed_ids, got_object_tag_get_object_id(tag), NULL); if (err) goto done; break; } } if (tree_id) { err = load_tree(traversed_ids, tree_id, "", repo, cancel_cb, cancel_arg); if (err) break; } if (commit || tag) (*ncommits)++; /* scanned tags are counted as commits */ err = report_cleanup_progress(progress_cb, progress_arg, rl, *ncommits, -1, -1, -1); if (err) break; if (commit) { /* Find parent commits to scan. */ const struct got_object_id_queue *parent_ids; parent_ids = got_object_commit_get_parent_ids(commit); err = got_object_id_queue_copy(parent_ids, &ids); if (err) break; got_object_commit_close(commit); commit = NULL; } if (tag) { got_object_tag_close(tag); tag = NULL; } got_object_qid_free(qid); qid = NULL; } done: if (qid) got_object_qid_free(qid); if (commit) got_object_commit_close(commit); if (tag) got_object_tag_close(tag); got_object_id_queue_free(&ids); return err; } static const struct got_error * is_object_packed(int *packed, struct got_repository *repo, struct got_object_id *id) { const struct got_error *err; struct got_object *obj; *packed = 0; err = got_object_open_packed(&obj, id, repo); if (err) { if (err->code == GOT_ERR_NO_OBJ) err = NULL; return err; } got_object_close(obj); *packed = 1; return NULL; } struct purge_loose_object_arg { struct got_repository *repo; got_cleanup_progress_cb progress_cb; void *progress_arg; struct got_ratelimit *rl; struct got_object_idset *traversed_ids; int nloose; int ncommits; int npacked; int npurged; off_t size_purged; int dry_run; time_t max_mtime; int ignore_mtime; }; static const struct got_error * purge_loose_object(struct got_object_id *id, void *data, void *arg) { struct purge_loose_object_arg *a = arg; const struct got_error *err, *unlock_err = NULL; char *path = NULL; int packed, fd = -1; struct stat sb; struct got_lockfile *lf = NULL; err = is_object_packed(&packed, a->repo, id); if (err) return err; if (!packed && got_object_idset_contains(a->traversed_ids, id)) return NULL; if (packed) a->npacked++; err = got_object_get_path(&path, id, a->repo); if (err) return err; err = got_object_open_loose_fd(&fd, id, a->repo); if (err) goto done; if (fstat(fd, &sb) == -1) { err = got_error_from_errno("fstat"); goto done; } /* * Do not delete objects which are younger than our maximum * modification time threshold. This prevents a race where * new objects which are being added to the repository * concurrently would be deleted. */ if (a->ignore_mtime || sb.st_mtime <= a->max_mtime) { if (!a->dry_run) { err = got_lockfile_lock(&lf, path, -1); if (err) goto done; if (unlink(path) == -1) { err = got_error_from_errno2("unlink", path); goto done; } } a->npurged++; a->size_purged += sb.st_size; err = report_cleanup_progress(a->progress_cb, a->progress_arg, a->rl, a->ncommits, a->nloose, a->npurged, -1); if (err) goto done; } done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); free(path); if (lf) unlock_err = got_lockfile_unlock(lf, -1); return err ? err : unlock_err; } static const struct got_error * repo_purge_unreferenced_loose_objects(struct got_repository *repo, struct got_object_idset *traversed_ids, off_t *size_before, off_t *size_after, int ncommits, int *nloose, int *npacked, int *npurged, int dry_run, int ignore_mtime, time_t max_mtime, struct got_ratelimit *rl, got_cleanup_progress_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err; struct got_object_idset *loose_ids; struct purge_loose_object_arg arg; err = get_loose_object_ids(&loose_ids, size_before, ncommits, progress_cb, progress_arg, rl, repo); if (err) return err; *nloose = got_object_idset_num_elements(loose_ids); if (*nloose == 0) { got_object_idset_free(loose_ids); if (progress_cb) { err = progress_cb(progress_arg, 0, 0, 0, -1); if (err) return err; } return NULL; } memset(&arg, 0, sizeof(arg)); arg.repo = repo; arg.progress_arg = progress_arg; arg.progress_cb = progress_cb; arg.rl = rl; arg.traversed_ids = traversed_ids; arg.nloose = *nloose; arg.npacked = 0; arg.npurged = 0; arg.size_purged = 0; arg.dry_run = dry_run; arg.max_mtime = max_mtime; arg.ignore_mtime = ignore_mtime; err = got_object_idset_for_each(loose_ids, purge_loose_object, &arg); if (err) goto done; *size_after = *size_before - arg.size_purged; *npacked = arg.npacked; *npurged = arg.npurged; /* Produce a final progress report. */ if (progress_cb) { err = progress_cb(progress_arg, ncommits, *nloose, arg.npurged, -1); if (err) goto done; } done: got_object_idset_free(loose_ids); return err; } static const struct got_error * purge_redundant_pack(struct got_repository *repo, const char *packidx_path, int dry_run, int ignore_mtime, time_t max_mtime, int *remove, off_t *size_before, off_t *size_after) { static const char *ext[] = {".idx", ".pack", ".rev", ".bitmap", ".promisor", ".mtimes"}; struct stat sb; char *dot, path[PATH_MAX]; size_t i; if (strlcpy(path, packidx_path, sizeof(path)) >= sizeof(path)) return got_error(GOT_ERR_NO_SPACE); /* * Do not delete pack files which are younger than our maximum * modification time threshold. This prevents a race where a * new pack file which is being added to the repository * concurrently would be deleted. */ if (fstatat(got_repo_get_fd(repo), path, &sb, 0) == -1) { if (errno == ENOENT) return NULL; return got_error_from_errno2("fstatat", path); } if (!ignore_mtime && sb.st_mtime > max_mtime) *remove = 0; /* * For compatibility with Git, if a matching .keep file exist * don't delete the packfile. */ dot = strrchr(path, '.'); *dot = '\0'; if (strlcat(path, ".keep", sizeof(path)) >= sizeof(path)) return got_error(GOT_ERR_NO_SPACE); if (faccessat(got_repo_get_fd(repo), path, F_OK, 0) == 0) *remove = 0; for (i = 0; i < nitems(ext); ++i) { *dot = '\0'; if (strlcat(path, ext[i], sizeof(path)) >= sizeof(path)) return got_error(GOT_ERR_NO_SPACE); if (fstatat(got_repo_get_fd(repo), path, &sb, 0) == -1) { if (errno == ENOENT) continue; return got_error_from_errno2("fstatat", path); } *size_before += sb.st_size; if (!*remove) { *size_after += sb.st_size; continue; } if (dry_run) continue; if (unlinkat(got_repo_get_fd(repo), path, 0) == -1) { if (errno == ENOENT) continue; return got_error_from_errno2("unlinkat", path); } } return NULL; } static const struct got_error * pack_is_redundant(int *redundant, struct got_repository *repo, struct got_object_idset *traversed_ids, const char *packidx_path, struct got_object_idset *idset) { const struct got_error *err; struct got_packidx *packidx; struct got_packidx_object_id *pid; struct got_object_id id; size_t i, nobjects; *redundant = 1; err = got_repo_get_packidx(&packidx, packidx_path, repo); if (err) return err; nobjects = be32toh(packidx->hdr.fanout_table[0xff]); for (i = 0; i < nobjects; ++i) { pid = &packidx->hdr.sorted_ids[i]; memset(&id, 0, sizeof(id)); memcpy(&id.sha1, pid->sha1, sizeof(id.sha1)); if (got_object_idset_contains(idset, &id)) continue; if (!got_object_idset_contains(traversed_ids, &id)) continue; *redundant = 0; err = got_object_idset_add(idset, &id, NULL); if (err) return err; } return NULL; } struct pack_info { const char *path; size_t nobjects; }; static int pack_info_cmp(const void *a, const void *b) { const struct pack_info *pa, *pb; pa = a; pb = b; if (pa->nobjects == pb->nobjects) return strcmp(pa->path, pb->path); if (pa->nobjects > pb->nobjects) return -1; return 1; } static const struct got_error * repo_purge_redundant_packfiles(struct got_repository *repo, struct got_object_idset *traversed_ids, off_t *size_before, off_t *size_after, int dry_run, int ignore_mtime, time_t max_mtime, int nloose, int ncommits, int npurged, struct got_ratelimit *rl, got_cleanup_progress_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err; struct pack_info *pinfo, *sorted = NULL; struct got_packidx *packidx; struct got_object_idset *idset = NULL; struct got_pathlist_entry *pe; size_t i, npacks; int remove, redundant_packs = 0; npacks = 0; TAILQ_FOREACH(pe, &repo->packidx_paths, entry) npacks++; if (npacks == 0) return NULL; sorted = calloc(npacks, sizeof(*sorted)); if (sorted == NULL) return got_error_from_errno("calloc"); i = 0; TAILQ_FOREACH(pe, &repo->packidx_paths, entry) { err = got_repo_get_packidx(&packidx, pe->path, repo); if (err) goto done; pinfo = &sorted[i++]; pinfo->path = pe->path; pinfo->nobjects = be32toh(packidx->hdr.fanout_table[0xff]); } qsort(sorted, npacks, sizeof(*sorted), pack_info_cmp); idset = got_object_idset_alloc(); if (idset == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } for (i = 0; i < npacks; ++i) { if (cancel_cb) { err = (*cancel_cb)(cancel_arg); if (err) break; } err = pack_is_redundant(&remove, repo, traversed_ids, sorted[i].path, idset); if (err) goto done; err = purge_redundant_pack(repo, sorted[i].path, dry_run, ignore_mtime, max_mtime, &remove, size_before, size_after); if (err) goto done; if (!remove) continue; err = report_cleanup_progress(progress_cb, progress_arg, rl, ncommits, nloose, npurged, ++redundant_packs); if (err) goto done; } /* Produce a final progress report. */ if (progress_cb) { err = progress_cb(progress_arg, ncommits, nloose, npurged, redundant_packs); if (err) goto done; } done: free(sorted); if (idset) got_object_idset_free(idset); return err; } const struct got_error * got_repo_cleanup(struct got_repository *repo, off_t *loose_before, off_t *loose_after, off_t *pack_before, off_t *pack_after, int *ncommits, int *nloose, int *npacked, int dry_run, int ignore_mtime, got_cleanup_progress_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *unlock_err, *err = NULL; struct got_lockfile *lk = NULL; struct got_ratelimit rl; struct got_reflist_head refs; struct got_object_idset *traversed_ids = NULL; struct got_reflist_entry *re; struct got_object_id **referenced_ids; int i, nreferenced; int npurged = 0; time_t max_mtime = 0; TAILQ_INIT(&refs); got_ratelimit_init(&rl, 0, 500); *loose_before = 0; *loose_after = 0; *pack_before = 0; *pack_after = 0; *ncommits = 0; *nloose = 0; *npacked = 0; err = repo_cleanup_lock(repo, &lk); if (err) return err; traversed_ids = got_object_idset_alloc(); if (traversed_ids == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } err = got_ref_list(&refs, repo, "", got_ref_cmp_by_name, NULL); if (err) goto done; if (!ignore_mtime) { TAILQ_FOREACH(re, &refs, entry) { time_t mtime = got_ref_get_mtime(re->ref); if (mtime > max_mtime) max_mtime = mtime; } /* * For safety, keep objects created within 10 minutes * before the youngest reference was created. */ if (max_mtime >= 600) max_mtime -= 600; } err = get_reflist_object_ids(&referenced_ids, &nreferenced, (1 << GOT_OBJ_TYPE_COMMIT) | (1 << GOT_OBJ_TYPE_TAG), &refs, repo, cancel_cb, cancel_arg); if (err) goto done; for (i = 0; i < nreferenced; i++) { struct got_object_id *id = referenced_ids[i]; err = load_commit_or_tag(ncommits, traversed_ids, id, repo, progress_cb, progress_arg, &rl, cancel_cb, cancel_arg); if (err) goto done; } err = repo_purge_unreferenced_loose_objects(repo, traversed_ids, loose_before, loose_after, *ncommits, nloose, npacked, &npurged, dry_run, ignore_mtime, max_mtime, &rl, progress_cb, progress_arg, cancel_cb, cancel_arg); if (err) goto done; err = repo_purge_redundant_packfiles(repo, traversed_ids, pack_before, pack_after, dry_run, ignore_mtime, max_mtime, *nloose, *ncommits, npurged, &rl, progress_cb, progress_arg, cancel_cb, cancel_arg); if (err) goto done; done: if (lk) { unlock_err = got_lockfile_unlock(lk, got_repo_get_fd(repo)); if (err == NULL) err = unlock_err; } if (traversed_ids) got_object_idset_free(traversed_ids); return err; } const struct got_error * got_repo_remove_lonely_packidx(struct got_repository *repo, int dry_run, got_lonely_packidx_progress_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; DIR *packdir = NULL; struct dirent *dent; char *pack_relpath = NULL; int packdir_fd; struct stat sb; packdir_fd = openat(got_repo_get_fd(repo), GOT_OBJECTS_PACK_DIR, O_DIRECTORY | O_CLOEXEC); if (packdir_fd == -1) { if (errno == ENOENT) return NULL; return got_error_from_errno_fmt("openat: %s/%s", got_repo_get_path_git_dir(repo), GOT_OBJECTS_PACK_DIR); } packdir = fdopendir(packdir_fd); if (packdir == NULL) { err = got_error_from_errno("fdopendir"); close(packdir_fd); goto done; } while ((dent = readdir(packdir)) != NULL) { if (cancel_cb) { err = cancel_cb(cancel_arg); if (err) goto done; } if (!got_repo_is_packidx_filename(dent->d_name, strlen(dent->d_name))) continue; err = got_packidx_get_packfile_path(&pack_relpath, dent->d_name); if (err) goto done; if (fstatat(packdir_fd, pack_relpath, &sb, 0) != -1) { free(pack_relpath); pack_relpath = NULL; continue; } if (errno != ENOENT) { err = got_error_from_errno_fmt("fstatat: %s/%s/%s", got_repo_get_path_git_dir(repo), GOT_OBJECTS_PACK_DIR, pack_relpath); goto done; } if (!dry_run) { if (unlinkat(packdir_fd, dent->d_name, 0) == -1) { err = got_error_from_errno("unlinkat"); goto done; } } if (progress_cb) { char *path; if (asprintf(&path, "%s/%s/%s", got_repo_get_path_git_dir(repo), GOT_OBJECTS_PACK_DIR, dent->d_name) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = progress_cb(progress_arg, path); free(path); if (err) goto done; } free(pack_relpath); pack_relpath = NULL; } done: if (packdir && closedir(packdir) != 0 && err == NULL) err = got_error_from_errno("closedir"); free(pack_relpath); return err; } got-portable-0.101/lib/send.c0000664000175100017510000004376214644144735011472 /* * Copyright (c) 2018, 2019 Ori Bernstein * Copyright (c) 2021 Stefan Sperling * Copyright (c) 2023 Josh Rickmar * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_reference.h" #include "got_repository.h" #include "got_path.h" #include "got_cancel.h" #include "got_worktree.h" #include "got_object.h" #include "got_opentemp.h" #include "got_send.h" #include "got_repository_admin.h" #include "got_commit_graph.h" #include "got_lib_delta.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_object_create.h" #include "got_lib_pack.h" #include "got_lib_hash.h" #include "got_lib_privsep.h" #include "got_lib_object_cache.h" #include "got_lib_repository.h" #include "got_lib_ratelimit.h" #include "got_lib_pack_create.h" #include "got_lib_dial.h" #include "got_lib_worktree_cvg.h" #include "got_lib_poll.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif #ifndef ssizeof #define ssizeof(_x) ((ssize_t)(sizeof(_x))) #endif #ifndef MIN #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) #endif const struct got_error * got_send_connect(pid_t *sendpid, int *sendfd, const char *proto, const char *host, const char *port, const char *server_path, int verbosity) { const struct got_error *err = NULL; *sendpid = -1; *sendfd = -1; if (strcmp(proto, "ssh") == 0 || strcmp(proto, "git+ssh") == 0) err = got_dial_ssh(sendpid, sendfd, host, port, server_path, GOT_DIAL_CMD_SEND, verbosity); else if (strcmp(proto, "git") == 0) err = got_dial_git(sendfd, host, port, server_path, GOT_DIAL_CMD_SEND); else if (strcmp(proto, "http") == 0 || strcmp(proto, "git+http") == 0) err = got_error_path(proto, GOT_ERR_NOT_IMPL); else err = got_error_path(proto, GOT_ERR_BAD_PROTO); return err; } struct pack_progress_arg { got_send_progress_cb progress_cb; void *progress_arg; int sendfd; int ncolored; int nfound; int ntrees; off_t packfile_size; int ncommits; int nobj_total; int nobj_deltify; int nobj_written; }; static const struct got_error * pack_progress(void *arg, int ncolored, int nfound, int ntrees, off_t packfile_size, int ncommits, int nobj_total, int nobj_deltify, int nobj_written) { const struct got_error *err; struct pack_progress_arg *a = arg; err = a->progress_cb(a->progress_arg, ncolored, nfound, ntrees, packfile_size, ncommits, nobj_total, nobj_deltify, nobj_written, 0, NULL, NULL, 0); if (err) return err; /* * Detect the server closing our connection while we are * busy creating a pack file. * * XXX This should be a temporary workaround. A better fix would * be to avoid use of an on-disk tempfile for pack file data. * Instead we could stream pack file data to got-send-pack while * the pack file is being generated. Write errors in got-send-pack * would then automatically abort the creation of pack file data. */ err = got_poll_fd(a->sendfd, 0, 0); if (err && err->code != GOT_ERR_TIMEOUT) { if (err->code == GOT_ERR_EOF) { err = got_error_msg(GOT_ERR_EOF, "server unexpectedly closed the connection"); } return err; } a->ncolored= ncolored; a->nfound = nfound; a->ntrees = ntrees; a->packfile_size = packfile_size; a->ncommits = ncommits; a->nobj_total = nobj_total; a->nobj_deltify = nobj_deltify; a->nobj_written = nobj_written; return NULL; } static const struct got_error * insert_sendable_ref(struct got_pathlist_head *refs, const char *refname, const char *target_refname, struct got_repository *repo) { const struct got_error *err; struct got_reference *ref; struct got_object_id *id = NULL; int obj_type; err = got_ref_open(&ref, repo, refname, 0); if (err) return err; if (got_ref_is_symbolic(ref)) { err = got_error_fmt(GOT_ERR_BAD_REF_TYPE, "cannot send symbolic reference %s", refname); goto done; } err = got_ref_resolve(&id, repo, ref); if (err) goto done; err = got_object_get_type(&obj_type, repo, id); if (err) goto done; switch (obj_type) { case GOT_OBJ_TYPE_COMMIT: case GOT_OBJ_TYPE_TAG: break; default: err = got_error_fmt(GOT_ERR_OBJ_TYPE," cannot send %s", refname); goto done; } err = got_pathlist_insert(NULL, refs, target_refname, id); done: if (ref) got_ref_close(ref); if (err) free(id); return err; } static const struct got_error * check_common_ancestry(const char *refname, struct got_object_id *my_id, struct got_object_id *their_id, struct got_repository *repo, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; struct got_object_id *yca_id; int obj_type; err = got_object_get_type(&obj_type, repo, their_id); if (err) return err; if (obj_type != GOT_OBJ_TYPE_COMMIT) return got_error_fmt(GOT_ERR_OBJ_TYPE, "bad object type on server for %s", refname); err = got_commit_graph_find_youngest_common_ancestor(&yca_id, my_id, their_id, 0, 0, repo, cancel_cb, cancel_arg); if (err) return err; if (yca_id == NULL) return got_error_fmt(GOT_ERR_SEND_ANCESTRY, "%s", refname); if (got_object_id_cmp(their_id, yca_id) != 0) err = got_error_fmt(GOT_ERR_SEND_ANCESTRY, "%s", refname); free(yca_id); return err; } static const struct got_error * realloc_ids(struct got_object_id ***ids, size_t *nalloc, size_t n) { struct got_object_id **new; const size_t alloc_chunksz = 256; if (*nalloc >= n) return NULL; new = recallocarray(*ids, *nalloc, *nalloc + alloc_chunksz, sizeof(struct got_object_id)); if (new == NULL) return got_error_from_errno("recallocarray"); *ids = new; *nalloc += alloc_chunksz; return NULL; } static struct got_pathlist_entry * find_ref(struct got_pathlist_head *refs, const char *refname) { struct got_pathlist_entry *pe; TAILQ_FOREACH(pe, refs, entry) { if (got_path_cmp(pe->path, refname, strlen(pe->path), strlen(refname)) == 0) { return pe; } } return NULL; } static const struct got_error * get_remote_refname(char **remote_refname, const char *remote_name, const char *refname) { if (strncmp(refname, "refs/", 5) == 0) refname += 5; if (strncmp(refname, "heads/", 6) == 0) refname += 6; if (asprintf(remote_refname, "refs/remotes/%s/%s", remote_name, refname) == -1) return got_error_from_errno("asprintf"); return NULL; } static const struct got_error * update_remote_ref(struct got_pathlist_entry *my_ref, const char *remote_name, struct got_repository *repo) { const struct got_error *err, *unlock_err; const char *refname = my_ref->path; struct got_object_id *my_id = my_ref->data; struct got_reference *ref = NULL; char *remote_refname = NULL; int ref_locked = 0; err = get_remote_refname(&remote_refname, remote_name, refname); if (err) goto done; err = got_ref_open(&ref, repo, remote_refname, 1 /* lock */); if (err) { if (err->code != GOT_ERR_NOT_REF) goto done; err = got_ref_alloc(&ref, remote_refname, my_id); if (err) goto done; } else { ref_locked = 1; err = got_ref_change_ref(ref, my_id); if (err) goto done; } err = got_ref_write(ref, repo); done: if (ref) { if (ref_locked) { unlock_err = got_ref_unlock(ref); if (unlock_err && err == NULL) err = unlock_err; } got_ref_close(ref); } free(remote_refname); return err; } const struct got_error* got_send_pack(const char *remote_name, struct got_pathlist_head *branch_names, struct got_pathlist_head *tag_names, struct got_pathlist_head *delete_branches, int verbosity, int overwrite_refs, int sendfd, struct got_repository *repo, got_send_progress_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg) { int imsg_sendfds[2]; int npackfd = -1, nsendfd = -1; int sendstatus, done = 0; const struct got_error *err; struct imsgbuf sendibuf; pid_t sendpid = -1; struct got_pathlist_head have_refs; struct got_pathlist_head their_refs; struct got_pathlist_entry *pe; struct got_object_id **our_ids = NULL; struct got_object_id **their_ids = NULL; int nours = 0, ntheirs = 0; size_t nalloc_ours = 0, nalloc_theirs = 0; int refs_to_send = 0, refs_to_delete = 0; off_t bytes_sent = 0, bytes_sent_cur = 0; struct pack_progress_arg ppa; uint8_t packsha1[SHA1_DIGEST_LENGTH]; int packfd = -1; FILE *delta_cache = NULL; char *s = NULL; TAILQ_INIT(&have_refs); TAILQ_INIT(&their_refs); TAILQ_FOREACH(pe, branch_names, entry) { const char *branchname = pe->path; const char *targetname = pe->data; if (targetname == NULL) targetname = branchname; if (strncmp(targetname, "refs/heads/", 11) != 0) { if (asprintf(&s, "refs/heads/%s", targetname) == -1) { err = got_error_from_errno("asprintf"); goto done; } } else { if ((s = strdup(targetname)) == NULL) { err = got_error_from_errno("strdup"); goto done; } } err = insert_sendable_ref(&have_refs, branchname, s, repo); if (err) goto done; s = NULL; } TAILQ_FOREACH(pe, delete_branches, entry) { const char *branchname = pe->path; struct got_pathlist_entry *ref; if (strncmp(branchname, "refs/heads/", 11) != 0) { err = got_error_fmt(GOT_ERR_SEND_DELETE_REF, "%s", branchname); goto done; } ref = find_ref(&have_refs, branchname); if (ref) { err = got_error_fmt(GOT_ERR_SEND_DELETE_REF, "changes on %s will be sent to server", branchname); goto done; } } TAILQ_FOREACH(pe, tag_names, entry) { const char *tagname = pe->path; if (strncmp(tagname, "refs/tags/", 10) != 0) { if (asprintf(&s, "refs/tags/%s", tagname) == -1) { err = got_error_from_errno("asprintf"); goto done; } } else { if ((s = strdup(pe->path)) == NULL) { err = got_error_from_errno("strdup"); goto done; } } err = insert_sendable_ref(&have_refs, s, s, repo); if (err) goto done; s = NULL; } if (TAILQ_EMPTY(&have_refs) && TAILQ_EMPTY(delete_branches)) { err = got_error(GOT_ERR_SEND_EMPTY); goto done; } packfd = got_opentempfd(); if (packfd == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } delta_cache = got_opentemp(); if (delta_cache == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_sendfds) == -1) { err = got_error_from_errno("socketpair"); goto done; } sendpid = fork(); if (sendpid == -1) { err = got_error_from_errno("fork"); goto done; } else if (sendpid == 0){ got_privsep_exec_child(imsg_sendfds, GOT_PATH_PROG_SEND_PACK, got_repo_get_path(repo)); } if (close(imsg_sendfds[1]) == -1) { err = got_error_from_errno("close"); goto done; } imsg_init(&sendibuf, imsg_sendfds[0]); nsendfd = dup(sendfd); if (nsendfd == -1) { err = got_error_from_errno("dup"); goto done; } /* * Prepare the array of our object IDs which * will be needed for generating a pack file. */ TAILQ_FOREACH(pe, &have_refs, entry) { struct got_object_id *id = pe->data; err = realloc_ids(&our_ids, &nalloc_ours, nours + 1); if (err) goto done; our_ids[nours] = id; nours++; } err = got_privsep_send_send_req(&sendibuf, nsendfd, &have_refs, delete_branches, verbosity); if (err) goto done; nsendfd = -1; err = got_privsep_recv_send_remote_refs(&their_refs, &sendibuf); if (err) goto done; /* * Process references reported by the server. * Push appropriate object IDs onto the "their IDs" array. * This array will be used to exclude objects which already * exist on the server from our pack file. */ TAILQ_FOREACH(pe, &their_refs, entry) { const char *refname = pe->path; struct got_object_id *their_id = pe->data; int have_their_id; struct got_object *obj; struct got_pathlist_entry *my_ref = NULL; int is_tag = 0; /* Don't blindly trust the server to send us valid names. */ if (!got_ref_name_is_valid(refname)) continue; if (strncmp(refname, "refs/tags/", 10) == 0) is_tag = 1; /* * Find out whether this is a reference we want to upload. * Otherwise we can still use this reference as a hint to * avoid uploading any objects the server already has. */ my_ref = find_ref(&have_refs, refname); if (my_ref) { struct got_object_id *my_id = my_ref->data; if (got_object_id_cmp(my_id, their_id) != 0) { if (!overwrite_refs && is_tag) { err = got_error_fmt( GOT_ERR_SEND_TAG_EXISTS, "%s", refname); goto done; } refs_to_send++; } } /* Check if their object exists locally. */ err = got_object_open(&obj, repo, their_id); if (err) { if (err->code != GOT_ERR_NO_OBJ) goto done; if (!overwrite_refs && my_ref != NULL) { err = got_error_fmt(GOT_ERR_SEND_ANCESTRY, "%s", refname); goto done; } have_their_id = 0; } else { got_object_close(obj); have_their_id = 1; } err = realloc_ids(&their_ids, &nalloc_theirs, ntheirs + 1); if (err) goto done; if (have_their_id) { /* Enforce linear ancestry if required. */ if (!overwrite_refs && my_ref && !is_tag) { struct got_object_id *my_id = my_ref->data; err = check_common_ancestry(refname, my_id, their_id, repo, cancel_cb, cancel_arg); if (err) goto done; } /* Exclude any objects reachable via their ID. */ their_ids[ntheirs] = their_id; ntheirs++; } else if (!is_tag) { char *remote_refname; struct got_reference *ref; /* * Exclude any objects which exist on the server * according to a locally cached remote reference. */ err = get_remote_refname(&remote_refname, remote_name, refname); if (err) goto done; err = got_ref_open(&ref, repo, remote_refname, 0); free(remote_refname); if (err) { if (err->code != GOT_ERR_NOT_REF) goto done; } else { err = got_ref_resolve(&their_ids[ntheirs], repo, ref); got_ref_close(ref); if (err) goto done; ntheirs++; } } } /* Account for any new references we are going to upload. */ TAILQ_FOREACH(pe, &have_refs, entry) { const char *refname = pe->path; if (find_ref(&their_refs, refname) == NULL) refs_to_send++; } /* Account for any existing references we are going to delete. */ TAILQ_FOREACH(pe, delete_branches, entry) { const char *branchname = pe->path; if (find_ref(&their_refs, branchname)) refs_to_delete++; } if (refs_to_send == 0 && refs_to_delete == 0) { got_privsep_send_stop(imsg_sendfds[0]); goto done; } if (refs_to_send > 0) { struct got_ratelimit rl; got_ratelimit_init(&rl, 0, 500); memset(&ppa, 0, sizeof(ppa)); ppa.progress_cb = progress_cb; ppa.progress_arg = progress_arg; ppa.sendfd = sendfd; err = got_pack_create(packsha1, packfd, delta_cache, their_ids, ntheirs, our_ids, nours, repo, 0, 1, 0, pack_progress, &ppa, &rl, cancel_cb, cancel_arg); if (err) goto done; npackfd = dup(packfd); if (npackfd == -1) { err = got_error_from_errno("dup"); goto done; } err = got_privsep_send_packfd(&sendibuf, npackfd); if (err != NULL) goto done; npackfd = -1; } else { err = got_privsep_send_packfd(&sendibuf, -1); if (err != NULL) goto done; } while (!done) { int success = 0; char *refname = NULL; char *errmsg = NULL; if (cancel_cb) { err = (*cancel_cb)(cancel_arg); if (err) goto done; } err = got_privsep_recv_send_progress(&done, &bytes_sent, &success, &refname, &errmsg, &sendibuf); if (err) goto done; if (refname && got_ref_name_is_valid(refname) && success && strncmp(refname, "refs/tags/", 10) != 0) { struct got_pathlist_entry *my_ref; /* * The server has accepted our changes. * Update our reference in refs/remotes/ accordingly. */ my_ref = find_ref(&have_refs, refname); if (my_ref) { err = update_remote_ref(my_ref, remote_name, repo); if (err) goto done; } } if (refname != NULL || bytes_sent_cur != bytes_sent) { err = progress_cb(progress_arg, ppa.ncolored, ppa.nfound, ppa.ntrees, ppa.packfile_size, ppa.ncommits, ppa.nobj_total, ppa.nobj_deltify, ppa.nobj_written, bytes_sent, refname, errmsg, success); if (err) { free(refname); free(errmsg); goto done; } bytes_sent_cur = bytes_sent; } free(refname); free(errmsg); } done: if (sendpid != -1) { if (err) got_privsep_send_stop(imsg_sendfds[0]); if (waitpid(sendpid, &sendstatus, 0) == -1 && err == NULL) err = got_error_from_errno("waitpid"); } if (packfd != -1 && close(packfd) == -1 && err == NULL) err = got_error_from_errno("close"); if (delta_cache && fclose(delta_cache) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (nsendfd != -1 && close(nsendfd) == -1 && err == NULL) err = got_error_from_errno("close"); if (npackfd != -1 && close(npackfd) == -1 && err == NULL) err = got_error_from_errno("close"); got_pathlist_free(&have_refs, GOT_PATHLIST_FREE_ALL); got_pathlist_free(&their_refs, GOT_PATHLIST_FREE_ALL); /* * Object ids are owned by have_refs/their_refs and are already freed; * Only the arrays must be freed. */ free(our_ids); free(their_ids); free(s); return err; } got-portable-0.101/lib/got_lib_object_idcache.h0000644000175100017510000000301014644143163015121 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct got_object_idcache; struct got_object_idcache *got_object_idcache_alloc(int); void got_object_idcache_free(struct got_object_idcache *); const struct got_error *got_object_idcache_add(struct got_object_idcache *, struct got_object_id *, void *); void *got_object_idcache_get(struct got_object_idcache *, struct got_object_id *); const struct got_error *got_object_idcache_remove_one(void **, struct got_object_idcache *, struct got_object_id *); int got_object_idcache_contains(struct got_object_idcache *, struct got_object_id *); void got_object_idcache_for_each(struct got_object_idcache *, void (*cb)(struct got_object_id *, void *, void *), void *); int got_object_idcache_num_elements(struct got_object_idcache *); got-portable-0.101/lib/got_lib_privsep.h0000664000175100017510000006676214644144735013742 /* * Copyright (c) 2018, 2019 Stefan Sperling * Copyright (c) 2019, Ori Bernstein * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * All code runs under the same UID but sensitive code paths are * run in a separate process with tighter pledge(2) promises. * Data is communicated between processes via imsg_flush(3) and imsg_read(3). * This behaviour is transparent to users of the library. * * We generally transmit data in imsg buffers, split across several messages * if necessary. File descriptors are used in cases where this is impractical, * such as when accessing pack files or when transferring large blobs. * * We exec(2) after a fork(2). Parts of our library functionality are * accessible via separate executables in a libexec directory. */ #define GOT_IMSG_FD_CHILD (STDERR_FILENO + 1) #ifndef GOT_LIBEXECDIR #define GOT_LIBEXECDIR /usr/local/bin #endif /* Names of helper programs in libexec directory */ #define GOT_PROG_READ_OBJECT got-read-object #define GOT_PROG_READ_TREE got-read-tree #define GOT_PROG_READ_COMMIT got-read-commit #define GOT_PROG_READ_BLOB got-read-blob #define GOT_PROG_READ_TAG got-read-tag #define GOT_PROG_READ_PACK got-read-pack #define GOT_PROG_READ_GITCONFIG got-read-gitconfig #define GOT_PROG_READ_GOTCONFIG got-read-gotconfig #define GOT_PROG_READ_PATCH got-read-patch #define GOT_PROG_FETCH_PACK got-fetch-pack #define GOT_PROG_INDEX_PACK got-index-pack #define GOT_PROG_SEND_PACK got-send-pack #define GOT_PROG_FETCH_HTTP got-fetch-http #define GOT_STRINGIFY(x) #x #define GOT_STRINGVAL(x) GOT_STRINGIFY(x) /* Paths to helper programs in libexec directory */ #define GOT_PATH_PROG_READ_OBJECT \ GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_READ_OBJECT) #define GOT_PATH_PROG_READ_TREE \ GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_READ_TREE) #define GOT_PATH_PROG_READ_COMMIT \ GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_READ_COMMIT) #define GOT_PATH_PROG_READ_BLOB \ GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_READ_BLOB) #define GOT_PATH_PROG_READ_TAG \ GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_READ_TAG) #define GOT_PATH_PROG_READ_PACK \ GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_READ_PACK) #define GOT_PATH_PROG_READ_GITCONFIG \ GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_READ_GITCONFIG) #define GOT_PATH_PROG_READ_GOTCONFIG \ GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_READ_GOTCONFIG) #define GOT_PATH_PROG_READ_PATCH \ GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_READ_PATCH) #define GOT_PATH_PROG_FETCH_PACK \ GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_FETCH_PACK) #define GOT_PATH_PROG_SEND_PACK \ GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_SEND_PACK) #define GOT_PATH_PROG_INDEX_PACK \ GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_INDEX_PACK) #define GOT_PATH_PROG_FETCH_HTTP \ GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_FETCH_HTTP) enum got_imsg_type { /* An error occured while processing a request. */ GOT_IMSG_ERROR, /* Stop the child process. */ GOT_IMSG_STOP, /* * Messages concerned with read access to objects in a repository. * Object and pack files are opened by the main process, where * data may be read as a byte string but without any interpretation. * Decompression and parsing of object and pack files occurs in a * separate process which runs under pledge("stdio recvfd"). * This sandboxes our own repository parsing code, as well as zlib. */ GOT_IMSG_OBJECT_REQUEST, GOT_IMSG_OBJECT, GOT_IMSG_COMMIT_REQUEST, GOT_IMSG_COMMIT, GOT_IMSG_COMMIT_LOGMSG, GOT_IMSG_TREE_REQUEST, GOT_IMSG_TREE, GOT_IMSG_TREE_ENTRIES, GOT_IMSG_BLOB_REQUEST, GOT_IMSG_BLOB_OUTFD, GOT_IMSG_BLOB, GOT_IMSG_TAG_REQUEST, GOT_IMSG_TAG, GOT_IMSG_TAG_TAGMSG, /* Messages related to networking. */ GOT_IMSG_FETCH_REQUEST, GOT_IMSG_FETCH_HAVE_REF, GOT_IMSG_FETCH_WANTED_BRANCH, GOT_IMSG_FETCH_WANTED_REF, GOT_IMSG_FETCH_OUTFD, GOT_IMSG_FETCH_SYMREFS, GOT_IMSG_FETCH_REF, GOT_IMSG_FETCH_SERVER_PROGRESS, GOT_IMSG_FETCH_DOWNLOAD_PROGRESS, GOT_IMSG_FETCH_DONE, GOT_IMSG_IDXPACK_REQUEST, GOT_IMSG_IDXPACK_OUTFD, GOT_IMSG_IDXPACK_PROGRESS, GOT_IMSG_IDXPACK_DONE, GOT_IMSG_SEND_REQUEST, GOT_IMSG_SEND_REF, GOT_IMSG_SEND_REMOTE_REF, GOT_IMSG_SEND_REF_STATUS, GOT_IMSG_SEND_PACK_REQUEST, GOT_IMSG_SEND_PACKFD, GOT_IMSG_SEND_UPLOAD_PROGRESS, GOT_IMSG_SEND_DONE, /* Messages related to pack files. */ GOT_IMSG_PACKIDX, GOT_IMSG_PACK, GOT_IMSG_PACKED_OBJECT_REQUEST, GOT_IMSG_COMMIT_TRAVERSAL_REQUEST, GOT_IMSG_TRAVERSED_COMMITS, GOT_IMSG_COMMIT_TRAVERSAL_DONE, GOT_IMSG_OBJECT_ENUMERATION_REQUEST, GOT_IMSG_ENUMERATED_COMMIT, GOT_IMSG_ENUMERATED_TREE, GOT_IMSG_TREE_ENUMERATION_DONE, GOT_IMSG_OBJECT_ENUMERATION_DONE, GOT_IMSG_OBJECT_ENUMERATION_INCOMPLETE, /* Message sending file descriptor to a temporary file. */ GOT_IMSG_TMPFD, /* Messages related to gitconfig files. */ GOT_IMSG_GITCONFIG_PARSE_REQUEST, GOT_IMSG_GITCONFIG_REPOSITORY_FORMAT_VERSION_REQUEST, GOT_IMSG_GITCONFIG_REPOSITORY_EXTENSIONS_REQUEST, GOT_IMSG_GITCONFIG_AUTHOR_NAME_REQUEST, GOT_IMSG_GITCONFIG_AUTHOR_EMAIL_REQUEST, GOT_IMSG_GITCONFIG_REMOTES_REQUEST, GOT_IMSG_GITCONFIG_INT_VAL, GOT_IMSG_GITCONFIG_STR_VAL, GOT_IMSG_GITCONFIG_PAIR, GOT_IMSG_GITCONFIG_REMOTES, GOT_IMSG_GITCONFIG_REMOTE, GOT_IMSG_GITCONFIG_OWNER_REQUEST, GOT_IMSG_GITCONFIG_OWNER, /* Messages related to gotconfig files. */ GOT_IMSG_GOTCONFIG_PARSE_REQUEST, GOT_IMSG_GOTCONFIG_AUTHOR_REQUEST, GOT_IMSG_GOTCONFIG_ALLOWEDSIGNERS_REQUEST, GOT_IMSG_GOTCONFIG_REVOKEDSIGNERS_REQUEST, GOT_IMSG_GOTCONFIG_SIGNERID_REQUEST, GOT_IMSG_GOTCONFIG_REMOTES_REQUEST, GOT_IMSG_GOTCONFIG_INT_VAL, GOT_IMSG_GOTCONFIG_STR_VAL, GOT_IMSG_GOTCONFIG_REMOTES, GOT_IMSG_GOTCONFIG_REMOTE, /* Raw object access. Uncompress object data but do not parse it. */ GOT_IMSG_RAW_OBJECT_REQUEST, GOT_IMSG_RAW_OBJECT_OUTFD, GOT_IMSG_PACKED_RAW_OBJECT_REQUEST, GOT_IMSG_RAW_OBJECT, /* Read raw delta data from pack files. */ GOT_IMSG_RAW_DELTA_OUTFD, GOT_IMSG_RAW_DELTA_REQUEST, GOT_IMSG_RAW_DELTA, /* Re-use deltas found in a pack file. */ GOT_IMSG_DELTA_REUSE_REQUEST, GOT_IMSG_REUSED_DELTAS, GOT_IMSG_DELTA_REUSE_DONE, /* Commit coloring in got-read-pack. */ GOT_IMSG_COMMIT_PAINTING_INIT, GOT_IMSG_COMMIT_PAINTING_REQUEST, GOT_IMSG_PAINTED_COMMITS, GOT_IMSG_COMMIT_PAINTING_DONE, /* Transfer a list of object IDs. */ GOT_IMSG_OBJ_ID_LIST, GOT_IMSG_OBJ_ID_LIST_DONE, /* Messages related to patch files. */ GOT_IMSG_PATCH_FILE, GOT_IMSG_PATCH_HUNK, GOT_IMSG_PATCH_DONE, GOT_IMSG_PATCH_LINE, GOT_IMSG_PATCH, GOT_IMSG_PATCH_EOF, }; /* Structure for GOT_IMSG_ERROR. */ struct got_imsg_error { int code; /* an error code from got_error.h */ int errno_code; /* in case code equals GOT_ERR_ERRNO */ } __attribute__((__packed__)); /* * Structure for GOT_IMSG_TREE_REQUEST and GOT_IMSG_OBJECT data. */ struct got_imsg_object { struct got_object_id id; /* These fields are the same as in struct got_object. */ int type; int flags; size_t hdrlen; size_t size; off_t pack_offset; int pack_idx; } __attribute__((__packed__)); /* Structure for GOT_IMSG_COMMIT data. */ struct got_imsg_commit_object { struct got_object_id tree_id; size_t author_len; time_t author_time; time_t author_gmtoff; size_t committer_len; time_t committer_time; time_t committer_gmtoff; size_t logmsg_len; int nparents; /* * Followed by author_len + committer_len data bytes */ /* Followed by 'nparents' struct got_object_id */ /* * Followed by 'logmsg_len' bytes of commit log message data in * one or more GOT_IMSG_COMMIT_LOGMSG messages. */ } __attribute__((__packed__)); struct got_imsg_tree_entry { char id[SHA1_DIGEST_LENGTH]; mode_t mode; size_t namelen; /* Followed by namelen bytes of entry's name, not NUL-terminated. */ } __attribute__((__packed__)); /* Structure for GOT_IMSG_TREE_ENTRIES. */ struct got_imsg_tree_entries { size_t nentries; /* Number of tree entries contained in this message. */ /* Followed by nentries * struct got_imsg_tree_entry */ }; /* Structure for GOT_IMSG_TREE_OBJECT_REPLY data. */ struct got_imsg_tree_object { int nentries; /* This many tree entries follow. */ }; /* Structure for GOT_IMSG_BLOB. */ struct got_imsg_blob { size_t size; size_t hdrlen; /* * If size <= GOT_PRIVSEP_INLINE_BLOB_DATA_MAX, blob data follows * in the imsg buffer. Otherwise, blob data has been written to a * file descriptor passed via the GOT_IMSG_BLOB_OUTFD imsg. */ #define GOT_PRIVSEP_INLINE_BLOB_DATA_MAX \ (MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof(struct got_imsg_blob)) }; /* Structure for GOT_IMSG_RAW_OBJECT. */ struct got_imsg_raw_obj { off_t size; size_t hdrlen; /* * If size <= GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX, object data follows * in the imsg buffer. Otherwise, object data has been written to a * file descriptor passed via the GOT_IMSG_RAW_OBJECT_OUTFD imsg. */ #define GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX \ (MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof(struct got_imsg_raw_obj)) }; /* Structure for GOT_IMSG_RAW_DELTA. */ struct got_imsg_raw_delta { struct got_object_id base_id; uint64_t base_size; uint64_t result_size; off_t delta_size; off_t delta_compressed_size; off_t delta_offset; off_t delta_out_offset; /* * Delta data has been written at delta_out_offset to the file * descriptor passed via the GOT_IMSG_RAW_DELTA_OUTFD imsg. */ }; /* Structures for GOT_IMSG_REUSED_DELTAS. */ struct got_imsg_reused_delta { struct got_object_id id; struct got_object_id base_id; uint64_t base_size; uint64_t result_size; off_t delta_size; off_t delta_compressed_size; off_t delta_offset; }; struct got_imsg_reused_deltas { size_t ndeltas; /* * Followed by ndeltas * struct got_imsg_reused_delta. */ #define GOT_IMSG_REUSED_DELTAS_MAX_NDELTAS \ ((MAX_IMSGSIZE - IMSG_HEADER_SIZE - \ sizeof(struct got_imsg_reused_deltas)) \ / sizeof(struct got_imsg_reused_delta)) }; /* Structure for GOT_IMSG_COMMIT_PAINTING_REQUEST. */ struct got_imsg_commit_painting_request { struct got_object_id id; int idx; int color; } __attribute__((__packed__)); /* Structure for GOT_IMSG_PAINTED_COMMITS. */ struct got_imsg_painted_commit { struct got_object_id id; intptr_t color; } __attribute__((__packed__)); struct got_imsg_painted_commits { int ncommits; int present_in_pack; /* * Followed by ncommits * struct got_imsg_painted_commit. */ } __attribute__((__packed__)); /* Structure for GOT_IMSG_TAG data. */ struct got_imsg_tag_object { struct got_object_id id; int obj_type; size_t tag_len; size_t tagger_len; time_t tagger_time; time_t tagger_gmtoff; size_t tagmsg_len; /* * Followed by tag_len + tagger_len data bytes */ /* * Followed by 'tagmsg_len' bytes of tag message data in * one or more GOT_IMSG_TAG_TAGMSG messages. */ } __attribute__((__packed__)); /* Structure for GOT_IMSG_FETCH_HAVE_REF data. */ struct got_imsg_fetch_have_ref { struct got_object_id id; size_t name_len; /* Followed by name_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOT_IMSG_FETCH_WANTED_BRANCH data. */ struct got_imsg_fetch_wanted_branch { size_t name_len; /* Followed by name_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOT_IMSG_FETCH_WANTED_REF data. */ struct got_imsg_fetch_wanted_ref { size_t name_len; /* Followed by name_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOT_IMSG_FETCH_REQUEST data. */ struct got_imsg_fetch_request { int no_head; int fetch_all_branches; int list_refs_only; int verbosity; size_t worktree_branch_len; size_t remote_head_len; size_t n_have_refs; size_t n_wanted_branches; size_t n_wanted_refs; /* Followed by worktree_branch_len bytes of reference name. */ /* Followed by remote_head_len bytes of reference name. */ /* Followed by n_have_refs GOT_IMSG_FETCH_HAVE_REF messages. */ /* Followed by n_wanted_branches times GOT_IMSG_FETCH_WANTED_BRANCH. */ /* Followed by n_wanted_refs times GOT_IMSG_FETCH_WANTED_REF. */ } __attribute__((__packed__)); /* Structures for GOT_IMSG_FETCH_SYMREFS data. */ struct got_imsg_fetch_symref { size_t name_len; size_t target_len; /* * Followed by name_len + target_len data bytes. */ } __attribute__((__packed__)); struct got_imsg_fetch_symrefs { size_t nsymrefs; /* Followed by nsymrefs times of got_imsg_fetch_symref data. */ } __attribute__((__packed__)); /* Structure for GOT_IMSG_FETCH_REF data. */ struct got_imsg_fetch_ref { /* Describes a reference which will be fetched. */ struct got_object_id refid; /* Followed by reference name in remaining data of imsg buffer. */ }; /* Structure for GOT_IMSG_FETCH_DOWNLOAD_PROGRESS data. */ struct got_imsg_fetch_download_progress { /* Number of packfile data bytes downloaded so far. */ off_t packfile_bytes; }; /* Structure for GOT_IMSG_SEND_REQUEST data. */ struct got_imsg_send_request { int verbosity; size_t nrefs; /* Followed by nrefs GOT_IMSG_SEND_REF messages. */ } __attribute__((__packed__)); /* Structure for GOT_IMSG_SEND_UPLOAD_PROGRESS data. */ struct got_imsg_send_upload_progress { /* Number of packfile data bytes uploaded so far. */ off_t packfile_bytes; }; /* Structure for GOT_IMSG_SEND_REF data. */ struct got_imsg_send_ref { struct got_object_id id; int delete; size_t name_len; /* Followed by name_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOT_IMSG_SEND_REMOTE_REF data. */ struct got_imsg_send_remote_ref { struct got_object_id id; size_t name_len; /* Followed by name_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOT_IMSG_SEND_REF_STATUS data. */ struct got_imsg_send_ref_status { int success; size_t name_len; size_t errmsg_len; /* Followed by name_len data bytes. */ /* Followed by errmsg_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOT_IMSG_IDXPACK_REQUEST data. */ struct got_imsg_index_pack_request { uint8_t pack_hash[SHA1_DIGEST_LENGTH]; } __attribute__((__packed__)); /* Structure for GOT_IMSG_IDXPACK_PROGRESS data. */ struct got_imsg_index_pack_progress { /* Total number of objects in pack file. */ int nobj_total; /* Number of objects indexed so far. */ int nobj_indexed; /* Number of non-deltified objects in pack file. */ int nobj_loose; /* Number of deltified objects resolved so far. */ int nobj_resolved; }; /* Structure for GOT_IMSG_PACKIDX. */ struct got_imsg_packidx { size_t len; off_t packfile_size; /* Additionally, a file desciptor is passed via imsg. */ }; /* Structure for GOT_IMSG_PACK. */ struct got_imsg_pack { char path_packfile[PATH_MAX]; off_t filesize; /* Additionally, a file desciptor is passed via imsg. */ } __attribute__((__packed__)); /* * Structure for GOT_IMSG_OBJECT_REQUEST, GOT_IMSG_BLOB_REQUEST, * GOT_IMSG_TREE_REQUEST, GOT_IMSG_COMMIT_REQUEST, and * GOT_IMSG_TAG_REQUEST data. */ struct got_object_id; /* * Structure for GOT_IMSG_PACKED_OBJECT_REQUEST and * GOT_IMSG_PACKED_RAW_OBJECT_REQUEST data. */ struct got_imsg_packed_object { struct got_object_id id; int idx; } __attribute__((__packed__)); /* * Structure for GOT_IMSG_DELTA data. */ struct got_imsg_delta { /* These fields are the same as in struct got_delta. */ off_t offset; size_t tslen; int type; size_t size; off_t data_offset; }; /* * Structure for GOT_IMSG_RAW_DELTA_REQUEST data. */ struct got_imsg_raw_delta_request { struct got_object_id id; int idx; }; /* * Structure for GOT_IMSG_OBJ_ID_LIST data. * Multiple such messages may be sent back-to-back, where each message * contains a chunk of IDs. The entire list must be terminated with a * GOT_IMSG_OBJ_ID_LIST_DONE message. */ struct got_imsg_object_idlist { size_t nids; /* * Followed by nids * struct got_object_id. */ #define GOT_IMSG_OBJ_ID_LIST_MAX_NIDS \ ((MAX_IMSGSIZE - IMSG_HEADER_SIZE - \ sizeof(struct got_imsg_object_idlist)) / sizeof(struct got_object_id)) }; /* Structure for GOT_IMSG_COMMIT_TRAVERSAL_REQUEST */ struct got_imsg_commit_traversal_request { struct got_imsg_packed_object iobj; size_t path_len; /* Followed by path_len bytes of path data */ } __attribute__((__packed__)); /* Structure for GOT_IMSG_TRAVERSED_COMMITS */ struct got_imsg_traversed_commits { size_t ncommits; /* Followed by ncommit struct got_object_id */ } __attribute__((__packed__)); /* Structure for GOT_IMSG_ENUMERATED_COMMIT */ struct got_imsg_enumerated_commit { struct got_object_id id; time_t mtime; } __attribute__((__packed__)); /* Structure for GOT_IMSG_ENUMERATED_TREE */ struct got_imsg_enumerated_tree { struct got_object_id id; /* tree ID */ int nentries; /* number of tree entries */ /* Followed by tree's path in remaining data of imsg buffer. */ /* Followed by nentries * GOT_IMSG_TREE_ENTRY messages. */ } __attribute__((__packed__)); /* * Structure for GOT_IMSG_GOTCONFIG_REMOTE and * GOT_IMSG_GOTCONFIG_REMOTE data. */ struct got_imsg_remote { size_t name_len; size_t fetch_url_len; size_t send_url_len; int mirror_references; int fetch_all_branches; int nfetch_branches; int nsend_branches; int nfetch_refs; /* Followed by name_len data bytes. */ /* Followed by fetch_url_len + send_url_len data bytes. */ /* Followed by nfetch_branches GOT_IMSG_GITCONFIG_STR_VAL messages. */ /* Followed by nsend_branches GOT_IMSG_GITCONFIG_STR_VAL messages. */ /* Followed by nfetch_refs GOT_IMSG_GITCONFIG_STR_VAL messages. */ } __attribute__((__packed__)); /* * Structure for GOT_IMSG_GITCONFIG_REMOTES data. */ struct got_imsg_remotes { int nremotes; /* This many GOT_IMSG_GITCONFIG_REMOTE messages follow. */ }; /* * Structure for GOT_IMSG_GITCONFIG_PAIR. */ struct got_imsg_gitconfig_pair { size_t klen; size_t vlen; /* Followed by klen data bytes of key string. */ /* Followed by vlen data bytes of value string. */ }; /* * Structure for GOT_IMSG_PATCH data. */ struct got_imsg_patch { int git; int xbit; char old[PATH_MAX]; char new[PATH_MAX]; char cid[41]; char blob[41]; }; /* * Structure for GOT_IMSG_PATCH_HUNK data. */ struct got_imsg_patch_hunk { int oldfrom; int oldlines; int newfrom; int newlines; }; struct got_remote_repo; struct got_pack; struct got_packidx; struct got_pathlist_head; const struct got_error *got_send_ack(pid_t); const struct got_error *got_privsep_wait_for_child(pid_t); const struct got_error *got_privsep_flush_imsg(struct imsgbuf *); const struct got_error *got_privsep_send_stop(int); const struct got_error *got_privsep_recv_imsg(struct imsg *, struct imsgbuf *, size_t); void got_privsep_send_error(struct imsgbuf *, const struct got_error *); const struct got_error *got_privsep_send_ack(struct imsgbuf *); const struct got_error *got_privsep_wait_ack(struct imsgbuf *); const struct got_error *got_privsep_send_obj_req(struct imsgbuf *, int, struct got_object_id *); const struct got_error *got_privsep_send_raw_obj_req(struct imsgbuf *, int, struct got_object_id *); const struct got_error *got_privsep_send_raw_obj_outfd(struct imsgbuf *, int); const struct got_error *got_privsep_send_commit_req(struct imsgbuf *, int, struct got_object_id *, int); const struct got_error *got_privsep_send_tree_req(struct imsgbuf *, int, struct got_object_id *, int); const struct got_error *got_privsep_send_tag_req(struct imsgbuf *, int, struct got_object_id *, int); const struct got_error *got_privsep_send_blob_req(struct imsgbuf *, int, struct got_object_id *, int); const struct got_error *got_privsep_send_blob_outfd(struct imsgbuf *, int); const struct got_error *got_privsep_send_tmpfd(struct imsgbuf *, int); const struct got_error *got_privsep_send_obj(struct imsgbuf *, struct got_object *); const struct got_error *got_privsep_send_index_pack_req(struct imsgbuf *, uint8_t *, int); const struct got_error *got_privsep_send_index_pack_outfd(struct imsgbuf *, int); const struct got_error *got_privsep_recv_index_progress(int *, int *, int *, int *, int *, struct imsgbuf *ibuf); const struct got_error *got_privsep_send_fetch_req(struct imsgbuf *, int, struct got_pathlist_head *, int, struct got_pathlist_head *, struct got_pathlist_head *, int, const char *, const char *, int, int); const struct got_error *got_privsep_send_fetch_outfd(struct imsgbuf *, int); const struct got_error *got_privsep_recv_fetch_progress(int *, struct got_object_id **, char **, struct got_pathlist_head *, char **, off_t *, uint8_t *, struct imsgbuf *); const struct got_error *got_privsep_send_send_req(struct imsgbuf *, int, struct got_pathlist_head *, struct got_pathlist_head *, int); const struct got_error *got_privsep_recv_send_remote_refs( struct got_pathlist_head *, struct imsgbuf *); const struct got_error *got_privsep_send_packfd(struct imsgbuf *, int); const struct got_error *got_privsep_recv_send_progress(int *, off_t *, int *, char **, char **, struct imsgbuf *); const struct got_error *got_privsep_get_imsg_obj(struct got_object **, struct imsg *, struct imsgbuf *); const struct got_error *got_privsep_recv_obj(struct got_object **, struct imsgbuf *); const struct got_error *got_privsep_send_raw_obj(struct imsgbuf *, off_t, size_t, uint8_t *); const struct got_error *got_privsep_recv_raw_obj(uint8_t **, off_t *, size_t *, struct imsgbuf *); const struct got_error *got_privsep_send_commit(struct imsgbuf *, struct got_commit_object *); const struct got_error *got_privsep_recv_commit(struct got_commit_object **, struct imsgbuf *); const struct got_error *got_privsep_recv_tree(struct got_tree_object **, struct imsgbuf *); struct got_parsed_tree_entry; const struct got_error *got_privsep_send_tree(struct imsgbuf *, struct got_parsed_tree_entry *, int); const struct got_error *got_privsep_send_blob(struct imsgbuf *, size_t, size_t, const uint8_t *); const struct got_error *got_privsep_recv_blob(uint8_t **, size_t *, size_t *, struct imsgbuf *); const struct got_error *got_privsep_send_tag(struct imsgbuf *, struct got_tag_object *); const struct got_error *got_privsep_recv_tag(struct got_tag_object **, struct imsgbuf *); const struct got_error *got_privsep_init_pack_child(struct imsgbuf *, struct got_pack *, struct got_packidx *); const struct got_error *got_privsep_send_packed_obj_req(struct imsgbuf *, int, struct got_object_id *); const struct got_error *got_privsep_send_packed_raw_obj_req(struct imsgbuf *, int, struct got_object_id *); const struct got_error *got_privsep_send_pack_child_ready(struct imsgbuf *); const struct got_error *got_privsep_send_gitconfig_parse_req(struct imsgbuf *, int); const struct got_error * got_privsep_send_gitconfig_repository_format_version_req(struct imsgbuf *); const struct got_error *got_privsep_send_gitconfig_repository_extensions_req( struct imsgbuf *); const struct got_error *got_privsep_send_gitconfig_author_name_req( struct imsgbuf *); const struct got_error *got_privsep_send_gitconfig_author_email_req( struct imsgbuf *); const struct got_error *got_privsep_send_gitconfig_remotes_req( struct imsgbuf *); const struct got_error *got_privsep_send_gitconfig_owner_req(struct imsgbuf *); const struct got_error *got_privsep_recv_gitconfig_str(char **, struct imsgbuf *); const struct got_error *got_privsep_recv_gitconfig_pair(char **, char **, struct imsgbuf *); const struct got_error *got_privsep_recv_gitconfig_int(int *, struct imsgbuf *); const struct got_error *got_privsep_recv_gitconfig_remotes( struct got_remote_repo **, int *, struct imsgbuf *); const struct got_error *got_privsep_send_gotconfig_parse_req(struct imsgbuf *, int); const struct got_error *got_privsep_send_gotconfig_author_req(struct imsgbuf *); const struct got_error *got_privsep_send_gotconfig_allowed_signers_req( struct imsgbuf *); const struct got_error *got_privsep_send_gotconfig_revoked_signers_req( struct imsgbuf *); const struct got_error *got_privsep_send_gotconfig_signer_id_req( struct imsgbuf *); const struct got_error *got_privsep_send_gotconfig_remotes_req( struct imsgbuf *); const struct got_error *got_privsep_recv_gotconfig_str(char **, struct imsgbuf *); const struct got_error *got_privsep_recv_gotconfig_remotes( struct got_remote_repo **, int *, struct imsgbuf *); const struct got_error *got_privsep_send_commit_traversal_request( struct imsgbuf *, struct got_object_id *, int, const char *); const struct got_error *got_privsep_recv_traversed_commits( struct got_commit_object **, struct got_object_id_queue *, struct imsgbuf *); const struct got_error *got_privsep_send_enumerated_tree(size_t *, struct imsgbuf *, struct got_object_id *, const char *, struct got_parsed_tree_entry *, int); const struct got_error *got_privsep_send_object_enumeration_request( struct imsgbuf *); const struct got_error *got_privsep_send_object_enumeration_done( struct imsgbuf *); const struct got_error *got_privsep_send_object_enumeration_incomplete( struct imsgbuf *); const struct got_error *got_privsep_send_enumerated_commit(struct imsgbuf *, struct got_object_id *, time_t); const struct got_error *got_privsep_recv_enumerated_objects(int *, struct imsgbuf *, got_object_enumerate_commit_cb, got_object_enumerate_tree_cb, void *, struct got_repository *); const struct got_error *got_privsep_send_raw_delta_req(struct imsgbuf *, int, struct got_object_id *); const struct got_error *got_privsep_send_raw_delta_outfd(struct imsgbuf *, int); const struct got_error *got_privsep_send_raw_delta(struct imsgbuf *, uint64_t, uint64_t, off_t, off_t, off_t, off_t, struct got_object_id *); const struct got_error *got_privsep_recv_raw_delta(uint64_t *, uint64_t *, off_t *, off_t *, off_t *, off_t *, struct got_object_id **, struct imsgbuf *); const struct got_error *got_privsep_send_object_idlist(struct imsgbuf *, struct got_object_id **, size_t); const struct got_error *got_privsep_send_object_idlist_done(struct imsgbuf *); const struct got_error *got_privsep_recv_object_idlist(int *, struct got_object_id **, size_t *, struct imsgbuf *); const struct got_error *got_privsep_send_delta_reuse_req(struct imsgbuf *); const struct got_error *got_privsep_send_reused_deltas(struct imsgbuf *, struct got_imsg_reused_delta *, size_t); const struct got_error *got_privsep_send_reused_deltas_done(struct imsgbuf *); const struct got_error *got_privsep_recv_reused_deltas(int *, struct got_imsg_reused_delta *, size_t *, struct imsgbuf *); const struct got_error *got_privsep_init_commit_painting(struct imsgbuf *); const struct got_error *got_privsep_send_painting_request(struct imsgbuf *, int, struct got_object_id *, intptr_t); typedef const struct got_error *(*got_privsep_recv_painted_commit_cb)(void *, struct got_object_id *, intptr_t); const struct got_error *got_privsep_send_painted_commits(struct imsgbuf *, struct got_object_id_queue *, int *, int, int); const struct got_error *got_privsep_send_painting_commits_done(struct imsgbuf *); const struct got_error *got_privsep_recv_painted_commits( struct got_object_id_queue *, got_privsep_recv_painted_commit_cb, void *, struct imsgbuf *); void got_privsep_exec_child(int[2], const char *, const char *); got-portable-0.101/lib/diff_internal.h0000644000175100017510000001157114644143163013333 /* Generic infrastructure to implement various diff algorithms. */ /* * Copyright (c) 2020 Neels Hofmeyr * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef MAX #define MAX(A,B) ((A)>(B)?(A):(B)) #endif #ifndef MIN #define MIN(A,B) ((A)<(B)?(A):(B)) #endif static inline bool diff_range_empty(const struct diff_range *r) { return r->start == r->end; } static inline bool diff_ranges_touch(const struct diff_range *a, const struct diff_range *b) { return (a->end >= b->start) && (a->start <= b->end); } static inline void diff_ranges_merge(struct diff_range *a, const struct diff_range *b) { *a = (struct diff_range){ .start = MIN(a->start, b->start), .end = MAX(a->end, b->end), }; } static inline int diff_range_len(const struct diff_range *r) { if (!r) return 0; return r->end - r->start; } /* Indicate whether two given diff atoms match. */ int diff_atom_same(bool *same, const struct diff_atom *left, const struct diff_atom *right); /* A diff chunk represents a set of atoms on the left and/or a set of atoms on * the right. * * If solved == false: * The diff algorithm has divided the source file, and this is a chunk that the * inner_algo should run on next. * The lines on the left should be diffed against the lines on the right. * (If there are no left lines or no right lines, it implies solved == true, * because there is nothing to diff.) * * If solved == true: * If there are only left atoms, it is a chunk removing atoms from the left ("a * minus chunk"). * If there are only right atoms, it is a chunk adding atoms from the right ("a * plus chunk"). * If there are both left and right lines, it is a chunk of equal content on * both sides, and left_count == right_count: * * - foo } * - bar }-- diff_chunk{ left_start = &left.atoms.head[0], left_count = 3, * - baz } right_start = NULL, right_count = 0 } * moo } * goo }-- diff_chunk{ left_start = &left.atoms.head[3], left_count = 3, * zoo } right_start = &right.atoms.head[0], right_count = 3 } * +loo } * +roo }-- diff_chunk{ left_start = NULL, left_count = 0, * +too } right_start = &right.atoms.head[3], right_count = 3 } * */ struct diff_chunk { bool solved; struct diff_atom *left_start; unsigned int left_count; struct diff_atom *right_start; unsigned int right_count; }; #define DIFF_RESULT_ALLOC_BLOCKSIZE 128 struct diff_chunk_context; bool diff_chunk_context_empty(const struct diff_chunk_context *cc); bool diff_chunk_contexts_touch(const struct diff_chunk_context *cc, const struct diff_chunk_context *other); void diff_chunk_contexts_merge(struct diff_chunk_context *cc, const struct diff_chunk_context *other); struct diff_state { /* The final result passed to the original diff caller. */ struct diff_result *result; /* The root diff_data is in result->left,right, these are (possibly) * subsections of the root data. */ struct diff_data left; struct diff_data right; unsigned int recursion_depth_left; /* Remaining chunks from one diff algorithm pass, if any solved == false * chunks came up. */ diff_chunk_arraylist_t temp_result; /* State buffer used by Myers algorithm. */ int *kd_buf; size_t kd_buf_size; /* in units of sizeof(int), not bytes */ }; struct diff_chunk *diff_state_add_chunk(struct diff_state *state, bool solved, struct diff_atom *left_start, unsigned int left_count, struct diff_atom *right_start, unsigned int right_count); struct diff_output_info; int diff_output_lines(struct diff_output_info *output_info, FILE *dest, const char *prefix, struct diff_atom *start_atom, unsigned int count); int diff_output_trailing_newline_msg(struct diff_output_info *outinfo, FILE *dest, const struct diff_chunk *c); #define DIFF_FUNCTION_CONTEXT_SIZE 55 int diff_output_match_function_prototype(char *prototype, size_t prototype_size, int *last_prototype_idx, const struct diff_result *result, const struct diff_chunk_context *cc); struct diff_output_info *diff_output_info_alloc(void); void diff_data_init_subsection(struct diff_data *d, struct diff_data *parent, struct diff_atom *from_atom, unsigned int atoms_count); got-portable-0.101/lib/date.c0000644000175100017510000000221614644143163011433 /* * Copyright (c) 2022 Josh Rickmar * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include "got_date.h" void got_date_format_gmtoff(char *buf, size_t sz, time_t gmtoff) { long long h, m; char sign = '+'; if (gmtoff < 0) { sign = '-'; gmtoff = -gmtoff; } h = (long long)gmtoff / 3600; m = ((long long)gmtoff - h*3600) / 60; snprintf(buf, sz, "%c%02lld%02lld", sign, h, m); } got-portable-0.101/lib/buf.h0000644000175100017510000000520414644143163011277 /* $OpenBSD: buf.h,v 1.13 2011/07/06 15:36:52 nicm Exp $ */ /* * Copyright (c) 2003 Jean-Francois Brousseau * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Buffer management * ----------------- * * This code provides an API to generic memory buffer management. All * operations are performed on a buf structure, which is kept opaque to the * API user in order to avoid corruption of the fields and make sure that only * the internals can modify the fields. * * The first step is to allocate a new buffer using the buf_alloc() * function, which returns a pointer to a new buffer. */ #ifndef BUF_H #define BUF_H #include typedef struct buf BUF; struct buf { /* buffer handle, buffer size, and data length */ u_char *cb_buf; size_t cb_size; size_t cb_len; }; const struct got_error *buf_alloc(BUF **, size_t); const struct got_error *buf_load(BUF **, FILE *); const struct got_error *buf_load_fd(BUF **, int fd); void buf_free(BUF *); void *buf_release(BUF *); u_char buf_getc(BUF *, size_t); void buf_empty(BUF *); const struct got_error *buf_discard(BUF *, size_t); const struct got_error *buf_append(size_t *, BUF *, const void *, size_t); const struct got_error *buf_putc(BUF *, int); const struct got_error *buf_puts(size_t *, BUF *b, const char *str); size_t buf_len(BUF *); int buf_write_fd(BUF *, int); const struct got_error *buf_write(BUF *, const char *, mode_t); const struct got_error *buf_write_stmp(BUF *, char *); u_char *buf_get(BUF *b); #endif /* BUF_H */ got-portable-0.101/lib/got_lib_inflate.h0000644000175100017510000000534714644143163013654 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct got_inflate_checksum { /* If not NULL, mix input bytes into this CRC checksum. */ uint32_t *input_crc; /* if not NULL, mix input bytes into this hash context. */ struct got_hash *input_ctx; /* If not NULL, mix output bytes into this CRC checksum. */ uint32_t *output_crc; /* If not NULL, mix output bytes into this hash context. */ struct got_hash *output_ctx; }; struct got_inflate_buf { z_stream z; uint8_t *inbuf; size_t inlen; uint8_t *outbuf; size_t outlen; int flags; #define GOT_INFLATE_F_HAVE_MORE 0x01 #define GOT_INFLATE_F_OWN_OUTBUF 0x02 struct got_inflate_checksum *csum; }; #define GOT_INFLATE_BUFSIZE 32768 const struct got_error *got_inflate_init(struct got_inflate_buf *, uint8_t *, size_t, struct got_inflate_checksum *); const struct got_error *got_inflate_read(struct got_inflate_buf *, FILE *, size_t *, size_t *); const struct got_error *got_inflate_read_fd(struct got_inflate_buf *, int, size_t *, size_t *); const struct got_error *got_inflate_read_mmap(struct got_inflate_buf *, uint8_t *, size_t, size_t, size_t *, size_t *); void got_inflate_end(struct got_inflate_buf *); const struct got_error *got_inflate_to_mem(uint8_t **, size_t *, size_t *, struct got_inflate_checksum *, FILE *); const struct got_error *got_inflate_to_mem_fd(uint8_t **, size_t *, size_t *, struct got_inflate_checksum *, size_t, int); const struct got_error *got_inflate_to_mem_mmap(uint8_t **, size_t *, size_t *, struct got_inflate_checksum *, uint8_t *, size_t, size_t); const struct got_error *got_inflate_to_file(size_t *, FILE *, struct got_inflate_checksum *, FILE *); const struct got_error *got_inflate_to_file_fd(size_t *, size_t *, struct got_inflate_checksum *, int, FILE *); const struct got_error *got_inflate_to_fd(size_t *, FILE *, struct got_inflate_checksum *, int); const struct got_error *got_inflate_to_file_mmap(size_t *, size_t *, struct got_inflate_checksum *, uint8_t *, size_t, size_t, FILE *); got-portable-0.101/lib/got_lib_lockfile.h0000644000175100017510000000227114644143163014013 /* * Copyright (c) 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Git-compatible lock file implementation. Lock files are used to * ensure exclusive access when files in a Git repository are modified. */ #define GOT_LOCKFILE_SUFFIX ".lock" struct got_lockfile { char *path; char *locked_path; int fd; }; const struct got_error *got_lockfile_lock(struct got_lockfile **, const char *, int); const struct got_error *got_lockfile_unlock(struct got_lockfile *, int); got-portable-0.101/lib/opentemp.c0000664000175100017510000000601114644144735012352 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include "got_opentemp.h" #include "got_error.h" int got_opentempfd(void) { char name[PATH_MAX]; int fd; if (strlcpy(name, GOT_TMPDIR_STR "/got.XXXXXXXXXX", sizeof(name)) >= sizeof(name)) return -1; fd = mkstemp(name); if (fd != -1) { if (unlink(name) == -1) { close(fd); return -1; } } return fd; } FILE * got_opentemp(void) { int fd; FILE *f; fd = got_opentempfd(); if (fd < 0) return NULL; f = fdopen(fd, "w+"); if (f == NULL) { close(fd); return NULL; } return f; } const struct got_error * got_opentemp_named(char **path, FILE **outfile, const char *basepath, const char *suffix) { const struct got_error *err = NULL; int fd; *outfile = NULL; if (asprintf(path, "%s-XXXXXXXXXX%s", basepath, suffix) == -1) { *path = NULL; return got_error_from_errno("asprintf"); } fd = mkstemps(*path, strlen(suffix)); if (fd == -1) { err = got_error_from_errno2("mkstemps", *path); free(*path); *path = NULL; return err; } *outfile = fdopen(fd, "w+"); if (*outfile == NULL) { err = got_error_from_errno2("fdopen", *path); close(fd); free(*path); *path = NULL; } return err; } const struct got_error * got_opentemp_named_fd(char **path, int *outfd, const char *basepath, const char *suffix) { const struct got_error *err = NULL; int fd; *outfd = -1; if (asprintf(path, "%s-XXXXXXXXXX%s", basepath, suffix) == -1) { *path = NULL; return got_error_from_errno("asprintf"); } fd = mkstemps(*path, strlen(suffix)); if (fd == -1) { err = got_error_from_errno("mkstemp"); free(*path); *path = NULL; return err; } *outfd = fd; return err; } const struct got_error * got_opentemp_truncate(FILE *f) { if (fpurge(f) == EOF) return got_error_from_errno("fpurge"); if (ftruncate(fileno(f), 0L) == -1) return got_error_from_errno("ftruncate"); if (fseeko(f, 0L, SEEK_SET) == -1) return got_error_from_errno("fseeko"); return NULL; } const struct got_error * got_opentemp_truncatefd(int fd) { if (ftruncate(fd, 0L) == -1) return got_error_from_errno("ftruncate"); if (lseek(fd, 0L, SEEK_SET) == -1) return got_error_from_errno("lseek"); return NULL; } got-portable-0.101/lib/got_lib_diff.h0000644000175100017510000000450314644143163013133 /* * Copyright (c) 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "arraylist.h" #include "diff_main.h" #include "diff_output.h" enum got_diff_output_format { GOT_DIFF_OUTPUT_UNIDIFF, GOT_DIFF_OUTPUT_PLAIN, }; struct got_diffreg_result { struct diff_result *result; char *map1; size_t size1; char *map2; size_t size2; struct diff_data left; struct diff_data right; }; #define GOT_DIFF_CONFLICT_MARKER_BEGIN "<<<<<<<" #define GOT_DIFF_CONFLICT_MARKER_ORIG "|||||||" #define GOT_DIFF_CONFLICT_MARKER_SEP "=======" #define GOT_DIFF_CONFLICT_MARKER_END ">>>>>>>" const struct got_error *got_diff_get_config(struct diff_config **, enum got_diff_algorithm, diff_atomize_func_t, void *); const struct got_error *got_diff_prepare_file(FILE *, char **, size_t *, struct diff_data *, const struct diff_config *, int, int); const struct got_error *got_diffreg(struct got_diffreg_result **, FILE *, FILE *, enum got_diff_algorithm, int, int); const struct got_error *got_diffreg_output(struct got_diff_line **, size_t *, struct got_diffreg_result *, int, int, const char *, const char *, enum got_diff_output_format, int, FILE *); const struct got_error *got_diffreg_result_free(struct got_diffreg_result *); const struct got_error *got_diffreg_close(char *, size_t, char *, size_t); const struct got_error *got_merge_diff3(int *, int, FILE *, FILE *, FILE *, const char *, const char *, const char *, enum got_diff_algorithm); const struct got_error *got_diff_files(struct got_diffreg_result **, FILE *, int, const char *, FILE *, int, const char *, int, int, int, FILE *, enum got_diff_algorithm); got-portable-0.101/lib/object_idset.c0000664000175100017510000001516114644144735013167 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_object.h" #include "got_error.h" #include "got_lib_delta.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_qid.h" #include "got_lib_object_idset.h" #include "got_lib_object_parse.h" #define GOT_OBJECT_IDSET_MIN_BUCKETS 64 struct got_object_idset { struct got_object_id_queue *ids; size_t nbuckets; unsigned int totelem; unsigned int flags; #define GOT_OBJECT_IDSET_F_TRAVERSAL 0x01 #define GOT_OBJECT_IDSET_F_NOMEM 0x02 SIPHASH_KEY key; }; struct got_object_idset * got_object_idset_alloc(void) { struct got_object_idset *set; int i; set = malloc(sizeof(*set)); if (set == NULL) return NULL; set->ids = calloc(GOT_OBJECT_IDSET_MIN_BUCKETS, sizeof(set->ids[0])); if (set->ids == NULL) { free(set); return NULL; } for (i = 0; i < GOT_OBJECT_IDSET_MIN_BUCKETS; i++) STAILQ_INIT(&set->ids[i]); set->totelem = 0; set->nbuckets = GOT_OBJECT_IDSET_MIN_BUCKETS; set->flags = 0; arc4random_buf(&set->key, sizeof(set->key)); return set; } void got_object_idset_free(struct got_object_idset *set) { size_t i; struct got_object_qid *qid; for (i = 0; i < set->nbuckets; i++) { while (!STAILQ_EMPTY(&set->ids[i])) { qid = STAILQ_FIRST(&set->ids[i]); STAILQ_REMOVE(&set->ids[i], qid, got_object_qid, entry); got_object_qid_free(qid); } } /* User data should be freed by caller. */ free(set->ids); free(set); } static uint64_t idset_hash(struct got_object_idset *set, struct got_object_id *id) { return SipHash24(&set->key, id->sha1, sizeof(id->sha1)); } static const struct got_error * idset_resize(struct got_object_idset *set, size_t nbuckets) { struct got_object_id_queue *ids; size_t i; ids = calloc(nbuckets, sizeof(ids[0])); if (ids == NULL) { if (errno != ENOMEM) return got_error_from_errno("calloc"); /* Proceed with our current amount of hash buckets. */ set->flags |= GOT_OBJECT_IDSET_F_NOMEM; return NULL; } for (i = 0; i < nbuckets; i++) STAILQ_INIT(&ids[i]); arc4random_buf(&set->key, sizeof(set->key)); for (i = 0; i < set->nbuckets; i++) { while (!STAILQ_EMPTY(&set->ids[i])) { struct got_object_qid *qid; uint64_t idx; qid = STAILQ_FIRST(&set->ids[i]); STAILQ_REMOVE(&set->ids[i], qid, got_object_qid, entry); idx = idset_hash(set, &qid->id) % nbuckets; STAILQ_INSERT_HEAD(&ids[idx], qid, entry); } } free(set->ids); set->ids = ids; set->nbuckets = nbuckets; return NULL; } static const struct got_error * idset_grow(struct got_object_idset *set) { size_t nbuckets; if (set->flags & GOT_OBJECT_IDSET_F_NOMEM) return NULL; if (set->nbuckets >= UINT_MAX / 2) nbuckets = UINT_MAX; else nbuckets = set->nbuckets * 2; return idset_resize(set, nbuckets); } const struct got_error * got_object_idset_add(struct got_object_idset *set, struct got_object_id *id, void *data) { const struct got_error *err; struct got_object_qid *qid; uint64_t idx; struct got_object_id_queue *head; /* This function may resize the set. */ if (set->flags & GOT_OBJECT_IDSET_F_TRAVERSAL) return got_error_msg(GOT_ERR_NOT_IMPL, "cannot add elements to idset during traversal"); if (set->totelem == UINT_MAX) return got_error(GOT_ERR_NO_SPACE); err = got_object_qid_alloc_partial(&qid); if (err) return err; memcpy(&qid->id, id, sizeof(qid->id)); qid->data = data; idx = idset_hash(set, id) % set->nbuckets; head = &set->ids[idx]; STAILQ_INSERT_HEAD(head, qid, entry); set->totelem++; if (set->nbuckets < set->totelem) err = idset_grow(set); return err; } static struct got_object_qid * find_element(struct got_object_idset *set, struct got_object_id *id) { uint64_t idx = idset_hash(set, id) % set->nbuckets; struct got_object_id_queue *head = &set->ids[idx]; struct got_object_qid *qid; STAILQ_FOREACH(qid, head, entry) { if (got_object_id_cmp(&qid->id, id) == 0) return qid; } return NULL; } void * got_object_idset_get(struct got_object_idset *set, struct got_object_id *id) { struct got_object_qid *qid = find_element(set, id); return qid ? qid->data : NULL; } const struct got_error * got_object_idset_remove(void **data, struct got_object_idset *set, struct got_object_id *id) { uint64_t idx; struct got_object_id_queue *head; struct got_object_qid *qid; if (data) *data = NULL; if (set->totelem == 0) return got_error(GOT_ERR_NO_OBJ); if (id == NULL) { /* Remove a "random" element. */ for (idx = 0; idx < set->nbuckets; idx++) { head = &set->ids[idx]; qid = STAILQ_FIRST(head); if (qid) break; } } else { idx = idset_hash(set, id) % set->nbuckets; head = &set->ids[idx]; STAILQ_FOREACH(qid, head, entry) { if (got_object_id_cmp(&qid->id, id) == 0) break; } if (qid == NULL) return got_error_no_obj(id); } if (data) *data = qid->data; STAILQ_REMOVE(head, qid, got_object_qid, entry); got_object_qid_free(qid); set->totelem--; return NULL; } int got_object_idset_contains(struct got_object_idset *set, struct got_object_id *id) { struct got_object_qid *qid = find_element(set, id); return qid ? 1 : 0; } const struct got_error * got_object_idset_for_each(struct got_object_idset *set, const struct got_error *(*cb)(struct got_object_id *, void *, void *), void *arg) { const struct got_error *err = NULL; struct got_object_id_queue *head; struct got_object_qid *qid, *tmp; size_t i; set->flags |= GOT_OBJECT_IDSET_F_TRAVERSAL; for (i = 0; i < set->nbuckets; i++) { head = &set->ids[i]; STAILQ_FOREACH_SAFE(qid, head, entry, tmp) { err = (*cb)(&qid->id, qid->data, arg); if (err) goto done; } } done: set->flags &= ~GOT_OBJECT_IDSET_F_TRAVERSAL; return err; } int got_object_idset_num_elements(struct got_object_idset *set) { return set->totelem; } got-portable-0.101/lib/bloom.h0000644000175100017510000001334714644143163011642 /* * Copyright (c) 2012-2017, Jyri J. Virkki * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Obtained from https://github.com/jvirkki/libbloom */ #ifndef _BLOOM_H #define _BLOOM_H #ifdef __cplusplus extern "C" { #endif /** *************************************************************************** * Structure to keep track of one bloom filter. Caller needs to * allocate this and pass it to the functions below. First call for * every struct must be to bloom_init(). * */ struct bloom { // These fields are part of the public interface of this structure. // Client code may read these values if desired. Client code MUST NOT // modify any of these. int entries; double error; int bits; int bytes; int hashes; uint32_t seed; // Fields below are private to the implementation. These may go away or // change incompatibly at any moment. Client code MUST NOT access or rely // on these. double bpe; unsigned char * bf; int ready; }; /** *************************************************************************** * Initialize the bloom filter for use. * * The filter is initialized with a bit field and number of hash functions * according to the computations from the wikipedia entry: * http://en.wikipedia.org/wiki/Bloom_filter * * Optimal number of bits is: * bits = (entries * ln(error)) / ln(2)^2 * * Optimal number of hash functions is: * hashes = bpe * ln(2) * * Parameters: * ----------- * bloom - Pointer to an allocated struct bloom (see above). * entries - The expected number of entries which will be inserted. * Must be at least 1000 (in practice, likely much larger). * error - Probability of collision (as long as entries are not * exceeded). * * Return: * ------- * 0 - on success * 1 - on failure * */ int bloom_init(struct bloom * bloom, int entries, double error); /** *************************************************************************** * Deprecated, use bloom_init() * */ int bloom_init_size(struct bloom * bloom, int entries, double error, unsigned int cache_size); /** *************************************************************************** * Check if the given element is in the bloom filter. Remember this may * return false positive if a collision occurred. * * Parameters: * ----------- * bloom - Pointer to an allocated struct bloom (see above). * buffer - Pointer to buffer containing element to check. * len - Size of 'buffer'. * * Return: * ------- * 0 - element is not present * 1 - element is present (or false positive due to collision) * -1 - bloom not initialized * */ int bloom_check(struct bloom * bloom, const void * buffer, int len); /** *************************************************************************** * Add the given element to the bloom filter. * The return code indicates if the element (or a collision) was already in, * so for the common check+add use case, no need to call check separately. * * Parameters: * ----------- * bloom - Pointer to an allocated struct bloom (see above). * buffer - Pointer to buffer containing element to add. * len - Size of 'buffer'. * * Return: * ------- * 0 - element was not present and was added * 1 - element (or a collision) had already been added previously * -1 - bloom not initialized * */ int bloom_add(struct bloom * bloom, const void * buffer, int len); /** *************************************************************************** * Print (to stdout) info about this bloom filter. Debugging aid. * */ void bloom_print(struct bloom * bloom); /** *************************************************************************** * Deallocate internal storage. * * Upon return, the bloom struct is no longer usable. You may call bloom_init * again on the same struct to reinitialize it again. * * Parameters: * ----------- * bloom - Pointer to an allocated struct bloom (see above). * * Return: none * */ void bloom_free(struct bloom * bloom); /** *************************************************************************** * Erase internal storage. * * Erases all elements. Upon return, the bloom struct returns to its initial * (initialized) state. * * Parameters: * ----------- * bloom - Pointer to an allocated struct bloom (see above). * * Return: * 0 - on success * 1 - on failure * */ int bloom_reset(struct bloom * bloom); #ifdef __cplusplus } #endif #endif got-portable-0.101/lib/diff_output.h0000644000175100017510000001101314644143163013046 /* Diff output generators and invocation shims. */ /* * Copyright (c) 2020 Neels Hofmeyr * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct diff_input_info { const char *left_path; const char *right_path; /* Set by caller of diff_output_* functions. */ int flags; #define DIFF_INPUT_LEFT_NONEXISTENT 0x00000001 #define DIFF_INPUT_RIGHT_NONEXISTENT 0x00000002 }; struct diff_output_info { /* * Byte offset to each line in the generated output file. * The total number of lines in the file is line_offsets.len - 1. * The last offset in this array corresponds to end-of-file. */ ARRAYLIST(off_t) line_offsets; /* * Type (i.e., context, minus, plus) of each line generated by the diff. * nb. 0x00 to 0x3b reserved for client-defined line types. */ ARRAYLIST(uint8_t) line_types; #define DIFF_LINE_HUNK 0x3c #define DIFF_LINE_MINUS 0x3d #define DIFF_LINE_PLUS 0x3e #define DIFF_LINE_CONTEXT 0x3f #define DIFF_LINE_NONE 0x40 /* binary or no EOF newline msg, etc. */ }; void diff_output_info_free(struct diff_output_info *output_info); struct diff_chunk_context { struct diff_range chunk; struct diff_range left, right; }; int diff_output_plain(struct diff_output_info **output_info, FILE *dest, const struct diff_input_info *info, const struct diff_result *result, int hunk_headers_only); int diff_output_unidiff(struct diff_output_info **output_info, FILE *dest, const struct diff_input_info *info, const struct diff_result *result, unsigned int context_lines); int diff_output_edscript(struct diff_output_info **output_info, FILE *dest, const struct diff_input_info *info, const struct diff_result *result); int diff_chunk_get_left_start(const struct diff_chunk *c, const struct diff_result *r, int context_lines); int diff_chunk_get_left_end(const struct diff_chunk *c, const struct diff_result *r, int context_lines); int diff_chunk_get_right_start(const struct diff_chunk *c, const struct diff_result *r, int context_lines); int diff_chunk_get_right_end(const struct diff_chunk *c, const struct diff_result *r, int context_lines); off_t diff_chunk_get_left_start_pos(const struct diff_chunk *c); off_t diff_chunk_get_right_start_pos(const struct diff_chunk *c); struct diff_chunk *diff_chunk_get(const struct diff_result *r, int chunk_idx); int diff_chunk_get_left_count(struct diff_chunk *c); int diff_chunk_get_right_count(struct diff_chunk *c); void diff_chunk_context_get(struct diff_chunk_context *cc, const struct diff_result *r, int chunk_idx, int context_lines); void diff_chunk_context_load_change(struct diff_chunk_context *cc, int *nchunks_used, struct diff_result *result, int start_chunk_idx, int context_lines); struct diff_output_unidiff_state; struct diff_output_unidiff_state *diff_output_unidiff_state_alloc(void); void diff_output_unidiff_state_reset(struct diff_output_unidiff_state *state); void diff_output_unidiff_state_free(struct diff_output_unidiff_state *state); int diff_output_unidiff_chunk(struct diff_output_info **output_info, FILE *dest, struct diff_output_unidiff_state *state, const struct diff_input_info *info, const struct diff_result *result, const struct diff_chunk_context *cc); int diff_output_chunk_left_version(struct diff_output_info **output_info, FILE *dest, const struct diff_input_info *info, const struct diff_result *result, const struct diff_chunk_context *cc); int diff_output_chunk_right_version(struct diff_output_info **output_info, FILE *dest, const struct diff_input_info *info, const struct diff_result *result, const struct diff_chunk_context *cc); const char *diff_output_get_label_left(const struct diff_input_info *info); const char *diff_output_get_label_right(const struct diff_input_info *info); got-portable-0.101/lib/got_lib_deltify.h0000644000175100017510000000524514644143163013667 /* * Copyright (c) 2020 Ori Bernstein * Copyright (c) 2021 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct got_delta_block { off_t len; off_t offset; uint32_t hash; }; struct got_delta_table { struct got_delta_block *blocks; int nblocks; int nalloc; /* * Index for blocks. offs[n] is zero when the slot is free, * otherwise it points to blocks[offs[n] - 1]. */ uint32_t *offs; int len; int size; }; struct got_delta_instruction { int copy; off_t offset; off_t len; }; enum { GOT_DELTIFY_MINCHUNK = 32, GOT_DELTIFY_MAXCHUNK = 8192, GOT_DELTIFY_SPLITMASK = (1 << 8) - 1, }; const struct got_error *got_deltify_init(struct got_delta_table **dt, FILE *f, off_t fileoffset, off_t filesize, uint32_t seed); const struct got_error *got_deltify_init_mem(struct got_delta_table **dt, uint8_t *data, off_t fileoffset, off_t filesize, uint32_t seed); const struct got_error *got_deltify(struct got_delta_instruction **deltas, int *ndeltas, FILE *f, off_t fileoffset, off_t filesize, uint32_t seed, struct got_delta_table *dt, FILE *basefile, off_t basefile_offset0, off_t basefile_size); const struct got_error *got_deltify_file_mem( struct got_delta_instruction **deltas, int *ndeltas, FILE *f, off_t fileoffset, off_t filesize, uint32_t seed, struct got_delta_table *dt, uint8_t *basedata, off_t basefile_offset0, off_t basefile_size); const struct got_error *got_deltify_mem_file( struct got_delta_instruction **deltas, int *ndeltas, uint8_t *data, off_t fileoffset, off_t filesize, uint32_t seed, struct got_delta_table *dt, FILE *basefile, off_t basefile_offset0, off_t basefile_size); const struct got_error *got_deltify_mem_mem( struct got_delta_instruction **deltas, int *ndeltas, uint8_t *data, off_t fileoffset, off_t filesize, uint32_t seed, struct got_delta_table *dt, uint8_t *basedata, off_t basefile_offset0, off_t basefile_size); void got_deltify_free(struct got_delta_table *dt); got-portable-0.101/lib/diff_debug.h0000644000175100017510000001255614644143163012611 /* * Copyright (c) 2020 Neels Hofmeyr * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #define DEBUG 0 #if DEBUG #include #include #define print(args...) fprintf(stderr, ##args) #define debug print #define debug_dump dump #define debug_dump_atom dump_atom #define debug_dump_atoms dump_atoms static inline void print_atom_byte(unsigned char c) { if (c == '\r') print("\\r"); else if (c == '\n') print("\\n"); else if ((c < 32 || c >= 127) && (c != '\t')) print("\\x%02x", c); else print("%c", c); } static inline void dump_atom(const struct diff_data *left, const struct diff_data *right, const struct diff_atom *atom) { if (!atom) { print("NULL atom\n"); return; } if (left) print(" %3u '", diff_atom_root_idx(left, atom)); if (atom->at == NULL) { off_t remain = atom->len; if (fseek(atom->root->f, atom->pos, SEEK_SET) == -1) abort(); /* cannot return error */ while (remain > 0) { char buf[16]; size_t r; int i; r = fread(buf, 1, MIN(remain, sizeof(buf)), atom->root->f); if (r == 0) break; remain -= r; for (i = 0; i < r; i++) print_atom_byte(buf[i]); } } else { const char *s; for (s = atom->at; s < (const char*)(atom->at + atom->len); s++) print_atom_byte(*s); } print("'\n"); } static inline void dump_atoms(const struct diff_data *d, struct diff_atom *atom, unsigned int count) { if (count > 42) { dump_atoms(d, atom, 20); print("[%u lines skipped]\n", count - 20 - 20); dump_atoms(d, atom + count - 20, 20); return; } else { struct diff_atom *i; foreach_diff_atom(i, atom, count) { dump_atom(d, NULL, i); } } } static inline void dump(struct diff_data *d) { dump_atoms(d, d->atoms.head, d->atoms.len); } /* kd is a quadratic space myers matrix from the original Myers algorithm. * kd_forward and kd_backward are linear slices of a myers matrix from the Myers * Divide algorithm. */ static inline void dump_myers_graph(const struct diff_data *l, const struct diff_data *r, int *kd, int *kd_forward, int kd_forward_d, int *kd_backward, int kd_backward_d) { #define COLOR_YELLOW "\033[1;33m" #define COLOR_GREEN "\033[1;32m" #define COLOR_BLUE "\033[1;34m" #define COLOR_RED "\033[1;31m" #define COLOR_END "\033[0;m" int x; int y; print(" "); for (x = 0; x <= l->atoms.len; x++) print("%2d", x % 100); print("\n"); for (y = 0; y <= r->atoms.len; y++) { print("%3d ", y); for (x = 0; x <= l->atoms.len; x++) { /* print d advancements from kd, if any. */ char label = 'o'; char *color = NULL; if (kd) { int max = l->atoms.len + r->atoms.len; size_t kd_len = max + 1 + max; int *kd_pos = kd; int di; #define xk_to_y(X, K) ((X) - (K)) for (di = 0; di < max; di++) { int ki; for (ki = di; ki >= -di; ki -= 2) { if (x != kd_pos[ki] || y != xk_to_y(x, ki)) continue; label = '0' + (di % 10); color = COLOR_YELLOW; break; } if (label != 'o') break; kd_pos += kd_len; } } if (kd_forward && kd_forward_d >= 0) { #define xc_to_y(X, C, DELTA) ((X) - (C) + (DELTA)) int ki; for (ki = kd_forward_d; ki >= -kd_forward_d; ki -= 2) { if (x != kd_forward[ki]) continue; if (y != xk_to_y(x, ki)) continue; label = 'F'; color = COLOR_GREEN; break; } } if (kd_backward && kd_backward_d >= 0) { int delta = (int)r->atoms.len - (int)l->atoms.len; int ki; for (ki = kd_backward_d; ki >= -kd_backward_d; ki -= 2) { if (x != kd_backward[ki]) continue; if (y != xc_to_y(x, ki, delta)) continue; if (label == 'o') { label = 'B'; color = COLOR_BLUE; } else { label = 'X'; color = COLOR_RED; } break; } } if (color) print("%s", color); print("%c", label); if (color) print("%s", COLOR_END); if (x < l->atoms.len) print("-"); } print("\n"); if (y == r->atoms.len) break; print(" "); for (x = 0; x < l->atoms.len; x++) { bool same; diff_atom_same(&same, &l->atoms.head[x], &r->atoms.head[y]); if (same) print("|\\"); else print("| "); } print("|\n"); } } static inline void debug_dump_myers_graph(const struct diff_data *l, const struct diff_data *r, int *kd, int *kd_forward, int kd_forward_d, int *kd_backward, int kd_backward_d) { if (l->atoms.len > 99 || r->atoms.len > 99) return; dump_myers_graph(l, r, kd, kd_forward, kd_forward_d, kd_backward, kd_backward_d); } #else #define debug(args...) #define debug_dump(args...) #define debug_dump_atom(args...) #define debug_dump_atoms(args...) #define debug_dump_myers_graph(args...) #endif got-portable-0.101/lib/pack_create.c0000664000175100017510000014073114644144735012774 /* * Copyright (c) 2020 Ori Bernstein * Copyright (c) 2021 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_cancel.h" #include "got_object.h" #include "got_path.h" #include "got_reference.h" #include "got_repository_admin.h" #include "got_lib_deltify.h" #include "got_lib_delta.h" #include "got_lib_hash.h" #include "got_lib_object.h" #include "got_lib_object_idset.h" #include "got_lib_object_cache.h" #include "got_lib_deflate.h" #include "got_lib_ratelimit.h" #include "got_lib_pack.h" #include "got_lib_pack_create.h" #include "got_lib_repository.h" #include "got_lib_inflate.h" #include "got_lib_poll.h" #include "murmurhash2.h" #ifndef MIN #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) #endif #ifndef MAX #define MAX(_a,_b) ((_a) > (_b) ? (_a) : (_b)) #endif #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif static const struct got_error * alloc_meta(struct got_pack_meta **new, struct got_object_id *id, const char *path, int obj_type, time_t mtime, uint32_t seed) { struct got_pack_meta *m; *new = NULL; m = calloc(1, sizeof(*m)); if (m == NULL) return got_error_from_errno("calloc"); memcpy(&m->id, id, sizeof(m->id)); m->path_hash = murmurhash2(path, strlen(path), seed); m->obj_type = obj_type; m->mtime = mtime; *new = m; return NULL; } static void clear_meta(struct got_pack_meta *meta) { if (meta == NULL) return; meta->path_hash = 0; free(meta->delta_buf); meta->delta_buf = NULL; free(meta->base_obj_id); meta->base_obj_id = NULL; meta->reused_delta_offset = 0; } static void free_nmeta(struct got_pack_meta **meta, int nmeta) { int i; for (i = 0; i < nmeta; i++) clear_meta(meta[i]); free(meta); } static int delta_order_cmp(const void *pa, const void *pb) { struct got_pack_meta *a, *b; a = *(struct got_pack_meta **)pa; b = *(struct got_pack_meta **)pb; if (a->obj_type != b->obj_type) return a->obj_type - b->obj_type; if (a->path_hash < b->path_hash) return -1; if (a->path_hash > b->path_hash) return 1; if (a->mtime < b->mtime) return -1; if (a->mtime > b->mtime) return 1; return got_object_id_cmp(&a->id, &b->id); } static off_t delta_size(struct got_delta_instruction *deltas, int ndeltas) { int i; off_t size = 32; for (i = 0; i < ndeltas; i++) { if (deltas[i].copy) size += GOT_DELTA_SIZE_SHIFT; else size += deltas[i].len + 1; } return size; } static const struct got_error * append(unsigned char **p, size_t *len, off_t *sz, void *seg, int nseg) { char *n; if (*len + nseg >= *sz) { while (*len + nseg >= *sz) *sz += *sz / 2; n = realloc(*p, *sz); if (n == NULL) return got_error_from_errno("realloc"); *p = n; } memcpy(*p + *len, seg, nseg); *len += nseg; return NULL; } static const struct got_error * encode_delta_in_mem(struct got_pack_meta *m, struct got_raw_object *o, struct got_delta_instruction *deltas, int ndeltas, off_t delta_size, off_t base_size) { const struct got_error *err; unsigned char buf[16], *bp; int i, j; size_t len = 0, compressed_len; off_t bufsize = delta_size; off_t n; struct got_delta_instruction *d; uint8_t *delta_buf; delta_buf = malloc(bufsize); if (delta_buf == NULL) return got_error_from_errno("malloc"); /* base object size */ buf[0] = base_size & GOT_DELTA_SIZE_VAL_MASK; n = base_size >> GOT_DELTA_SIZE_SHIFT; for (i = 1; n > 0; i++) { buf[i - 1] |= GOT_DELTA_SIZE_MORE; buf[i] = n & GOT_DELTA_SIZE_VAL_MASK; n >>= GOT_DELTA_SIZE_SHIFT; } err = append(&delta_buf, &len, &bufsize, buf, i); if (err) goto done; /* target object size */ buf[0] = o->size & GOT_DELTA_SIZE_VAL_MASK; n = o->size >> GOT_DELTA_SIZE_SHIFT; for (i = 1; n > 0; i++) { buf[i - 1] |= GOT_DELTA_SIZE_MORE; buf[i] = n & GOT_DELTA_SIZE_VAL_MASK; n >>= GOT_DELTA_SIZE_SHIFT; } err = append(&delta_buf, &len, &bufsize, buf, i); if (err) goto done; for (j = 0; j < ndeltas; j++) { d = &deltas[j]; if (d->copy) { n = d->offset; bp = &buf[1]; buf[0] = GOT_DELTA_BASE_COPY; for (i = 0; i < 4; i++) { /* DELTA_COPY_OFF1 ... DELTA_COPY_OFF4 */ buf[0] |= 1 << i; *bp++ = n & 0xff; n >>= 8; if (n == 0) break; } n = d->len; if (n != GOT_DELTA_COPY_DEFAULT_LEN) { /* DELTA_COPY_LEN1 ... DELTA_COPY_LEN3 */ for (i = 0; i < 3 && n > 0; i++) { buf[0] |= 1 << (i + 4); *bp++ = n & 0xff; n >>= 8; } } err = append(&delta_buf, &len, &bufsize, buf, bp - buf); if (err) goto done; } else if (o->f == NULL) { n = 0; while (n != d->len) { buf[0] = (d->len - n < 127) ? d->len - n : 127; err = append(&delta_buf, &len, &bufsize, buf, 1); if (err) goto done; err = append(&delta_buf, &len, &bufsize, o->data + o->hdrlen + d->offset + n, buf[0]); if (err) goto done; n += buf[0]; } } else { char content[128]; size_t r; if (fseeko(o->f, o->hdrlen + d->offset, SEEK_SET) == -1) { err = got_error_from_errno("fseeko"); goto done; } n = 0; while (n != d->len) { buf[0] = (d->len - n < 127) ? d->len - n : 127; err = append(&delta_buf, &len, &bufsize, buf, 1); if (err) goto done; r = fread(content, 1, buf[0], o->f); if (r != buf[0]) { err = got_ferror(o->f, GOT_ERR_IO); goto done; } err = append(&delta_buf, &len, &bufsize, content, buf[0]); if (err) goto done; n += buf[0]; } } } err = got_deflate_to_mem_mmap(&m->delta_buf, &compressed_len, NULL, NULL, delta_buf, 0, len); if (err) goto done; m->delta_len = len; m->delta_compressed_len = compressed_len; done: free(delta_buf); return err; } static const struct got_error * encode_delta(struct got_pack_meta *m, struct got_raw_object *o, struct got_delta_instruction *deltas, int ndeltas, off_t base_size, FILE *f) { const struct got_error *err; unsigned char buf[16], *bp; int i, j; off_t n; struct got_deflate_buf zb; struct got_delta_instruction *d; off_t delta_len = 0, compressed_len = 0; err = got_deflate_init(&zb, NULL, GOT_DEFLATE_BUFSIZE); if (err) return err; /* base object size */ buf[0] = base_size & GOT_DELTA_SIZE_VAL_MASK; n = base_size >> GOT_DELTA_SIZE_SHIFT; for (i = 1; n > 0; i++) { buf[i - 1] |= GOT_DELTA_SIZE_MORE; buf[i] = n & GOT_DELTA_SIZE_VAL_MASK; n >>= GOT_DELTA_SIZE_SHIFT; } err = got_deflate_append_to_file_mmap(&zb, &compressed_len, buf, 0, i, f, NULL); if (err) goto done; delta_len += i; /* target object size */ buf[0] = o->size & GOT_DELTA_SIZE_VAL_MASK; n = o->size >> GOT_DELTA_SIZE_SHIFT; for (i = 1; n > 0; i++) { buf[i - 1] |= GOT_DELTA_SIZE_MORE; buf[i] = n & GOT_DELTA_SIZE_VAL_MASK; n >>= GOT_DELTA_SIZE_SHIFT; } err = got_deflate_append_to_file_mmap(&zb, &compressed_len, buf, 0, i, f, NULL); if (err) goto done; delta_len += i; for (j = 0; j < ndeltas; j++) { d = &deltas[j]; if (d->copy) { n = d->offset; bp = &buf[1]; buf[0] = GOT_DELTA_BASE_COPY; for (i = 0; i < 4; i++) { /* DELTA_COPY_OFF1 ... DELTA_COPY_OFF4 */ buf[0] |= 1 << i; *bp++ = n & 0xff; n >>= 8; if (n == 0) break; } n = d->len; if (n != GOT_DELTA_COPY_DEFAULT_LEN) { /* DELTA_COPY_LEN1 ... DELTA_COPY_LEN3 */ for (i = 0; i < 3 && n > 0; i++) { buf[0] |= 1 << (i + 4); *bp++ = n & 0xff; n >>= 8; } } err = got_deflate_append_to_file_mmap(&zb, &compressed_len, buf, 0, bp - buf, f, NULL); if (err) goto done; delta_len += (bp - buf); } else if (o->f == NULL) { n = 0; while (n != d->len) { buf[0] = (d->len - n < 127) ? d->len - n : 127; err = got_deflate_append_to_file_mmap(&zb, &compressed_len, buf, 0, 1, f, NULL); if (err) goto done; delta_len++; err = got_deflate_append_to_file_mmap(&zb, &compressed_len, o->data + o->hdrlen + d->offset + n, 0, buf[0], f, NULL); if (err) goto done; delta_len += buf[0]; n += buf[0]; } } else { char content[128]; size_t r; if (fseeko(o->f, o->hdrlen + d->offset, SEEK_SET) == -1) { err = got_error_from_errno("fseeko"); goto done; } n = 0; while (n != d->len) { buf[0] = (d->len - n < 127) ? d->len - n : 127; err = got_deflate_append_to_file_mmap(&zb, &compressed_len, buf, 0, 1, f, NULL); if (err) goto done; delta_len++; r = fread(content, 1, buf[0], o->f); if (r != buf[0]) { err = got_ferror(o->f, GOT_ERR_IO); goto done; } err = got_deflate_append_to_file_mmap(&zb, &compressed_len, content, 0, buf[0], f, NULL); if (err) goto done; delta_len += buf[0]; n += buf[0]; } } } err = got_deflate_flush(&zb, f, NULL, &compressed_len); if (err) goto done; /* sanity check */ if (compressed_len != ftello(f) - m->delta_offset) { err = got_error(GOT_ERR_COMPRESSION); goto done; } m->delta_len = delta_len; m->delta_compressed_len = compressed_len; done: got_deflate_end(&zb); return err; } const struct got_error * got_pack_report_progress(got_pack_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl, int ncolored, int nfound, int ntrees, off_t packfile_size, int ncommits, int nobj_total, int obj_deltify, int nobj_written) { const struct got_error *err; int elapsed; if (progress_cb == NULL) return NULL; err = got_ratelimit_check(&elapsed, rl); if (err || !elapsed) return err; return progress_cb(progress_arg, ncolored, nfound, ntrees, packfile_size, ncommits, nobj_total, obj_deltify, nobj_written); } const struct got_error * got_pack_add_meta(struct got_pack_meta *m, struct got_pack_metavec *v) { if (v->nmeta == v->metasz){ size_t newsize = 2 * v->metasz; struct got_pack_meta **new; new = reallocarray(v->meta, newsize, sizeof(*new)); if (new == NULL) return got_error_from_errno("reallocarray"); v->meta = new; v->metasz = newsize; } v->meta[v->nmeta++] = m; return NULL; } const struct got_error * got_pack_find_pack_for_reuse(struct got_packidx **best_packidx, struct got_repository *repo) { const struct got_error *err = NULL; struct got_pathlist_entry *pe; const char *best_packidx_path = NULL; int nobj_max = 0; *best_packidx = NULL; TAILQ_FOREACH(pe, &repo->packidx_paths, entry) { const char *path_packidx = pe->path; struct got_packidx *packidx; int nobj; err = got_repo_get_packidx(&packidx, path_packidx, repo); if (err) break; nobj = be32toh(packidx->hdr.fanout_table[0xff]); if (nobj > nobj_max) { best_packidx_path = path_packidx; nobj_max = nobj; } } if (best_packidx_path) { err = got_repo_get_packidx(best_packidx, best_packidx_path, repo); } return err; } const struct got_error * got_pack_cache_pack_for_packidx(struct got_pack **pack, struct got_packidx *packidx, struct got_repository *repo) { const struct got_error *err; char *path_packfile = NULL; err = got_packidx_get_packfile_path(&path_packfile, packidx->path_packidx); if (err) return err; *pack = got_repo_get_cached_pack(repo, path_packfile); if (*pack == NULL) { err = got_repo_cache_pack(pack, repo, path_packfile, packidx); if (err) goto done; } done: free(path_packfile); return err; } static const struct got_error * pick_deltas(struct got_pack_meta **meta, int nmeta, int ncolored, int nfound, int ntrees, int ncommits, int nreused, FILE *delta_cache, struct got_repository *repo, got_pack_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; struct got_pack_meta *m = NULL, *base = NULL; struct got_raw_object *raw = NULL, *base_raw = NULL; struct got_delta_instruction *deltas = NULL, *best_deltas = NULL; int i, j, ndeltas, best_ndeltas; off_t size, best_size; const int max_base_candidates = 3; size_t delta_memsize = 0; const size_t max_delta_memsize = 4 * GOT_DELTA_RESULT_SIZE_CACHED_MAX; int outfd = -1; uint32_t delta_seed; delta_seed = arc4random(); qsort(meta, nmeta, sizeof(struct got_pack_meta *), delta_order_cmp); for (i = 0; i < nmeta; i++) { if (cancel_cb) { err = (*cancel_cb)(cancel_arg); if (err) break; } err = got_pack_report_progress(progress_cb, progress_arg, rl, ncolored, nfound, ntrees, 0L, ncommits, nreused + nmeta, nreused + i, 0); if (err) goto done; m = meta[i]; if (m->obj_type == GOT_OBJ_TYPE_COMMIT || m->obj_type == GOT_OBJ_TYPE_TAG) continue; err = got_object_raw_open(&raw, &outfd, repo, &m->id); if (err) goto done; m->size = raw->size; if (raw->f == NULL) { err = got_deltify_init_mem(&m->dtab, raw->data, raw->hdrlen, raw->size + raw->hdrlen, delta_seed); } else { err = got_deltify_init(&m->dtab, raw->f, raw->hdrlen, raw->size + raw->hdrlen, delta_seed); } if (err) goto done; if (i > max_base_candidates) { struct got_pack_meta *n = NULL; n = meta[i - (max_base_candidates + 1)]; got_deltify_free(n->dtab); n->dtab = NULL; } best_size = raw->size; best_ndeltas = 0; for (j = MAX(0, i - max_base_candidates); j < i; j++) { if (cancel_cb) { err = (*cancel_cb)(cancel_arg); if (err) goto done; } base = meta[j]; /* long chains make unpacking slow, avoid such bases */ if (base->nchain >= 128 || base->obj_type != m->obj_type) continue; err = got_object_raw_open(&base_raw, &outfd, repo, &base->id); if (err) goto done; if (raw->f == NULL && base_raw->f == NULL) { err = got_deltify_mem_mem(&deltas, &ndeltas, raw->data, raw->hdrlen, raw->size + raw->hdrlen, delta_seed, base->dtab, base_raw->data, base_raw->hdrlen, base_raw->size + base_raw->hdrlen); } else if (raw->f == NULL) { err = got_deltify_mem_file(&deltas, &ndeltas, raw->data, raw->hdrlen, raw->size + raw->hdrlen, delta_seed, base->dtab, base_raw->f, base_raw->hdrlen, base_raw->size + base_raw->hdrlen); } else if (base_raw->f == NULL) { err = got_deltify_file_mem(&deltas, &ndeltas, raw->f, raw->hdrlen, raw->size + raw->hdrlen, delta_seed, base->dtab, base_raw->data, base_raw->hdrlen, base_raw->size + base_raw->hdrlen); } else { err = got_deltify(&deltas, &ndeltas, raw->f, raw->hdrlen, raw->size + raw->hdrlen, delta_seed, base->dtab, base_raw->f, base_raw->hdrlen, base_raw->size + base_raw->hdrlen); } got_object_raw_close(base_raw); base_raw = NULL; if (err) goto done; size = delta_size(deltas, ndeltas); if (size + 32 < best_size){ /* * if we already picked a best delta, * replace it. */ best_size = size; free(best_deltas); best_deltas = deltas; best_ndeltas = ndeltas; deltas = NULL; m->nchain = base->nchain + 1; m->prev = base; m->head = base->head; if (m->head == NULL) m->head = base; } else { free(deltas); deltas = NULL; ndeltas = 0; } } if (best_ndeltas > 0) { if (best_size <= GOT_DELTA_RESULT_SIZE_CACHED_MAX && delta_memsize + best_size <= max_delta_memsize) { delta_memsize += best_size; err = encode_delta_in_mem(m, raw, best_deltas, best_ndeltas, best_size, m->prev->size); } else { m->delta_offset = ftello(delta_cache); err = encode_delta(m, raw, best_deltas, best_ndeltas, m->prev->size, delta_cache); } free(best_deltas); best_deltas = NULL; best_ndeltas = 0; if (err) goto done; } got_object_raw_close(raw); raw = NULL; } done: for (i = MAX(0, nmeta - max_base_candidates); i < nmeta; i++) { got_deltify_free(meta[i]->dtab); meta[i]->dtab = NULL; } if (raw) got_object_raw_close(raw); if (base_raw) got_object_raw_close(base_raw); if (outfd != -1 && close(outfd) == -1 && err == NULL) err = got_error_from_errno("close"); free(deltas); free(best_deltas); return err; } static const struct got_error * search_packidx(int *found, struct got_object_id *id, struct got_repository *repo) { const struct got_error *err = NULL; struct got_packidx *packidx = NULL; int idx; *found = 0; err = got_repo_search_packidx(&packidx, &idx, repo, id); if (err == NULL) *found = 1; /* object is already packed */ else if (err->code == GOT_ERR_NO_OBJ) err = NULL; return err; } const struct got_error * got_pack_add_object(int want_meta, struct got_object_idset *idset, struct got_object_id *id, const char *path, int obj_type, time_t mtime, uint32_t seed, int loose_obj_only, struct got_repository *repo, int *ncolored, int *nfound, int *ntrees, got_pack_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl) { const struct got_error *err; struct got_pack_meta *m = NULL; if (loose_obj_only) { int is_packed; err = search_packidx(&is_packed, id, repo); if (err) return err; if (is_packed && want_meta) return NULL; } if (want_meta) { err = alloc_meta(&m, id, path, obj_type, mtime, seed); if (err) return err; (*nfound)++; err = got_pack_report_progress(progress_cb, progress_arg, rl, *ncolored, *nfound, *ntrees, 0L, 0, 0, 0, 0); if (err) { clear_meta(m); free(m); return err; } } err = got_object_idset_add(idset, id, m); if (err) { clear_meta(m); free(m); } return err; } const struct got_error * got_pack_load_tree_entries(struct got_object_id_queue *ids, int want_meta, struct got_object_idset *idset, struct got_object_idset *idset_exclude, struct got_tree_object *tree, const char *dpath, time_t mtime, uint32_t seed, struct got_repository *repo, int loose_obj_only, int *ncolored, int *nfound, int *ntrees, got_pack_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err; char *p = NULL; int i; (*ntrees)++; err = got_pack_report_progress(progress_cb, progress_arg, rl, *ncolored, *nfound, *ntrees, 0L, 0, 0, 0, 0); if (err) return err; for (i = 0; i < got_object_tree_get_nentries(tree); i++) { struct got_tree_entry *e = got_object_tree_get_entry(tree, i); struct got_object_id *id = got_tree_entry_get_id(e); mode_t mode = got_tree_entry_get_mode(e); if (cancel_cb) { err = (*cancel_cb)(cancel_arg); if (err) break; } if (got_object_tree_entry_is_submodule(e) || got_object_idset_contains(idset, id) || got_object_idset_contains(idset_exclude, id)) continue; /* * If got-read-pack is crawling trees for us then * we are only here to collect blob IDs. */ if (ids == NULL && S_ISDIR(mode)) continue; if (asprintf(&p, "%s%s%s", dpath, got_path_is_root_dir(dpath) ? "" : "/", got_tree_entry_get_name(e)) == -1) { err = got_error_from_errno("asprintf"); break; } if (S_ISDIR(mode)) { struct got_object_qid *qid; err = got_object_qid_alloc(&qid, id); if (err) break; qid->data = p; p = NULL; STAILQ_INSERT_TAIL(ids, qid, entry); } else if (S_ISREG(mode) || S_ISLNK(mode)) { err = got_pack_add_object(want_meta, want_meta ? idset : idset_exclude, id, p, GOT_OBJ_TYPE_BLOB, mtime, seed, loose_obj_only, repo, ncolored, nfound, ntrees, progress_cb, progress_arg, rl); if (err) break; free(p); p = NULL; } else { free(p); p = NULL; } } free(p); return err; } const struct got_error * got_pack_load_tree(int want_meta, struct got_object_idset *idset, struct got_object_idset *idset_exclude, struct got_object_id *tree_id, const char *dpath, time_t mtime, uint32_t seed, struct got_repository *repo, int loose_obj_only, int *ncolored, int *nfound, int *ntrees, got_pack_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; struct got_object_id_queue tree_ids; struct got_object_qid *qid; struct got_tree_object *tree = NULL; if (got_object_idset_contains(idset, tree_id) || got_object_idset_contains(idset_exclude, tree_id)) return NULL; err = got_object_qid_alloc(&qid, tree_id); if (err) return err; qid->data = strdup(dpath); if (qid->data == NULL) { err = got_error_from_errno("strdup"); got_object_qid_free(qid); return err; } STAILQ_INIT(&tree_ids); STAILQ_INSERT_TAIL(&tree_ids, qid, entry); while (!STAILQ_EMPTY(&tree_ids)) { const char *path; if (cancel_cb) { err = (*cancel_cb)(cancel_arg); if (err) break; } qid = STAILQ_FIRST(&tree_ids); STAILQ_REMOVE_HEAD(&tree_ids, entry); path = qid->data; if (got_object_idset_contains(idset, &qid->id) || got_object_idset_contains(idset_exclude, &qid->id)) { free(qid->data); got_object_qid_free(qid); continue; } err = got_pack_add_object(want_meta, want_meta ? idset : idset_exclude, &qid->id, path, GOT_OBJ_TYPE_TREE, mtime, seed, loose_obj_only, repo, ncolored, nfound, ntrees, progress_cb, progress_arg, rl); if (err) { free(qid->data); got_object_qid_free(qid); break; } err = got_object_open_as_tree(&tree, repo, &qid->id); if (err) { free(qid->data); got_object_qid_free(qid); break; } err = got_pack_load_tree_entries(&tree_ids, want_meta, idset, idset_exclude, tree, path, mtime, seed, repo, loose_obj_only, ncolored, nfound, ntrees, progress_cb, progress_arg, rl, cancel_cb, cancel_arg); free(qid->data); got_object_qid_free(qid); if (err) break; got_object_tree_close(tree); tree = NULL; } STAILQ_FOREACH(qid, &tree_ids, entry) free(qid->data); got_object_id_queue_free(&tree_ids); if (tree) got_object_tree_close(tree); return err; } static const struct got_error * load_commit(int want_meta, struct got_object_idset *idset, struct got_object_idset *idset_exclude, struct got_object_id *id, struct got_repository *repo, uint32_t seed, int loose_obj_only, int *ncolored, int *nfound, int *ntrees, got_pack_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err; struct got_commit_object *commit; if (got_object_idset_contains(idset, id) || got_object_idset_contains(idset_exclude, id)) return NULL; if (loose_obj_only) { int is_packed; err = search_packidx(&is_packed, id, repo); if (err) return err; if (is_packed && want_meta) return NULL; } err = got_object_open_as_commit(&commit, repo, id); if (err) return err; err = got_pack_add_object(want_meta, want_meta ? idset : idset_exclude, id, "", GOT_OBJ_TYPE_COMMIT, got_object_commit_get_committer_time(commit), seed, loose_obj_only, repo, ncolored, nfound, ntrees, progress_cb, progress_arg, rl); if (err) goto done; err = got_pack_load_tree(want_meta, idset, idset_exclude, got_object_commit_get_tree_id(commit), "", got_object_commit_get_committer_time(commit), seed, repo, loose_obj_only, ncolored, nfound, ntrees, progress_cb, progress_arg, rl, cancel_cb, cancel_arg); done: got_object_commit_close(commit); return err; } static const struct got_error * load_tag(int want_meta, struct got_object_idset *idset, struct got_object_idset *idset_exclude, struct got_object_id *id, struct got_repository *repo, uint32_t seed, int loose_obj_only, int *ncolored, int *nfound, int *ntrees, got_pack_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err; struct got_tag_object *tag = NULL; if (got_object_idset_contains(idset, id) || got_object_idset_contains(idset_exclude, id)) return NULL; if (loose_obj_only) { int is_packed; err = search_packidx(&is_packed, id, repo); if (err) return err; if (is_packed && want_meta) return NULL; } err = got_object_open_as_tag(&tag, repo, id); if (err) return err; err = got_pack_add_object(want_meta, want_meta ? idset : idset_exclude, id, "", GOT_OBJ_TYPE_TAG, got_object_tag_get_tagger_time(tag), seed, loose_obj_only, repo, ncolored, nfound, ntrees, progress_cb, progress_arg, rl); if (err) goto done; switch (got_object_tag_get_object_type(tag)) { case GOT_OBJ_TYPE_COMMIT: err = load_commit(want_meta, idset, idset_exclude, got_object_tag_get_object_id(tag), repo, seed, loose_obj_only, ncolored, nfound, ntrees, progress_cb, progress_arg, rl, cancel_cb, cancel_arg); break; case GOT_OBJ_TYPE_TREE: err = got_pack_load_tree(want_meta, idset, idset_exclude, got_object_tag_get_object_id(tag), "", got_object_tag_get_tagger_time(tag), seed, repo, loose_obj_only, ncolored, nfound, ntrees, progress_cb, progress_arg, rl, cancel_cb, cancel_arg); break; default: break; } done: got_object_tag_close(tag); return err; } const struct got_error * got_pack_paint_commit(struct got_object_qid *qid, intptr_t color) { if (color < 0 || color >= COLOR_MAX) return got_error(GOT_ERR_RANGE); qid->data = (void *)color; return NULL; } const struct got_error * got_pack_queue_commit_id(struct got_object_id_queue *ids, struct got_object_id *id, intptr_t color, struct got_repository *repo) { const struct got_error *err; struct got_object_qid *qid; err = got_object_qid_alloc(&qid, id); if (err) return err; STAILQ_INSERT_TAIL(ids, qid, entry); return got_pack_paint_commit(qid, color); } struct append_id_arg { struct got_object_id **array; int idx; struct got_object_idset *drop; struct got_object_idset *skip; }; static const struct got_error * append_id(struct got_object_id *id, void *data, void *arg) { struct append_id_arg *a = arg; if (got_object_idset_contains(a->skip, id) || got_object_idset_contains(a->drop, id)) return NULL; a->array[++a->idx] = got_object_id_dup(id); if (a->array[a->idx] == NULL) return got_error_from_errno("got_object_id_dup"); return NULL; } static const struct got_error * queue_commit_or_tag_id(struct got_object_id *id, intptr_t color, struct got_object_id_queue *ids, struct got_repository *repo) { const struct got_error *err; struct got_tag_object *tag = NULL; int obj_type; err = got_object_get_type(&obj_type, repo, id); if (err) return err; if (obj_type == GOT_OBJ_TYPE_TAG) { err = got_object_open_as_tag(&tag, repo, id); if (err) return err; obj_type = got_object_tag_get_object_type(tag); id = got_object_tag_get_object_id(tag); } if (obj_type == GOT_OBJ_TYPE_COMMIT) { err = got_pack_queue_commit_id(ids, id, color, repo); if (err) goto done; } done: if (tag) got_object_tag_close(tag); return err; } const struct got_error * got_pack_find_pack_for_commit_painting(struct got_packidx **best_packidx, struct got_object_id_queue *ids, int nids, struct got_repository *repo) { const struct got_error *err = NULL; struct got_pathlist_entry *pe; const char *best_packidx_path = NULL; int nobj_max = 0; int ncommits_max = 0; *best_packidx = NULL; /* * Find the largest pack which contains at least some of the * commits we are interested in. */ TAILQ_FOREACH(pe, &repo->packidx_paths, entry) { const char *path_packidx = pe->path; struct got_packidx *packidx; int nobj, idx, ncommits = 0; struct got_object_qid *qid; err = got_repo_get_packidx(&packidx, path_packidx, repo); if (err) break; nobj = be32toh(packidx->hdr.fanout_table[0xff]); if (nobj <= nobj_max) continue; STAILQ_FOREACH(qid, ids, entry) { idx = got_packidx_get_object_idx(packidx, &qid->id); if (idx != -1) ncommits++; } if (ncommits > ncommits_max) { best_packidx_path = path_packidx; nobj_max = nobj; ncommits_max = ncommits; } } if (best_packidx_path && err == NULL) { err = got_repo_get_packidx(best_packidx, best_packidx_path, repo); } return err; } static const struct got_error * findtwixt(struct got_object_id ***res, int *nres, int *ncolored, struct got_object_id **head, int nhead, struct got_object_id **tail, int ntail, struct got_repository *repo, got_pack_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; struct got_object_id_queue ids; struct got_object_idset *keep, *drop, *skip = NULL; int i, nkeep; STAILQ_INIT(&ids); *res = NULL; *nres = 0; *ncolored = 0; keep = got_object_idset_alloc(); if (keep == NULL) return got_error_from_errno("got_object_idset_alloc"); drop = got_object_idset_alloc(); if (drop == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } skip = got_object_idset_alloc(); if (skip == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } for (i = 0; i < nhead; i++) { struct got_object_id *id = head[i]; if (id == NULL) continue; err = queue_commit_or_tag_id(id, COLOR_KEEP, &ids, repo); if (err) goto done; } for (i = 0; i < ntail; i++) { struct got_object_id *id = tail[i]; if (id == NULL) continue; err = queue_commit_or_tag_id(id, COLOR_DROP, &ids, repo); if (err) goto done; } err = got_pack_paint_commits(ncolored, &ids, nhead + ntail, keep, drop, skip, repo, progress_cb, progress_arg, rl, cancel_cb, cancel_arg); if (err) goto done; nkeep = got_object_idset_num_elements(keep); if (nkeep > 0) { struct append_id_arg arg; arg.array = calloc(nkeep, sizeof(struct got_object_id *)); if (arg.array == NULL) { err = got_error_from_errno("calloc"); goto done; } arg.idx = -1; arg.skip = skip; arg.drop = drop; err = got_object_idset_for_each(keep, append_id, &arg); if (err) { free(arg.array); goto done; } *res = arg.array; *nres = arg.idx + 1; } done: got_object_idset_free(keep); got_object_idset_free(drop); if (skip) got_object_idset_free(skip); got_object_id_queue_free(&ids); return err; } static const struct got_error * find_pack_for_enumeration(struct got_packidx **best_packidx, struct got_object_id **ids, int nids, struct got_repository *repo) { const struct got_error *err = NULL; struct got_pathlist_entry *pe; const char *best_packidx_path = NULL; int nobj_max = 0; int ncommits_max = 0; *best_packidx = NULL; /* * Find the largest pack which contains at least some of the * commits and tags we are interested in. */ TAILQ_FOREACH(pe, &repo->packidx_paths, entry) { const char *path_packidx = pe->path; struct got_packidx *packidx; int nobj, i, idx, ncommits = 0; err = got_repo_get_packidx(&packidx, path_packidx, repo); if (err) break; nobj = be32toh(packidx->hdr.fanout_table[0xff]); if (nobj <= nobj_max) continue; for (i = 0; i < nids; i++) { idx = got_packidx_get_object_idx(packidx, ids[i]); if (idx != -1) ncommits++; } if (ncommits > ncommits_max) { best_packidx_path = path_packidx; nobj_max = nobj; ncommits_max = ncommits; } } if (best_packidx_path && err == NULL) { err = got_repo_get_packidx(best_packidx, best_packidx_path, repo); } return err; } static const struct got_error * load_object_ids(int *ncolored, int *nfound, int *ntrees, struct got_object_idset *idset, struct got_object_id **theirs, int ntheirs, struct got_object_id **ours, int nours, struct got_repository *repo, uint32_t seed, int loose_obj_only, got_pack_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; struct got_object_id **ids = NULL; struct got_packidx *packidx = NULL; int i, nobj = 0, obj_type, found_all_objects = 0; struct got_object_idset *idset_exclude; idset_exclude = got_object_idset_alloc(); if (idset_exclude == NULL) return got_error_from_errno("got_object_idset_alloc"); *ncolored = 0; *nfound = 0; *ntrees = 0; err = findtwixt(&ids, &nobj, ncolored, ours, nours, theirs, ntheirs, repo, progress_cb, progress_arg, rl, cancel_cb, cancel_arg); if (err) goto done; err = find_pack_for_enumeration(&packidx, theirs, ntheirs, repo); if (err) goto done; if (packidx) { err = got_pack_load_packed_object_ids(&found_all_objects, theirs, ntheirs, NULL, 0, 0, seed, idset, idset_exclude, loose_obj_only, repo, packidx, ncolored, nfound, ntrees, progress_cb, progress_arg, rl, cancel_cb, cancel_arg); if (err) goto done; } for (i = 0; i < ntheirs; i++) { struct got_object_id *id = theirs[i]; if (id == NULL) continue; err = got_object_get_type(&obj_type, repo, id); if (err) return err; if (obj_type == GOT_OBJ_TYPE_COMMIT) { if (!found_all_objects) { err = load_commit(0, idset, idset_exclude, id, repo, seed, loose_obj_only, ncolored, nfound, ntrees, progress_cb, progress_arg, rl, cancel_cb, cancel_arg); if (err) goto done; } } else if (obj_type == GOT_OBJ_TYPE_TAG) { err = load_tag(0, idset, idset_exclude, id, repo, seed, loose_obj_only, ncolored, nfound, ntrees, progress_cb, progress_arg, rl, cancel_cb, cancel_arg); if (err) goto done; } } found_all_objects = 0; err = find_pack_for_enumeration(&packidx, ids, nobj, repo); if (err) goto done; if (packidx) { err = got_pack_load_packed_object_ids(&found_all_objects, ids, nobj, theirs, ntheirs, 1, seed, idset, idset_exclude, loose_obj_only, repo, packidx, ncolored, nfound, ntrees, progress_cb, progress_arg, rl, cancel_cb, cancel_arg); if (err) goto done; } if (!found_all_objects) { for (i = 0; i < nobj; i++) { err = load_commit(1, idset, idset_exclude, ids[i], repo, seed, loose_obj_only, ncolored, nfound, ntrees, progress_cb, progress_arg, rl, cancel_cb, cancel_arg); if (err) goto done; } } for (i = 0; i < nours; i++) { struct got_object_id *id = ours[i]; struct got_pack_meta *m; if (id == NULL) continue; m = got_object_idset_get(idset, id); if (m == NULL) { err = got_object_get_type(&obj_type, repo, id); if (err) goto done; } else obj_type = m->obj_type; if (obj_type != GOT_OBJ_TYPE_TAG) continue; err = load_tag(1, idset, idset_exclude, id, repo, seed, loose_obj_only, ncolored, nfound, ntrees, progress_cb, progress_arg, rl, cancel_cb, cancel_arg); if (err) goto done; } done: for (i = 0; i < nobj; i++) { free(ids[i]); } free(ids); got_object_idset_free(idset_exclude); return err; } static const struct got_error * hwrite(int fd, const void *buf, off_t len, struct got_hash *ctx) { got_hash_update(ctx, buf, len); return got_poll_write_full(fd, buf, len); } static const struct got_error * hcopy(FILE *fsrc, int fd_dst, off_t len, struct got_hash *ctx) { const struct got_error *err; unsigned char buf[65536]; off_t remain = len; size_t n; while (remain > 0) { size_t copylen = MIN(sizeof(buf), remain); n = fread(buf, 1, copylen, fsrc); if (n != copylen) return got_ferror(fsrc, GOT_ERR_IO); got_hash_update(ctx, buf, copylen); err = got_poll_write_full(fd_dst, buf, copylen); if (err) return err; remain -= copylen; } return NULL; } static const struct got_error * hcopy_mmap(uint8_t *src, off_t src_offset, size_t src_size, int fd, off_t len, struct got_hash *ctx) { if (src_offset + len > src_size) return got_error(GOT_ERR_RANGE); got_hash_update(ctx, src + src_offset, len); return got_poll_write_full(fd, src + src_offset, len); } static void putbe32(char *b, uint32_t n) { b[0] = n >> 24; b[1] = n >> 16; b[2] = n >> 8; b[3] = n >> 0; } static int write_order_cmp(const void *pa, const void *pb) { struct got_pack_meta *a, *b, *ahd, *bhd; a = *(struct got_pack_meta **)pa; b = *(struct got_pack_meta **)pb; ahd = (a->head == NULL) ? a : a->head; bhd = (b->head == NULL) ? b : b->head; if (bhd->mtime < ahd->mtime) return -1; if (bhd->mtime > ahd->mtime) return 1; if (bhd < ahd) return -1; if (bhd > ahd) return 1; if (a->nchain != b->nchain) return a->nchain - b->nchain; if (a->mtime < b->mtime) return -1; if (a->mtime > b->mtime) return 1; return got_object_id_cmp(&a->id, &b->id); } static int reuse_write_order_cmp(const void *pa, const void *pb) { struct got_pack_meta *a, *b; a = *(struct got_pack_meta **)pa; b = *(struct got_pack_meta **)pb; if (a->reused_delta_offset < b->reused_delta_offset) return -1; if (a->reused_delta_offset > b->reused_delta_offset) return 1; return 0; } static const struct got_error * packhdr(int *hdrlen, char *hdr, size_t bufsize, int obj_type, size_t len) { size_t i; *hdrlen = 0; hdr[0] = obj_type << 4; hdr[0] |= len & 0xf; len >>= 4; for (i = 1; len != 0; i++){ if (i >= bufsize) return got_error(GOT_ERR_NO_SPACE); hdr[i - 1] |= GOT_DELTA_SIZE_MORE; hdr[i] = len & GOT_DELTA_SIZE_VAL_MASK; len >>= GOT_DELTA_SIZE_SHIFT; } *hdrlen = i; return NULL; } static int packoff(char *hdr, off_t off) { int i, j; char rbuf[8]; rbuf[0] = off & GOT_DELTA_SIZE_VAL_MASK; for (i = 1; (off >>= GOT_DELTA_SIZE_SHIFT) != 0; i++) { rbuf[i] = (--off & GOT_DELTA_SIZE_VAL_MASK) | GOT_DELTA_SIZE_MORE; } j = 0; while (i > 0) hdr[j++] = rbuf[--i]; return j; } static const struct got_error * deltahdr(off_t *packfile_size, struct got_hash *ctx, int packfd, int force_refdelta, struct got_pack_meta *m) { const struct got_error *err; char buf[32]; int nh; if (m->prev->off != 0 && !force_refdelta) { err = packhdr(&nh, buf, sizeof(buf), GOT_OBJ_TYPE_OFFSET_DELTA, m->delta_len); if (err) return err; nh += packoff(buf + nh, m->off - m->prev->off); err = hwrite(packfd, buf, nh, ctx); if (err) return err; *packfile_size += nh; } else { err = packhdr(&nh, buf, sizeof(buf), GOT_OBJ_TYPE_REF_DELTA, m->delta_len); if (err) return err; err = hwrite(packfd, buf, nh, ctx); if (err) return err; *packfile_size += nh; err = hwrite(packfd, m->prev->id.sha1, sizeof(m->prev->id.sha1), ctx); if (err) return err; *packfile_size += sizeof(m->prev->id.sha1); } return NULL; } static const struct got_error * write_packed_object(off_t *packfile_size, int packfd, FILE *delta_cache, uint8_t *delta_cache_map, size_t delta_cache_size, struct got_pack_meta *m, int *outfd, struct got_hash *ctx, struct got_repository *repo, int force_refdelta) { const struct got_error *err = NULL; struct got_deflate_checksum csum; char buf[32]; int nh; struct got_raw_object *raw = NULL; off_t outlen, delta_offset; memset(&csum, 0, sizeof(csum)); csum.output_ctx = ctx; if (m->reused_delta_offset) delta_offset = m->reused_delta_offset; else delta_offset = m->delta_offset; m->off = *packfile_size; if (m->delta_len == 0) { err = got_object_raw_open(&raw, outfd, repo, &m->id); if (err) goto done; err = packhdr(&nh, buf, sizeof(buf), m->obj_type, raw->size); if (err) goto done; err = hwrite(packfd, buf, nh, ctx); if (err) goto done; *packfile_size += nh; if (raw->f == NULL) { err = got_deflate_to_fd_mmap(&outlen, raw->data + raw->hdrlen, 0, raw->size, packfd, &csum); if (err) goto done; } else { if (fseeko(raw->f, raw->hdrlen, SEEK_SET) == -1) { err = got_error_from_errno("fseeko"); goto done; } err = got_deflate_to_fd(&outlen, raw->f, raw->size, packfd, &csum); if (err) goto done; } *packfile_size += outlen; got_object_raw_close(raw); raw = NULL; } else if (m->delta_buf) { err = deltahdr(packfile_size, ctx, packfd, force_refdelta, m); if (err) goto done; err = hwrite(packfd, m->delta_buf, m->delta_compressed_len, ctx); if (err) goto done; *packfile_size += m->delta_compressed_len; free(m->delta_buf); m->delta_buf = NULL; } else if (delta_cache_map) { err = deltahdr(packfile_size, ctx, packfd, force_refdelta, m); if (err) goto done; err = hcopy_mmap(delta_cache_map, delta_offset, delta_cache_size, packfd, m->delta_compressed_len, ctx); if (err) goto done; *packfile_size += m->delta_compressed_len; } else { if (fseeko(delta_cache, delta_offset, SEEK_SET) == -1) { err = got_error_from_errno("fseeko"); goto done; } err = deltahdr(packfile_size, ctx, packfd, force_refdelta, m); if (err) goto done; err = hcopy(delta_cache, packfd, m->delta_compressed_len, ctx); if (err) goto done; *packfile_size += m->delta_compressed_len; } done: if (raw) got_object_raw_close(raw); return err; } static const struct got_error * genpack(uint8_t *pack_sha1, int packfd, struct got_pack *reuse_pack, FILE *delta_cache, struct got_pack_meta **deltify, int ndeltify, struct got_pack_meta **reuse, int nreuse, int ncolored, int nfound, int ntrees, int nours, struct got_repository *repo, int force_refdelta, got_pack_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; int i; struct got_hash ctx; struct got_pack_meta *m; char buf[32]; off_t packfile_size = 0; int outfd = -1; int delta_cache_fd = -1; uint8_t *delta_cache_map = NULL; size_t delta_cache_size = 0; FILE *packfile = NULL; got_hash_init(&ctx, GOT_HASH_SHA1); #ifndef GOT_PACK_NO_MMAP delta_cache_fd = dup(fileno(delta_cache)); if (delta_cache_fd != -1) { struct stat sb; if (fstat(delta_cache_fd, &sb) == -1) { err = got_error_from_errno("fstat"); goto done; } if (sb.st_size > 0 && sb.st_size <= SIZE_MAX) { delta_cache_map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, delta_cache_fd, 0); if (delta_cache_map == MAP_FAILED) { if (errno != ENOMEM) { err = got_error_from_errno("mmap"); goto done; } delta_cache_map = NULL; /* fallback on stdio */ } else delta_cache_size = (size_t)sb.st_size; } } #endif err = hwrite(packfd, "PACK", 4, &ctx); if (err) goto done; putbe32(buf, GOT_PACKFILE_VERSION); err = hwrite(packfd, buf, 4, &ctx); if (err) goto done; putbe32(buf, ndeltify + nreuse); err = hwrite(packfd, buf, 4, &ctx); if (err) goto done; qsort(deltify, ndeltify, sizeof(struct got_pack_meta *), write_order_cmp); for (i = 0; i < ndeltify; i++) { err = got_pack_report_progress(progress_cb, progress_arg, rl, ncolored, nfound, ntrees, packfile_size, nours, ndeltify + nreuse, ndeltify + nreuse, i); if (err) goto done; m = deltify[i]; err = write_packed_object(&packfile_size, packfd, delta_cache, delta_cache_map, delta_cache_size, m, &outfd, &ctx, repo, force_refdelta); if (err) goto done; } qsort(reuse, nreuse, sizeof(struct got_pack_meta *), reuse_write_order_cmp); if (nreuse > 0 && reuse_pack->map == NULL) { int fd = dup(reuse_pack->fd); if (fd == -1) { err = got_error_from_errno("dup"); goto done; } packfile = fdopen(fd, "r"); if (packfile == NULL) { err = got_error_from_errno("fdopen"); close(fd); goto done; } } for (i = 0; i < nreuse; i++) { err = got_pack_report_progress(progress_cb, progress_arg, rl, ncolored, nfound, ntrees, packfile_size, nours, ndeltify + nreuse, ndeltify + nreuse, ndeltify + i); if (err) goto done; m = reuse[i]; err = write_packed_object(&packfile_size, packfd, packfile, reuse_pack->map, reuse_pack->filesize, m, &outfd, &ctx, repo, force_refdelta); if (err) goto done; } got_hash_final(&ctx, pack_sha1); err = got_poll_write_full(packfd, pack_sha1, SHA1_DIGEST_LENGTH); if (err) goto done; packfile_size += SHA1_DIGEST_LENGTH; packfile_size += sizeof(struct got_packfile_hdr); if (progress_cb) { err = progress_cb(progress_arg, ncolored, nfound, ntrees, packfile_size, nours, ndeltify + nreuse, ndeltify + nreuse, ndeltify + nreuse); if (err) goto done; } done: if (outfd != -1 && close(outfd) == -1 && err == NULL) err = got_error_from_errno("close"); if (delta_cache_map && munmap(delta_cache_map, delta_cache_size) == -1) err = got_error_from_errno("munmap"); if (delta_cache_fd != -1 && close(delta_cache_fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (packfile && fclose(packfile) == EOF && err == NULL) err = got_error_from_errno("fclose"); return err; } static const struct got_error * add_meta_idset_cb(struct got_object_id *id, void *data, void *arg) { struct got_pack_meta *m = data; struct got_pack_metavec *v = arg; if (m->reused_delta_offset != 0) return NULL; return got_pack_add_meta(m, v); } const struct got_error * got_pack_create(uint8_t *packsha1, int packfd, FILE *delta_cache, struct got_object_id **theirs, int ntheirs, struct got_object_id **ours, int nours, struct got_repository *repo, int loose_obj_only, int allow_empty, int force_refdelta, got_pack_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err; struct got_object_idset *idset; struct got_packidx *reuse_packidx = NULL; struct got_pack *reuse_pack = NULL; struct got_pack_metavec deltify, reuse; int ncolored = 0, nfound = 0, ntrees = 0; size_t ndeltify; uint32_t seed; seed = arc4random(); memset(&deltify, 0, sizeof(deltify)); memset(&reuse, 0, sizeof(reuse)); idset = got_object_idset_alloc(); if (idset == NULL) return got_error_from_errno("got_object_idset_alloc"); err = load_object_ids(&ncolored, &nfound, &ntrees, idset, theirs, ntheirs, ours, nours, repo, seed, loose_obj_only, progress_cb, progress_arg, rl, cancel_cb, cancel_arg); if (err) goto done; if (progress_cb) { err = progress_cb(progress_arg, ncolored, nfound, ntrees, 0L, nours, got_object_idset_num_elements(idset), 0, 0); if (err) goto done; } if (got_object_idset_num_elements(idset) == 0 && !allow_empty) { err = got_error(GOT_ERR_CANNOT_PACK); goto done; } reuse.metasz = 64; reuse.meta = calloc(reuse.metasz, sizeof(struct got_pack_meta *)); if (reuse.meta == NULL) { err = got_error_from_errno("calloc"); goto done; } err = got_pack_search_deltas(&reuse_packidx, &reuse_pack, &reuse, idset, ncolored, nfound, ntrees, nours, repo, progress_cb, progress_arg, rl, cancel_cb, cancel_arg); if (err) goto done; if (reuse_packidx && reuse_pack) { err = got_repo_pin_pack(repo, reuse_packidx, reuse_pack); if (err) goto done; } if (fseeko(delta_cache, 0L, SEEK_END) == -1) { err = got_error_from_errno("fseeko"); goto done; } ndeltify = got_object_idset_num_elements(idset) - reuse.nmeta; if (ndeltify > 0) { deltify.meta = calloc(ndeltify, sizeof(struct got_pack_meta *)); if (deltify.meta == NULL) { err = got_error_from_errno("calloc"); goto done; } deltify.metasz = ndeltify; err = got_object_idset_for_each(idset, add_meta_idset_cb, &deltify); if (err) goto done; if (deltify.nmeta > 0) { err = pick_deltas(deltify.meta, deltify.nmeta, ncolored, nfound, ntrees, nours, reuse.nmeta, delta_cache, repo, progress_cb, progress_arg, rl, cancel_cb, cancel_arg); if (err) goto done; } } if (fflush(delta_cache) == EOF) { err = got_error_from_errno("fflush"); goto done; } if (progress_cb) { /* * Report a 1-byte packfile write to indicate we are about * to start sending packfile data. gotd(8) needs this. */ err = progress_cb(progress_arg, ncolored, nfound, ntrees, 1 /* packfile_size */, nours, got_object_idset_num_elements(idset), deltify.nmeta + reuse.nmeta, 0); if (err) goto done; } /* Pinned pack may have moved to different cache slot. */ reuse_pack = got_repo_get_pinned_pack(repo); err = genpack(packsha1, packfd, reuse_pack, delta_cache, deltify.meta, deltify.nmeta, reuse.meta, reuse.nmeta, ncolored, nfound, ntrees, nours, repo, force_refdelta, progress_cb, progress_arg, rl, cancel_cb, cancel_arg); if (err) goto done; done: free_nmeta(deltify.meta, deltify.nmeta); free_nmeta(reuse.meta, reuse.nmeta); got_object_idset_free(idset); got_repo_unpin_pack(repo); return err; } got-portable-0.101/lib/diffreg.c0000664000175100017510000002230514644144735012135 /* * Copyright (c) 2020 Neels Hofmeyr * Copyright (c) 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include "got_object.h" #include "got_opentemp.h" #include "got_error.h" #include "got_diff.h" #include "got_lib_diff.h" const struct diff_algo_config myers_then_patience; const struct diff_algo_config myers_then_myers_divide; const struct diff_algo_config patience; const struct diff_algo_config myers_divide; const struct diff_algo_config myers_then_patience = { .impl = diff_algo_myers, .permitted_state_size = 1024 * 1024 * sizeof(int), .fallback_algo = &patience, }; const struct diff_algo_config myers_then_myers_divide = { .impl = diff_algo_myers, .permitted_state_size = 1024 * 1024 * sizeof(int), .fallback_algo = &myers_divide, }; const struct diff_algo_config patience = { .impl = diff_algo_patience, /* After subdivision, do Patience again: */ .inner_algo = &patience, /* If subdivision failed, do Myers Divide et Impera: */ .fallback_algo = &myers_then_myers_divide, }; const struct diff_algo_config myers_divide = { .impl = diff_algo_myers_divide, /* When division succeeded, start from the top: */ .inner_algo = &myers_then_myers_divide, /* (fallback_algo = NULL implies diff_algo_none). */ }; /* If the state for a forward-Myers is small enough, use Myers, otherwise first * do a Myers-divide. */ const struct diff_config diff_config_myers_then_myers_divide = { .atomize_func = diff_atomize_text_by_line, .algo = &myers_then_myers_divide, }; /* If the state for a forward-Myers is small enough, use Myers, otherwise first * do a Patience. */ const struct diff_config diff_config_myers_then_patience = { .atomize_func = diff_atomize_text_by_line, .algo = &myers_then_patience, }; /* Directly force Patience as a first divider of the source file. */ const struct diff_config diff_config_patience = { .atomize_func = diff_atomize_text_by_line, .algo = &patience, }; /* Directly force Patience as a first divider of the source file. */ const struct diff_config diff_config_no_algo = { .atomize_func = diff_atomize_text_by_line, }; const struct got_error * got_diffreg_close(char *p1, size_t size1, char *p2, size_t size2) { const struct got_error *err = NULL; if (p1 && munmap(p1, size1) == -1 && err == NULL) err = got_error_from_errno("munmap"); if (p2 && munmap(p2, size2) == -1 && err == NULL) err = got_error_from_errno("munmap"); return err; } const struct got_error * got_diff_get_config(struct diff_config **cfg, enum got_diff_algorithm algorithm, diff_atomize_func_t atomize_func, void *atomize_func_data) { *cfg = calloc(1, sizeof(**cfg)); if (*cfg == NULL) return got_error_from_errno("calloc"); switch (algorithm) { case GOT_DIFF_ALGORITHM_PATIENCE: (*cfg)->algo = &patience; break; case GOT_DIFF_ALGORITHM_MYERS: (*cfg)->algo = &myers_then_myers_divide; break; default: return got_error_msg(GOT_ERR_NOT_IMPL, "bad diff algorithm"); } if (atomize_func) { (*cfg)->atomize_func = atomize_func; (*cfg)->atomize_func_data = atomize_func_data; } else (*cfg)->atomize_func = diff_atomize_text_by_line; (*cfg)->max_recursion_depth = 0; /* use default recursion depth */ return NULL; } const struct got_error * got_diff_prepare_file(FILE *f, char **p, size_t *size, struct diff_data *diff_data, const struct diff_config *cfg, int ignore_whitespace, int force_text_diff) { const struct got_error *err = NULL; struct stat st; int diff_flags = 0, rc; *size = 0; diff_flags |= DIFF_FLAG_SHOW_PROTOTYPES; if (ignore_whitespace) diff_flags |= DIFF_FLAG_IGNORE_WHITESPACE; if (force_text_diff) diff_flags |= DIFF_FLAG_FORCE_TEXT_DATA; if (fstat(fileno(f), &st) == -1) { err = got_error_from_errno("fstat"); goto done; } #ifndef GOT_DIFF_NO_MMAP *p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fileno(f), 0); if (*p == MAP_FAILED) #endif *p = NULL; /* fall back on file I/O */ rc = diff_atomize_file(diff_data, cfg, f, *p, st.st_size, diff_flags); if (rc) { err = got_error_set_errno(rc, "diff_atomize_file"); goto done; } done: if (err) diff_data_free(diff_data); else *size = st.st_size; return err; } const struct got_error * got_diffreg(struct got_diffreg_result **diffreg_result, FILE *f1, FILE *f2, enum got_diff_algorithm algorithm, int ignore_whitespace, int force_text_diff) { const struct got_error *err = NULL; struct diff_config *cfg = NULL; char *p1 = NULL, *p2 = NULL; size_t size1, size2; struct diff_data d_left, d_right; struct diff_data *left, *right; struct diff_result *diff_result; if (diffreg_result) { *diffreg_result = calloc(1, sizeof(**diffreg_result)); if (*diffreg_result == NULL) return got_error_from_errno("calloc"); left = &(*diffreg_result)->left; right = &(*diffreg_result)->right; } else { memset(&d_left, 0, sizeof(d_left)); memset(&d_right, 0, sizeof(d_right)); left = &d_left; right = &d_right; } err = got_diff_get_config(&cfg, algorithm, NULL, NULL); if (err) goto done; err = got_diff_prepare_file(f1, &p1, &size1, left, cfg, ignore_whitespace, force_text_diff); if (err) goto done; err = got_diff_prepare_file(f2, &p2, &size2, right, cfg, ignore_whitespace, force_text_diff); if (err) goto done; diff_result = diff_main(cfg, left, right); if (diff_result == NULL) { err = got_error_set_errno(ENOMEM, "malloc"); goto done; } if (diff_result->rc != DIFF_RC_OK) { err = got_error_set_errno(diff_result->rc, "diff"); goto done; } if (diffreg_result) { (*diffreg_result)->result = diff_result; (*diffreg_result)->map1 = p1; (*diffreg_result)->size1 = size1; (*diffreg_result)->map2 = p2; (*diffreg_result)->size2 = size2; } done: free(cfg); if (diffreg_result == NULL) { diff_data_free(left); diff_data_free(right); } if (err) { got_diffreg_close(p1, size1, p2, size2); if (diffreg_result) { diff_data_free(left); diff_data_free(right); free(*diffreg_result); *diffreg_result = NULL; } } return err; } const struct got_error * got_diffreg_output(struct got_diff_line **lines, size_t *nlines, struct got_diffreg_result *diff_result, int f1_exists, int f2_exists, const char *path1, const char *path2, enum got_diff_output_format output_format, int context_lines, FILE *outfile) { struct diff_input_info info = { .left_path = path1, .right_path = path2, .flags = 0, }; int rc; struct diff_output_info *output_info; if (!f1_exists) info.flags |= DIFF_INPUT_LEFT_NONEXISTENT; if (!f2_exists) info.flags |= DIFF_INPUT_RIGHT_NONEXISTENT; switch (output_format) { case GOT_DIFF_OUTPUT_UNIDIFF: rc = diff_output_unidiff( lines && *lines ? &output_info : NULL, outfile, &info, diff_result->result, context_lines); if (rc != DIFF_RC_OK) return got_error_set_errno(rc, "diff_output_unidiff"); break; case GOT_DIFF_OUTPUT_PLAIN: rc = diff_output_plain(lines && *lines ? &output_info : NULL, outfile, &info, diff_result->result, 1); if (rc != DIFF_RC_OK) return got_error_set_errno(rc, "diff_output_edscript"); break; } if (lines && *lines) { if (output_info->line_offsets.len > 0) { struct got_diff_line *p; off_t prev_offset = 0, *o; uint8_t *o2; int i, len; if (*nlines > 0) { prev_offset = (*lines)[*nlines - 1].offset; /* * First line offset is always zero. Skip it * when appending to a pre-populated array. */ o = &output_info->line_offsets.head[1]; o2 = &output_info->line_types.head[1]; len = output_info->line_offsets.len - 1; } else { o = &output_info->line_offsets.head[0]; o2 = &output_info->line_types.head[0]; len = output_info->line_offsets.len; } p = reallocarray(*lines, *nlines + len, sizeof(**lines)); if (p == NULL) return got_error_from_errno("calloc"); for (i = 0; i < len; i++) { p[*nlines + i].offset = o[i] + prev_offset; p[*nlines + i].type = o2[i]; } *lines = p; *nlines += len; } diff_output_info_free(output_info); } return NULL; } const struct got_error * got_diffreg_result_free(struct got_diffreg_result *diffreg_result) { const struct got_error *err; if (diffreg_result == NULL) return NULL; diff_result_free(diffreg_result->result); diff_data_free(&diffreg_result->left); diff_data_free(&diffreg_result->right); err = got_diffreg_close(diffreg_result->map1, diffreg_result->size1, diffreg_result->map2, diffreg_result->size2); free(diffreg_result); return err; } got-portable-0.101/lib/read_gitconfig_privsep.c0000664000175100017510000001216214644144735015243 /* * Copyright (c) 2019, 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_repository.h" #include "got_path.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_object_cache.h" #include "got_lib_privsep.h" #include "got_lib_pack.h" #include "got_lib_repository.h" const struct got_error * got_repo_read_gitconfig(int *gitconfig_repository_format_version, char **gitconfig_author_name, char **gitconfig_author_email, struct got_remote_repo **remotes, int *nremotes, char **gitconfig_owner, char ***extnames, char ***extvals, int *nextensions, const char *gitconfig_path) { const struct got_error *err = NULL, *child_err = NULL; int fd = -1; int imsg_fds[2] = { -1, -1 }; pid_t pid; struct imsgbuf *ibuf; *gitconfig_repository_format_version = 0; if (extnames) *extnames = NULL; if (extvals) *extvals = NULL; if (nextensions) *nextensions = 0; *gitconfig_author_name = NULL; *gitconfig_author_email = NULL; if (remotes) *remotes = NULL; if (nremotes) *nremotes = 0; if (gitconfig_owner) *gitconfig_owner = NULL; fd = open(gitconfig_path, O_RDONLY | O_CLOEXEC); if (fd == -1) { if (errno == ENOENT) return NULL; return got_error_from_errno2("open", gitconfig_path); } ibuf = calloc(1, sizeof(*ibuf)); if (ibuf == NULL) { err = got_error_from_errno("calloc"); goto done; } if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) { err = got_error_from_errno("socketpair"); goto done; } pid = fork(); if (pid == -1) { err = got_error_from_errno("fork"); goto done; } else if (pid == 0) { got_privsep_exec_child(imsg_fds, GOT_PATH_PROG_READ_GITCONFIG, gitconfig_path); /* not reached */ } if (close(imsg_fds[1]) == -1) { err = got_error_from_errno("close"); goto done; } imsg_fds[1] = -1; imsg_init(ibuf, imsg_fds[0]); err = got_privsep_send_gitconfig_parse_req(ibuf, fd); if (err) goto done; fd = -1; err = got_privsep_send_gitconfig_repository_format_version_req(ibuf); if (err) goto done; err = got_privsep_recv_gitconfig_int( gitconfig_repository_format_version, ibuf); if (err) goto done; if (extnames && extvals && nextensions) { err = got_privsep_send_gitconfig_repository_extensions_req( ibuf); if (err) goto done; err = got_privsep_recv_gitconfig_int(nextensions, ibuf); if (err) goto done; if (*nextensions > 0) { int i; *extnames = calloc(*nextensions, sizeof(char *)); if (*extnames == NULL) { err = got_error_from_errno("calloc"); goto done; } *extvals = calloc(*nextensions, sizeof(char *)); if (*extvals == NULL) { err = got_error_from_errno("calloc"); goto done; } for (i = 0; i < *nextensions; i++) { char *ext, *val; err = got_privsep_recv_gitconfig_pair(&ext, &val, ibuf); if (err) goto done; (*extnames)[i] = ext; (*extvals)[i] = val; } } } err = got_privsep_send_gitconfig_author_name_req(ibuf); if (err) goto done; err = got_privsep_recv_gitconfig_str(gitconfig_author_name, ibuf); if (err) goto done; err = got_privsep_send_gitconfig_author_email_req(ibuf); if (err) goto done; err = got_privsep_recv_gitconfig_str(gitconfig_author_email, ibuf); if (err) goto done; if (remotes && nremotes) { err = got_privsep_send_gitconfig_remotes_req(ibuf); if (err) goto done; err = got_privsep_recv_gitconfig_remotes(remotes, nremotes, ibuf); if (err) goto done; } if (gitconfig_owner) { err = got_privsep_send_gitconfig_owner_req(ibuf); if (err) goto done; err = got_privsep_recv_gitconfig_str(gitconfig_owner, ibuf); if (err) goto done; } err = got_privsep_send_stop(imsg_fds[0]); child_err = got_privsep_wait_for_child(pid); if (child_err && err == NULL) err = child_err; done: if (imsg_fds[0] != -1 && close(imsg_fds[0]) == -1 && err == NULL) err = got_error_from_errno("close"); if (imsg_fds[1] != -1 && close(imsg_fds[1]) == -1 && err == NULL) err = got_error_from_errno("close"); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno2("close", gitconfig_path); free(ibuf); return err; } got-portable-0.101/lib/deflate.c0000664000175100017510000002561614644144735012143 /* * Copyright (c) 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_lib_deflate.h" #include "got_lib_hash.h" #include "got_lib_poll.h" #ifndef MIN #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) #endif static const struct got_error * wrap_deflate_error(int zerr, const char *prefix) { if (zerr == Z_ERRNO) return got_error_from_errno(prefix); if (zerr == Z_MEM_ERROR) return got_error_set_errno(ENOMEM, prefix); return got_error(GOT_ERR_COMPRESSION); } const struct got_error * got_deflate_init(struct got_deflate_buf *zb, uint8_t *outbuf, size_t bufsize) { const struct got_error *err = NULL; int zerr; memset(zb, 0, sizeof(*zb)); zb->z.zalloc = Z_NULL; zb->z.zfree = Z_NULL; zerr = deflateInit(&zb->z, Z_DEFAULT_COMPRESSION); if (zerr != Z_OK) return wrap_deflate_error(zerr, "deflateInit"); zb->inlen = zb->outlen = bufsize; zb->inbuf = calloc(1, zb->inlen); if (zb->inbuf == NULL) { err = got_error_from_errno("calloc"); goto done; } zb->flags = 0; if (outbuf == NULL) { zb->outbuf = calloc(1, zb->outlen); if (zb->outbuf == NULL) { err = got_error_from_errno("calloc"); goto done; } zb->flags |= GOT_DEFLATE_F_OWN_OUTBUF; } else zb->outbuf = outbuf; done: if (err) got_deflate_end(zb); return err; } static void csum_output(struct got_deflate_checksum *csum, const uint8_t *buf, size_t len) { if (csum->output_crc) *csum->output_crc = crc32(*csum->output_crc, buf, len); if (csum->output_ctx) got_hash_update(csum->output_ctx, buf, len); } const struct got_error * got_deflate_read(struct got_deflate_buf *zb, FILE *f, off_t len, size_t *outlenp, off_t *consumed) { size_t last_total_out = zb->z.total_out; z_stream *z = &zb->z; int ret = Z_ERRNO; z->next_out = zb->outbuf; z->avail_out = zb->outlen; *outlenp = 0; *consumed = 0; do { size_t last_total_in = z->total_in; if (z->avail_in == 0) { size_t n = 0; if (*consumed < len) { n = fread(zb->inbuf, 1, MIN(zb->inlen, len - *consumed), f); } if (n == 0) { if (ferror(f)) return got_ferror(f, GOT_ERR_IO); /* EOF */ ret = deflate(z, Z_FINISH); break; } z->next_in = zb->inbuf; z->avail_in = n; } ret = deflate(z, Z_NO_FLUSH); *consumed += z->total_in - last_total_in; } while (ret == Z_OK && z->avail_out > 0); if (ret == Z_OK) { zb->flags |= GOT_DEFLATE_F_HAVE_MORE; } else { if (ret != Z_STREAM_END) return wrap_deflate_error(ret, "deflate"); zb->flags &= ~GOT_DEFLATE_F_HAVE_MORE; } *outlenp = z->total_out - last_total_out; return NULL; } static const struct got_error * deflate_read_mmap(struct got_deflate_buf *zb, uint8_t *map, size_t offset, size_t len, size_t *outlenp, size_t *consumed, int flush_on_eof) { z_stream *z = &zb->z; size_t last_total_out = z->total_out; int ret = Z_ERRNO; z->next_out = zb->outbuf; z->avail_out = zb->outlen; *outlenp = 0; *consumed = 0; do { size_t last_total_in = z->total_in; if (z->avail_in == 0) { z->next_in = map + offset + *consumed; if (len - *consumed > UINT_MAX) z->avail_in = UINT_MAX; else z->avail_in = len - *consumed; if (z->avail_in == 0) { /* EOF */ if (flush_on_eof) ret = deflate(z, Z_FINISH); break; } } ret = deflate(z, Z_NO_FLUSH); *consumed += z->total_in - last_total_in; } while (ret == Z_OK && z->avail_out > 0); if (ret == Z_OK) { zb->flags |= GOT_DEFLATE_F_HAVE_MORE; } else { if (ret != Z_STREAM_END) return wrap_deflate_error(ret, "deflate"); zb->flags &= ~GOT_DEFLATE_F_HAVE_MORE; } *outlenp = z->total_out - last_total_out; return NULL; } const struct got_error * got_deflate_read_mmap(struct got_deflate_buf *zb, uint8_t *map, size_t offset, size_t len, size_t *outlenp, size_t *consumed) { return deflate_read_mmap(zb, map, offset, len, outlenp, consumed, 1); } const struct got_error * got_deflate_flush(struct got_deflate_buf *zb, FILE *outfile, struct got_deflate_checksum *csum, off_t *outlenp) { int ret; size_t n; z_stream *z = &zb->z; if (z->avail_in != 0) return got_error_msg(GOT_ERR_COMPRESSION, "cannot flush zb with pending input data"); do { size_t avail, last_total_out = zb->z.total_out; z->next_out = zb->outbuf; z->avail_out = zb->outlen; ret = deflate(z, Z_FINISH); if (ret != Z_STREAM_END && ret != Z_OK) return wrap_deflate_error(ret, "deflate"); avail = z->total_out - last_total_out; if (avail > 0) { n = fwrite(zb->outbuf, avail, 1, outfile); if (n != 1) return got_ferror(outfile, GOT_ERR_IO); if (csum) csum_output(csum, zb->outbuf, avail); if (outlenp) *outlenp += avail; } } while (ret != Z_STREAM_END); zb->flags &= ~GOT_DEFLATE_F_HAVE_MORE; return NULL; } void got_deflate_end(struct got_deflate_buf *zb) { free(zb->inbuf); if (zb->flags & GOT_DEFLATE_F_OWN_OUTBUF) free(zb->outbuf); deflateEnd(&zb->z); } const struct got_error * got_deflate_to_fd(off_t *outlen, FILE *infile, off_t len, int outfd, struct got_deflate_checksum *csum) { const struct got_error *err; size_t avail; off_t consumed; struct got_deflate_buf zb; err = got_deflate_init(&zb, NULL, GOT_DEFLATE_BUFSIZE); if (err) goto done; *outlen = 0; do { err = got_deflate_read(&zb, infile, len, &avail, &consumed); if (err) goto done; len -= consumed; if (avail > 0) { err = got_poll_write_full(outfd, zb.outbuf, avail); if (err) goto done; if (csum) csum_output(csum, zb.outbuf, avail); *outlen += avail; } } while (zb.flags & GOT_DEFLATE_F_HAVE_MORE); done: got_deflate_end(&zb); return err; } const struct got_error * got_deflate_to_fd_mmap(off_t *outlen, uint8_t *map, size_t offset, size_t len, int outfd, struct got_deflate_checksum *csum) { const struct got_error *err; size_t avail, consumed; struct got_deflate_buf zb; err = got_deflate_init(&zb, NULL, GOT_DEFLATE_BUFSIZE); if (err) goto done; *outlen = 0; do { err = got_deflate_read_mmap(&zb, map, offset, len, &avail, &consumed); if (err) goto done; offset += consumed; len -= consumed; if (avail > 0) { err = got_poll_write_full(outfd, zb.outbuf, avail); if (err) goto done; if (csum) csum_output(csum, zb.outbuf, avail); *outlen += avail; } } while (zb.flags & GOT_DEFLATE_F_HAVE_MORE); done: got_deflate_end(&zb); return err; } const struct got_error * got_deflate_to_file(off_t *outlen, FILE *infile, off_t len, FILE *outfile, struct got_deflate_checksum *csum) { const struct got_error *err; size_t avail; off_t consumed; struct got_deflate_buf zb; err = got_deflate_init(&zb, NULL, GOT_DEFLATE_BUFSIZE); if (err) goto done; *outlen = 0; do { err = got_deflate_read(&zb, infile, len, &avail, &consumed); if (err) goto done; len -= consumed; if (avail > 0) { size_t n; n = fwrite(zb.outbuf, avail, 1, outfile); if (n != 1) { err = got_ferror(outfile, GOT_ERR_IO); goto done; } if (csum) csum_output(csum, zb.outbuf, avail); *outlen += avail; } } while (zb.flags & GOT_DEFLATE_F_HAVE_MORE); done: got_deflate_end(&zb); return err; } const struct got_error * got_deflate_to_file_mmap(off_t *outlen, uint8_t *map, size_t offset, size_t len, FILE *outfile, struct got_deflate_checksum *csum) { const struct got_error *err; size_t avail, consumed; struct got_deflate_buf zb; err = got_deflate_init(&zb, NULL, GOT_DEFLATE_BUFSIZE); if (err) goto done; *outlen = 0; do { err = got_deflate_read_mmap(&zb, map, offset, len, &avail, &consumed); if (err) goto done; offset += consumed; len -= consumed; if (avail > 0) { size_t n; n = fwrite(zb.outbuf, avail, 1, outfile); if (n != 1) { err = got_ferror(outfile, GOT_ERR_IO); goto done; } if (csum) csum_output(csum, zb.outbuf, avail); *outlen += avail; } } while (zb.flags & GOT_DEFLATE_F_HAVE_MORE); done: got_deflate_end(&zb); return err; } const struct got_error * got_deflate_append_to_file_mmap(struct got_deflate_buf *zb, off_t *outlen, uint8_t *map, size_t offset, size_t len, FILE *outfile, struct got_deflate_checksum *csum) { const struct got_error *err; size_t avail, consumed; do { err = deflate_read_mmap(zb, map, offset, len, &avail, &consumed, 0); if (err) break; offset += consumed; len -= consumed; if (avail > 0) { size_t n; n = fwrite(zb->outbuf, avail, 1, outfile); if (n != 1) { err = got_ferror(outfile, GOT_ERR_IO); break; } if (csum) csum_output(csum, zb->outbuf, avail); if (outlen) *outlen += avail; } } while ((zb->flags & GOT_DEFLATE_F_HAVE_MORE) && len > 0); return err; } const struct got_error * got_deflate_to_mem_mmap(uint8_t **outbuf, size_t *outlen, size_t *consumed_total, struct got_deflate_checksum *csum, uint8_t *map, size_t offset, size_t len) { const struct got_error *err; size_t avail, consumed; struct got_deflate_buf zb; void *newbuf; size_t nbuf = 1; if (outbuf) { *outbuf = malloc(GOT_DEFLATE_BUFSIZE); if (*outbuf == NULL) return got_error_from_errno("malloc"); err = got_deflate_init(&zb, *outbuf, GOT_DEFLATE_BUFSIZE); if (err) { free(*outbuf); *outbuf = NULL; return err; } } else { err = got_deflate_init(&zb, NULL, GOT_DEFLATE_BUFSIZE); if (err) return err; } *outlen = 0; if (consumed_total) *consumed_total = 0; do { err = got_deflate_read_mmap(&zb, map, offset, len, &avail, &consumed); if (err) goto done; offset += consumed; if (consumed_total) *consumed_total += consumed; len -= consumed; if (avail > 0 && csum) csum_output(csum, zb.outbuf, avail); *outlen += avail; if ((zb.flags & GOT_DEFLATE_F_HAVE_MORE) && outbuf != NULL) { newbuf = reallocarray(*outbuf, ++nbuf, GOT_DEFLATE_BUFSIZE); if (newbuf == NULL) { err = got_error_from_errno("reallocarray"); free(*outbuf); *outbuf = NULL; *outlen = 0; goto done; } *outbuf = newbuf; zb.outbuf = newbuf + *outlen; zb.outlen = (nbuf * GOT_DEFLATE_BUFSIZE) - *outlen; } } while (zb.flags & GOT_DEFLATE_F_HAVE_MORE); done: got_deflate_end(&zb); return err; } got-portable-0.101/lib/got_lib_pack.h0000664000175100017510000001613114644143345013145 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct got_pack_privsep_child { int imsg_fd; pid_t pid; struct imsgbuf *ibuf; }; /* An open pack file. */ struct got_pack { char *path_packfile; int fd; uint8_t *map; off_t filesize; struct got_pack_privsep_child *privsep_child; int basefd; int accumfd; int child_has_tempfiles; int child_has_delta_outfd; struct got_delta_cache *delta_cache; }; struct got_packidx; const struct got_error *got_pack_start_privsep_child(struct got_pack *, struct got_packidx *); const struct got_error *got_pack_close(struct got_pack *); const struct got_error *got_pack_parse_offset_delta(off_t *, size_t *, struct got_pack *, off_t, size_t); const struct got_error *got_pack_parse_ref_delta(struct got_object_id *, struct got_pack *, off_t, int); const struct got_error *got_pack_resolve_delta_chain(struct got_delta_chain *, struct got_packidx *, struct got_pack *, off_t, size_t, int, size_t, unsigned int); const struct got_error *got_pack_parse_object_type_and_size(uint8_t *, uint64_t *, size_t *, struct got_pack *, off_t); #define GOT_PACK_PREFIX "pack-" #define GOT_PACKFILE_SUFFIX ".pack" #define GOT_PACKIDX_SUFFIX ".idx" #define GOT_PACKFILE_NAMELEN (strlen(GOT_PACK_PREFIX) + \ SHA1_DIGEST_STRING_LENGTH - 1 + \ strlen(GOT_PACKFILE_SUFFIX)) #define GOT_PACKIDX_NAMELEN (strlen(GOT_PACK_PREFIX) + \ SHA1_DIGEST_STRING_LENGTH - 1 + \ strlen(GOT_PACKIDX_SUFFIX)) /* See Documentation/technical/pack-format.txt in Git. */ struct got_packidx_trailer { u_int8_t packfile_sha1[SHA1_DIGEST_LENGTH]; u_int8_t packidx_sha1[SHA1_DIGEST_LENGTH]; } __attribute__((__packed__)); struct got_packidx_object_id { u_int8_t sha1[SHA1_DIGEST_LENGTH]; } __attribute__((__packed__)); /* Ignore pack index version 1 which is no longer written by Git. */ #define GOT_PACKIDX_VERSION 2 struct got_packidx_v2_hdr { uint32_t *magic; /* big endian */ #define GOT_PACKIDX_V2_MAGIC 0xff744f63 /* "\377t0c" */ uint32_t *version; /* * Each entry N in the fanout table contains the number of objects in * the packfile whose SHA1 begins with a byte less than or equal to N. * The last entry (index 255) contains the number of objects in the * pack file whose first SHA1 byte is <= 0xff, and thus records the * total number of objects in the pack file. All pointer variables * below point to tables with a corresponding number of entries. */ uint32_t *fanout_table; /* values are big endian */ #define GOT_PACKIDX_V2_FANOUT_TABLE_ITEMS (0xff + 1) /* Sorted SHA1 checksums for each object in the pack file. */ struct got_packidx_object_id *sorted_ids; /* CRC32 of the packed representation of each object. */ uint32_t *crc32; /* Offset into the pack file for each object. */ uint32_t *offsets; /* values are big endian */ #define GOT_PACKIDX_OFFSET_VAL_MASK 0x7fffffff #define GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX 0x80000000 /* Large offsets table is empty for pack files < 2 GB. */ uint64_t *large_offsets; /* values are big endian */ struct got_packidx_trailer *trailer; }; struct got_pack_offset_index { uint32_t offset; uint32_t idx; }; struct got_pack_large_offset_index { uint64_t offset; uint32_t idx; }; /* An open pack index file. */ struct got_packidx { char *path_packidx; /* actual on-disk path */ int fd; uint8_t *map; size_t len; size_t nlargeobj; struct got_packidx_v2_hdr hdr; /* convenient pointers into map */ struct got_pack_offset_index *sorted_offsets; struct got_pack_large_offset_index *sorted_large_offsets; }; struct got_packfile_hdr { uint32_t signature; #define GOT_PACKFILE_SIGNATURE 0x5041434b /* 'P' 'A' 'C' 'K' */ uint32_t version; /* big endian */ #define GOT_PACKFILE_VERSION 2 uint32_t nobjects; /* big endian */ }; struct got_packfile_obj_hdr { /* * The object size field uses a variable length encoding: * size0...sizeN form a 4+7+7+...+7 bit integer, where size0 is the * least significant part and sizeN is the most significant part. * If the MSB of a size byte is set, an additional size byte follows. * Of the 7 remaining bits of size0, the first 3 bits indicate the * object's type, and the remaining 4 bits contribute to the size. */ uint8_t *size; /* variable length */ #define GOT_PACK_OBJ_SIZE_MORE 0x80 #define GOT_PACK_OBJ_SIZE0_TYPE_MASK 0x70 /* See struct got_object->type */ #define GOT_PACK_OBJ_SIZE0_TYPE_MASK_SHIFT 4 #define GOT_PACK_OBJ_SIZE0_VAL_MASK 0x0f #define GOT_PACK_OBJ_SIZE_VAL_MASK 0x7f }; #define GOT_PACK_OBJ_DELTA_OFF_MORE 0x80 #define GOT_PACK_OBJ_DELTA_OFF_VAL_MASK 0x7f const struct got_error *got_packidx_init_hdr(struct got_packidx *, int, off_t); const struct got_error *got_packidx_open(struct got_packidx **, int, const char *, int); const struct got_error *got_packidx_close(struct got_packidx *); const struct got_error *got_packidx_get_packfile_path(char **, const char *); off_t got_packidx_get_object_offset(struct got_packidx *, int idx); int got_packidx_get_object_idx(struct got_packidx *, struct got_object_id *); const struct got_error *got_packidx_get_offset_idx(int *, struct got_packidx *, off_t); const struct got_error *got_packidx_get_object_id(struct got_object_id *, struct got_packidx *, int); const struct got_error *got_packidx_match_id_str_prefix( struct got_object_id_queue *, struct got_packidx *, const char *); const struct got_error *got_packfile_open_object(struct got_object **, struct got_pack *, struct got_packidx *, int, struct got_object_id *); const struct got_error *got_pack_get_delta_chain_max_size(uint64_t *, struct got_delta_chain *, struct got_pack *); const struct got_error *got_pack_get_max_delta_object_size(uint64_t *, struct got_object *, struct got_pack *); const struct got_error *got_pack_dump_delta_chain_to_file(size_t *, struct got_delta_chain *, struct got_pack *, FILE *, FILE *, FILE *); const struct got_error *got_pack_dump_delta_chain_to_mem(uint8_t **, size_t *, struct got_delta_chain *, struct got_pack *); const struct got_error *got_packfile_extract_object(struct got_pack *, struct got_object *, FILE *, FILE *, FILE *); const struct got_error *got_packfile_extract_object_to_mem(uint8_t **, size_t *, struct got_object *, struct got_pack *); const struct got_error *got_packfile_extract_raw_delta(uint8_t **, size_t *, size_t *, off_t *, off_t *, off_t *, struct got_object_id *, uint64_t *, uint64_t *, struct got_pack *, struct got_packidx *, int); got-portable-0.101/lib/hash.c0000664000175100017510000001152514644144735011454 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include "got_object.h" #include "got_error.h" #include "got_lib_hash.h" struct got_object_id * got_object_id_dup(struct got_object_id *id1) { struct got_object_id *id2; id2 = malloc(sizeof(*id2)); if (id2 == NULL) return NULL; memcpy(id2, id1, sizeof(*id2)); return id2; } int got_object_id_cmp(const struct got_object_id *id1, const struct got_object_id *id2) { return memcmp(id1->sha1, id2->sha1, SHA1_DIGEST_LENGTH); } const struct got_error * got_object_id_str(char **outbuf, struct got_object_id *id) { static const size_t len = GOT_OBJECT_ID_HEX_MAXLEN; *outbuf = malloc(len); if (*outbuf == NULL) return got_error_from_errno("malloc"); if (got_object_id_hex(id, *outbuf, len) == NULL) { free(*outbuf); *outbuf = NULL; return got_error(GOT_ERR_BAD_OBJ_ID_STR); } return NULL; } int got_parse_xdigit(uint8_t *val, const char *hex) { char *ep; long lval; errno = 0; lval = strtol(hex, &ep, 16); if (hex[0] == '\0' || *ep != '\0') return 0; if (errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) return 0; *val = (uint8_t)lval; return 1; } static int parse_digest(uint8_t *digest, int len, const char *line) { uint8_t b = 0; char hex[3] = {'\0', '\0', '\0'}; int i, j; for (i = 0; i < len; i++) { if (line[0] == '\0' || line[1] == '\0') return 0; for (j = 0; j < 2; j++) { hex[j] = *line; line++; } if (!got_parse_xdigit(&b, hex)) return 0; digest[i] = b; } return 1; } static char * digest_to_str(const uint8_t *digest, int len, char *buf) { const char hex[] = "0123456789abcdef"; char *p = buf; int i; for (i = 0; i < len; i++) { *p++ = hex[digest[i] >> 4]; *p++ = hex[digest[i] & 0xf]; } *p = '\0'; return buf; } char * got_sha1_digest_to_str(const uint8_t *digest, char *buf, size_t size) { if (size < SHA1_DIGEST_STRING_LENGTH) return NULL; return digest_to_str(digest, SHA1_DIGEST_LENGTH, buf); } char * got_sha256_digest_to_str(const uint8_t *digest, char *buf, size_t size) { if (size < SHA256_DIGEST_STRING_LENGTH) return NULL; return digest_to_str(digest, SHA256_DIGEST_LENGTH, buf); } int got_parse_hash_digest(uint8_t *digest, const char *line, enum got_hash_algorithm algo) { switch (algo) { case GOT_HASH_SHA1: return parse_digest(digest, SHA1_DIGEST_LENGTH, line); case GOT_HASH_SHA256: return parse_digest(digest, SHA256_DIGEST_LENGTH, line); default: return 0; } } char * got_object_id_hex(struct got_object_id *id, char *buf, size_t len) { return got_sha1_digest_to_str(id->sha1, buf, len); } int got_parse_object_id(struct got_object_id *id, const char *line, enum got_hash_algorithm algo) { memset(id, 0, sizeof(*id)); /* XXX: temporary until we grow got_object_id */ if (algo != GOT_HASH_SHA1) return 0; return got_parse_hash_digest(id->sha1, line, algo); } void got_hash_init(struct got_hash *hash, enum got_hash_algorithm algo) { memset(hash, 0, sizeof(*hash)); hash->algo = algo; if (algo == GOT_HASH_SHA1) SHA1Init(&hash->sha1_ctx); else if (algo == GOT_HASH_SHA256) SHA256Init(&hash->sha256_ctx); } void got_hash_update(struct got_hash *hash, const void *data, size_t len) { if (hash->algo == GOT_HASH_SHA1) SHA1Update(&hash->sha1_ctx, data, len); else if (hash->algo == GOT_HASH_SHA256) SHA256Update(&hash->sha256_ctx, data, len); } void got_hash_final(struct got_hash *hash, uint8_t *out) { if (hash->algo == GOT_HASH_SHA1) SHA1Final(out, &hash->sha1_ctx); else if (hash->algo == GOT_HASH_SHA256) SHA256Final(out, &hash->sha256_ctx); } void got_hash_final_object_id(struct got_hash *hash, struct got_object_id *id) { memset(id, 0, sizeof(*id)); if (hash->algo == GOT_HASH_SHA1) SHA1Final(id->sha1, &hash->sha1_ctx); else abort(); } int got_hash_cmp(enum got_hash_algorithm algo, uint8_t *b1, uint8_t *b2) { if (algo == GOT_HASH_SHA1) return memcmp(b1, b2, SHA1_DIGEST_LENGTH); else if (algo == GOT_HASH_SHA256) return memcmp(b1, b2, SHA256_DIGEST_LENGTH); return -1; } got-portable-0.101/lib/error.c0000664000175100017510000004373014644144735011665 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_lib_delta.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_hash.h" #include "got_lib_object_parse.h" #ifndef nitems #define nitems(_a) (sizeof(_a) / sizeof((_a)[0])) #endif #if defined(__GLIBC__) /* * The autoconf test for strerror_r is broken in current versions * of autoconf: https://savannah.gnu.org/support/?110367 */ char *__xpg_strerror_r(int, char *, size_t); #define strerror_r __xpg_strerror_r #endif static const struct got_error got_errors[] = { { GOT_ERR_OK, "no error occurred?!?" }, { GOT_ERR_ERRNO, "see errno" }, { GOT_ERR_NOT_GIT_REPO, "no git repository found" }, { GOT_ERR_BAD_FILETYPE, "bad file type" }, { GOT_ERR_BAD_PATH, "bad path" }, { GOT_ERR_NOT_REF, "no such reference found" }, { GOT_ERR_IO, "input/output error" }, { GOT_ERR_EOF, "unexpected end of file" }, { GOT_ERR_DECOMPRESSION,"decompression failed" }, { GOT_ERR_NO_SPACE, "buffer too small" }, { GOT_ERR_BAD_OBJ_HDR, "bad object header" }, { GOT_ERR_OBJ_TYPE, "wrong type of object" }, { GOT_ERR_BAD_OBJ_DATA, "bad object data" }, { GOT_ERR_AMBIGUOUS_ID, "ambiguous object ID" }, { GOT_ERR_BAD_PACKIDX, "bad pack index file" }, { GOT_ERR_PACKIDX_CSUM, "pack index file checksum error" }, { GOT_ERR_BAD_PACKFILE, "bad pack file" }, { GOT_ERR_NO_OBJ, "object not found" }, { GOT_ERR_NOT_IMPL, "feature not implemented" }, { GOT_ERR_OBJ_NOT_PACKED,"object is not packed" }, { GOT_ERR_BAD_DELTA_CHAIN,"bad delta chain" }, { GOT_ERR_BAD_DELTA, "bad delta" }, { GOT_ERR_COMPRESSION, "compression failed" }, { GOT_ERR_BAD_OBJ_ID_STR,"bad object id string" }, { GOT_ERR_WORKTREE_EXISTS,"worktree already exists" }, { GOT_ERR_WORKTREE_META,"bad worktree meta data" }, { GOT_ERR_WORKTREE_VERS,"unsupported worktree format version" }, { GOT_ERR_WORKTREE_BUSY,"worktree already locked" }, { GOT_ERR_FILE_OBSTRUCTED,"file is obstructed" }, { GOT_ERR_RECURSION, "recursion limit reached" }, { GOT_ERR_TIMEOUT, "operation timed out" }, { GOT_ERR_INTERRUPT, "operation interrupted" }, { GOT_ERR_PRIVSEP_READ, "no data received in imsg" }, { GOT_ERR_PRIVSEP_LEN, "unexpected amount of data received in imsg" }, { GOT_ERR_PRIVSEP_PIPE, "privsep peer process closed pipe" }, { GOT_ERR_PRIVSEP_NO_FD,"privsep file descriptor unavailable" }, { GOT_ERR_PRIVSEP_MSG, "received unexpected privsep message" }, { GOT_ERR_PRIVSEP_DIED, "unprivileged process died unexpectedly" }, { GOT_ERR_PRIVSEP_EXIT, "bad exit code from unprivileged process" }, { GOT_ERR_PACK_OFFSET, "bad offset in pack file" }, { GOT_ERR_OBJ_EXISTS, "object already exists" }, { GOT_ERR_BAD_OBJ_ID, "bad object id" }, { GOT_ERR_ITER_COMPLETED,"iteration completed" }, { GOT_ERR_RANGE, "value out of range" }, { GOT_ERR_EXPECTED, "expected an error but have no error" }, { GOT_ERR_CANCELLED, "operation in progress has been cancelled" }, { GOT_ERR_NO_TREE_ENTRY,"no such entry found in tree" }, { GOT_ERR_FILEIDX_SIG, "bad file index signature" }, { GOT_ERR_FILEIDX_VER, "unknown file index format version" }, { GOT_ERR_FILEIDX_CSUM, "bad file index checksum" }, { GOT_ERR_PATH_PREFIX, "worktree already contains items from a " "different path prefix" }, { GOT_ERR_ANCESTRY, "target commit is on a different branch" }, { GOT_ERR_FILEIDX_BAD, "file index is corrupt" }, { GOT_ERR_BAD_REF_DATA, "could not parse reference data" }, { GOT_ERR_TREE_DUP_ENTRY,"duplicate entry in tree object" }, { GOT_ERR_DIR_DUP_ENTRY,"duplicate entry in directory" }, { GOT_ERR_NOT_WORKTREE, "no work tree found" }, { GOT_ERR_UUID_VERSION, "bad uuid version" }, { GOT_ERR_UUID_INVALID, "uuid invalid" }, { GOT_ERR_UUID, "uuid error" }, { GOT_ERR_LOCKFILE_TIMEOUT,"lockfile timeout" }, { GOT_ERR_BAD_REF_NAME, "bad reference name" }, { GOT_ERR_WORKTREE_REPO,"cannot create worktree inside a git repository" }, { GOT_ERR_FILE_MODIFIED,"file contains modifications" }, { GOT_ERR_FILE_STATUS, "file has unexpected status" }, { GOT_ERR_COMMIT_CONFLICT,"cannot commit file in conflicted status" }, { GOT_ERR_BAD_REF_TYPE, "bad reference type" }, { GOT_ERR_COMMIT_NO_AUTHOR,"GOT_AUTHOR environment variable is not set" }, { GOT_ERR_COMMIT_HEAD_CHANGED, "branch head in repository has changed " "while commit was in progress" }, { GOT_ERR_COMMIT_OUT_OF_DATE, "work tree must be updated before these " "changes can be committed" }, { GOT_ERR_COMMIT_MSG_EMPTY, "commit message cannot be empty" }, { GOT_ERR_DIR_NOT_EMPTY, "directory exists and is not empty" }, { GOT_ERR_COMMIT_NO_CHANGES, "no changes to commit" }, { GOT_ERR_BRANCH_MOVED, "work tree's head reference now points to a " "different branch; new head reference and/or update -b required" }, { GOT_ERR_OBJ_TOO_LARGE, "object too large" }, { GOT_ERR_SAME_BRANCH, "commit is already contained in this branch" }, { GOT_ERR_ROOT_COMMIT, "specified commit has no parent commit" }, { GOT_ERR_MIXED_COMMITS,"work tree contains files from multiple " "base commits; the entire work tree must be updated first" }, { GOT_ERR_CONFLICTS, "work tree contains conflicted files; these " "conflicts must be resolved first" }, { GOT_ERR_BRANCH_EXISTS,"specified branch already exists" }, { GOT_ERR_MODIFIED, "work tree contains local changes; these " "changes must be committed or reverted first" }, { GOT_ERR_NOT_REBASING, "rebase operation not in progress" }, { GOT_ERR_REBASE_COMMITID,"rebase commit ID mismatch" }, { GOT_ERR_WRONG_BRANCH, "update -b required" }, { GOT_ERR_REBASING, "a rebase operation is in progress in this " "work tree and must be continued or aborted first" }, { GOT_ERR_REBASE_PATH, "cannot rebase branch which contains " "changes outside of this work tree's path prefix" }, { GOT_ERR_NOT_HISTEDIT, "histedit operation not in progress" }, { GOT_ERR_EMPTY_HISTEDIT,"no commits to edit; perhaps the work tree " "must be updated to an older commit first" }, { GOT_ERR_NO_HISTEDIT_CMD,"no histedit commands provided" }, { GOT_ERR_HISTEDIT_SYNTAX,"syntax error in histedit command list" }, { GOT_ERR_HISTEDIT_CANCEL,"histedit operation cancelled" }, { 95, "unused error code" }, { GOT_ERR_HISTEDIT_BUSY,"histedit operation is in progress in this " "work tree and must be continued or aborted first" }, { GOT_ERR_HISTEDIT_CMD, "bad histedit command" }, { GOT_ERR_HISTEDIT_PATH, "cannot edit branch history which contains " "changes outside of this work tree's path prefix" }, { GOT_ERR_PACKFILE_CSUM, "pack file checksum error" }, { GOT_ERR_COMMIT_BRANCH, "will not commit to a branch outside the " "\"refs/heads/\" reference namespace" }, { GOT_ERR_FILE_STAGED, "file is staged" }, { GOT_ERR_STAGE_NO_CHANGE, "no changes to stage" }, { GOT_ERR_STAGE_CONFLICT, "cannot stage file in conflicted status" }, { GOT_ERR_STAGE_OUT_OF_DATE, "work tree must be updated before " "changes can be staged" }, { GOT_ERR_FILE_NOT_STAGED, "file is not staged" }, { GOT_ERR_STAGED_PATHS, "work tree contains files with staged " "changes; these changes must be committed or unstaged first" }, { GOT_ERR_PATCH_CHOICE, "invalid patch choice" }, { GOT_ERR_COMMIT_NO_EMAIL, "commit author's email address is required " "for compatibility with Git" }, { GOT_ERR_TAG_EXISTS,"specified tag already exists" }, { GOT_ERR_GIT_REPO_FORMAT,"unknown git repository format version" }, { GOT_ERR_REBASE_REQUIRED,"specified branch must be rebased first" }, { GOT_ERR_REGEX, "regular expression error" }, { GOT_ERR_REF_NAME_MINUS, "reference name may not start with '-'" }, { GOT_ERR_GITCONFIG_SYNTAX, "gitconfig syntax error" }, { GOT_ERR_REBASE_OUT_OF_DATE, "work tree must be updated before it " "can be used to rebase a branch" }, { GOT_ERR_CACHE_DUP_ENTRY, "duplicate cache entry" }, { GOT_ERR_FETCH_FAILED, "fetch failed" }, { GOT_ERR_PARSE_URI, "failed to parse uri" }, { GOT_ERR_BAD_PROTO, "unknown protocol" }, { GOT_ERR_ADDRINFO, "getaddrinfo failed" }, { GOT_ERR_BAD_PACKET, "bad packet received" }, { GOT_ERR_NO_REMOTE, "remote repository not found" }, { GOT_ERR_FETCH_NO_BRANCH, "could not find any branches to fetch" }, { GOT_ERR_FETCH_BAD_REF, "reference cannot be fetched" }, { GOT_ERR_TREE_ENTRY_TYPE, "unexpected tree entry type" }, { GOT_ERR_PARSE_CONFIG, "configuration file syntax error" }, { GOT_ERR_NO_CONFIG_FILE, "configuration file doesn't exit" }, { GOT_ERR_BAD_SYMLINK, "symbolic link points outside of paths under " "version control" }, { GOT_ERR_GIT_REPO_EXT, "unsupported repository format extension" }, { GOT_ERR_CANNOT_PACK, "not enough objects to pack" }, { GOT_ERR_LONELY_PACKIDX, "pack index has no corresponding pack file; " "pack file must be restored or 'gotadmin cleanup -p' must be run" }, { GOT_ERR_OBJ_CSUM, "bad object checksum" }, { GOT_ERR_SEND_BAD_REF, "reference cannot be sent" }, { GOT_ERR_SEND_FAILED, "could not send pack file" }, { GOT_ERR_SEND_EMPTY, "no references to send" }, { GOT_ERR_SEND_ANCESTRY, "branch on server has a different ancestry; either fetch changes from server and then rebase or merge local branch before sending, or ignore ancestry with send -f (can lead to data loss on server)" }, { GOT_ERR_CAPA_DELETE_REFS, "server cannot delete references" }, { GOT_ERR_SEND_DELETE_REF, "reference cannot be deleted" }, { GOT_ERR_SEND_TAG_EXISTS, "tag already exists on server" }, { GOT_ERR_NOT_MERGING, "merge operation not in progress" }, { GOT_ERR_MERGE_OUT_OF_DATE, "work tree must be updated before it " "can be used to merge a branch" }, { GOT_ERR_MERGE_STAGED_PATHS, "work tree contains files with staged " "changes; these changes must be unstaged before merging can " "proceed" }, { GOT_ERR_MERGE_BUSY,"a merge operation is in progress in this " "work tree and must be continued or aborted first" }, { GOT_ERR_MERGE_PATH, "cannot merge branch which contains " "changes outside of this work tree's path prefix" }, { GOT_ERR_FILE_BINARY, "found a binary file instead of text" }, { GOT_ERR_PATCH_MALFORMED, "malformed patch" }, { GOT_ERR_PATCH_TRUNCATED, "patch truncated" }, { GOT_ERR_NO_PATCH, "no patch found" }, { GOT_ERR_HUNK_FAILED, "hunk failed to apply" }, { GOT_ERR_PATCH_FAILED, "patch failed to apply" }, { GOT_ERR_FILEIDX_DUP_ENTRY, "duplicate file index entry" }, { GOT_ERR_PIN_PACK, "could not pin pack file" }, { GOT_ERR_BAD_TAG_SIGNATURE, "invalid tag signature" }, { GOT_ERR_VERIFY_TAG_SIGNATURE, "cannot verify signature" }, { GOT_ERR_SIGNING_TAG, "unable to sign tag" }, { GOT_ERR_BAD_OPTION, "option cannot be used" }, { GOT_ERR_BAD_QUERYSTRING, "invalid query string" }, { GOT_ERR_INTEGRATE_BRANCH, "will not integrate into a reference " "outside the \"refs/heads/\" reference namespace" }, { GOT_ERR_BAD_REQUEST, "unexpected request received" }, { GOT_ERR_CLIENT_ID, "unknown client identifier" }, { GOT_ERR_REPO_TEMPFILE, "no repository tempfile available" }, { GOT_ERR_REFS_PROTECTED, "reference namespace is protected" }, { GOT_ERR_REF_PROTECTED, "reference is protected" }, { GOT_ERR_REF_BUSY, "reference cannot be updated; please try again" }, { GOT_ERR_COMMIT_BAD_AUTHOR, "commit author formatting would " "make Git unhappy" }, { GOT_ERR_UID, "bad user ID" }, { GOT_ERR_GID, "bad group ID" }, { GOT_ERR_NO_PROG, "command not found or not accessible" }, { GOT_ERR_MERGE_COMMIT_OUT_OF_DATE, "merging cannot proceed because " "the work tree is no longer up-to-date; merge must be aborted " "and retried" }, { GOT_ERR_BUNDLE_FORMAT, "unknown git bundle version" }, { GOT_ERR_BAD_KEYWORD, "invalid commit keyword" } }; static struct got_custom_error { struct got_error err; char msg[GOT_ERR_MAX_MSG_SIZE]; } custom_errors[16]; static struct got_custom_error * get_custom_err(void) { static unsigned int idx; return &custom_errors[(idx++) % nitems(custom_errors)]; } const struct got_error * got_error(int code) { size_t i; for (i = 0; i < nitems(got_errors); i++) { if (code == got_errors[i].code) return &got_errors[i]; } abort(); } const struct got_error * got_error_msg(int code, const char *msg) { struct got_custom_error *cerr = get_custom_err(); struct got_error *err = &cerr->err; size_t i; for (i = 0; i < nitems(got_errors); i++) { if (code == got_errors[i].code) { err->code = code; strlcpy(cerr->msg, msg, sizeof(cerr->msg)); err->msg = cerr->msg; return err; } } abort(); } const struct got_error * got_error_from_errno(const char *prefix) { struct got_custom_error *cerr = get_custom_err(); struct got_error *err = &cerr->err; char strerr[128]; strerror_r(errno, strerr, sizeof(strerr)); snprintf(cerr->msg, sizeof(cerr->msg), "%s: %s", prefix, strerr); err->code = GOT_ERR_ERRNO; err->msg = cerr->msg; return err; } const struct got_error * got_error_from_errno2(const char *prefix, const char *prefix2) { struct got_custom_error *cerr = get_custom_err(); struct got_error *err = &cerr->err; char strerr[128]; strerror_r(errno, strerr, sizeof(strerr)); snprintf(cerr->msg, sizeof(cerr->msg), "%s: %s: %s", prefix, prefix2, strerr); err->code = GOT_ERR_ERRNO; err->msg = cerr->msg; return err; } const struct got_error * got_error_from_errno3(const char *prefix, const char *prefix2, const char *prefix3) { struct got_custom_error *cerr = get_custom_err(); struct got_error *err = &cerr->err; char strerr[128]; strerror_r(errno, strerr, sizeof(strerr)); snprintf(cerr->msg, sizeof(cerr->msg), "%s: %s: %s: %s", prefix, prefix2, prefix3, strerr); err->code = GOT_ERR_ERRNO; err->msg = cerr->msg; return err; } const struct got_error * got_error_from_errno_fmt(const char *fmt, ...) { struct got_custom_error *cerr = get_custom_err(); struct got_error *err = &cerr->err; char buf[PATH_MAX * 4]; char strerr[128]; va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); strerror_r(errno, strerr, sizeof(strerr)); snprintf(cerr->msg, sizeof(cerr->msg), "%s: %s", buf, strerr); err->code = GOT_ERR_ERRNO; err->msg = cerr->msg; return err; } const struct got_error * got_error_set_errno(int code, const char *prefix) { errno = code; return got_error_from_errno(prefix); } const struct got_error * got_ferror(FILE *f, int code) { if (ferror(f)) return got_error_from_errno(""); return got_error(code); } const struct got_error * got_error_no_obj(struct got_object_id *id) { char id_str[GOT_OBJECT_ID_HEX_MAXLEN]; char msg[sizeof("object not found") + sizeof(id_str)]; int ret; if (!got_object_id_hex(id, id_str, sizeof(id_str))) return got_error(GOT_ERR_NO_OBJ); ret = snprintf(msg, sizeof(msg), "object %s not found", id_str); if (ret < 0 || (size_t)ret >= sizeof(msg)) return got_error(GOT_ERR_NO_OBJ); return got_error_msg(GOT_ERR_NO_OBJ, msg); } const struct got_error * got_error_checksum(struct got_object_id *id) { char id_str[GOT_OBJECT_ID_HEX_MAXLEN]; char msg[sizeof("checksum failure for object ") + sizeof(id_str)]; int ret; if (!got_object_id_hex(id, id_str, sizeof(id_str))) return got_error(GOT_ERR_OBJ_CSUM); ret = snprintf(msg, sizeof(msg), "checksum failure for object %s", id_str); if (ret < 0 || (size_t)ret >= sizeof(msg)) return got_error(GOT_ERR_OBJ_CSUM); return got_error_msg(GOT_ERR_OBJ_CSUM, msg); } const struct got_error * got_error_not_ref(const char *refname) { char msg[sizeof("reference not found") + 1004]; int ret; ret = snprintf(msg, sizeof(msg), "reference %s not found", refname); if (ret < 0 || (size_t)ret >= sizeof(msg)) return got_error(GOT_ERR_NOT_REF); return got_error_msg(GOT_ERR_NOT_REF, msg); } const struct got_error * got_error_uuid(uint32_t uuid_status, const char *prefix) { switch (uuid_status) { case uuid_s_ok: return NULL; case uuid_s_bad_version: return got_error(GOT_ERR_UUID_VERSION); case uuid_s_invalid_string_uuid: return got_error(GOT_ERR_UUID_INVALID); case uuid_s_no_memory: return got_error_set_errno(ENOMEM, prefix); default: return got_error(GOT_ERR_UUID); } } const struct got_error * got_error_path(const char *path, int code) { struct got_custom_error *cerr = get_custom_err(); struct got_error *err = &cerr->err; size_t i; for (i = 0; i < nitems(got_errors); i++) { if (code == got_errors[i].code) { err->code = code; snprintf(cerr->msg, sizeof(cerr->msg), "%s: %s", path, got_errors[i].msg); err->msg = cerr->msg; return err; } } abort(); } const struct got_error * got_error_fmt(int code, const char *fmt, ...) { struct got_custom_error *cerr = get_custom_err(); struct got_error *err = &cerr->err; char buf[PATH_MAX * 4]; va_list ap; size_t i; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); for (i = 0; i < nitems(got_errors); i++) { if (code == got_errors[i].code) { err->code = code; snprintf(cerr->msg, sizeof(cerr->msg), "%s: %s", buf, got_errors[i].msg); err->msg = cerr->msg; return err; } } abort(); } int got_err_open_nofollow_on_symlink(void) { /* * Check whether open(2) with O_NOFOLLOW failed on a symlink. * Posix mandates ELOOP and OpenBSD follows it. Others return * different error codes. We carry this workaround to help the * portable version a little. */ return (errno == ELOOP #ifdef EMLINK || errno == EMLINK #endif #ifdef EFTYPE || errno == EFTYPE #endif ); } got-portable-0.101/lib/repository.c0000664000175100017510000017124514644144735012756 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bloom.h" #include "got_error.h" #include "got_reference.h" #include "got_repository.h" #include "got_path.h" #include "got_cancel.h" #include "got_object.h" #include "got_opentemp.h" #include "got_lib_delta.h" #include "got_lib_delta_cache.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_object_create.h" #include "got_lib_pack.h" #include "got_lib_privsep.h" #include "got_lib_hash.h" #include "got_lib_object_cache.h" #include "got_lib_repository.h" #include "got_lib_gotconfig.h" #ifndef nitems #define nitems(_a) (sizeof(_a) / sizeof((_a)[0])) #endif #define GOT_PACK_NUM_TEMPFILES GOT_PACK_CACHE_SIZE * 2 RB_PROTOTYPE(got_packidx_bloom_filter_tree, got_packidx_bloom_filter, entry, got_packidx_bloom_filter_cmp); static inline int is_boolean_val(const char *val) { return (strcasecmp(val, "true") == 0 || strcasecmp(val, "false") == 0 || strcasecmp(val, "on") == 0 || strcasecmp(val, "off") == 0 || strcasecmp(val, "yes") == 0 || strcasecmp(val, "no") == 0 || strcasecmp(val, "1") == 0 || strcasecmp(val, "0") == 0); } static inline int get_boolean_val(const char *val) { return (strcasecmp(val, "true") == 0 || strcasecmp(val, "on") == 0 || strcasecmp(val, "yes") == 0 || strcasecmp(val, "1") == 0); } const char * got_repo_get_path(struct got_repository *repo) { return repo->path; } const char * got_repo_get_path_git_dir(struct got_repository *repo) { return repo->path_git_dir; } int got_repo_get_fd(struct got_repository *repo) { return repo->gitdir_fd; } enum got_hash_algorithm got_repo_get_object_format(struct got_repository *repo) { return repo->algo; } const char * got_repo_get_gitconfig_author_name(struct got_repository *repo) { return repo->gitconfig_author_name; } const char * got_repo_get_gitconfig_author_email(struct got_repository *repo) { return repo->gitconfig_author_email; } const char * got_repo_get_global_gitconfig_author_name(struct got_repository *repo) { return repo->global_gitconfig_author_name; } const char * got_repo_get_global_gitconfig_author_email(struct got_repository *repo) { return repo->global_gitconfig_author_email; } const char * got_repo_get_gitconfig_owner(struct got_repository *repo) { return repo->gitconfig_owner; } int got_repo_has_extension(struct got_repository *repo, const char *ext) { int i; for (i = 0; i < repo->nextensions; ++i) { if (!strcasecmp(ext, repo->extnames[i])) return get_boolean_val(repo->extvals[i]); } return 0; } int got_repo_is_bare(struct got_repository *repo) { return (strcmp(repo->path, repo->path_git_dir) == 0); } static char * get_path_git_child(struct got_repository *repo, const char *basename) { char *path_child; if (asprintf(&path_child, "%s/%s", repo->path_git_dir, basename) == -1) return NULL; return path_child; } char * got_repo_get_path_objects(struct got_repository *repo) { return get_path_git_child(repo, GOT_OBJECTS_DIR); } char * got_repo_get_path_objects_pack(struct got_repository *repo) { return get_path_git_child(repo, GOT_OBJECTS_PACK_DIR); } char * got_repo_get_path_refs(struct got_repository *repo) { return get_path_git_child(repo, GOT_REFS_DIR); } char * got_repo_get_path_packed_refs(struct got_repository *repo) { return get_path_git_child(repo, GOT_PACKED_REFS_FILE); } static char * get_path_head(struct got_repository *repo) { return get_path_git_child(repo, GOT_HEAD_FILE); } char * got_repo_get_path_gitconfig(struct got_repository *repo) { return get_path_git_child(repo, GOT_GITCONFIG); } char * got_repo_get_path_gotconfig(struct got_repository *repo) { return get_path_git_child(repo, GOT_GOTCONFIG_FILENAME); } const struct got_gotconfig * got_repo_get_gotconfig(struct got_repository *repo) { return repo->gotconfig; } void got_repo_get_gitconfig_remotes(int *nremotes, const struct got_remote_repo **remotes, struct got_repository *repo) { *nremotes = repo->ngitconfig_remotes; *remotes = repo->gitconfig_remotes; } static int is_git_repo(struct got_repository *repo) { const char *path_git = got_repo_get_path_git_dir(repo); char *path_objects = got_repo_get_path_objects(repo); char *path_refs = got_repo_get_path_refs(repo); char *path_head = get_path_head(repo); int ret = 0; struct stat sb; struct got_reference *head_ref; if (lstat(path_git, &sb) == -1) goto done; if (!S_ISDIR(sb.st_mode)) goto done; if (lstat(path_objects, &sb) == -1) goto done; if (!S_ISDIR(sb.st_mode)) goto done; if (lstat(path_refs, &sb) == -1) goto done; if (!S_ISDIR(sb.st_mode)) goto done; if (lstat(path_head, &sb) == -1) goto done; if (!S_ISREG(sb.st_mode)) goto done; /* Check if the HEAD reference can be opened. */ if (got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0) != NULL) goto done; got_ref_close(head_ref); ret = 1; done: free(path_objects); free(path_refs); free(path_head); return ret; } static const struct got_error * close_tempfiles(int *fds, size_t nfds) { const struct got_error *err = NULL; int i; for (i = 0; i < nfds; i++) { if (fds[i] == -1) continue; if (close(fds[i]) == -1) { err = got_error_from_errno("close"); break; } } free(fds); return err; } static const struct got_error * open_tempfiles(int **fds, size_t array_size, size_t nfds) { const struct got_error *err = NULL; int i; *fds = calloc(array_size, sizeof(**fds)); if (*fds == NULL) return got_error_from_errno("calloc"); for (i = 0; i < array_size; i++) (*fds)[i] = -1; for (i = 0; i < nfds; i++) { (*fds)[i] = got_opentempfd(); if ((*fds)[i] == -1) { err = got_error_from_errno("got_opentempfd"); close_tempfiles(*fds, nfds); *fds = NULL; return err; } } return NULL; } static const struct got_error * get_pack_cache_size(int *pack_cache_size) { struct rlimit rl; if (getrlimit(RLIMIT_NOFILE, &rl) == -1) return got_error_from_errno("getrlimit"); *pack_cache_size = GOT_PACK_CACHE_SIZE; if (*pack_cache_size > rl.rlim_cur / 8) *pack_cache_size = rl.rlim_cur / 8; return NULL; } const struct got_error * got_repo_pack_fds_open(int **pack_fds) { const struct got_error *err; int nfds; err = get_pack_cache_size(&nfds); if (err) return err; /* * We need one basefd and one accumfd per cached pack. * Our constants should be set up in a way such that * this error never triggers. */ if (nfds * 2 > GOT_PACK_NUM_TEMPFILES) return got_error(GOT_ERR_NO_SPACE); return open_tempfiles(pack_fds, GOT_PACK_NUM_TEMPFILES, nfds * 2); } const struct got_error * got_repo_pack_fds_close(int *pack_fds) { return close_tempfiles(pack_fds, GOT_PACK_NUM_TEMPFILES); } const struct got_error * got_repo_temp_fds_open(int **temp_fds) { return open_tempfiles(temp_fds, GOT_REPO_NUM_TEMPFILES, GOT_REPO_NUM_TEMPFILES); } void got_repo_temp_fds_set(struct got_repository *repo, int *temp_fds) { int i; for (i = 0; i < GOT_REPO_NUM_TEMPFILES; i++) repo->tempfiles[i] = temp_fds[i]; } const struct got_error * got_repo_temp_fds_get(int *fd, int *idx, struct got_repository *repo) { int i; *fd = -1; *idx = -1; for (i = 0; i < nitems(repo->tempfiles); i++) { if (repo->tempfile_use_mask & (1 << i)) continue; if (repo->tempfiles[i] != -1) { if (ftruncate(repo->tempfiles[i], 0L) == -1) return got_error_from_errno("ftruncate"); *fd = repo->tempfiles[i]; *idx = i; repo->tempfile_use_mask |= (1 << i); return NULL; } } return got_error(GOT_ERR_REPO_TEMPFILE); } void got_repo_temp_fds_put(int idx, struct got_repository *repo) { repo->tempfile_use_mask &= ~(1 << idx); } const struct got_error * got_repo_temp_fds_close(int *temp_fds) { return close_tempfiles(temp_fds, GOT_REPO_NUM_TEMPFILES); } const struct got_error * got_repo_cache_object(struct got_repository *repo, struct got_object_id *id, struct got_object *obj) { #ifndef GOT_NO_OBJ_CACHE const struct got_error *err = NULL; err = got_object_cache_add(&repo->objcache, id, obj); if (err) { if (err->code == GOT_ERR_OBJ_EXISTS || err->code == GOT_ERR_OBJ_TOO_LARGE) err = NULL; return err; } obj->refcnt++; #endif return NULL; } struct got_object * got_repo_get_cached_object(struct got_repository *repo, struct got_object_id *id) { return (struct got_object *)got_object_cache_get(&repo->objcache, id); } const struct got_error * got_repo_cache_tree(struct got_repository *repo, struct got_object_id *id, struct got_tree_object *tree) { #ifndef GOT_NO_OBJ_CACHE const struct got_error *err = NULL; err = got_object_cache_add(&repo->treecache, id, tree); if (err) { if (err->code == GOT_ERR_OBJ_EXISTS || err->code == GOT_ERR_OBJ_TOO_LARGE) err = NULL; return err; } tree->refcnt++; #endif return NULL; } struct got_tree_object * got_repo_get_cached_tree(struct got_repository *repo, struct got_object_id *id) { return (struct got_tree_object *)got_object_cache_get( &repo->treecache, id); } const struct got_error * got_repo_cache_commit(struct got_repository *repo, struct got_object_id *id, struct got_commit_object *commit) { #ifndef GOT_NO_OBJ_CACHE const struct got_error *err = NULL; err = got_object_cache_add(&repo->commitcache, id, commit); if (err) { if (err->code == GOT_ERR_OBJ_EXISTS || err->code == GOT_ERR_OBJ_TOO_LARGE) err = NULL; return err; } commit->refcnt++; #endif return NULL; } struct got_commit_object * got_repo_get_cached_commit(struct got_repository *repo, struct got_object_id *id) { return (struct got_commit_object *)got_object_cache_get( &repo->commitcache, id); } const struct got_error * got_repo_cache_tag(struct got_repository *repo, struct got_object_id *id, struct got_tag_object *tag) { #ifndef GOT_NO_OBJ_CACHE const struct got_error *err = NULL; err = got_object_cache_add(&repo->tagcache, id, tag); if (err) { if (err->code == GOT_ERR_OBJ_EXISTS || err->code == GOT_ERR_OBJ_TOO_LARGE) err = NULL; return err; } tag->refcnt++; #endif return NULL; } struct got_tag_object * got_repo_get_cached_tag(struct got_repository *repo, struct got_object_id *id) { return (struct got_tag_object *)got_object_cache_get( &repo->tagcache, id); } const struct got_error * got_repo_cache_raw_object(struct got_repository *repo, struct got_object_id *id, struct got_raw_object *raw) { #ifndef GOT_NO_OBJ_CACHE const struct got_error *err = NULL; err = got_object_cache_add(&repo->rawcache, id, raw); if (err) { if (err->code == GOT_ERR_OBJ_EXISTS || err->code == GOT_ERR_OBJ_TOO_LARGE) err = NULL; return err; } raw->refcnt++; #endif return NULL; } struct got_raw_object * got_repo_get_cached_raw_object(struct got_repository *repo, struct got_object_id *id) { return (struct got_raw_object *)got_object_cache_get(&repo->rawcache, id); } static const struct got_error * open_repo(struct got_repository *repo, const char *path) { const struct got_error *err = NULL; repo->gitdir_fd = -1; /* bare git repository? */ repo->path_git_dir = strdup(path); if (repo->path_git_dir == NULL) return got_error_from_errno("strdup"); if (is_git_repo(repo)) { repo->path = strdup(repo->path_git_dir); if (repo->path == NULL) { err = got_error_from_errno("strdup"); goto done; } repo->gitdir_fd = open(repo->path_git_dir, O_DIRECTORY | O_CLOEXEC); if (repo->gitdir_fd == -1) { err = got_error_from_errno2("open", repo->path_git_dir); goto done; } return NULL; } /* git repository with working tree? */ free(repo->path_git_dir); repo->path_git_dir = NULL; if (asprintf(&repo->path_git_dir, "%s/%s", path, GOT_GIT_DIR) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (is_git_repo(repo)) { repo->path = strdup(path); if (repo->path == NULL) { err = got_error_from_errno("strdup"); goto done; } repo->gitdir_fd = open(repo->path_git_dir, O_DIRECTORY | O_CLOEXEC); if (repo->gitdir_fd == -1) { err = got_error_from_errno2("open", repo->path_git_dir); goto done; } return NULL; } err = got_error(GOT_ERR_NOT_GIT_REPO); done: if (err) { free(repo->path); repo->path = NULL; free(repo->path_git_dir); repo->path_git_dir = NULL; if (repo->gitdir_fd != -1) close(repo->gitdir_fd); repo->gitdir_fd = -1; } return err; } static const struct got_error * read_gitconfig(struct got_repository *repo, const char *global_gitconfig_path) { const struct got_error *err = NULL; char *repo_gitconfig_path = NULL; if (global_gitconfig_path) { /* Read settings from ~/.gitconfig. */ int dummy_repo_version; err = got_repo_read_gitconfig(&dummy_repo_version, &repo->global_gitconfig_author_name, &repo->global_gitconfig_author_email, NULL, NULL, NULL, NULL, NULL, NULL, global_gitconfig_path); if (err) return err; } /* Read repository's .git/config file. */ repo_gitconfig_path = got_repo_get_path_gitconfig(repo); if (repo_gitconfig_path == NULL) return got_error_from_errno("got_repo_get_path_gitconfig"); err = got_repo_read_gitconfig( &repo->gitconfig_repository_format_version, &repo->gitconfig_author_name, &repo->gitconfig_author_email, &repo->gitconfig_remotes, &repo->ngitconfig_remotes, &repo->gitconfig_owner, &repo->extnames, &repo->extvals, &repo->nextensions, repo_gitconfig_path); if (err) goto done; if (getenv("GOT_IGNORE_GITCONFIG") != NULL) { int i; for (i = 0; i < repo->ngitconfig_remotes; i++) { got_repo_free_remote_repo_data( &repo->gitconfig_remotes[i]); } free(repo->gitconfig_remotes); repo->gitconfig_remotes = NULL; repo->ngitconfig_remotes = 0; free(repo->gitconfig_author_name); repo->gitconfig_author_name = NULL; free(repo->gitconfig_author_email); repo->gitconfig_author_email = NULL; free(repo->global_gitconfig_author_name); repo->global_gitconfig_author_name = NULL; free(repo->global_gitconfig_author_email); repo->global_gitconfig_author_email = NULL; } done: free(repo_gitconfig_path); return err; } static const struct got_error * read_gotconfig(struct got_repository *repo) { const struct got_error *err = NULL; char *gotconfig_path; gotconfig_path = got_repo_get_path_gotconfig(repo); if (gotconfig_path == NULL) return got_error_from_errno("got_repo_get_path_gotconfig"); err = got_gotconfig_read(&repo->gotconfig, gotconfig_path); free(gotconfig_path); return err; } /* Supported repository format extensions. */ static const char *const repo_extensions[] = { "noop", /* Got supports repository format version 1. */ "preciousObjects", /* Supported by gotadmin cleanup. */ "worktreeConfig", /* Got does not care about Git work trees. */ }; const struct got_error * got_repo_open(struct got_repository **repop, const char *path, const char *global_gitconfig_path, int *pack_fds) { struct got_repository *repo = NULL; const struct got_error *err = NULL; char *repo_path = NULL; size_t i, j = 0; *repop = NULL; repo = calloc(1, sizeof(*repo)); if (repo == NULL) return got_error_from_errno("calloc"); RB_INIT(&repo->packidx_bloom_filters); TAILQ_INIT(&repo->packidx_paths); for (i = 0; i < nitems(repo->privsep_children); i++) { memset(&repo->privsep_children[i], 0, sizeof(repo->privsep_children[0])); repo->privsep_children[i].imsg_fd = -1; } err = got_object_cache_init(&repo->objcache, GOT_OBJECT_CACHE_TYPE_OBJ); if (err) goto done; err = got_object_cache_init(&repo->treecache, GOT_OBJECT_CACHE_TYPE_TREE); if (err) goto done; err = got_object_cache_init(&repo->commitcache, GOT_OBJECT_CACHE_TYPE_COMMIT); if (err) goto done; err = got_object_cache_init(&repo->tagcache, GOT_OBJECT_CACHE_TYPE_TAG); if (err) goto done; err = got_object_cache_init(&repo->rawcache, GOT_OBJECT_CACHE_TYPE_RAW); if (err) goto done; err = get_pack_cache_size(&repo->pack_cache_size); if (err) goto done; for (i = 0; i < nitems(repo->packs); i++) { if (pack_fds != NULL && i < repo->pack_cache_size) { repo->packs[i].basefd = pack_fds[j++]; repo->packs[i].accumfd = pack_fds[j++]; } else { repo->packs[i].basefd = -1; repo->packs[i].accumfd = -1; } } for (i = 0; i < nitems(repo->tempfiles); i++) repo->tempfiles[i] = -1; repo->pinned_pack = -1; repo->pinned_packidx = -1; repo->pinned_pid = 0; repo_path = realpath(path, NULL); if (repo_path == NULL) { err = got_error_from_errno2("realpath", path); goto done; } for (;;) { char *parent_path; err = open_repo(repo, repo_path); if (err == NULL) break; if (err->code != GOT_ERR_NOT_GIT_REPO) goto done; if (repo_path[0] == '/' && repo_path[1] == '\0') { err = got_error(GOT_ERR_NOT_GIT_REPO); goto done; } err = got_path_dirname(&parent_path, repo_path); if (err) goto done; free(repo_path); repo_path = parent_path; } err = read_gotconfig(repo); if (err) goto done; err = read_gitconfig(repo, global_gitconfig_path); if (err) goto done; if (repo->gitconfig_repository_format_version != 0) { err = got_error_path(path, GOT_ERR_GIT_REPO_FORMAT); goto done; } for (i = 0; i < repo->nextensions; i++) { char *ext = repo->extnames[i]; char *val = repo->extvals[i]; int j, supported = 0; if (!is_boolean_val(val)) { err = got_error_path(ext, GOT_ERR_GIT_REPO_EXT); goto done; } if (!get_boolean_val(val)) continue; for (j = 0; j < nitems(repo_extensions); j++) { if (strcmp(ext, repo_extensions[j]) == 0) { supported = 1; break; } } if (!supported) { err = got_error_path(ext, GOT_ERR_GIT_REPO_EXT); goto done; } } err = got_repo_list_packidx(&repo->packidx_paths, repo); done: if (err) got_repo_close(repo); else *repop = repo; free(repo_path); return err; } const struct got_error * got_repo_close(struct got_repository *repo) { const struct got_error *err = NULL, *child_err; struct got_packidx_bloom_filter *bf; size_t i; for (i = 0; i < repo->pack_cache_size; i++) { if (repo->packidx_cache[i] == NULL) break; got_packidx_close(repo->packidx_cache[i]); } while ((bf = RB_MIN(got_packidx_bloom_filter_tree, &repo->packidx_bloom_filters))) { RB_REMOVE(got_packidx_bloom_filter_tree, &repo->packidx_bloom_filters, bf); bloom_free(bf->bloom); free(bf->bloom); free(bf); } for (i = 0; i < repo->pack_cache_size; i++) if (repo->packs[i].path_packfile) if (repo->packs[i].path_packfile) got_pack_close(&repo->packs[i]); free(repo->path); free(repo->path_git_dir); got_object_cache_close(&repo->objcache); got_object_cache_close(&repo->treecache); got_object_cache_close(&repo->commitcache); got_object_cache_close(&repo->tagcache); got_object_cache_close(&repo->rawcache); for (i = 0; i < nitems(repo->privsep_children); i++) { if (repo->privsep_children[i].imsg_fd == -1) continue; imsg_clear(repo->privsep_children[i].ibuf); free(repo->privsep_children[i].ibuf); err = got_privsep_send_stop(repo->privsep_children[i].imsg_fd); if (err && err->code == GOT_ERR_EOF) err = NULL; child_err = got_privsep_wait_for_child( repo->privsep_children[i].pid); if (child_err && err == NULL) err = child_err; if (close(repo->privsep_children[i].imsg_fd) == -1 && err == NULL) err = got_error_from_errno("close"); } if (repo->gitdir_fd != -1 && close(repo->gitdir_fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (repo->gotconfig) got_gotconfig_free(repo->gotconfig); free(repo->gitconfig_author_name); free(repo->gitconfig_author_email); for (i = 0; i < repo->ngitconfig_remotes; i++) got_repo_free_remote_repo_data(&repo->gitconfig_remotes[i]); free(repo->gitconfig_remotes); for (i = 0; i < repo->nextensions; i++) { free(repo->extnames[i]); free(repo->extvals[i]); } free(repo->extnames); free(repo->extvals); got_pathlist_free(&repo->packidx_paths, GOT_PATHLIST_FREE_PATH); free(repo); return err; } const struct got_error * got_repo_remote_repo_dup(struct got_remote_repo **newp, const struct got_remote_repo *repo) { const struct got_error *err = NULL; struct got_remote_repo *new; int i; new = calloc(1, sizeof(*new)); if (new == NULL) return got_error_from_errno("calloc"); if (repo->name) { new->name = strdup(repo->name); if (new->name == NULL) { err = got_error_from_errno("strdup"); goto done; } } if (repo->fetch_url) { new->fetch_url = strdup(repo->fetch_url); if (new->fetch_url == NULL) { err = got_error_from_errno("strdup"); goto done; } } if (repo->send_url) { new->send_url = strdup(repo->send_url); if (new->send_url == NULL) { err = got_error_from_errno("strdup"); goto done; } } new->mirror_references = repo->mirror_references; new->fetch_all_branches = repo->fetch_all_branches; new->nfetch_branches = repo->nfetch_branches; if (repo->fetch_branches) { new->fetch_branches = calloc(repo->nfetch_branches, sizeof(char *)); if (new->fetch_branches == NULL) { err = got_error_from_errno("calloc"); goto done; } for (i = 0; i < repo->nfetch_branches; i++) { new->fetch_branches[i] = strdup( repo->fetch_branches[i]); if (new->fetch_branches[i] == NULL) { err = got_error_from_errno("strdup"); goto done; } } } new->nsend_branches = repo->nsend_branches; if (repo->send_branches) { new->send_branches = calloc(repo->nsend_branches, sizeof(char *)); if (new->send_branches == NULL) { err = got_error_from_errno("calloc"); goto done; } for (i = 0; i < repo->nsend_branches; i++) { new->send_branches[i] = strdup( repo->send_branches[i]); if (new->send_branches[i] == NULL) { err = got_error_from_errno("strdup"); goto done; } } } new->nfetch_refs = repo->nfetch_refs; if (repo->fetch_refs) { new->fetch_refs = calloc(repo->nfetch_refs, sizeof(char *)); if (new->fetch_refs == NULL) { err = got_error_from_errno("calloc"); goto done; } for (i = 0; i < repo->nfetch_refs; i++) { new->fetch_refs[i] = strdup( repo->fetch_refs[i]); if (new->fetch_refs[i] == NULL) { err = got_error_from_errno("strdup"); goto done; } } } done: if (err) { got_repo_free_remote_repo_data(new); free(new); } else *newp = new; return err; } void got_repo_free_remote_repo_data(struct got_remote_repo *repo) { int i; if (repo == NULL) return; free(repo->name); repo->name = NULL; free(repo->fetch_url); repo->fetch_url = NULL; free(repo->send_url); repo->send_url = NULL; for (i = 0; i < repo->nfetch_branches; i++) free(repo->fetch_branches[i]); free(repo->fetch_branches); repo->fetch_branches = NULL; repo->nfetch_branches = 0; for (i = 0; i < repo->nsend_branches; i++) free(repo->send_branches[i]); free(repo->send_branches); repo->send_branches = NULL; repo->nsend_branches = 0; for (i = 0; i < repo->nfetch_refs; i++) free(repo->fetch_refs[i]); free(repo->fetch_refs); repo->fetch_refs = NULL; repo->nfetch_refs = 0; } const struct got_error * got_repo_map_path(char **in_repo_path, struct got_repository *repo, const char *input_path) { const struct got_error *err = NULL; const char *repo_abspath = NULL; size_t repolen, len; char *canonpath, *path = NULL; *in_repo_path = NULL; canonpath = strdup(input_path); if (canonpath == NULL) { err = got_error_from_errno("strdup"); goto done; } err = got_canonpath(input_path, canonpath, strlen(canonpath) + 1); if (err) goto done; repo_abspath = got_repo_get_path(repo); if (canonpath[0] == '\0') { path = strdup(canonpath); if (path == NULL) { err = got_error_from_errno("strdup"); goto done; } } else { path = realpath(canonpath, NULL); if (path == NULL) { if (errno != ENOENT) { err = got_error_from_errno2("realpath", canonpath); goto done; } /* * Path is not on disk. * Assume it is already relative to repository root. */ path = strdup(canonpath); if (path == NULL) { err = got_error_from_errno("strdup"); goto done; } } repolen = strlen(repo_abspath); len = strlen(path); if (strcmp(path, repo_abspath) == 0) { free(path); path = strdup(""); if (path == NULL) { err = got_error_from_errno("strdup"); goto done; } } else if (len > repolen && got_path_is_child(path, repo_abspath, repolen)) { /* Matched an on-disk path inside repository. */ if (got_repo_is_bare(repo)) { /* * Matched an on-disk path inside repository * database. Treat input as repository-relative. */ free(path); path = canonpath; canonpath = NULL; } else { char *child; /* Strip common prefix with repository path. */ err = got_path_skip_common_ancestor(&child, repo_abspath, path); if (err) goto done; free(path); path = child; } } else { /* * Matched unrelated on-disk path. * Treat input as repository-relative. */ free(path); path = canonpath; canonpath = NULL; } } /* Make in-repository path absolute */ if (path[0] != '/') { char *abspath; if (asprintf(&abspath, "/%s", path) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(path); path = abspath; } done: free(canonpath); if (err) free(path); else *in_repo_path = path; return err; } static const struct got_error * cache_packidx(struct got_repository *repo, struct got_packidx *packidx, const char *path_packidx) { const struct got_error *err = NULL; size_t i; for (i = 0; i < repo->pack_cache_size; i++) { if (repo->packidx_cache[i] == NULL) break; if (strcmp(repo->packidx_cache[i]->path_packidx, path_packidx) == 0) { return got_error(GOT_ERR_CACHE_DUP_ENTRY); } } if (i == repo->pack_cache_size) { do { i--; } while (i > 0 && repo->pinned_packidx >= 0 && i == repo->pinned_packidx); err = got_packidx_close(repo->packidx_cache[i]); if (err) return err; } repo->packidx_cache[i] = packidx; return NULL; } int got_repo_is_packidx_filename(const char *name, size_t len) { if (len != GOT_PACKIDX_NAMELEN) return 0; if (strncmp(name, GOT_PACK_PREFIX, strlen(GOT_PACK_PREFIX)) != 0) return 0; if (strcmp(name + strlen(GOT_PACK_PREFIX) + SHA1_DIGEST_STRING_LENGTH - 1, GOT_PACKIDX_SUFFIX) != 0) return 0; return 1; } static struct got_packidx_bloom_filter * get_packidx_bloom_filter(struct got_repository *repo, const char *path, size_t path_len) { struct got_packidx_bloom_filter key; if (strlcpy(key.path, path, sizeof(key.path)) >= sizeof(key.path)) return NULL; /* XXX */ key.path_len = path_len; return RB_FIND(got_packidx_bloom_filter_tree, &repo->packidx_bloom_filters, &key); } int got_repo_check_packidx_bloom_filter(struct got_repository *repo, const char *path_packidx, struct got_object_id *id) { struct got_packidx_bloom_filter *bf; bf = get_packidx_bloom_filter(repo, path_packidx, strlen(path_packidx)); if (bf) return bloom_check(bf->bloom, id->sha1, sizeof(id->sha1)); /* No bloom filter means this pack index must be searched. */ return 1; } static const struct got_error * add_packidx_bloom_filter(struct got_repository *repo, struct got_packidx *packidx, const char *path_packidx) { int i, nobjects = be32toh(packidx->hdr.fanout_table[0xff]); struct got_packidx_bloom_filter *bf; size_t len; /* * Don't use bloom filters for very large pack index files. * Large pack files will contain a relatively large fraction * of our objects so we will likely need to visit them anyway. * The more objects a pack file contains the higher the probability * of a false-positive match from the bloom filter. And reading * all object IDs from a large pack index file can be expensive. */ if (nobjects > 100000) /* cut-off at about 2MB, at 20 bytes per ID */ return NULL; /* Do we already have a filter for this pack index? */ if (get_packidx_bloom_filter(repo, path_packidx, strlen(path_packidx)) != NULL) return NULL; bf = calloc(1, sizeof(*bf)); if (bf == NULL) return got_error_from_errno("calloc"); bf->bloom = calloc(1, sizeof(*bf->bloom)); if (bf->bloom == NULL) { free(bf); return got_error_from_errno("calloc"); } len = strlcpy(bf->path, path_packidx, sizeof(bf->path)); if (len >= sizeof(bf->path)) { free(bf->bloom); free(bf); return got_error(GOT_ERR_NO_SPACE); } bf->path_len = len; /* Minimum size supported by our bloom filter is 1000 entries. */ bloom_init(bf->bloom, nobjects < 1000 ? 1000 : nobjects, 0.1); for (i = 0; i < nobjects; i++) { struct got_packidx_object_id *id; id = &packidx->hdr.sorted_ids[i]; bloom_add(bf->bloom, id->sha1, sizeof(id->sha1)); } RB_INSERT(got_packidx_bloom_filter_tree, &repo->packidx_bloom_filters, bf); return NULL; } static void purge_packidx_paths(struct got_pathlist_head *packidx_paths) { struct got_pathlist_entry *pe; while (!TAILQ_EMPTY(packidx_paths)) { pe = TAILQ_FIRST(packidx_paths); TAILQ_REMOVE(packidx_paths, pe, entry); free((char *)pe->path); free(pe); } } static const struct got_error * refresh_packidx_paths(struct got_repository *repo) { const struct got_error *err = NULL; char *objects_pack_dir = NULL; struct stat sb; objects_pack_dir = got_repo_get_path_objects_pack(repo); if (objects_pack_dir == NULL) return got_error_from_errno("got_repo_get_path_objects_pack"); if (stat(objects_pack_dir, &sb) == -1) { if (errno != ENOENT) { err = got_error_from_errno2("stat", objects_pack_dir); goto done; } } else if (TAILQ_EMPTY(&repo->packidx_paths) || sb.st_mtim.tv_sec != repo->pack_path_mtime.tv_sec || sb.st_mtim.tv_nsec != repo->pack_path_mtime.tv_nsec) { purge_packidx_paths(&repo->packidx_paths); err = got_repo_list_packidx(&repo->packidx_paths, repo); if (err) goto done; } done: free(objects_pack_dir); return err; } const struct got_error * got_repo_search_packidx(struct got_packidx **packidx, int *idx, struct got_repository *repo, struct got_object_id *id) { const struct got_error *err; struct got_pathlist_entry *pe; size_t i; /* Search pack index cache. */ for (i = 0; i < repo->pack_cache_size; i++) { if (repo->packidx_cache[i] == NULL) break; if (!got_repo_check_packidx_bloom_filter(repo, repo->packidx_cache[i]->path_packidx, id)) continue; /* object will not be found in this index */ *idx = got_packidx_get_object_idx(repo->packidx_cache[i], id); if (*idx != -1) { *packidx = repo->packidx_cache[i]; /* * Move this cache entry to the front. Repeatedly * searching a wrong pack index can be expensive. */ if (i > 0) { memmove(&repo->packidx_cache[1], &repo->packidx_cache[0], i * sizeof(repo->packidx_cache[0])); repo->packidx_cache[0] = *packidx; if (repo->pinned_packidx >= 0 && repo->pinned_packidx < i) repo->pinned_packidx++; else if (repo->pinned_packidx == i) repo->pinned_packidx = 0; } return NULL; } } /* No luck. Search the filesystem. */ err = refresh_packidx_paths(repo); if (err) return err; TAILQ_FOREACH(pe, &repo->packidx_paths, entry) { const char *path_packidx = pe->path; int is_cached = 0; if (!got_repo_check_packidx_bloom_filter(repo, pe->path, id)) continue; /* object will not be found in this index */ for (i = 0; i < repo->pack_cache_size; i++) { if (repo->packidx_cache[i] == NULL) break; if (strcmp(repo->packidx_cache[i]->path_packidx, path_packidx) == 0) { is_cached = 1; break; } } if (is_cached) continue; /* already searched */ err = got_packidx_open(packidx, got_repo_get_fd(repo), path_packidx, 0); if (err) goto done; err = add_packidx_bloom_filter(repo, *packidx, path_packidx); if (err) goto done; err = cache_packidx(repo, *packidx, path_packidx); if (err) goto done; *idx = got_packidx_get_object_idx(*packidx, id); if (*idx != -1) { err = NULL; /* found the object */ goto done; } } err = got_error_no_obj(id); done: return err; } const struct got_error * got_repo_list_packidx(struct got_pathlist_head *packidx_paths, struct got_repository *repo) { const struct got_error *err = NULL; DIR *packdir = NULL; struct dirent *dent; char *path_packidx = NULL; int packdir_fd; struct stat sb; packdir_fd = openat(got_repo_get_fd(repo), GOT_OBJECTS_PACK_DIR, O_DIRECTORY | O_CLOEXEC); if (packdir_fd == -1) { return got_error_from_errno_fmt("openat: %s/%s", got_repo_get_path_git_dir(repo), GOT_OBJECTS_PACK_DIR); } packdir = fdopendir(packdir_fd); if (packdir == NULL) { err = got_error_from_errno("fdopendir"); close(packdir_fd); goto done; } if (fstat(packdir_fd, &sb) == -1) { err = got_error_from_errno("fstat"); goto done; } repo->pack_path_mtime.tv_sec = sb.st_mtim.tv_sec; repo->pack_path_mtime.tv_nsec = sb.st_mtim.tv_nsec; while ((dent = readdir(packdir)) != NULL) { if (!got_repo_is_packidx_filename(dent->d_name, strlen(dent->d_name))) continue; if (asprintf(&path_packidx, "%s/%s", GOT_OBJECTS_PACK_DIR, dent->d_name) == -1) { err = got_error_from_errno("asprintf"); path_packidx = NULL; break; } err = got_pathlist_append(packidx_paths, path_packidx, NULL); if (err) break; } done: if (err) free(path_packidx); if (packdir && closedir(packdir) != 0 && err == NULL) err = got_error_from_errno("closedir"); return err; } const struct got_error * got_repo_get_packidx(struct got_packidx **packidx, const char *path_packidx, struct got_repository *repo) { const struct got_error *err; size_t i; *packidx = NULL; /* Search pack index cache. */ for (i = 0; i < repo->pack_cache_size; i++) { if (repo->packidx_cache[i] == NULL) break; if (strcmp(repo->packidx_cache[i]->path_packidx, path_packidx) == 0) { *packidx = repo->packidx_cache[i]; return NULL; } } /* No luck. Search the filesystem. */ err = got_packidx_open(packidx, got_repo_get_fd(repo), path_packidx, 0); if (err) return err; err = add_packidx_bloom_filter(repo, *packidx, path_packidx); if (err) goto done; err = cache_packidx(repo, *packidx, path_packidx); done: if (err) { got_packidx_close(*packidx); *packidx = NULL; } return err; } static const struct got_error * read_packfile_hdr(int fd, struct got_packidx *packidx) { const struct got_error *err = NULL; uint32_t totobj = be32toh(packidx->hdr.fanout_table[0xff]); struct got_packfile_hdr hdr; ssize_t n; n = read(fd, &hdr, sizeof(hdr)); if (n < 0) return got_error_from_errno("read"); if (n != sizeof(hdr)) return got_error(GOT_ERR_BAD_PACKFILE); if (be32toh(hdr.signature) != GOT_PACKFILE_SIGNATURE || be32toh(hdr.version) != GOT_PACKFILE_VERSION || be32toh(hdr.nobjects) != totobj) err = got_error(GOT_ERR_BAD_PACKFILE); return err; } static const struct got_error * open_packfile(int *fd, struct got_repository *repo, const char *relpath, struct got_packidx *packidx) { const struct got_error *err = NULL; *fd = openat(got_repo_get_fd(repo), relpath, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (*fd == -1) return got_error_from_errno_fmt("openat: %s/%s", got_repo_get_path_git_dir(repo), relpath); if (packidx) { err = read_packfile_hdr(*fd, packidx); if (err) { close(*fd); *fd = -1; } } return err; } const struct got_error * got_repo_cache_pack(struct got_pack **packp, struct got_repository *repo, const char *path_packfile, struct got_packidx *packidx) { const struct got_error *err = NULL; struct got_pack *pack = NULL; struct stat sb; size_t i; if (packp) *packp = NULL; for (i = 0; i < repo->pack_cache_size; i++) { pack = &repo->packs[i]; if (pack->path_packfile == NULL) break; if (strcmp(pack->path_packfile, path_packfile) == 0) return got_error(GOT_ERR_CACHE_DUP_ENTRY); } if (i == repo->pack_cache_size) { struct got_pack tmp; do { i--; } while (i > 0 && repo->pinned_pack >= 0 && i == repo->pinned_pack); err = got_pack_close(&repo->packs[i]); if (err) return err; if (ftruncate(repo->packs[i].basefd, 0L) == -1) return got_error_from_errno("ftruncate"); if (ftruncate(repo->packs[i].accumfd, 0L) == -1) return got_error_from_errno("ftruncate"); memcpy(&tmp, &repo->packs[i], sizeof(tmp)); memcpy(&repo->packs[i], &repo->packs[0], sizeof(repo->packs[i])); memcpy(&repo->packs[0], &tmp, sizeof(repo->packs[0])); if (repo->pinned_pack == 0) repo->pinned_pack = i; else if (repo->pinned_pack == i) repo->pinned_pack = 0; i = 0; } pack = &repo->packs[i]; pack->path_packfile = strdup(path_packfile); if (pack->path_packfile == NULL) { err = got_error_from_errno("strdup"); goto done; } err = open_packfile(&pack->fd, repo, path_packfile, packidx); if (err) goto done; if (fstat(pack->fd, &sb) != 0) { err = got_error_from_errno("fstat"); goto done; } pack->filesize = sb.st_size; pack->privsep_child = NULL; err = got_delta_cache_alloc(&pack->delta_cache); if (err) goto done; #ifndef GOT_PACK_NO_MMAP if (pack->filesize > 0 && pack->filesize <= SIZE_MAX) { pack->map = mmap(NULL, pack->filesize, PROT_READ, MAP_PRIVATE, pack->fd, 0); if (pack->map == MAP_FAILED) { if (errno != ENOMEM) { err = got_error_from_errno("mmap"); goto done; } pack->map = NULL; /* fall back to read(2) */ } } #endif done: if (err) { if (pack) got_pack_close(pack); } else if (packp) *packp = pack; return err; } struct got_pack * got_repo_get_cached_pack(struct got_repository *repo, const char *path_packfile) { struct got_pack *pack = NULL; size_t i; for (i = 0; i < repo->pack_cache_size; i++) { pack = &repo->packs[i]; if (pack->path_packfile == NULL) break; if (strcmp(pack->path_packfile, path_packfile) == 0) return pack; } return NULL; } const struct got_error * got_repo_pin_pack(struct got_repository *repo, struct got_packidx *packidx, struct got_pack *pack) { size_t i; int pinned_pack = -1, pinned_packidx = -1; for (i = 0; i < repo->pack_cache_size; i++) { if (repo->packidx_cache[i] && strcmp(repo->packidx_cache[i]->path_packidx, packidx->path_packidx) == 0) pinned_packidx = i; if (repo->packs[i].path_packfile && strcmp(repo->packs[i].path_packfile, pack->path_packfile) == 0) pinned_pack = i; } if (pinned_packidx == -1 || pinned_pack == -1) return got_error(GOT_ERR_PIN_PACK); repo->pinned_pack = pinned_pack; repo->pinned_packidx = pinned_packidx; if (repo->packs[pinned_pack].privsep_child) repo->pinned_pid = repo->packs[pinned_pack].privsep_child->pid; return NULL; } struct got_pack * got_repo_get_pinned_pack(struct got_repository *repo) { if (repo->pinned_pack >= 0 && repo->pinned_pack < repo->pack_cache_size) return &repo->packs[repo->pinned_pack]; return NULL; } void got_repo_unpin_pack(struct got_repository *repo) { repo->pinned_packidx = -1; repo->pinned_pack = -1; repo->pinned_pid = 0; } const struct got_error * got_repo_init(const char *repo_path, const char *head_name) { const struct got_error *err = NULL; const char *dirnames[] = { GOT_OBJECTS_DIR, GOT_OBJECTS_PACK_DIR, GOT_REFS_DIR, }; const char *description_str = "Unnamed repository; " "edit this file 'description' to name the repository."; const char *headref = "ref: refs/heads/"; const char *gitconfig_str = "[core]\n" "\trepositoryformatversion = 0\n" "\tfilemode = true\n" "\tbare = true\n"; char *headref_str, *path; size_t i; if (!got_path_dir_is_empty(repo_path)) return got_error(GOT_ERR_DIR_NOT_EMPTY); for (i = 0; i < nitems(dirnames); i++) { if (asprintf(&path, "%s/%s", repo_path, dirnames[i]) == -1) { return got_error_from_errno("asprintf"); } err = got_path_mkdir(path); free(path); if (err) return err; } if (asprintf(&path, "%s/%s", repo_path, "description") == -1) return got_error_from_errno("asprintf"); err = got_path_create_file(path, description_str); free(path); if (err) return err; if (asprintf(&path, "%s/%s", repo_path, GOT_HEAD_FILE) == -1) return got_error_from_errno("asprintf"); if (asprintf(&headref_str, "%s%s", headref, head_name ? head_name : "main") == -1) { free(path); return got_error_from_errno("asprintf"); } err = got_path_create_file(path, headref_str); free(headref_str); free(path); if (err) return err; if (asprintf(&path, "%s/%s", repo_path, "config") == -1) return got_error_from_errno("asprintf"); err = got_path_create_file(path, gitconfig_str); free(path); if (err) return err; return NULL; } static const struct got_error * match_packed_object(struct got_object_id **unique_id, struct got_repository *repo, const char *id_str_prefix, int obj_type) { const struct got_error *err = NULL; struct got_object_id_queue matched_ids; struct got_pathlist_entry *pe; struct timespec tv; int retries = 0; const int max_retries = 10; STAILQ_INIT(&matched_ids); err = refresh_packidx_paths(repo); if (err) return err; /* * Opening objects while iterating over the pack-index path * list is racy. If the set of pack files in the repository * changes during loop iteration, refresh_packidx_paths() will * be called again, via got_object_get_type(), invalidating * the packidx_paths list we are iterating over. * To work around this we keep track of the current modification * time and retry the entire loop if it changes. */ retry: tv.tv_sec = repo->pack_path_mtime.tv_sec; tv.tv_nsec = repo->pack_path_mtime.tv_nsec; TAILQ_FOREACH(pe, &repo->packidx_paths, entry) { const char *path_packidx; struct got_packidx *packidx; struct got_object_qid *qid; /* * If the modification time of the 'objects/pack' directory * has changed then 'pe' could now be an invalid pointer. */ if (tv.tv_sec != repo->pack_path_mtime.tv_sec || tv.tv_nsec != repo->pack_path_mtime.tv_nsec) { if (++retries > max_retries) { err = got_error_msg(GOT_ERR_TIMEOUT, "too many concurrent pack file " "modifications"); goto done; } goto retry; } path_packidx = pe->path; err = got_packidx_open(&packidx, got_repo_get_fd(repo), path_packidx, 0); if (err) break; got_object_id_queue_free(&matched_ids); err = got_packidx_match_id_str_prefix(&matched_ids, packidx, id_str_prefix); if (err) { got_packidx_close(packidx); break; } err = got_packidx_close(packidx); if (err) break; STAILQ_FOREACH(qid, &matched_ids, entry) { if (obj_type != GOT_OBJ_TYPE_ANY) { int matched_type; err = got_object_get_type(&matched_type, repo, &qid->id); if (err) goto done; if (matched_type != obj_type) continue; } if (*unique_id == NULL) { *unique_id = got_object_id_dup(&qid->id); if (*unique_id == NULL) { err = got_error_from_errno("malloc"); goto done; } } else { if (got_object_id_cmp(*unique_id, &qid->id) == 0) continue; /* packed multiple times */ err = got_error(GOT_ERR_AMBIGUOUS_ID); goto done; } } } done: got_object_id_queue_free(&matched_ids); if (err) { free(*unique_id); *unique_id = NULL; } return err; } static const struct got_error * match_loose_object(struct got_object_id **unique_id, const char *path_objects, const char *object_dir, const char *id_str_prefix, int obj_type, struct got_repository *repo) { const struct got_error *err = NULL; char *path, *id_str = NULL; DIR *dir = NULL; struct dirent *dent; struct got_object_id id; if (asprintf(&path, "%s/%s", path_objects, object_dir) == -1) { err = got_error_from_errno("asprintf"); goto done; } dir = opendir(path); if (dir == NULL) { if (errno == ENOENT) { err = NULL; goto done; } err = got_error_from_errno2("opendir", path); goto done; } while ((dent = readdir(dir)) != NULL) { int cmp; free(id_str); id_str = NULL; if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) continue; if (asprintf(&id_str, "%s%s", object_dir, dent->d_name) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (!got_parse_object_id(&id, id_str, repo->algo)) continue; /* * Directory entries do not necessarily appear in * sorted order, so we must iterate over all of them. */ cmp = strncmp(id_str, id_str_prefix, strlen(id_str_prefix)); if (cmp != 0) continue; if (*unique_id == NULL) { if (obj_type != GOT_OBJ_TYPE_ANY) { int matched_type; err = got_object_get_type(&matched_type, repo, &id); if (err) goto done; if (matched_type != obj_type) continue; } *unique_id = got_object_id_dup(&id); if (*unique_id == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } } else { if (got_object_id_cmp(*unique_id, &id) == 0) continue; /* both packed and loose */ err = got_error(GOT_ERR_AMBIGUOUS_ID); goto done; } } done: if (dir && closedir(dir) != 0 && err == NULL) err = got_error_from_errno("closedir"); if (err) { free(*unique_id); *unique_id = NULL; } free(id_str); free(path); return err; } const struct got_error * got_repo_match_object_id_prefix(struct got_object_id **id, const char *id_str_prefix, int obj_type, struct got_repository *repo) { const struct got_error *err = NULL; char *path_objects = NULL, *object_dir = NULL; size_t len; int i; *id = NULL; path_objects = got_repo_get_path_objects(repo); len = strlen(id_str_prefix); if (len > SHA1_DIGEST_STRING_LENGTH - 1) { err = got_error_path(id_str_prefix, GOT_ERR_BAD_OBJ_ID_STR); goto done; } for (i = 0; i < len; i++) { if (isxdigit((unsigned char)id_str_prefix[i])) continue; err = got_error_path(id_str_prefix, GOT_ERR_BAD_OBJ_ID_STR); goto done; } if (len >= 2) { err = match_packed_object(id, repo, id_str_prefix, obj_type); if (err) goto done; object_dir = strndup(id_str_prefix, 2); if (object_dir == NULL) { err = got_error_from_errno("strdup"); goto done; } err = match_loose_object(id, path_objects, object_dir, id_str_prefix, obj_type, repo); } else if (len == 1) { int i; for (i = 0; i < 0xf; i++) { if (asprintf(&object_dir, "%s%.1x", id_str_prefix, i) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = match_packed_object(id, repo, object_dir, obj_type); if (err) goto done; err = match_loose_object(id, path_objects, object_dir, id_str_prefix, obj_type, repo); if (err) goto done; } } else { err = got_error_path(id_str_prefix, GOT_ERR_BAD_OBJ_ID_STR); goto done; } done: free(path_objects); free(object_dir); if (err) { free(*id); *id = NULL; } else if (*id == NULL) { switch (obj_type) { case GOT_OBJ_TYPE_BLOB: err = got_error_fmt(GOT_ERR_NO_OBJ, "%s %s", GOT_OBJ_LABEL_BLOB, id_str_prefix); break; case GOT_OBJ_TYPE_TREE: err = got_error_fmt(GOT_ERR_NO_OBJ, "%s %s", GOT_OBJ_LABEL_TREE, id_str_prefix); break; case GOT_OBJ_TYPE_COMMIT: err = got_error_fmt(GOT_ERR_NO_OBJ, "%s %s", GOT_OBJ_LABEL_COMMIT, id_str_prefix); break; case GOT_OBJ_TYPE_TAG: err = got_error_fmt(GOT_ERR_NO_OBJ, "%s %s", GOT_OBJ_LABEL_TAG, id_str_prefix); break; default: err = got_error_path(id_str_prefix, GOT_ERR_NO_OBJ); break; } } return err; } const struct got_error * got_repo_match_object_id(struct got_object_id **id, char **label, const char *id_str, int obj_type, struct got_reflist_head *refs, struct got_repository *repo) { const struct got_error *err; struct got_tag_object *tag; struct got_reference *ref = NULL; *id = NULL; if (label) *label = NULL; if (refs) { err = got_repo_object_match_tag(&tag, id_str, obj_type, refs, repo); if (err == NULL) { *id = got_object_id_dup( got_object_tag_get_object_id(tag)); if (*id == NULL) err = got_error_from_errno("got_object_id_dup"); else if (label && asprintf(label, "refs/tags/%s", got_object_tag_get_name(tag)) == -1) { err = got_error_from_errno("asprintf"); free(*id); *id = NULL; } got_object_tag_close(tag); return err; } else if (err->code != GOT_ERR_OBJ_TYPE && err->code != GOT_ERR_NO_OBJ) return err; } err = got_ref_open(&ref, repo, id_str, 0); if (err == NULL) { err = got_ref_resolve(id, repo, ref); if (err) goto done; if (label) { *label = strdup(got_ref_get_name(ref)); if (*label == NULL) { err = got_error_from_errno("strdup"); goto done; } } } else { if (err->code != GOT_ERR_NOT_REF && err->code != GOT_ERR_BAD_REF_NAME) goto done; err = got_repo_match_object_id_prefix(id, id_str, obj_type, repo); if (err) { if (err->code == GOT_ERR_BAD_OBJ_ID_STR) err = got_error_not_ref(id_str); goto done; } if (label) { err = got_object_id_str(label, *id); if (*label == NULL) { err = got_error_from_errno("strdup"); goto done; } } } done: if (ref) got_ref_close(ref); return err; } const struct got_error * got_repo_object_match_tag(struct got_tag_object **tag, const char *name, int obj_type, struct got_reflist_head *refs, struct got_repository *repo) { const struct got_error *err = NULL; struct got_reflist_entry *re; struct got_object_id *tag_id; int name_is_absolute = (strncmp(name, "refs/", 5) == 0); *tag = NULL; TAILQ_FOREACH(re, refs, entry) { const char *refname; refname = got_ref_get_name(re->ref); if (got_ref_is_symbolic(re->ref)) continue; if (strncmp(refname, "refs/tags/", 10) != 0) continue; if (!name_is_absolute) refname += strlen("refs/tags/"); if (strcmp(refname, name) != 0) continue; err = got_ref_resolve(&tag_id, repo, re->ref); if (err) break; err = got_object_open_as_tag(tag, repo, tag_id); free(tag_id); if (err) break; if (obj_type == GOT_OBJ_TYPE_ANY || got_object_tag_get_object_type(*tag) == obj_type) break; got_object_tag_close(*tag); *tag = NULL; } if (err == NULL && *tag == NULL) err = got_error_fmt(GOT_ERR_NO_OBJ, "%s %s", GOT_OBJ_LABEL_TAG, name); return err; } const struct got_error * got_repo_find_object_id(struct got_object_id *id, struct got_repository *repo) { const struct got_error *err; struct got_object_id *matched_id = NULL; char *id_str = NULL; err = got_object_id_str(&id_str, id); if (err) return err; err = got_repo_match_object_id_prefix(&matched_id, id_str, GOT_OBJ_TYPE_ANY, repo); free(id_str); return err; } static const struct got_error * alloc_added_blob_tree_entry(struct got_tree_entry **new_te, const char *name, mode_t mode, struct got_object_id *blob_id) { const struct got_error *err = NULL; *new_te = NULL; *new_te = calloc(1, sizeof(**new_te)); if (*new_te == NULL) return got_error_from_errno("calloc"); if (strlcpy((*new_te)->name, name, sizeof((*new_te)->name)) >= sizeof((*new_te)->name)) { err = got_error(GOT_ERR_NO_SPACE); goto done; } if (S_ISLNK(mode)) { (*new_te)->mode = S_IFLNK; } else { (*new_te)->mode = S_IFREG; (*new_te)->mode |= (mode & (S_IRWXU | S_IRWXG | S_IRWXO)); } memcpy(&(*new_te)->id, blob_id, sizeof((*new_te)->id)); done: if (err && *new_te) { free(*new_te); *new_te = NULL; } return err; } static const struct got_error * import_file(struct got_tree_entry **new_te, struct dirent *de, const char *path, struct got_repository *repo) { const struct got_error *err; struct got_object_id *blob_id = NULL; char *filepath; struct stat sb; if (asprintf(&filepath, "%s%s%s", path, path[0] == '\0' ? "" : "/", de->d_name) == -1) return got_error_from_errno("asprintf"); if (lstat(filepath, &sb) != 0) { err = got_error_from_errno2("lstat", path); goto done; } err = got_object_blob_create(&blob_id, filepath, repo); if (err) goto done; err = alloc_added_blob_tree_entry(new_te, de->d_name, sb.st_mode, blob_id); done: free(filepath); if (err) free(blob_id); return err; } static const struct got_error * insert_tree_entry(struct got_tree_entry *new_te, struct got_pathlist_head *paths) { const struct got_error *err = NULL; struct got_pathlist_entry *new_pe; err = got_pathlist_insert(&new_pe, paths, new_te->name, new_te); if (err) return err; if (new_pe == NULL) return got_error(GOT_ERR_TREE_DUP_ENTRY); return NULL; } static const struct got_error *write_tree(struct got_object_id **, const char *, struct got_pathlist_head *, struct got_repository *, got_repo_import_cb progress_cb, void *progress_arg); static const struct got_error * import_subdir(struct got_tree_entry **new_te, struct dirent *de, const char *path, struct got_pathlist_head *ignores, struct got_repository *repo, got_repo_import_cb progress_cb, void *progress_arg) { const struct got_error *err; struct got_object_id *id = NULL; char *subdirpath; if (asprintf(&subdirpath, "%s%s%s", path, path[0] == '\0' ? "" : "/", de->d_name) == -1) return got_error_from_errno("asprintf"); (*new_te) = calloc(1, sizeof(**new_te)); if (*new_te == NULL) return got_error_from_errno("calloc"); (*new_te)->mode = S_IFDIR; if (strlcpy((*new_te)->name, de->d_name, sizeof((*new_te)->name)) >= sizeof((*new_te)->name)) { err = got_error(GOT_ERR_NO_SPACE); goto done; } err = write_tree(&id, subdirpath, ignores, repo, progress_cb, progress_arg); if (err) goto done; memcpy(&(*new_te)->id, id, sizeof((*new_te)->id)); done: free(id); free(subdirpath); if (err) { free(*new_te); *new_te = NULL; } return err; } static const struct got_error * write_tree(struct got_object_id **new_tree_id, const char *path_dir, struct got_pathlist_head *ignores, struct got_repository *repo, got_repo_import_cb progress_cb, void *progress_arg) { const struct got_error *err = NULL; DIR *dir; struct dirent *de; int nentries; struct got_tree_entry *new_te = NULL; struct got_pathlist_head paths; struct got_pathlist_entry *pe; *new_tree_id = NULL; TAILQ_INIT(&paths); dir = opendir(path_dir); if (dir == NULL) { err = got_error_from_errno2("opendir", path_dir); goto done; } nentries = 0; while ((de = readdir(dir)) != NULL) { int ignore = 0; int type; if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) continue; err = got_path_dirent_type(&type, path_dir, de); if (err) goto done; TAILQ_FOREACH(pe, ignores, entry) { if (type == DT_DIR && pe->path_len > 0 && pe->path[pe->path_len - 1] == '/') { char stripped[PATH_MAX]; if (strlcpy(stripped, pe->path, sizeof(stripped)) >= sizeof(stripped)) { err = got_error(GOT_ERR_NO_SPACE); goto done; } got_path_strip_trailing_slashes(stripped); if (fnmatch(stripped, de->d_name, 0) == 0) { ignore = 1; break; } } else if (fnmatch(pe->path, de->d_name, 0) == 0) { ignore = 1; break; } } if (ignore) continue; if (type == DT_DIR) { err = import_subdir(&new_te, de, path_dir, ignores, repo, progress_cb, progress_arg); if (err) { if (err->code != GOT_ERR_NO_TREE_ENTRY) goto done; err = NULL; continue; } } else if (type == DT_REG || type == DT_LNK) { err = import_file(&new_te, de, path_dir, repo); if (err) goto done; } else continue; err = insert_tree_entry(new_te, &paths); if (err) goto done; nentries++; } if (TAILQ_EMPTY(&paths)) { err = got_error_msg(GOT_ERR_NO_TREE_ENTRY, "cannot create tree without any entries"); goto done; } TAILQ_FOREACH(pe, &paths, entry) { struct got_tree_entry *te = pe->data; char *path; if (!S_ISREG(te->mode) && !S_ISLNK(te->mode)) continue; if (asprintf(&path, "%s/%s", path_dir, pe->path) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = (*progress_cb)(progress_arg, path); free(path); if (err) goto done; } err = got_object_tree_create(new_tree_id, &paths, nentries, repo); done: if (dir) closedir(dir); got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE); return err; } const struct got_error * got_repo_import(struct got_object_id **new_commit_id, const char *path_dir, const char *logmsg, const char *author, struct got_pathlist_head *ignores, struct got_repository *repo, got_repo_import_cb progress_cb, void *progress_arg) { const struct got_error *err; struct got_object_id *new_tree_id; err = write_tree(&new_tree_id, path_dir, ignores, repo, progress_cb, progress_arg); if (err) return err; err = got_object_commit_create(new_commit_id, new_tree_id, NULL, 0, author, time(NULL), author, time(NULL), logmsg, repo); free(new_tree_id); return err; } const struct got_error * got_repo_get_loose_object_info(int *nobjects, off_t *ondisk_size, struct got_repository *repo) { const struct got_error *err = NULL; char *path_objects = NULL, *path = NULL; DIR *dir = NULL; struct got_object_id id; int i; *nobjects = 0; *ondisk_size = 0; path_objects = got_repo_get_path_objects(repo); if (path_objects == NULL) return got_error_from_errno("got_repo_get_path_objects"); for (i = 0; i <= 0xff; i++) { struct dirent *dent; if (asprintf(&path, "%s/%.2x", path_objects, i) == -1) { err = got_error_from_errno("asprintf"); break; } dir = opendir(path); if (dir == NULL) { if (errno == ENOENT) { err = NULL; continue; } err = got_error_from_errno2("opendir", path); break; } while ((dent = readdir(dir)) != NULL) { char *id_str; int fd; struct stat sb; if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) continue; if (asprintf(&id_str, "%.2x%s", i, dent->d_name) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (!got_parse_object_id(&id, id_str, repo->algo)) { free(id_str); continue; } free(id_str); err = got_object_open_loose_fd(&fd, &id, repo); if (err) goto done; if (fstat(fd, &sb) == -1) { err = got_error_from_errno("fstat"); close(fd); goto done; } (*nobjects)++; (*ondisk_size) += sb.st_size; if (close(fd) == -1) { err = got_error_from_errno("close"); goto done; } } if (closedir(dir) != 0) { err = got_error_from_errno("closedir"); goto done; } dir = NULL; free(path); path = NULL; } done: if (dir && closedir(dir) != 0 && err == NULL) err = got_error_from_errno("closedir"); if (err) { *nobjects = 0; *ondisk_size = 0; } free(path_objects); free(path); return err; } const struct got_error * got_repo_get_packfile_info(int *npackfiles, int *nobjects, off_t *total_packsize, struct got_repository *repo) { const struct got_error *err = NULL; DIR *packdir = NULL; struct dirent *dent; struct got_packidx *packidx = NULL; char *path_packidx; char *path_packfile; int packdir_fd; struct stat sb; *npackfiles = 0; *nobjects = 0; *total_packsize = 0; packdir_fd = openat(got_repo_get_fd(repo), GOT_OBJECTS_PACK_DIR, O_DIRECTORY); if (packdir_fd == -1) { return got_error_from_errno_fmt("openat: %s/%s", got_repo_get_path_git_dir(repo), GOT_OBJECTS_PACK_DIR); } packdir = fdopendir(packdir_fd); if (packdir == NULL) { err = got_error_from_errno("fdopendir"); close(packdir_fd); goto done; } while ((dent = readdir(packdir)) != NULL) { if (!got_repo_is_packidx_filename(dent->d_name, strlen(dent->d_name))) continue; if (asprintf(&path_packidx, "%s/%s", GOT_OBJECTS_PACK_DIR, dent->d_name) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_packidx_open(&packidx, got_repo_get_fd(repo), path_packidx, 0); free(path_packidx); if (err) goto done; if (fstat(packidx->fd, &sb) == -1) goto done; *total_packsize += sb.st_size; err = got_packidx_get_packfile_path(&path_packfile, packidx->path_packidx); if (err) goto done; if (fstatat(got_repo_get_fd(repo), path_packfile, &sb, 0) == -1) { free(path_packfile); goto done; } free(path_packfile); *total_packsize += sb.st_size; *nobjects += be32toh(packidx->hdr.fanout_table[0xff]); (*npackfiles)++; got_packidx_close(packidx); packidx = NULL; } done: if (packidx) got_packidx_close(packidx); if (packdir && closedir(packdir) != 0 && err == NULL) err = got_error_from_errno("closedir"); if (err) { *npackfiles = 0; *nobjects = 0; *total_packsize = 0; } return err; } RB_GENERATE(got_packidx_bloom_filter_tree, got_packidx_bloom_filter, entry, got_packidx_bloom_filter_cmp); got-portable-0.101/lib/diff_output_unidiff.c0000644000175100017510000004177714644143163014571 /* Produce a unidiff output from a diff_result. */ /* * Copyright (c) 2020 Neels Hofmeyr * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include "diff_internal.h" #include "diff_debug.h" off_t diff_chunk_get_left_start_pos(const struct diff_chunk *c) { return c->left_start->pos; } off_t diff_chunk_get_right_start_pos(const struct diff_chunk *c) { return c->right_start->pos; } bool diff_chunk_context_empty(const struct diff_chunk_context *cc) { return diff_range_empty(&cc->chunk); } int diff_chunk_get_left_start(const struct diff_chunk *c, const struct diff_result *r, int context_lines) { int left_start = diff_atom_root_idx(r->left, c->left_start); return MAX(0, left_start - context_lines); } int diff_chunk_get_left_end(const struct diff_chunk *c, const struct diff_result *r, int context_lines) { int left_start = diff_chunk_get_left_start(c, r, 0); return MIN(r->left->atoms.len, left_start + c->left_count + context_lines); } int diff_chunk_get_right_start(const struct diff_chunk *c, const struct diff_result *r, int context_lines) { int right_start = diff_atom_root_idx(r->right, c->right_start); return MAX(0, right_start - context_lines); } int diff_chunk_get_right_end(const struct diff_chunk *c, const struct diff_result *r, int context_lines) { int right_start = diff_chunk_get_right_start(c, r, 0); return MIN(r->right->atoms.len, right_start + c->right_count + context_lines); } struct diff_chunk * diff_chunk_get(const struct diff_result *r, int chunk_idx) { return &r->chunks.head[chunk_idx]; } int diff_chunk_get_left_count(struct diff_chunk *c) { return c->left_count; } int diff_chunk_get_right_count(struct diff_chunk *c) { return c->right_count; } void diff_chunk_context_get(struct diff_chunk_context *cc, const struct diff_result *r, int chunk_idx, int context_lines) { const struct diff_chunk *c = &r->chunks.head[chunk_idx]; int left_start = diff_chunk_get_left_start(c, r, context_lines); int left_end = diff_chunk_get_left_end(c, r, context_lines); int right_start = diff_chunk_get_right_start(c, r, context_lines); int right_end = diff_chunk_get_right_end(c, r, context_lines); *cc = (struct diff_chunk_context){ .chunk = { .start = chunk_idx, .end = chunk_idx + 1, }, .left = { .start = left_start, .end = left_end, }, .right = { .start = right_start, .end = right_end, }, }; } bool diff_chunk_contexts_touch(const struct diff_chunk_context *cc, const struct diff_chunk_context *other) { return diff_ranges_touch(&cc->chunk, &other->chunk) || diff_ranges_touch(&cc->left, &other->left) || diff_ranges_touch(&cc->right, &other->right); } void diff_chunk_contexts_merge(struct diff_chunk_context *cc, const struct diff_chunk_context *other) { diff_ranges_merge(&cc->chunk, &other->chunk); diff_ranges_merge(&cc->left, &other->left); diff_ranges_merge(&cc->right, &other->right); } void diff_chunk_context_load_change(struct diff_chunk_context *cc, int *nchunks_used, struct diff_result *result, int start_chunk_idx, int context_lines) { int i; int seen_minus = 0, seen_plus = 0; if (nchunks_used) *nchunks_used = 0; for (i = start_chunk_idx; i < result->chunks.len; i++) { struct diff_chunk *chunk = &result->chunks.head[i]; enum diff_chunk_type t = diff_chunk_type(chunk); struct diff_chunk_context next; if (t != CHUNK_MINUS && t != CHUNK_PLUS) { if (nchunks_used) (*nchunks_used)++; if (seen_minus || seen_plus) break; else continue; } else if (t == CHUNK_MINUS) seen_minus = 1; else if (t == CHUNK_PLUS) seen_plus = 1; if (diff_chunk_context_empty(cc)) { /* Note down the start point, any number of subsequent * chunks may be joined up to this chunk by being * directly adjacent. */ diff_chunk_context_get(cc, result, i, context_lines); if (nchunks_used) (*nchunks_used)++; continue; } /* There already is a previous chunk noted down for being * printed. Does it join up with this one? */ diff_chunk_context_get(&next, result, i, context_lines); if (diff_chunk_contexts_touch(cc, &next)) { /* This next context touches or overlaps the previous * one, join. */ diff_chunk_contexts_merge(cc, &next); if (nchunks_used) (*nchunks_used)++; continue; } else break; } } struct diff_output_unidiff_state { bool header_printed; char prototype[DIFF_FUNCTION_CONTEXT_SIZE]; int last_prototype_idx; }; struct diff_output_unidiff_state * diff_output_unidiff_state_alloc(void) { struct diff_output_unidiff_state *state; state = calloc(1, sizeof(struct diff_output_unidiff_state)); if (state != NULL) diff_output_unidiff_state_reset(state); return state; } void diff_output_unidiff_state_reset(struct diff_output_unidiff_state *state) { state->header_printed = false; memset(state->prototype, 0, sizeof(state->prototype)); state->last_prototype_idx = 0; } void diff_output_unidiff_state_free(struct diff_output_unidiff_state *state) { free(state); } static int output_unidiff_chunk(struct diff_output_info *outinfo, FILE *dest, struct diff_output_unidiff_state *state, const struct diff_input_info *info, const struct diff_result *result, bool print_header, bool show_function_prototypes, const struct diff_chunk_context *cc) { int rc, left_start, left_len, right_start, right_len; off_t outoff = 0, *offp; uint8_t *typep; if (diff_range_empty(&cc->left) && diff_range_empty(&cc->right)) return DIFF_RC_OK; if (outinfo && outinfo->line_offsets.len > 0) { unsigned int idx = outinfo->line_offsets.len - 1; outoff = outinfo->line_offsets.head[idx]; } if (print_header && !(state->header_printed)) { rc = fprintf(dest, "--- %s\n", diff_output_get_label_left(info)); if (rc < 0) return errno; if (outinfo) { ARRAYLIST_ADD(offp, outinfo->line_offsets); if (offp == NULL) return ENOMEM; outoff += rc; *offp = outoff; ARRAYLIST_ADD(typep, outinfo->line_types); if (typep == NULL) return ENOMEM; *typep = DIFF_LINE_MINUS; } rc = fprintf(dest, "+++ %s\n", diff_output_get_label_right(info)); if (rc < 0) return errno; if (outinfo) { ARRAYLIST_ADD(offp, outinfo->line_offsets); if (offp == NULL) return ENOMEM; outoff += rc; *offp = outoff; ARRAYLIST_ADD(typep, outinfo->line_types); if (typep == NULL) return ENOMEM; *typep = DIFF_LINE_PLUS; } state->header_printed = true; } left_len = cc->left.end - cc->left.start; if (result->left->atoms.len == 0) left_start = 0; else if (left_len == 0 && cc->left.start > 0) left_start = cc->left.start; else left_start = cc->left.start + 1; right_len = cc->right.end - cc->right.start; if (result->right->atoms.len == 0) right_start = 0; else if (right_len == 0 && cc->right.start > 0) right_start = cc->right.start; else right_start = cc->right.start + 1; if (show_function_prototypes) { rc = diff_output_match_function_prototype(state->prototype, sizeof(state->prototype), &state->last_prototype_idx, result, cc); if (rc) return rc; } if (left_len == 1 && right_len == 1) { rc = fprintf(dest, "@@ -%d +%d @@%s%s\n", left_start, right_start, state->prototype[0] ? " " : "", state->prototype[0] ? state->prototype : ""); } else if (left_len == 1 && right_len != 1) { rc = fprintf(dest, "@@ -%d +%d,%d @@%s%s\n", left_start, right_start, right_len, state->prototype[0] ? " " : "", state->prototype[0] ? state->prototype : ""); } else if (left_len != 1 && right_len == 1) { rc = fprintf(dest, "@@ -%d,%d +%d @@%s%s\n", left_start, left_len, right_start, state->prototype[0] ? " " : "", state->prototype[0] ? state->prototype : ""); } else { rc = fprintf(dest, "@@ -%d,%d +%d,%d @@%s%s\n", left_start, left_len, right_start, right_len, state->prototype[0] ? " " : "", state->prototype[0] ? state->prototype : ""); } if (rc < 0) return errno; if (outinfo) { ARRAYLIST_ADD(offp, outinfo->line_offsets); if (offp == NULL) return ENOMEM; outoff += rc; *offp = outoff; ARRAYLIST_ADD(typep, outinfo->line_types); if (typep == NULL) return ENOMEM; *typep = DIFF_LINE_HUNK; } /* Got the absolute line numbers where to start printing, and the index * of the interesting (non-context) chunk. * To print context lines above the interesting chunk, nipping on the * previous chunk index may be necessary. * It is guaranteed to be only context lines where left == right, so it * suffices to look on the left. */ const struct diff_chunk *first_chunk; int chunk_start_line; first_chunk = &result->chunks.head[cc->chunk.start]; chunk_start_line = diff_atom_root_idx(result->left, first_chunk->left_start); if (cc->left.start < chunk_start_line) { rc = diff_output_lines(outinfo, dest, " ", &result->left->atoms.head[cc->left.start], chunk_start_line - cc->left.start); if (rc) return rc; } /* Now write out all the joined chunks and contexts between them */ int c_idx; for (c_idx = cc->chunk.start; c_idx < cc->chunk.end; c_idx++) { const struct diff_chunk *c = &result->chunks.head[c_idx]; if (c->left_count && c->right_count) rc = diff_output_lines(outinfo, dest, c->solved ? " " : "?", c->left_start, c->left_count); else if (c->left_count && !c->right_count) rc = diff_output_lines(outinfo, dest, c->solved ? "-" : "?", c->left_start, c->left_count); else if (c->right_count && !c->left_count) rc = diff_output_lines(outinfo, dest, c->solved ? "+" : "?", c->right_start, c->right_count); if (rc) return rc; if (cc->chunk.end == result->chunks.len) { rc = diff_output_trailing_newline_msg(outinfo, dest, c); if (rc != DIFF_RC_OK) return rc; } } /* Trailing context? */ const struct diff_chunk *last_chunk; int chunk_end_line; last_chunk = &result->chunks.head[cc->chunk.end - 1]; chunk_end_line = diff_atom_root_idx(result->left, last_chunk->left_start + last_chunk->left_count); if (cc->left.end > chunk_end_line) { rc = diff_output_lines(outinfo, dest, " ", &result->left->atoms.head[chunk_end_line], cc->left.end - chunk_end_line); if (rc) return rc; if (cc->left.end == result->left->atoms.len) { rc = diff_output_trailing_newline_msg(outinfo, dest, &result->chunks.head[result->chunks.len - 1]); if (rc != DIFF_RC_OK) return rc; } } return DIFF_RC_OK; } int diff_output_unidiff_chunk(struct diff_output_info **output_info, FILE *dest, struct diff_output_unidiff_state *state, const struct diff_input_info *info, const struct diff_result *result, const struct diff_chunk_context *cc) { struct diff_output_info *outinfo = NULL; int flags = (result->left->root->diff_flags | result->right->root->diff_flags); bool show_function_prototypes = (flags & DIFF_FLAG_SHOW_PROTOTYPES); if (output_info) { *output_info = diff_output_info_alloc(); if (*output_info == NULL) return ENOMEM; outinfo = *output_info; } return output_unidiff_chunk(outinfo, dest, state, info, result, false, show_function_prototypes, cc); } int diff_output_unidiff(struct diff_output_info **output_info, FILE *dest, const struct diff_input_info *info, const struct diff_result *result, unsigned int context_lines) { struct diff_output_unidiff_state *state; struct diff_chunk_context cc = {}; struct diff_output_info *outinfo = NULL; int atomizer_flags = (result->left->atomizer_flags| result->right->atomizer_flags); int flags = (result->left->root->diff_flags | result->right->root->diff_flags); bool show_function_prototypes = (flags & DIFF_FLAG_SHOW_PROTOTYPES); bool force_text = (flags & DIFF_FLAG_FORCE_TEXT_DATA); bool have_binary = (atomizer_flags & DIFF_ATOMIZER_FOUND_BINARY_DATA); off_t outoff = 0, *offp; uint8_t *typep; int rc, i; if (!result) return EINVAL; if (result->rc != DIFF_RC_OK) return result->rc; if (output_info) { *output_info = diff_output_info_alloc(); if (*output_info == NULL) return ENOMEM; outinfo = *output_info; } if (have_binary && !force_text) { for (i = 0; i < result->chunks.len; i++) { struct diff_chunk *c = &result->chunks.head[i]; enum diff_chunk_type t = diff_chunk_type(c); if (t != CHUNK_MINUS && t != CHUNK_PLUS) continue; if (outinfo && outinfo->line_offsets.len > 0) { unsigned int idx = outinfo->line_offsets.len - 1; outoff = outinfo->line_offsets.head[idx]; } rc = fprintf(dest, "Binary files %s and %s differ\n", diff_output_get_label_left(info), diff_output_get_label_right(info)); if (outinfo) { ARRAYLIST_ADD(offp, outinfo->line_offsets); if (offp == NULL) return ENOMEM; outoff += rc; *offp = outoff; ARRAYLIST_ADD(typep, outinfo->line_types); if (typep == NULL) return ENOMEM; *typep = DIFF_LINE_NONE; } break; } return DIFF_RC_OK; } state = diff_output_unidiff_state_alloc(); if (state == NULL) { if (output_info) { diff_output_info_free(*output_info); *output_info = NULL; } return ENOMEM; } #if DEBUG unsigned int check_left_pos, check_right_pos; check_left_pos = 0; check_right_pos = 0; for (i = 0; i < result->chunks.len; i++) { struct diff_chunk *c = &result->chunks.head[i]; enum diff_chunk_type t = diff_chunk_type(c); debug("[%d] %s lines L%d R%d @L %d @R %d\n", i, (t == CHUNK_MINUS ? "minus" : (t == CHUNK_PLUS ? "plus" : (t == CHUNK_SAME ? "same" : "?"))), c->left_count, c->right_count, c->left_start ? diff_atom_root_idx(result->left, c->left_start) : -1, c->right_start ? diff_atom_root_idx(result->right, c->right_start) : -1); assert(check_left_pos == diff_atom_root_idx(result->left, c->left_start)); assert(check_right_pos == diff_atom_root_idx(result->right, c->right_start)); check_left_pos += c->left_count; check_right_pos += c->right_count; } assert(check_left_pos == result->left->atoms.len); assert(check_right_pos == result->right->atoms.len); #endif for (i = 0; i < result->chunks.len; i++) { struct diff_chunk *c = &result->chunks.head[i]; enum diff_chunk_type t = diff_chunk_type(c); struct diff_chunk_context next; if (t != CHUNK_MINUS && t != CHUNK_PLUS) continue; if (diff_chunk_context_empty(&cc)) { /* These are the first lines being printed. * Note down the start point, any number of subsequent * chunks may be joined up to this unidiff chunk by * context lines or by being directly adjacent. */ diff_chunk_context_get(&cc, result, i, context_lines); debug("new chunk to be printed:" " chunk %d-%d left %d-%d right %d-%d\n", cc.chunk.start, cc.chunk.end, cc.left.start, cc.left.end, cc.right.start, cc.right.end); continue; } /* There already is a previous chunk noted down for being * printed. Does it join up with this one? */ diff_chunk_context_get(&next, result, i, context_lines); debug("new chunk to be printed:" " chunk %d-%d left %d-%d right %d-%d\n", next.chunk.start, next.chunk.end, next.left.start, next.left.end, next.right.start, next.right.end); if (diff_chunk_contexts_touch(&cc, &next)) { /* This next context touches or overlaps the previous * one, join. */ diff_chunk_contexts_merge(&cc, &next); debug("new chunk to be printed touches previous chunk," " now: left %d-%d right %d-%d\n", cc.left.start, cc.left.end, cc.right.start, cc.right.end); continue; } /* No touching, so the previous context is complete with a gap * between it and this next one. Print the previous one and * start fresh here. */ debug("new chunk to be printed does not touch previous chunk;" " print left %d-%d right %d-%d\n", cc.left.start, cc.left.end, cc.right.start, cc.right.end); output_unidiff_chunk(outinfo, dest, state, info, result, true, show_function_prototypes, &cc); cc = next; debug("new unprinted chunk is left %d-%d right %d-%d\n", cc.left.start, cc.left.end, cc.right.start, cc.right.end); } if (!diff_chunk_context_empty(&cc)) output_unidiff_chunk(outinfo, dest, state, info, result, true, show_function_prototypes, &cc); diff_output_unidiff_state_free(state); return DIFF_RC_OK; } got-portable-0.101/lib/pollfd.c0000664000175100017510000000575514644144735012021 /* * Copyright (c) 2018, 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include "got_error.h" #include "got_lib_poll.h" const struct got_error * got_poll_fd(int fd, int events, int timeout) { struct pollfd pfd[1]; struct timespec ts; sigset_t sigset; int n; pfd[0].fd = fd; pfd[0].events = events; ts.tv_sec = timeout; ts.tv_nsec = 0; if (sigemptyset(&sigset) == -1) return got_error_from_errno("sigemptyset"); if (sigaddset(&sigset, SIGWINCH) == -1) return got_error_from_errno("sigaddset"); n = ppoll(pfd, 1, timeout == INFTIM ? NULL : &ts, &sigset); if (n == -1) return got_error_from_errno("ppoll"); if (n == 0) { if (pfd[0].revents & POLLHUP) return got_error(GOT_ERR_EOF); return got_error(GOT_ERR_TIMEOUT); } if (pfd[0].revents & (POLLERR | POLLNVAL)) return got_error_from_errno("poll error"); if (pfd[0].revents & events) return NULL; if (pfd[0].revents & POLLHUP) return got_error(GOT_ERR_EOF); return got_error(GOT_ERR_INTERRUPT); } const struct got_error * got_poll_read_full_timeout(int fd, size_t *len, void *buf, size_t bufsize, size_t minbytes, int timeout) { const struct got_error *err = NULL; size_t have = 0; ssize_t r; if (minbytes > bufsize) return got_error(GOT_ERR_NO_SPACE); while (have < minbytes) { err = got_poll_fd(fd, POLLIN, timeout); if (err) return err; r = read(fd, buf + have, bufsize - have); if (r == -1) return got_error_from_errno("read"); if (r == 0) return got_error(GOT_ERR_EOF); have += r; } *len = have; return NULL; } const struct got_error * got_poll_read_full(int fd, size_t *len, void *buf, size_t bufsize, size_t minbytes) { return got_poll_read_full_timeout(fd, len, buf, bufsize, minbytes, INFTIM); } const struct got_error * got_poll_write_full(int fd, const void *buf, off_t len) { const struct got_error *err = NULL; off_t wlen = 0; ssize_t w = 0; while (wlen != len) { if (wlen > 0) { err = got_poll_fd(fd, POLLOUT, INFTIM); if (err) return err; } w = write(fd, buf + wlen, len - wlen); if (w == -1) { if (errno != EAGAIN) return got_error_from_errno("write"); } else wlen += w; } return NULL; } got-portable-0.101/lib/got_lib_worktree.h0000644000175100017510000001052414644143163014065 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct got_worktree { char *root_path; const char *meta_dir; char *repo_path; int root_fd; char *path_prefix; struct got_object_id *base_commit_id; char *head_ref_name; uuid_t uuid; /* * File descriptor for the lock file, open while a work tree is open. * When a work tree is opened, a shared lock on the lock file is * acquired with flock(2). This shared lock is held until the work * tree is closed, i.e. throughout the lifetime of any operation * which uses a work tree. * Before any modifications are made to the on-disk state of work * tree meta data, tracked files, or directory tree structure, this * shared lock must be upgraded to an exclusive lock. */ int lockfd; /* Absolute path to worktree's got.conf file. */ char *gotconfig_path; /* Settings read from got.conf. */ struct got_gotconfig *gotconfig; }; struct got_commitable { char *path; char *in_repo_path; char *ondisk_path; unsigned char status; unsigned char staged_status; struct got_object_id *blob_id; struct got_object_id *base_blob_id; struct got_object_id *staged_blob_id; struct got_object_id *base_commit_id; mode_t mode; int flags; #define GOT_COMMITABLE_ADDED 0x01 }; /* Also defined in got_worktree.h */ #ifndef GOT_WORKTREE_GOT_DIR #define GOT_WORKTREE_GOT_DIR ".got" #endif #ifndef GOT_WORKTREE_CVG_DIR #define GOT_WORKTREE_CVG_DIR ".cvg" #endif #define GOT_WORKTREE_FILE_INDEX "file-index" #define GOT_WORKTREE_REPOSITORY "repository" #define GOT_WORKTREE_PATH_PREFIX "path-prefix" #define GOT_WORKTREE_HEAD_REF "head-ref" #define GOT_WORKTREE_BASE_COMMIT "base-commit" #define GOT_WORKTREE_LOCK "lock" #define GOT_WORKTREE_FORMAT "format" #define GOT_WORKTREE_UUID "uuid" #define GOT_WORKTREE_HISTEDIT_SCRIPT "histedit-script" #define GOT_WORKTREE_FORMAT_VERSION 1 #define GOT_WORKTREE_INVALID_COMMIT_ID GOT_SHA1_STRING_ZERO #define GOT_WORKTREE_BASE_REF_PREFIX "refs/got/worktree/base" /* Temporary branch which accumulates commits during a rebase operation. */ #define GOT_WORKTREE_REBASE_TMP_REF_PREFIX "refs/got/worktree/rebase/tmp" /* Symbolic reference pointing at the name of the new base branch. */ #define GOT_WORKTREE_NEWBASE_REF_PREFIX "refs/got/worktree/rebase/newbase" /* Symbolic reference pointing at the name of the branch being rebased. */ #define GOT_WORKTREE_REBASE_BRANCH_REF_PREFIX "refs/got/worktree/rebase/branch" /* Reference pointing at the ID of the current commit being rebased. */ #define GOT_WORKTREE_REBASE_COMMIT_REF_PREFIX "refs/got/worktree/rebase/commit" /* Temporary branch which accumulates commits during a histedit operation. */ #define GOT_WORKTREE_HISTEDIT_TMP_REF_PREFIX "refs/got/worktree/histedit/tmp" /* Symbolic reference pointing at the name of the branch being edited. */ #define GOT_WORKTREE_HISTEDIT_BRANCH_REF_PREFIX \ "refs/got/worktree/histedit/branch" /* Reference pointing at the ID of the work tree's pre-edit base commit. */ #define GOT_WORKTREE_HISTEDIT_BASE_COMMIT_REF_PREFIX \ "refs/got/worktree/histedit/base-commit" /* Reference pointing at the ID of the current commit being edited. */ #define GOT_WORKTREE_HISTEDIT_COMMIT_REF_PREFIX \ "refs/got/worktree/histedit/commit" /* Symbolic reference pointing at the name of the merge source branch. */ #define GOT_WORKTREE_MERGE_BRANCH_REF_PREFIX "refs/got/worktree/merge/branch" /* Reference pointing at the ID of the merge source branches's tip commit. */ #define GOT_WORKTREE_MERGE_COMMIT_REF_PREFIX "refs/got/worktree/merge/commit" /* Reference pointing to temporary commits that may need trivial rebasing. */ #define GOT_WORKTREE_COMMIT_REF_PREFIX "refs/got/worktree/commit" got-portable-0.101/lib/got_lib_object_parse.h0000644000175100017510000000456714644143163014675 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct got_pathlist_head; const struct got_error *got_object_type_label(const char **, int); struct got_commit_object *got_object_commit_alloc_partial(void); struct got_tree_entry *got_alloc_tree_entry_partial(void); const struct got_error *got_object_parse_commit(struct got_commit_object **, char *, size_t); const struct got_error *got_object_read_commit(struct got_commit_object **, int, struct got_object_id *, size_t); struct got_parsed_tree_entry { const char *name; /* Points to name in parsed buffer */ size_t namelen; /* strlen(name) */ mode_t mode; /* Mode parsed from tree buffer. */ uint8_t *id; /* Points to ID in parsed tree buffer. */ }; const struct got_error *got_object_parse_tree_entry( struct got_parsed_tree_entry *, size_t *, char *, size_t); const struct got_error *got_object_parse_tree(struct got_parsed_tree_entry **, size_t *, size_t *, uint8_t *, size_t); const struct got_error *got_object_read_tree(struct got_parsed_tree_entry **, size_t *, size_t *, uint8_t **, int, struct got_object_id *); const struct got_error *got_object_parse_tag(struct got_tag_object **, uint8_t *, size_t); const struct got_error *got_object_read_tag(struct got_tag_object **, int, struct got_object_id *, size_t); struct got_pack; struct got_packidx; struct got_inflate_checksum; const struct got_error *got_object_parse_header(struct got_object **, char *, size_t); const struct got_error *got_object_read_header(struct got_object **, int); const struct got_error *got_object_read_raw(uint8_t **, off_t *, size_t *, size_t, int, struct got_object_id *, int); got-portable-0.101/lib/got_lib_dial.h0000664000175100017510000000270214644143163013135 /* * Copyright (c) 2019 Ori Bernstein * Copyright (c) 2021 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #define GOT_DIAL_CMD_SEND "git-receive-pack" #define GOT_DIAL_CMD_FETCH "git-upload-pack" const struct got_error *got_dial_git(int *newfd, const char *host, const char *port, const char *path, const char *command); const struct got_error *got_dial_ssh(pid_t *newpid, int *newfd, const char *host, const char *port, const char *path, const char *command, int verbosity); const struct got_error *got_dial_http(pid_t *newpid, int *newfd, const char *host, const char *port, const char *path, int, int); const struct got_error *got_dial_parse_command(char **command, char **repo_path, const char *gitcmd); got-portable-0.101/lib/got_lib_poll.h0000664000175100017510000000214214644143163013170 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ const struct got_error *got_poll_fd(int fd, int events, int timeout); const struct got_error *got_poll_read_full_timeout(int, size_t *, void *, size_t, size_t, int); const struct got_error *got_poll_read_full(int, size_t *, void *, size_t, size_t); const struct got_error *got_poll_write_full(int, const void *, off_t); got-portable-0.101/lib/got_lib_gotconfig.h0000644000175100017510000000216514644143163014204 /* * Copyright (c) 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #define GOT_GOTCONFIG_FILENAME "got.conf" struct got_gotconfig { char *author; int nremotes; struct got_remote_repo *remotes; char *allowed_signers_file; char *revoked_signers_file; char *signer_id; }; const struct got_error *got_gotconfig_read(struct got_gotconfig **, const char *); void got_gotconfig_free(struct got_gotconfig *); got-portable-0.101/lib/pkt.c0000664000175100017510000001073614644143163011324 /* * Copyright (c) 2019 Ori Bernstein * Copyright (c) 2021 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include "got_error.h" #include "got_lib_pkt.h" #include "got_lib_poll.h" const struct got_error * got_pkt_readn(ssize_t *off, int fd, void *buf, size_t n, int timeout) { const struct got_error *err; size_t len; err = got_poll_read_full_timeout(fd, &len, buf, n, n, timeout); if (err) return err; /* XXX size_t -> ssize_t */ if (len > SSIZE_MAX) return got_error(GOT_ERR_RANGE); *off = len; return NULL; } const struct got_error * got_pkt_flushpkt(int fd, int chattygot) { ssize_t w; if (chattygot > 1) fprintf(stderr, "%s: writepkt: 0000\n", getprogname()); w = write(fd, "0000", 4); if (w == -1) return got_error_from_errno("write"); if (w != 4) return got_error(GOT_ERR_IO); return NULL; } const struct got_error * got_pkt_readlen(int *len, const char *str, int chattygot) { int i; *len = 0; for (i = 0; i < 4; i++) { if ('0' <= str[i] && str[i] <= '9') { *len *= 16; *len += str[i] - '0'; } else if ('a' <= str[i] && str[i] <= 'f') { *len *= 16; *len += str[i] - 'a' + 10; } else { if (chattygot) fprintf(stderr, "%s: bad length: '.4%s'\n", getprogname(), str); return got_error_msg(GOT_ERR_BAD_PACKET, "packet length has invalid format"); } } return NULL; } /* * Packet header contains a 4-byte hexstring which specifies the length * of data which follows. */ const struct got_error * got_pkt_readhdr(int *datalen, int fd, int chattygot, int timeout) { static const struct got_error *err; char lenstr[4]; ssize_t r; int n; *datalen = 0; err = got_pkt_readn(&r, fd, lenstr, 4, timeout); if (err) return err; if (r == 0) { /* implicit "0000" */ if (chattygot > 1) fprintf(stderr, "%s: readpkt: 0000\n", getprogname()); return NULL; } if (r != 4) return got_error_msg(GOT_ERR_BAD_PACKET, "wrong packet header length"); err = got_pkt_readlen(&n, lenstr, chattygot); if (n == 0) return err; if (n <= 4) return got_error_msg(GOT_ERR_BAD_PACKET, "packet too short"); n -= 4; *datalen = n; return NULL; } const struct got_error * got_pkt_readpkt(int *outlen, int fd, char *buf, int buflen, int chattygot, int timeout) { const struct got_error *err = NULL; int datalen, i; ssize_t n; err = got_pkt_readhdr(&datalen, fd, chattygot, timeout); if (err) return err; if (datalen > buflen) return got_error(GOT_ERR_NO_SPACE); err = got_pkt_readn(&n, fd, buf, datalen, timeout); if (err) return err; if (n != datalen) return got_error_msg(GOT_ERR_BAD_PACKET, "short packet"); if (chattygot > 1) { fprintf(stderr, "%s: readpkt: %zd:\t", getprogname(), n); for (i = 0; i < n; i++) { if (isprint((unsigned char)buf[i])) fputc(buf[i], stderr); else fprintf(stderr, "[0x%.2x]", buf[i]); } fputc('\n', stderr); } *outlen = n; return NULL; } const struct got_error * got_pkt_writepkt(int fd, char *buf, int nbuf, int chattygot) { char len[5]; int i, ret; ssize_t w; ret = snprintf(len, sizeof(len), "%04x", nbuf + 4); if (ret < 0 || (size_t)ret >= sizeof(len)) return got_error(GOT_ERR_NO_SPACE); w = write(fd, len, 4); if (w == -1) return got_error_from_errno("write"); if (w != 4) return got_error(GOT_ERR_IO); w = write(fd, buf, nbuf); if (w == -1) return got_error_from_errno("write"); if (w != nbuf) return got_error(GOT_ERR_IO); if (chattygot > 1) { fprintf(stderr, "%s: writepkt: %s:\t", getprogname(), len); for (i = 0; i < nbuf; i++) { if (isprint((unsigned char)buf[i])) fputc(buf[i], stderr); else fprintf(stderr, "[0x%.2x]", buf[i]); } fputc('\n', stderr); } return NULL; } got-portable-0.101/lib/read_gotconfig_privsep.c0000664000175100017510000000756414644144735015263 /* * Copyright (c) 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_repository.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_privsep.h" #include "got_lib_gotconfig.h" #include "got_gotconfig.h" const struct got_error * got_gotconfig_read(struct got_gotconfig **conf, const char *gotconfig_path) { const struct got_error *err = NULL, *child_err = NULL; int fd = -1; int imsg_fds[2] = { -1, -1 }; pid_t pid; struct imsgbuf *ibuf = NULL; *conf = calloc(1, sizeof(**conf)); if (*conf == NULL) return got_error_from_errno("calloc"); fd = open(gotconfig_path, O_RDONLY | O_CLOEXEC); if (fd == -1) { if (errno == ENOENT) return NULL; err = got_error_from_errno2("open", gotconfig_path); goto done; } ibuf = calloc(1, sizeof(*ibuf)); if (ibuf == NULL) { err = got_error_from_errno("calloc"); goto done; } if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) { err = got_error_from_errno("socketpair"); goto done; } pid = fork(); if (pid == -1) { err = got_error_from_errno("fork"); goto done; } else if (pid == 0) { got_privsep_exec_child(imsg_fds, GOT_PATH_PROG_READ_GOTCONFIG, gotconfig_path); /* not reached */ } if (close(imsg_fds[1]) == -1) { err = got_error_from_errno("close"); goto done; } imsg_fds[1] = -1; imsg_init(ibuf, imsg_fds[0]); err = got_privsep_send_gotconfig_parse_req(ibuf, fd); if (err) goto done; fd = -1; err = got_privsep_send_gotconfig_author_req(ibuf); if (err) goto done; err = got_privsep_recv_gotconfig_str(&(*conf)->author, ibuf); if (err) goto done; err = got_privsep_send_gotconfig_allowed_signers_req(ibuf); if (err) goto done; err = got_privsep_recv_gotconfig_str(&(*conf)->allowed_signers_file, ibuf); if (err) goto done; err = got_privsep_send_gotconfig_revoked_signers_req(ibuf); if (err) goto done; err = got_privsep_recv_gotconfig_str(&(*conf)->revoked_signers_file, ibuf); if (err) goto done; err = got_privsep_send_gotconfig_signer_id_req(ibuf); if (err) goto done; err = got_privsep_recv_gotconfig_str(&(*conf)->signer_id, ibuf); if (err) goto done; err = got_privsep_send_gotconfig_remotes_req(ibuf); if (err) goto done; err = got_privsep_recv_gotconfig_remotes(&(*conf)->remotes, &(*conf)->nremotes, ibuf); if (err) goto done; err = got_privsep_send_stop(imsg_fds[0]); child_err = got_privsep_wait_for_child(pid); if (child_err && err == NULL) err = child_err; done: if (imsg_fds[0] != -1 && close(imsg_fds[0]) == -1 && err == NULL) err = got_error_from_errno("close"); if (imsg_fds[1] != -1 && close(imsg_fds[1]) == -1 && err == NULL) err = got_error_from_errno("close"); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno2("close", gotconfig_path); if (err) { got_gotconfig_free(*conf); *conf = NULL; } free(ibuf); return err; } got-portable-0.101/lib/got_lib_pkt.h0000664000175100017510000000262014644143163013021 /* * Copyright (c) 2019 Ori Bernstein * Copyright (c) 2021 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #define GOT_PKT_MAX 65536 const struct got_error *got_pkt_readn(ssize_t *off, int fd, void *buf, size_t n, int timeout); const struct got_error *got_pkt_flushpkt(int fd, int chattygot); const struct got_error *got_pkt_readlen(int *len, const char *str, int chattygot); const struct got_error *got_pkt_readhdr(int *datalen, int fd, int chattygot, int timeout); const struct got_error *got_pkt_readpkt(int *outlen, int fd, char *buf, int buflen, int chattygot, int timeout); const struct got_error *got_pkt_writepkt(int fd, char *buf, int nbuf, int chattygot); got-portable-0.101/lib/diff_main.h0000644000175100017510000002257514644143163012451 /* Generic infrastructure to implement various diff algorithms. */ /* * Copyright (c) 2020 Neels Hofmeyr * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct diff_range { int start; int end; }; /* List of all possible return codes of a diff invocation. */ #define DIFF_RC_USE_DIFF_ALGO_FALLBACK -1 #define DIFF_RC_OK 0 /* Any positive return values are errno values from sys/errno.h */ struct diff_atom { struct diff_data *root; /* back pointer to root diff data */ off_t pos; /* set whether memory-mapped or not */ const uint8_t *at; /* only set if memory-mapped */ off_t len; /* This hash is just a very cheap speed up for finding *mismatching* * atoms. When hashes match, we still need to compare entire atoms to * find out whether they are indeed identical or not. * Calculated over all atom bytes with diff_atom_hash_update(). */ unsigned int hash; }; /* Mix another atom_byte into the provided hash value and return the result. * The hash value passed in for the first byte of the atom must be zero. */ unsigned int diff_atom_hash_update(unsigned int hash, unsigned char atom_byte); /* Compare two atoms for equality. Return 0 on success, or errno on failure. * Set cmp to -1, 0, or 1, just like strcmp(). */ int diff_atom_cmp(int *cmp, const struct diff_atom *left, const struct diff_atom *right); /* The atom's index in the entire file. For atoms divided by lines of text, this * yields the line number (starting with 0). Also works for diff_data that * reference only a subsection of a file, always reflecting the global position * in the file (and not the relative position within the subsection). */ #define diff_atom_root_idx(DIFF_DATA, ATOM) \ ((ATOM) && ((ATOM) >= (DIFF_DATA)->root->atoms.head) \ ? (unsigned int)((ATOM) - ((DIFF_DATA)->root->atoms.head)) \ : (DIFF_DATA)->root->atoms.len) /* The atom's index within DIFF_DATA. For atoms divided by lines of text, this * yields the line number (starting with 0). */ #define diff_atom_idx(DIFF_DATA, ATOM) \ ((ATOM) && ((ATOM) >= (DIFF_DATA)->atoms.head) \ ? (unsigned int)((ATOM) - ((DIFF_DATA)->atoms.head)) \ : (DIFF_DATA)->atoms.len) #define foreach_diff_atom(ATOM, FIRST_ATOM, COUNT) \ for ((ATOM) = (FIRST_ATOM); \ (ATOM) \ && ((ATOM) >= (FIRST_ATOM)) \ && ((ATOM) - (FIRST_ATOM) < (COUNT)); \ (ATOM)++) #define diff_data_foreach_atom(ATOM, DIFF_DATA) \ foreach_diff_atom(ATOM, (DIFF_DATA)->atoms.head, (DIFF_DATA)->atoms.len) #define diff_data_foreach_atom_from(FROM, ATOM, DIFF_DATA) \ for ((ATOM) = (FROM); \ (ATOM) \ && ((ATOM) >= (DIFF_DATA)->atoms.head) \ && ((ATOM) - (DIFF_DATA)->atoms.head < (DIFF_DATA)->atoms.len); \ (ATOM)++) #define diff_data_foreach_atom_backwards_from(FROM, ATOM, DIFF_DATA) \ for ((ATOM) = (FROM); \ (ATOM) \ && ((ATOM) >= (DIFF_DATA)->atoms.head) \ && ((ATOM) - (DIFF_DATA)->atoms.head >= 0); \ (ATOM)--) /* For each file, there is a "root" struct diff_data referencing the entire * file, which the atoms are parsed from. In recursion of diff algorithm, there * may be "child" struct diff_data only referencing a subsection of the file, * re-using the atoms parsing. For "root" structs, atoms_allocated will be * nonzero, indicating that the array of atoms is owned by that struct. For * "child" structs, atoms_allocated == 0, to indicate that the struct is * referencing a subset of atoms. */ struct diff_data { FILE *f; /* if root diff_data and not memory-mapped */ off_t pos; /* if not memory-mapped */ const uint8_t *data; /* if memory-mapped */ off_t len; int atomizer_flags; ARRAYLIST(struct diff_atom) atoms; struct diff_data *root; struct diff_data *current; void *algo_data; int diff_flags; int err; }; /* Flags set by file atomizer. */ #define DIFF_ATOMIZER_FOUND_BINARY_DATA 0x00000001 /* Flags set by caller of diff_main(). */ #define DIFF_FLAG_IGNORE_WHITESPACE 0x00000001 #define DIFF_FLAG_SHOW_PROTOTYPES 0x00000002 #define DIFF_FLAG_FORCE_TEXT_DATA 0x00000004 void diff_data_free(struct diff_data *diff_data); struct diff_chunk; typedef ARRAYLIST(struct diff_chunk) diff_chunk_arraylist_t; struct diff_result { int rc; /* * Pointers to diff data passed in via diff_main. * Do not free these diff_data before freeing the diff_result struct. */ struct diff_data *left; struct diff_data *right; diff_chunk_arraylist_t chunks; }; enum diff_chunk_type { CHUNK_EMPTY, CHUNK_PLUS, CHUNK_MINUS, CHUNK_SAME, CHUNK_ERROR, }; enum diff_chunk_type diff_chunk_type(const struct diff_chunk *c); struct diff_state; /* Signature of a utility function to divide a file into diff atoms. * An example is diff_atomize_text_by_line() in diff_atomize_text.c. * * func_data: context pointer (free to be used by implementation). * d: struct diff_data with d->data and d->len already set up, and * d->atoms to be created and d->atomizer_flags to be set up. */ typedef int (*diff_atomize_func_t)(void *func_data, struct diff_data *d); extern int diff_atomize_text_by_line(void *func_data, struct diff_data *d); struct diff_algo_config; typedef int (*diff_algo_impl_t)( const struct diff_algo_config *algo_config, struct diff_state *state); /* Form a result with all left-side removed and all right-side added, i.e. no * actual diff algorithm involved. */ int diff_algo_none(const struct diff_algo_config *algo_config, struct diff_state *state); /* Myers Diff tracing from the start all the way through to the end, requiring * quadratic amounts of memory. This can fail if the required space surpasses * algo_config->permitted_state_size. */ extern int diff_algo_myers(const struct diff_algo_config *algo_config, struct diff_state *state); /* Myers "Divide et Impera": tracing forwards from the start and backwards from * the end to find a midpoint that divides the problem into smaller chunks. * Requires only linear amounts of memory. */ extern int diff_algo_myers_divide( const struct diff_algo_config *algo_config, struct diff_state *state); /* Patience Diff algorithm, which divides a larger diff into smaller chunks. For * very specific scenarios, it may lead to a complete diff result by itself, but * needs a fallback algo to solve chunks that don't have common-unique atoms. */ extern int diff_algo_patience( const struct diff_algo_config *algo_config, struct diff_state *state); /* Diff algorithms to use, possibly nested. For example: * * struct diff_algo_config myers, patience, myers_divide; * * myers = (struct diff_algo_config){ * .impl = diff_algo_myers, * .permitted_state_size = 32 * 1024 * 1024, * // When too large, do diff_algo_patience: * .fallback_algo = &patience, * }; * * const struct diff_algo_config patience = (struct diff_algo_config){ * .impl = diff_algo_patience, * // After subdivision, do Patience again: * .inner_algo = &patience, * // If subdivision failed, do Myers Divide et Impera: * .fallback_algo = &myers_then_myers_divide, * }; * * const struct diff_algo_config myers_divide = (struct diff_algo_config){ * .impl = diff_algo_myers_divide, * // When division succeeded, start from the top: * .inner_algo = &myers_then_myers_divide, * // (fallback_algo = NULL implies diff_algo_none). * }; * struct diff_config config = { * .algo = &myers, * ... * }; * diff_main(&config, ...); */ struct diff_algo_config { diff_algo_impl_t impl; /* Fail this algo if it would use more than this amount of memory, and * instead use fallback_algo (diff_algo_myers). permitted_state_size == * 0 means no limitation. */ size_t permitted_state_size; /* For algorithms that divide into smaller chunks, use this algorithm to * solve the divided chunks. */ const struct diff_algo_config *inner_algo; /* If the algorithm fails (e.g. diff_algo_myers_if_small needs too large * state, or diff_algo_patience can't find any common-unique atoms), * then use this algorithm instead. */ const struct diff_algo_config *fallback_algo; }; struct diff_config { diff_atomize_func_t atomize_func; void *atomize_func_data; const struct diff_algo_config *algo; /* How deep to step into subdivisions of a source file, a paranoia / * safety measure to guard against infinite loops through diff * algorithms. When the maximum recursion is reached, employ * diff_algo_none (i.e. remove all left atoms and add all right atoms). */ unsigned int max_recursion_depth; }; int diff_atomize_file(struct diff_data *d, const struct diff_config *config, FILE *f, const uint8_t *data, off_t len, int diff_flags); struct diff_result *diff_main(const struct diff_config *config, struct diff_data *left, struct diff_data *right); void diff_result_free(struct diff_result *result); int diff_result_contains_printable_chunks(struct diff_result *result); got-portable-0.101/lib/got_lib_ratelimit.h0000644000175100017510000000177214644143163014222 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct got_ratelimit { struct timespec last; struct timespec interval; }; void got_ratelimit_init(struct got_ratelimit *, time_t, unsigned int); const struct got_error *got_ratelimit_check(int *, struct got_ratelimit *); got-portable-0.101/lib/bloom.c0000644000175100017510000001143114644143163011625 /* * Copyright (c) 2012-2019, Jyri J. Virkki * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Obtained from https://github.com/jvirkki/libbloom */ /* * Refer to bloom.h for documentation on the public interfaces. */ #include #include #include #include #include #include #include #include #include #include #include "bloom.h" #include "murmurhash2.h" #define MAKESTRING(n) STRING(n) #define STRING(n) #n inline static int test_bit_set_bit(unsigned char * buf, unsigned int x, int set_bit) { unsigned int byte = x >> 3; unsigned char c = buf[byte]; // expensive memory access unsigned int mask = 1 << (x % 8); if (c & mask) { return 1; } else { if (set_bit) { buf[byte] = c | mask; } return 0; } } static int bloom_check_add(struct bloom * bloom, const void * buffer, int len, int add) { if (bloom->ready == 0) { printf("bloom at %p not initialized!\n", (void *)bloom); return -1; } int hits = 0; register unsigned int a = murmurhash2(buffer, len, bloom->seed); register unsigned int b = murmurhash2(buffer, len, a); register unsigned int x; register unsigned int i; for (i = 0; i < bloom->hashes; i++) { x = (a + i*b) % bloom->bits; if (test_bit_set_bit(bloom->bf, x, add)) { hits++; } else if (!add) { // Don't care about the presence of all the bits. Just our own. return 0; } } if (hits == bloom->hashes) { return 1; // 1 == element already in (or collision) } return 0; } int bloom_init_size(struct bloom * bloom, int entries, double error, unsigned int cache_size) { return bloom_init(bloom, entries, error); } int bloom_init(struct bloom * bloom, int entries, double error) { bloom->ready = 0; bloom->seed = arc4random(); if (entries < 1000 || error == 0) { return 1; } bloom->entries = entries; bloom->error = error; double num = log(bloom->error); double denom = 0.480453013918201; // ln(2)^2 bloom->bpe = -(num / denom); double dentries = (double)entries; bloom->bits = (int)(dentries * bloom->bpe); if (bloom->bits % 8) { bloom->bytes = (bloom->bits / 8) + 1; } else { bloom->bytes = bloom->bits / 8; } bloom->hashes = (int)ceil(0.693147180559945 * bloom->bpe); // ln(2) bloom->bf = (unsigned char *)calloc(bloom->bytes, sizeof(unsigned char)); if (bloom->bf == NULL) { // LCOV_EXCL_START return 1; } // LCOV_EXCL_STOP bloom->ready = 1; return 0; } int bloom_check(struct bloom * bloom, const void * buffer, int len) { return bloom_check_add(bloom, buffer, len, 0); } int bloom_add(struct bloom * bloom, const void * buffer, int len) { return bloom_check_add(bloom, buffer, len, 1); } void bloom_print(struct bloom * bloom) { printf("bloom at %p\n", (void *)bloom); printf(" ->entries = %d\n", bloom->entries); printf(" ->error = %f\n", bloom->error); printf(" ->bits = %d\n", bloom->bits); printf(" ->bits per elem = %f\n", bloom->bpe); printf(" ->bytes = %d\n", bloom->bytes); printf(" ->hash functions = %d\n", bloom->hashes); } void bloom_free(struct bloom * bloom) { if (bloom->ready) { free(bloom->bf); } bloom->ready = 0; } int bloom_reset(struct bloom * bloom) { if (!bloom->ready) return 1; memset(bloom->bf, 0, bloom->bytes); return 0; } got-portable-0.101/lib/got_lib_object_create.h0000644000175100017510000000255614644143163015022 /* * Copyright (c) 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ const struct got_error *got_object_blob_file_create(struct got_object_id **, FILE **, off_t *, const char *); const struct got_error *got_object_blob_create(struct got_object_id **, const char *, struct got_repository *); const struct got_error *got_object_tree_create(struct got_object_id **, struct got_pathlist_head *, int, struct got_repository *); const struct got_error *got_object_commit_create(struct got_object_id **, struct got_object_id *, struct got_object_id_queue *, int, const char *, time_t, const char *, time_t, const char *, struct got_repository *); got-portable-0.101/lib/fetch.c0000664000175100017510000003537514644144735011633 /* * Copyright (c) 2018, 2019 Ori Bernstein * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_reference.h" #include "got_repository.h" #include "got_path.h" #include "got_cancel.h" #include "got_worktree.h" #include "got_object.h" #include "got_opentemp.h" #include "got_fetch.h" #include "got_lib_delta.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_object_create.h" #include "got_lib_pack.h" #include "got_lib_hash.h" #include "got_lib_privsep.h" #include "got_lib_object_cache.h" #include "got_lib_repository.h" #include "got_lib_dial.h" #include "got_lib_pkt.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif #ifndef ssizeof #define ssizeof(_x) ((ssize_t)(sizeof(_x))) #endif #ifndef MIN #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) #endif const struct got_error * got_fetch_connect(pid_t *fetchpid, int *fetchfd, const char *proto, const char *host, const char *port, const char *server_path, int verbosity) { const struct got_error *err = NULL; *fetchpid = -1; *fetchfd = -1; if (strcmp(proto, "ssh") == 0 || strcmp(proto, "git+ssh") == 0) err = got_dial_ssh(fetchpid, fetchfd, host, port, server_path, GOT_DIAL_CMD_FETCH, verbosity); else if (strcmp(proto, "git") == 0) err = got_dial_git(fetchfd, host, port, server_path, GOT_DIAL_CMD_FETCH); else if (strcmp(proto, "http") == 0 || strcmp(proto, "git+http") == 0 || strcmp(proto, "https") == 0 || strcmp(proto, "git+https") == 0) err = got_dial_http(fetchpid, fetchfd, host, port, server_path, verbosity, strstr(proto, "https") != NULL); else err = got_error_path(proto, GOT_ERR_BAD_PROTO); return err; } const struct got_error * got_fetch_pack(struct got_object_id **pack_hash, struct got_pathlist_head *refs, struct got_pathlist_head *symrefs, const char *remote_name, int mirror_references, int fetch_all_branches, struct got_pathlist_head *wanted_branches, struct got_pathlist_head *wanted_refs, int list_refs_only, int verbosity, int fetchfd, struct got_repository *repo, const char *worktree_refname, const char *remote_head, int no_head, got_fetch_progress_cb progress_cb, void *progress_arg) { size_t i; int imsg_fetchfds[2], imsg_idxfds[2]; int packfd = -1, npackfd = -1, idxfd = -1, nidxfd = -1, nfetchfd = -1; int tmpfds[3]; int fetchstatus, idxstatus, done = 0; const struct got_error *err; struct imsgbuf fetchibuf, idxibuf; pid_t fetchpid, idxpid; char *tmppackpath = NULL, *tmpidxpath = NULL; char *packpath = NULL, *idxpath = NULL, *id_str = NULL; const char *repo_path = NULL; struct got_pathlist_head have_refs; struct got_pathlist_entry *pe; struct got_reflist_head my_refs; struct got_reflist_entry *re; off_t packfile_size = 0; struct got_packfile_hdr pack_hdr; uint32_t nobj = 0; char *path; char *progress = NULL; *pack_hash = NULL; /* * Prevent fetching of references that won't make any * sense outside of the remote repository's context. */ TAILQ_FOREACH(pe, wanted_refs, entry) { const char *refname = pe->path; if (strncmp(refname, "refs/got/", 9) == 0 || strncmp(refname, "got/", 4) == 0 || strncmp(refname, "refs/remotes/", 13) == 0 || strncmp(refname, "remotes/", 8) == 0) return got_error_path(refname, GOT_ERR_FETCH_BAD_REF); } if (!list_refs_only) repo_path = got_repo_get_path_git_dir(repo); for (i = 0; i < nitems(tmpfds); i++) tmpfds[i] = -1; TAILQ_INIT(&have_refs); TAILQ_INIT(&my_refs); if (!list_refs_only) { err = got_ref_list(&my_refs, repo, NULL, got_ref_cmp_by_name, NULL); if (err) goto done; } TAILQ_FOREACH(re, &my_refs, entry) { struct got_object_id *id; const char *refname; if (got_ref_is_symbolic(re->ref)) continue; err = got_ref_resolve(&id, repo, re->ref); if (err) goto done; refname = strdup(got_ref_get_name(re->ref)); if (refname == NULL) { err = got_error_from_errno("strdup"); goto done; } err = got_pathlist_append(&have_refs, refname, id); if (err) goto done; } if (list_refs_only) { packfd = got_opentempfd(); if (packfd == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } } else { if (asprintf(&path, "%s/%s/fetching.pack", repo_path, GOT_OBJECTS_PACK_DIR) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_opentemp_named_fd(&tmppackpath, &packfd, path, ""); free(path); if (err) goto done; if (fchmod(packfd, GOT_DEFAULT_FILE_MODE) != 0) { err = got_error_from_errno2("fchmod", tmppackpath); goto done; } } if (list_refs_only) { idxfd = got_opentempfd(); if (idxfd == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } } else { if (asprintf(&path, "%s/%s/fetching.idx", repo_path, GOT_OBJECTS_PACK_DIR) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_opentemp_named_fd(&tmpidxpath, &idxfd, path, ""); free(path); if (err) goto done; if (fchmod(idxfd, GOT_DEFAULT_FILE_MODE) != 0) { err = got_error_from_errno2("fchmod", tmpidxpath); goto done; } } nidxfd = dup(idxfd); if (nidxfd == -1) { err = got_error_from_errno("dup"); goto done; } for (i = 0; i < nitems(tmpfds); i++) { tmpfds[i] = got_opentempfd(); if (tmpfds[i] == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } } if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fetchfds) == -1) { err = got_error_from_errno("socketpair"); goto done; } fetchpid = fork(); if (fetchpid == -1) { err = got_error_from_errno("fork"); goto done; } else if (fetchpid == 0){ got_privsep_exec_child(imsg_fetchfds, GOT_PATH_PROG_FETCH_PACK, tmppackpath); } if (close(imsg_fetchfds[1]) == -1) { err = got_error_from_errno("close"); goto done; } imsg_init(&fetchibuf, imsg_fetchfds[0]); nfetchfd = dup(fetchfd); if (nfetchfd == -1) { err = got_error_from_errno("dup"); goto done; } err = got_privsep_send_fetch_req(&fetchibuf, nfetchfd, &have_refs, fetch_all_branches, wanted_branches, wanted_refs, list_refs_only, worktree_refname, remote_head, no_head, verbosity); if (err != NULL) goto done; nfetchfd = -1; npackfd = dup(packfd); if (npackfd == -1) { err = got_error_from_errno("dup"); goto done; } err = got_privsep_send_fetch_outfd(&fetchibuf, npackfd); if (err != NULL) goto done; npackfd = -1; packfile_size = 0; progress = calloc(GOT_PKT_MAX, 1); if (progress == NULL) { err = got_error_from_errno("calloc"); goto done; } *pack_hash = calloc(1, sizeof(**pack_hash)); if (*pack_hash == NULL) { err = got_error_from_errno("calloc"); goto done; } while (!done) { struct got_object_id *id = NULL; char *refname = NULL; char *server_progress = NULL; off_t packfile_size_cur = 0; err = got_privsep_recv_fetch_progress(&done, &id, &refname, symrefs, &server_progress, &packfile_size_cur, (*pack_hash)->sha1, &fetchibuf); if (err != NULL) goto done; /* Don't report size progress for an empty pack file. */ if (packfile_size_cur <= ssizeof(pack_hdr) + SHA1_DIGEST_LENGTH) packfile_size_cur = 0; if (!done && refname && id) { err = got_pathlist_insert(NULL, refs, refname, id); if (err) goto done; } else if (!done && server_progress) { char *p; /* * XXX git-daemon tends to send batched output with * lines spanning separate packets. Buffer progress * output until we see a CR or LF to avoid giving * partial lines of progress output to the callback. */ if (strlcat(progress, server_progress, GOT_PKT_MAX) >= GOT_PKT_MAX) { progress[0] = '\0'; /* discard */ continue; } while ((p = strchr(progress, '\r')) != NULL || (p = strchr(progress, '\n')) != NULL) { char *s; size_t n; char c = *p; *p = '\0'; if (asprintf(&s, "%s%s", progress, c == '\n' ? "\n" : "") == -1) { err = got_error_from_errno("asprintf"); goto done; } err = progress_cb(progress_arg, s, packfile_size_cur, 0, 0, 0, 0); free(s); if (err) break; n = strlen(progress); if (n < GOT_PKT_MAX - 1) { memmove(progress, &progress[n + 1], GOT_PKT_MAX - n - 1); } else progress[0] = '\0'; } free(server_progress); if (err) goto done; } else if (!done && packfile_size_cur != packfile_size) { err = progress_cb(progress_arg, NULL, packfile_size_cur, 0, 0, 0, 0); if (err) break; packfile_size = packfile_size_cur; } } if (close(imsg_fetchfds[0]) == -1) { err = got_error_from_errno("close"); goto done; } if (waitpid(fetchpid, &fetchstatus, 0) == -1) { err = got_error_from_errno("waitpid"); goto done; } if (lseek(packfd, 0, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } /* If zero data was fetched without error we are already up-to-date. */ if (packfile_size == 0) { free(*pack_hash); *pack_hash = NULL; goto done; } else if (packfile_size < ssizeof(pack_hdr) + SHA1_DIGEST_LENGTH) { err = got_error_msg(GOT_ERR_BAD_PACKFILE, "short pack file"); goto done; } else { ssize_t n; n = read(packfd, &pack_hdr, ssizeof(pack_hdr)); if (n == -1) { err = got_error_from_errno("read"); goto done; } if (n != ssizeof(pack_hdr)) { err = got_error(GOT_ERR_IO); goto done; } if (pack_hdr.signature != htobe32(GOT_PACKFILE_SIGNATURE)) { err = got_error_msg(GOT_ERR_BAD_PACKFILE, "bad pack file signature"); goto done; } if (pack_hdr.version != htobe32(GOT_PACKFILE_VERSION)) { err = got_error_msg(GOT_ERR_BAD_PACKFILE, "bad pack file version"); goto done; } nobj = be32toh(pack_hdr.nobjects); if (nobj == 0 && packfile_size > ssizeof(pack_hdr) + SHA1_DIGEST_LENGTH) { err = got_error_msg(GOT_ERR_BAD_PACKFILE, "bad pack file with zero objects"); goto done; } if (nobj != 0 && packfile_size <= ssizeof(pack_hdr) + SHA1_DIGEST_LENGTH) { err = got_error_msg(GOT_ERR_BAD_PACKFILE, "empty pack file with non-zero object count"); goto done; } } /* * If the pack file contains no objects, we may only need to update * references in our repository. The caller will take care of that. */ if (nobj == 0) { free(*pack_hash); *pack_hash = NULL; goto done; } if (lseek(packfd, 0, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_idxfds) == -1) { err = got_error_from_errno("socketpair"); goto done; } idxpid = fork(); if (idxpid == -1) { err= got_error_from_errno("fork"); goto done; } else if (idxpid == 0) got_privsep_exec_child(imsg_idxfds, GOT_PATH_PROG_INDEX_PACK, tmppackpath); if (close(imsg_idxfds[1]) == -1) { err = got_error_from_errno("close"); goto done; } imsg_init(&idxibuf, imsg_idxfds[0]); npackfd = dup(packfd); if (npackfd == -1) { err = got_error_from_errno("dup"); goto done; } err = got_privsep_send_index_pack_req(&idxibuf, (*pack_hash)->sha1, npackfd); if (err != NULL) goto done; npackfd = -1; err = got_privsep_send_index_pack_outfd(&idxibuf, nidxfd); if (err != NULL) goto done; nidxfd = -1; for (i = 0; i < nitems(tmpfds); i++) { err = got_privsep_send_tmpfd(&idxibuf, tmpfds[i]); if (err != NULL) goto done; tmpfds[i] = -1; } done = 0; while (!done) { int nobj_total, nobj_indexed, nobj_loose, nobj_resolved; err = got_privsep_recv_index_progress(&done, &nobj_total, &nobj_indexed, &nobj_loose, &nobj_resolved, &idxibuf); if (err != NULL) goto done; if (nobj_indexed != 0) { err = progress_cb(progress_arg, NULL, packfile_size, nobj_total, nobj_indexed, nobj_loose, nobj_resolved); if (err) break; } } if (close(imsg_idxfds[0]) == -1) { err = got_error_from_errno("close"); goto done; } if (waitpid(idxpid, &idxstatus, 0) == -1) { err = got_error_from_errno("waitpid"); goto done; } err = got_object_id_str(&id_str, *pack_hash); if (err) goto done; if (asprintf(&packpath, "%s/%s/pack-%s.pack", repo_path, GOT_OBJECTS_PACK_DIR, id_str) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (asprintf(&idxpath, "%s/%s/pack-%s.idx", repo_path, GOT_OBJECTS_PACK_DIR, id_str) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(id_str); id_str = NULL; if (rename(tmppackpath, packpath) == -1) { err = got_error_from_errno3("rename", tmppackpath, packpath); goto done; } free(tmppackpath); tmppackpath = NULL; if (rename(tmpidxpath, idxpath) == -1) { err = got_error_from_errno3("rename", tmpidxpath, idxpath); goto done; } free(tmpidxpath); tmpidxpath = NULL; done: if (tmppackpath && unlink(tmppackpath) == -1 && err == NULL) err = got_error_from_errno2("unlink", tmppackpath); if (tmpidxpath && unlink(tmpidxpath) == -1 && err == NULL) err = got_error_from_errno2("unlink", tmpidxpath); if (nfetchfd != -1 && close(nfetchfd) == -1 && err == NULL) err = got_error_from_errno("close"); if (npackfd != -1 && close(npackfd) == -1 && err == NULL) err = got_error_from_errno("close"); if (packfd != -1 && close(packfd) == -1 && err == NULL) err = got_error_from_errno("close"); if (idxfd != -1 && close(idxfd) == -1 && err == NULL) err = got_error_from_errno("close"); for (i = 0; i < nitems(tmpfds); i++) { if (tmpfds[i] != -1 && close(tmpfds[i]) == -1 && err == NULL) err = got_error_from_errno("close"); } free(tmppackpath); free(tmpidxpath); free(idxpath); free(id_str); free(packpath); free(progress); got_pathlist_free(&have_refs, GOT_PATHLIST_FREE_ALL); got_ref_list_free(&my_refs); if (err) { free(*pack_hash); *pack_hash = NULL; got_pathlist_free(refs, GOT_PATHLIST_FREE_ALL); got_pathlist_free(symrefs, GOT_PATHLIST_FREE_ALL); } return err; } got-portable-0.101/lib/got_lib_hash.h0000664000175100017510000000556214644143345013160 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #define GOT_SHA1_STRING_ZERO "0000000000000000000000000000000000000000" #define GOT_SHA256_STRING_ZERO "0000000000000000000000000000000000000000000000000000000000000000" #define GOT_HASH_DIGEST_MAXLEN SHA256_DIGEST_LENGTH int got_parse_xdigit(uint8_t *, const char *); char *got_sha1_digest_to_str(const uint8_t *, char *, size_t); char *got_sha256_digest_to_str(const uint8_t *, char *, size_t); int got_parse_hash_digest(uint8_t *, const char *, enum got_hash_algorithm); /* * Write the string representation fo an object ID in the given buffer. * This buffer must be at least GOT_OBJECT_ID_HEX_MAXLEN bytes in size. * The output depneds on the hash function used by the repository format. */ char *got_object_id_hex(struct got_object_id *, char *, size_t); int got_parse_object_id(struct got_object_id *, const char *, enum got_hash_algorithm); static inline int got_hash_digest_length(enum got_hash_algorithm algo) { switch (algo) { case GOT_HASH_SHA1: return SHA1_DIGEST_LENGTH; case GOT_HASH_SHA256: return SHA256_DIGEST_LENGTH; default: return 0; } } static inline int got_hash_digest_string_length(enum got_hash_algorithm algo) { switch (algo) { case GOT_HASH_SHA1: return SHA1_DIGEST_STRING_LENGTH; case GOT_HASH_SHA256: return SHA256_DIGEST_STRING_LENGTH; default: return 0; } } struct got_hash { SHA1_CTX sha1_ctx; SHA2_CTX sha256_ctx; enum got_hash_algorithm algo; }; /* * These functions allow to compute and check hashes. * The hash function used is specified during got_hash_init. * Data can be added with got_hash_update and, once done, the checksum * saved in a buffer long at least GOT_HASH_DIGEST_MAXLEN bytes with * got_hash_final or in an got_object_id with got_hash_final_object_id. */ void got_hash_init(struct got_hash *, enum got_hash_algorithm); void got_hash_update(struct got_hash *, const void *, size_t); void got_hash_final(struct got_hash *, uint8_t *); void got_hash_final_object_id(struct got_hash *, struct got_object_id *); /* * Compare two hash digest; similar to memcmp(). */ int got_hash_cmp(enum got_hash_algorithm, uint8_t *, uint8_t *); got-portable-0.101/lib/utf8.c0000664000175100017510000000407214644144735011416 /* * Copyright (c) 2015 Ingo Schwarze * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include "got_error.h" #include "got_utf8.h" const struct got_error * got_mbsavis(char** outp, int *widthp, const char *mbs) { const char *src; /* Iterate mbs. */ char *dst; /* Iterate *outp. */ wchar_t wc; int total_width; /* Display width of the whole string. */ int width; /* Display width of a single Unicode char. */ int len; /* Length in bytes of UTF-8 encoded string. */ len = strlen(mbs); if ((*outp = malloc(len + 1)) == NULL) return got_error_from_errno("malloc"); if (MB_CUR_MAX == 1) { memcpy(*outp, mbs, len + 1); *widthp = len; return NULL; } src = mbs; dst = *outp; total_width = 0; while (*src != '\0') { if ((len = mbtowc(&wc, src, MB_CUR_MAX)) == -1) { total_width++; *dst++ = '?'; src++; } else if ((width = wcwidth(wc)) == -1) { total_width++; *dst++ = '?'; src += len; } else { total_width += width; while (len-- > 0) *dst++ = *src++; } } *dst = '\0'; *widthp = total_width; return NULL; } int got_locale_is_utf8(void) { char *codeset = nl_langinfo(CODESET); return (strcmp(codeset, "UTF-8") == 0); } got-portable-0.101/lib/murmurhash2.h0000644000175100017510000000054314644143163013001 //----------------------------------------------------------------------------- // MurmurHash2 was written by Austin Appleby, and is placed in the public // domain. The author hereby disclaims copyright to this source code. /* Obtained from https://github.com/aappleby/smhasher */ uint32_t murmurhash2(const unsigned char *key, int len, uint32_t seed); got-portable-0.101/lib/worktree_cvg.c0000664000175100017510000024402614644144735013236 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_repository.h" #include "got_reference.h" #include "got_object.h" #include "got_path.h" #include "got_cancel.h" #include "got_worktree.h" #include "got_worktree_cvg.h" #include "got_opentemp.h" #include "got_diff.h" #include "got_send.h" #include "got_fetch.h" #include "got_lib_worktree.h" #include "got_lib_hash.h" #include "got_lib_fileindex.h" #include "got_lib_inflate.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_object_create.h" #include "got_lib_object_idset.h" #include "got_lib_diff.h" #ifndef MIN #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) #endif #define GOT_MERGE_LABEL_MERGED "merged change" #define GOT_MERGE_LABEL_BASE "3-way merge base" static const struct got_error * lock_worktree(struct got_worktree *worktree, int operation) { if (flock(worktree->lockfd, operation | LOCK_NB) == -1) return (errno == EWOULDBLOCK ? got_error(GOT_ERR_WORKTREE_BUSY) : got_error_from_errno2("flock", got_worktree_get_root_path(worktree))); return NULL; } static const struct got_error * is_bad_symlink_target(int *is_bad_symlink, const char *target_path, size_t target_len, const char *ondisk_path, const char *wtroot_path) { const struct got_error *err = NULL; char canonpath[PATH_MAX]; char *path_got = NULL; *is_bad_symlink = 0; if (target_len >= sizeof(canonpath)) { *is_bad_symlink = 1; return NULL; } /* * We do not use realpath(3) to resolve the symlink's target * path because we don't want to resolve symlinks recursively. * Instead we make the path absolute and then canonicalize it. * Relative symlink target lookup should begin at the directory * in which the blob object is being installed. */ if (!got_path_is_absolute(target_path)) { char *abspath, *parent; err = got_path_dirname(&parent, ondisk_path); if (err) return err; if (asprintf(&abspath, "%s/%s", parent, target_path) == -1) { free(parent); return got_error_from_errno("asprintf"); } free(parent); if (strlen(abspath) >= sizeof(canonpath)) { err = got_error_path(abspath, GOT_ERR_BAD_PATH); free(abspath); return err; } err = got_canonpath(abspath, canonpath, sizeof(canonpath)); free(abspath); if (err) return err; } else { err = got_canonpath(target_path, canonpath, sizeof(canonpath)); if (err) return err; } /* Only allow symlinks pointing at paths within the work tree. */ if (!got_path_is_child(canonpath, wtroot_path, strlen(wtroot_path))) { *is_bad_symlink = 1; return NULL; } /* Do not allow symlinks pointing into the .got directory. */ if (asprintf(&path_got, "%s/%s", wtroot_path, GOT_WORKTREE_GOT_DIR) == -1) return got_error_from_errno("asprintf"); if (got_path_is_child(canonpath, path_got, strlen(path_got))) *is_bad_symlink = 1; free(path_got); return NULL; } /* * Upgrade STATUS_MODIFY to STATUS_CONFLICT if a * conflict marker is found in newly added lines only. */ static const struct got_error * get_modified_file_content_status(unsigned char *status, struct got_blob_object *blob, const char *path, struct stat *sb, FILE *ondisk_file) { const struct got_error *err, *free_err; const char *markers[3] = { GOT_DIFF_CONFLICT_MARKER_BEGIN, GOT_DIFF_CONFLICT_MARKER_SEP, GOT_DIFF_CONFLICT_MARKER_END }; FILE *f1 = NULL; struct got_diffreg_result *diffreg_result = NULL; struct diff_result *r; int nchunks_parsed, n, i = 0, ln = 0; char *line = NULL; size_t linesize = 0; ssize_t linelen; if (*status != GOT_STATUS_MODIFY) return NULL; f1 = got_opentemp(); if (f1 == NULL) return got_error_from_errno("got_opentemp"); if (blob) { got_object_blob_rewind(blob); err = got_object_blob_dump_to_file(NULL, NULL, NULL, f1, blob); if (err) goto done; } err = got_diff_files(&diffreg_result, f1, 1, NULL, ondisk_file, 1, NULL, 0, 0, 1, NULL, GOT_DIFF_ALGORITHM_MYERS); if (err) goto done; r = diffreg_result->result; for (n = 0; n < r->chunks.len; n += nchunks_parsed) { struct diff_chunk *c; struct diff_chunk_context cc = {}; off_t pos; /* * We can optimise a little by advancing straight * to the next chunk if this one has no added lines. */ c = diff_chunk_get(r, n); if (diff_chunk_type(c) != CHUNK_PLUS) { nchunks_parsed = 1; continue; /* removed or unchanged lines */ } pos = diff_chunk_get_right_start_pos(c); if (fseek(ondisk_file, pos, SEEK_SET) == -1) { err = got_ferror(ondisk_file, GOT_ERR_IO); goto done; } diff_chunk_context_load_change(&cc, &nchunks_parsed, r, n, 0); ln = cc.right.start; while (ln < cc.right.end) { linelen = getline(&line, &linesize, ondisk_file); if (linelen == -1) { if (feof(ondisk_file)) break; err = got_ferror(ondisk_file, GOT_ERR_IO); break; } if (line && strncmp(line, markers[i], strlen(markers[i])) == 0) { if (strcmp(markers[i], GOT_DIFF_CONFLICT_MARKER_END) == 0) { *status = GOT_STATUS_CONFLICT; goto done; } else i++; } ++ln; } } done: free(line); if (f1 != NULL && fclose(f1) == EOF && err == NULL) err = got_error_from_errno("fclose"); free_err = got_diffreg_result_free(diffreg_result); if (err == NULL) err = free_err; return err; } static int xbit_differs(struct got_fileindex_entry *ie, uint16_t st_mode) { mode_t ie_mode = got_fileindex_perms_to_st(ie); return ((ie_mode & S_IXUSR) != (st_mode & S_IXUSR)); } static int stat_info_differs(struct got_fileindex_entry *ie, struct stat *sb) { return !(ie->ctime_sec == sb->st_ctim.tv_sec && ie->ctime_nsec == sb->st_ctim.tv_nsec && ie->mtime_sec == sb->st_mtim.tv_sec && ie->mtime_nsec == sb->st_mtim.tv_nsec && ie->size == (sb->st_size & 0xffffffff) && !xbit_differs(ie, sb->st_mode)); } static unsigned char get_staged_status(struct got_fileindex_entry *ie) { switch (got_fileindex_entry_stage_get(ie)) { case GOT_FILEIDX_STAGE_ADD: return GOT_STATUS_ADD; case GOT_FILEIDX_STAGE_DELETE: return GOT_STATUS_DELETE; case GOT_FILEIDX_STAGE_MODIFY: return GOT_STATUS_MODIFY; default: return GOT_STATUS_NO_CHANGE; } } static const struct got_error * get_symlink_modification_status(unsigned char *status, struct got_fileindex_entry *ie, const char *abspath, int dirfd, const char *de_name, struct got_blob_object *blob) { const struct got_error *err = NULL; char target_path[PATH_MAX]; char etarget[PATH_MAX]; ssize_t elen; size_t len, target_len = 0; const uint8_t *buf = got_object_blob_get_read_buf(blob); size_t hdrlen = got_object_blob_get_hdrlen(blob); *status = GOT_STATUS_NO_CHANGE; /* Blob object content specifies the target path of the link. */ do { err = got_object_blob_read_block(&len, blob); if (err) return err; if (len + target_len >= sizeof(target_path)) { /* * Should not happen. The blob contents were OK * when this symlink was installed. */ return got_error(GOT_ERR_NO_SPACE); } if (len > 0) { /* Skip blob object header first time around. */ memcpy(target_path + target_len, buf + hdrlen, len - hdrlen); target_len += len - hdrlen; hdrlen = 0; } } while (len != 0); target_path[target_len] = '\0'; if (dirfd != -1) { elen = readlinkat(dirfd, de_name, etarget, sizeof(etarget)); if (elen == -1) return got_error_from_errno2("readlinkat", abspath); } else { elen = readlink(abspath, etarget, sizeof(etarget)); if (elen == -1) return got_error_from_errno2("readlink", abspath); } if (elen != target_len || memcmp(etarget, target_path, target_len) != 0) *status = GOT_STATUS_MODIFY; return NULL; } static const struct got_error * get_file_status(unsigned char *status, struct stat *sb, struct got_fileindex_entry *ie, const char *abspath, int dirfd, const char *de_name, struct got_repository *repo) { const struct got_error *err = NULL; struct got_object_id id; size_t hdrlen; int fd = -1, fd1 = -1; FILE *f = NULL; uint8_t fbuf[8192]; struct got_blob_object *blob = NULL; size_t flen, blen; unsigned char staged_status; staged_status = get_staged_status(ie); *status = GOT_STATUS_NO_CHANGE; memset(sb, 0, sizeof(*sb)); /* * Whenever the caller provides a directory descriptor and a * directory entry name for the file, use them! This prevents * race conditions if filesystem paths change beneath our feet. */ if (dirfd != -1) { if (fstatat(dirfd, de_name, sb, AT_SYMLINK_NOFOLLOW) == -1) { if (errno == ENOENT) { if (got_fileindex_entry_has_file_on_disk(ie)) *status = GOT_STATUS_MISSING; else *status = GOT_STATUS_DELETE; goto done; } err = got_error_from_errno2("fstatat", abspath); goto done; } } else { fd = open(abspath, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1 && errno != ENOENT && !got_err_open_nofollow_on_symlink()) return got_error_from_errno2("open", abspath); else if (fd == -1 && got_err_open_nofollow_on_symlink()) { if (lstat(abspath, sb) == -1) return got_error_from_errno2("lstat", abspath); } else if (fd == -1 || fstat(fd, sb) == -1) { if (errno == ENOENT) { if (got_fileindex_entry_has_file_on_disk(ie)) *status = GOT_STATUS_MISSING; else *status = GOT_STATUS_DELETE; goto done; } err = got_error_from_errno2("fstat", abspath); goto done; } } if (!S_ISREG(sb->st_mode) && !S_ISLNK(sb->st_mode)) { *status = GOT_STATUS_OBSTRUCTED; goto done; } if (!got_fileindex_entry_has_file_on_disk(ie)) { *status = GOT_STATUS_DELETE; goto done; } else if (!got_fileindex_entry_has_blob(ie) && staged_status != GOT_STATUS_ADD) { *status = GOT_STATUS_ADD; goto done; } if (!stat_info_differs(ie, sb)) goto done; if (S_ISLNK(sb->st_mode) && got_fileindex_entry_filetype_get(ie) != GOT_FILEIDX_MODE_SYMLINK) { *status = GOT_STATUS_MODIFY; goto done; } if (staged_status == GOT_STATUS_MODIFY || staged_status == GOT_STATUS_ADD) got_fileindex_entry_get_staged_blob_id(&id, ie); else got_fileindex_entry_get_blob_id(&id, ie); fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } err = got_object_open_as_blob(&blob, repo, &id, sizeof(fbuf), fd1); if (err) goto done; if (S_ISLNK(sb->st_mode)) { err = get_symlink_modification_status(status, ie, abspath, dirfd, de_name, blob); goto done; } if (dirfd != -1) { fd = openat(dirfd, de_name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { err = got_error_from_errno2("openat", abspath); goto done; } } f = fdopen(fd, "r"); if (f == NULL) { err = got_error_from_errno2("fdopen", abspath); goto done; } fd = -1; hdrlen = got_object_blob_get_hdrlen(blob); for (;;) { const uint8_t *bbuf = got_object_blob_get_read_buf(blob); err = got_object_blob_read_block(&blen, blob); if (err) goto done; /* Skip length of blob object header first time around. */ flen = fread(fbuf, 1, sizeof(fbuf) - hdrlen, f); if (flen == 0 && ferror(f)) { err = got_error_from_errno("fread"); goto done; } if (blen - hdrlen == 0) { if (flen != 0) *status = GOT_STATUS_MODIFY; break; } else if (flen == 0) { if (blen - hdrlen != 0) *status = GOT_STATUS_MODIFY; break; } else if (blen - hdrlen == flen) { /* Skip blob object header first time around. */ if (memcmp(bbuf + hdrlen, fbuf, flen) != 0) { *status = GOT_STATUS_MODIFY; break; } } else { *status = GOT_STATUS_MODIFY; break; } hdrlen = 0; } if (*status == GOT_STATUS_MODIFY) { rewind(f); err = get_modified_file_content_status(status, blob, ie->path, sb, f); } else if (xbit_differs(ie, sb->st_mode)) *status = GOT_STATUS_MODE_CHANGE; done: if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob) got_object_blob_close(blob); if (f != NULL && fclose(f) == EOF && err == NULL) err = got_error_from_errno2("fclose", abspath); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno2("close", abspath); return err; } static const struct got_error * get_ref_name(char **refname, struct got_worktree *worktree, const char *prefix) { const struct got_error *err = NULL; char *uuidstr = NULL; *refname = NULL; err = got_worktree_get_uuid(&uuidstr, worktree); if (err) return err; if (asprintf(refname, "%s-%s", prefix, uuidstr) == -1) { err = got_error_from_errno("asprintf"); *refname = NULL; } free(uuidstr); return err; } static const struct got_error * get_base_ref_name(char **refname, struct got_worktree *worktree) { return get_ref_name(refname, worktree, GOT_WORKTREE_BASE_REF_PREFIX); } /* * Prevent Git's garbage collector from deleting our base commit by * setting a reference to our base commit's ID. */ static const struct got_error * ref_base_commit(struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err = NULL; struct got_reference *ref = NULL; char *refname; err = get_base_ref_name(&refname, worktree); if (err) return err; err = got_ref_alloc(&ref, refname, worktree->base_commit_id); if (err) goto done; err = got_ref_write(ref, repo); done: free(refname); if (ref) got_ref_close(ref); return err; } static const struct got_error * get_fileindex_path(char **fileindex_path, struct got_worktree *worktree) { const struct got_error *err = NULL; if (asprintf(fileindex_path, "%s/%s/%s", worktree->root_path, GOT_WORKTREE_GOT_DIR, GOT_WORKTREE_FILE_INDEX) == -1) { err = got_error_from_errno("asprintf"); *fileindex_path = NULL; } return err; } static const struct got_error * open_fileindex(struct got_fileindex **fileindex, char **fileindex_path, struct got_worktree *worktree) { const struct got_error *err = NULL; FILE *index = NULL; *fileindex_path = NULL; *fileindex = got_fileindex_alloc(); if (*fileindex == NULL) return got_error_from_errno("got_fileindex_alloc"); err = get_fileindex_path(fileindex_path, worktree); if (err) goto done; index = fopen(*fileindex_path, "rbe"); if (index == NULL) { if (errno != ENOENT) err = got_error_from_errno2("fopen", *fileindex_path); } else { err = got_fileindex_read(*fileindex, index); if (fclose(index) == EOF && err == NULL) err = got_error_from_errno("fclose"); } done: if (err) { free(*fileindex_path); *fileindex_path = NULL; got_fileindex_free(*fileindex); *fileindex = NULL; } return err; } static const struct got_error * sync_fileindex(struct got_fileindex *fileindex, const char *fileindex_path) { const struct got_error *err = NULL; char *new_fileindex_path = NULL; FILE *new_index = NULL; struct timespec timeout; err = got_opentemp_named(&new_fileindex_path, &new_index, fileindex_path, ""); if (err) goto done; err = got_fileindex_write(fileindex, new_index); if (err) goto done; if (rename(new_fileindex_path, fileindex_path) != 0) { err = got_error_from_errno3("rename", new_fileindex_path, fileindex_path); unlink(new_fileindex_path); } /* * Sleep for a short amount of time to ensure that files modified after * this program exits have a different time stamp from the one which * was recorded in the file index. */ timeout.tv_sec = 0; timeout.tv_nsec = 1; nanosleep(&timeout, NULL); done: if (new_index) fclose(new_index); free(new_fileindex_path); return err; } struct diff_dir_cb_arg { struct got_fileindex *fileindex; struct got_worktree *worktree; const char *status_path; size_t status_path_len; struct got_repository *repo; got_worktree_status_cb status_cb; void *status_arg; got_cancel_cb cancel_cb; void *cancel_arg; /* A pathlist containing per-directory pathlists of ignore patterns. */ struct got_pathlist_head *ignores; int report_unchanged; int no_ignores; }; static const struct got_error * report_file_status(struct got_fileindex_entry *ie, const char *abspath, int dirfd, const char *de_name, got_worktree_status_cb status_cb, void *status_arg, struct got_repository *repo, int report_unchanged) { const struct got_error *err = NULL; unsigned char status = GOT_STATUS_NO_CHANGE; unsigned char staged_status; struct stat sb; struct got_object_id blob_id, commit_id, staged_blob_id; struct got_object_id *blob_idp = NULL, *commit_idp = NULL; struct got_object_id *staged_blob_idp = NULL; staged_status = get_staged_status(ie); err = get_file_status(&status, &sb, ie, abspath, dirfd, de_name, repo); if (err) return err; if (status == GOT_STATUS_NO_CHANGE && staged_status == GOT_STATUS_NO_CHANGE && !report_unchanged) return NULL; if (got_fileindex_entry_has_blob(ie)) blob_idp = got_fileindex_entry_get_blob_id(&blob_id, ie); if (got_fileindex_entry_has_commit(ie)) commit_idp = got_fileindex_entry_get_commit_id(&commit_id, ie); if (staged_status == GOT_STATUS_ADD || staged_status == GOT_STATUS_MODIFY) { staged_blob_idp = got_fileindex_entry_get_staged_blob_id( &staged_blob_id, ie); } return (*status_cb)(status_arg, status, staged_status, ie->path, blob_idp, staged_blob_idp, commit_idp, dirfd, de_name); } static const struct got_error * status_old_new(void *arg, struct got_fileindex_entry *ie, struct dirent *de, const char *parent_path, int dirfd) { const struct got_error *err = NULL; struct diff_dir_cb_arg *a = arg; char *abspath; if (a->cancel_cb) { err = a->cancel_cb(a->cancel_arg); if (err) return err; } if (got_path_cmp(parent_path, a->status_path, strlen(parent_path), a->status_path_len) != 0 && !got_path_is_child(parent_path, a->status_path, a->status_path_len)) return NULL; if (parent_path[0]) { if (asprintf(&abspath, "%s/%s/%s", a->worktree->root_path, parent_path, de->d_name) == -1) return got_error_from_errno("asprintf"); } else { if (asprintf(&abspath, "%s/%s", a->worktree->root_path, de->d_name) == -1) return got_error_from_errno("asprintf"); } err = report_file_status(ie, abspath, dirfd, de->d_name, a->status_cb, a->status_arg, a->repo, a->report_unchanged); free(abspath); return err; } static const struct got_error * status_old(void *arg, struct got_fileindex_entry *ie, const char *parent_path) { const struct got_error *err = NULL; struct diff_dir_cb_arg *a = arg; struct got_object_id blob_id, commit_id; unsigned char status; if (a->cancel_cb) { err = a->cancel_cb(a->cancel_arg); if (err) return err; } if (!got_path_is_child(ie->path, a->status_path, a->status_path_len)) return NULL; got_fileindex_entry_get_blob_id(&blob_id, ie); got_fileindex_entry_get_commit_id(&commit_id, ie); if (got_fileindex_entry_has_file_on_disk(ie)) status = GOT_STATUS_MISSING; else status = GOT_STATUS_DELETE; return (*a->status_cb)(a->status_arg, status, get_staged_status(ie), ie->path, &blob_id, NULL, &commit_id, -1, NULL); } static void free_ignores(struct got_pathlist_head *ignores) { struct got_pathlist_entry *pe; TAILQ_FOREACH(pe, ignores, entry) { struct got_pathlist_head *ignorelist = pe->data; got_pathlist_free(ignorelist, GOT_PATHLIST_FREE_PATH); } got_pathlist_free(ignores, GOT_PATHLIST_FREE_PATH); } static const struct got_error * read_ignores(struct got_pathlist_head *ignores, const char *path, FILE *f) { const struct got_error *err = NULL; struct got_pathlist_entry *pe = NULL; struct got_pathlist_head *ignorelist; char *line = NULL, *pattern, *dirpath = NULL; size_t linesize = 0; ssize_t linelen; ignorelist = calloc(1, sizeof(*ignorelist)); if (ignorelist == NULL) return got_error_from_errno("calloc"); TAILQ_INIT(ignorelist); while ((linelen = getline(&line, &linesize, f)) != -1) { if (linelen > 0 && line[linelen - 1] == '\n') line[linelen - 1] = '\0'; /* Git's ignores may contain comments. */ if (line[0] == '#') continue; /* Git's negated patterns are not (yet?) supported. */ if (line[0] == '!') continue; if (asprintf(&pattern, "%s%s%s", path, path[0] ? "/" : "", line) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_pathlist_insert(NULL, ignorelist, pattern, NULL); if (err) goto done; } if (ferror(f)) { err = got_error_from_errno("getline"); goto done; } dirpath = strdup(path); if (dirpath == NULL) { err = got_error_from_errno("strdup"); goto done; } err = got_pathlist_insert(&pe, ignores, dirpath, ignorelist); done: free(line); if (err || pe == NULL) { free(dirpath); got_pathlist_free(ignorelist, GOT_PATHLIST_FREE_PATH); } return err; } static int match_path(const char *pattern, size_t pattern_len, const char *path, int flags) { char buf[PATH_MAX]; /* * Trailing slashes signify directories. * Append a * to make such patterns conform to fnmatch rules. */ if (pattern_len > 0 && pattern[pattern_len - 1] == '/') { if (snprintf(buf, sizeof(buf), "%s*", pattern) >= sizeof(buf)) return FNM_NOMATCH; /* XXX */ return fnmatch(buf, path, flags); } return fnmatch(pattern, path, flags); } static int match_ignores(struct got_pathlist_head *ignores, const char *path) { struct got_pathlist_entry *pe; /* Handle patterns which match in all directories. */ TAILQ_FOREACH(pe, ignores, entry) { struct got_pathlist_head *ignorelist = pe->data; struct got_pathlist_entry *pi; TAILQ_FOREACH(pi, ignorelist, entry) { const char *p; if (pi->path_len < 3 || strncmp(pi->path, "**/", 3) != 0) continue; p = path; while (*p) { if (match_path(pi->path + 3, pi->path_len - 3, p, FNM_PATHNAME | FNM_LEADING_DIR)) { /* Retry in next directory. */ while (*p && *p != '/') p++; while (*p == '/') p++; continue; } return 1; } } } /* * The ignores pathlist contains ignore lists from children before * parents, so we can find the most specific ignorelist by walking * ignores backwards. */ pe = TAILQ_LAST(ignores, got_pathlist_head); while (pe) { if (got_path_is_child(path, pe->path, pe->path_len)) { struct got_pathlist_head *ignorelist = pe->data; struct got_pathlist_entry *pi; TAILQ_FOREACH(pi, ignorelist, entry) { int flags = FNM_LEADING_DIR; if (strstr(pi->path, "/**/") == NULL) flags |= FNM_PATHNAME; if (match_path(pi->path, pi->path_len, path, flags)) continue; return 1; } } pe = TAILQ_PREV(pe, got_pathlist_head, entry); } return 0; } static const struct got_error * add_ignores(struct got_pathlist_head *ignores, const char *root_path, const char *path, int dirfd, const char *ignores_filename) { const struct got_error *err = NULL; char *ignorespath; int fd = -1; FILE *ignoresfile = NULL; if (asprintf(&ignorespath, "%s/%s%s%s", root_path, path, path[0] ? "/" : "", ignores_filename) == -1) return got_error_from_errno("asprintf"); if (dirfd != -1) { fd = openat(dirfd, ignores_filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { if (errno != ENOENT && errno != EACCES) err = got_error_from_errno2("openat", ignorespath); } else { ignoresfile = fdopen(fd, "r"); if (ignoresfile == NULL) err = got_error_from_errno2("fdopen", ignorespath); else { fd = -1; err = read_ignores(ignores, path, ignoresfile); } } } else { ignoresfile = fopen(ignorespath, "re"); if (ignoresfile == NULL) { if (errno != ENOENT && errno != EACCES) err = got_error_from_errno2("fopen", ignorespath); } else err = read_ignores(ignores, path, ignoresfile); } if (ignoresfile && fclose(ignoresfile) == EOF && err == NULL) err = got_error_from_errno2("fclose", path); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno2("close", path); free(ignorespath); return err; } static const struct got_error * status_new(int *ignore, void *arg, struct dirent *de, const char *parent_path, int dirfd) { const struct got_error *err = NULL; struct diff_dir_cb_arg *a = arg; char *path = NULL; if (ignore != NULL) *ignore = 0; if (a->cancel_cb) { err = a->cancel_cb(a->cancel_arg); if (err) return err; } if (parent_path[0]) { if (asprintf(&path, "%s/%s", parent_path, de->d_name) == -1) return got_error_from_errno("asprintf"); } else { path = de->d_name; } if (de->d_type == DT_DIR) { if (!a->no_ignores && ignore != NULL && match_ignores(a->ignores, path)) *ignore = 1; } else if (!match_ignores(a->ignores, path) && got_path_is_child(path, a->status_path, a->status_path_len)) err = (*a->status_cb)(a->status_arg, GOT_STATUS_UNVERSIONED, GOT_STATUS_NO_CHANGE, path, NULL, NULL, NULL, -1, NULL); if (parent_path[0]) free(path); return err; } static const struct got_error * status_traverse(void *arg, const char *path, int dirfd) { const struct got_error *err = NULL; struct diff_dir_cb_arg *a = arg; if (a->no_ignores) return NULL; err = add_ignores(a->ignores, a->worktree->root_path, path, dirfd, ".cvsignore"); if (err) return err; err = add_ignores(a->ignores, a->worktree->root_path, path, dirfd, ".gitignore"); return err; } static const struct got_error * report_single_file_status(const char *path, const char *ondisk_path, struct got_fileindex *fileindex, got_worktree_status_cb status_cb, void *status_arg, struct got_repository *repo, int report_unchanged, struct got_pathlist_head *ignores, int no_ignores) { struct got_fileindex_entry *ie; struct stat sb; ie = got_fileindex_entry_get(fileindex, path, strlen(path)); if (ie) return report_file_status(ie, ondisk_path, -1, NULL, status_cb, status_arg, repo, report_unchanged); if (lstat(ondisk_path, &sb) == -1) { if (errno != ENOENT) return got_error_from_errno2("lstat", ondisk_path); return (*status_cb)(status_arg, GOT_STATUS_NONEXISTENT, GOT_STATUS_NO_CHANGE, path, NULL, NULL, NULL, -1, NULL); } if (!no_ignores && match_ignores(ignores, path)) return NULL; if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) return (*status_cb)(status_arg, GOT_STATUS_UNVERSIONED, GOT_STATUS_NO_CHANGE, path, NULL, NULL, NULL, -1, NULL); return NULL; } static const struct got_error * add_ignores_from_parent_paths(struct got_pathlist_head *ignores, const char *root_path, const char *path) { const struct got_error *err; char *parent_path, *next_parent_path = NULL; err = add_ignores(ignores, root_path, "", -1, ".cvsignore"); if (err) return err; err = add_ignores(ignores, root_path, "", -1, ".gitignore"); if (err) return err; err = got_path_dirname(&parent_path, path); if (err) { if (err->code == GOT_ERR_BAD_PATH) return NULL; /* cannot traverse parent */ return err; } for (;;) { err = add_ignores(ignores, root_path, parent_path, -1, ".cvsignore"); if (err) break; err = add_ignores(ignores, root_path, parent_path, -1, ".gitignore"); if (err) break; err = got_path_dirname(&next_parent_path, parent_path); if (err) { if (err->code == GOT_ERR_BAD_PATH) err = NULL; /* traversed everything */ break; } if (got_path_is_root_dir(parent_path)) break; free(parent_path); parent_path = next_parent_path; next_parent_path = NULL; } free(parent_path); free(next_parent_path); return err; } struct find_missing_children_args { const char *parent_path; size_t parent_len; struct got_pathlist_head *children; got_cancel_cb cancel_cb; void *cancel_arg; }; static const struct got_error * find_missing_children(void *arg, struct got_fileindex_entry *ie) { const struct got_error *err = NULL; struct find_missing_children_args *a = arg; if (a->cancel_cb) { err = a->cancel_cb(a->cancel_arg); if (err) return err; } if (got_path_is_child(ie->path, a->parent_path, a->parent_len)) err = got_pathlist_append(a->children, ie->path, NULL); return err; } static const struct got_error * report_children(struct got_pathlist_head *children, struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_repository *repo, int is_root_dir, int report_unchanged, struct got_pathlist_head *ignores, int no_ignores, got_worktree_status_cb status_cb, void *status_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; struct got_pathlist_entry *pe; char *ondisk_path = NULL; TAILQ_FOREACH(pe, children, entry) { if (cancel_cb) { err = cancel_cb(cancel_arg); if (err) break; } if (asprintf(&ondisk_path, "%s%s%s", worktree->root_path, !is_root_dir ? "/" : "", pe->path) == -1) { err = got_error_from_errno("asprintf"); ondisk_path = NULL; break; } err = report_single_file_status(pe->path, ondisk_path, fileindex, status_cb, status_arg, repo, report_unchanged, ignores, no_ignores); if (err) break; free(ondisk_path); ondisk_path = NULL; } free(ondisk_path); return err; } static const struct got_error * worktree_status(struct got_worktree *worktree, const char *path, struct got_fileindex *fileindex, struct got_repository *repo, got_worktree_status_cb status_cb, void *status_arg, got_cancel_cb cancel_cb, void *cancel_arg, int no_ignores, int report_unchanged) { const struct got_error *err = NULL; int fd = -1; struct got_fileindex_diff_dir_cb fdiff_cb; struct diff_dir_cb_arg arg; char *ondisk_path = NULL; struct got_pathlist_head ignores, missing_children; struct got_fileindex_entry *ie; TAILQ_INIT(&ignores); TAILQ_INIT(&missing_children); if (asprintf(&ondisk_path, "%s%s%s", worktree->root_path, path[0] ? "/" : "", path) == -1) return got_error_from_errno("asprintf"); ie = got_fileindex_entry_get(fileindex, path, strlen(path)); if (ie) { err = report_single_file_status(path, ondisk_path, fileindex, status_cb, status_arg, repo, report_unchanged, &ignores, no_ignores); goto done; } else { struct find_missing_children_args fmca; fmca.parent_path = path; fmca.parent_len = strlen(path); fmca.children = &missing_children; fmca.cancel_cb = cancel_cb; fmca.cancel_arg = cancel_arg; err = got_fileindex_for_each_entry_safe(fileindex, find_missing_children, &fmca); if (err) goto done; } fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC); if (fd == -1) { if (errno != ENOTDIR && errno != ENOENT && errno != EACCES && !got_err_open_nofollow_on_symlink()) err = got_error_from_errno2("open", ondisk_path); else { if (!no_ignores) { err = add_ignores_from_parent_paths(&ignores, worktree->root_path, ondisk_path); if (err) goto done; } if (TAILQ_EMPTY(&missing_children)) { err = report_single_file_status(path, ondisk_path, fileindex, status_cb, status_arg, repo, report_unchanged, &ignores, no_ignores); if (err) goto done; } else { err = report_children(&missing_children, worktree, fileindex, repo, (path[0] == '\0'), report_unchanged, &ignores, no_ignores, status_cb, status_arg, cancel_cb, cancel_arg); if (err) goto done; } } } else { fdiff_cb.diff_old_new = status_old_new; fdiff_cb.diff_old = status_old; fdiff_cb.diff_new = status_new; fdiff_cb.diff_traverse = status_traverse; arg.fileindex = fileindex; arg.worktree = worktree; arg.status_path = path; arg.status_path_len = strlen(path); arg.repo = repo; arg.status_cb = status_cb; arg.status_arg = status_arg; arg.cancel_cb = cancel_cb; arg.cancel_arg = cancel_arg; arg.report_unchanged = report_unchanged; arg.no_ignores = no_ignores; if (!no_ignores) { err = add_ignores_from_parent_paths(&ignores, worktree->root_path, path); if (err) goto done; } arg.ignores = &ignores; err = got_fileindex_diff_dir(fileindex, fd, worktree->root_path, path, repo, &fdiff_cb, &arg); } done: free_ignores(&ignores); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); free(ondisk_path); return err; } static void free_commitable(struct got_commitable *ct) { free(ct->path); free(ct->in_repo_path); free(ct->ondisk_path); free(ct->blob_id); free(ct->base_blob_id); free(ct->staged_blob_id); free(ct->base_commit_id); free(ct); } struct collect_commitables_arg { struct got_pathlist_head *commitable_paths; struct got_repository *repo; struct got_worktree *worktree; struct got_fileindex *fileindex; int have_staged_files; int allow_bad_symlinks; int diff_header_shown; int commit_conflicts; FILE *diff_outfile; FILE *f1; FILE *f2; }; /* * Create a file which contains the target path of a symlink so we can feed * it as content to the diff engine. */ static const struct got_error * get_symlink_target_file(int *fd, int dirfd, const char *de_name, const char *abspath) { const struct got_error *err = NULL; char target_path[PATH_MAX]; ssize_t target_len, outlen; *fd = -1; if (dirfd != -1) { target_len = readlinkat(dirfd, de_name, target_path, PATH_MAX); if (target_len == -1) return got_error_from_errno2("readlinkat", abspath); } else { target_len = readlink(abspath, target_path, PATH_MAX); if (target_len == -1) return got_error_from_errno2("readlink", abspath); } *fd = got_opentempfd(); if (*fd == -1) return got_error_from_errno("got_opentempfd"); outlen = write(*fd, target_path, target_len); if (outlen == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } if (lseek(*fd, 0, SEEK_SET) == -1) { err = got_error_from_errno2("lseek", abspath); goto done; } done: if (err) { close(*fd); *fd = -1; } return err; } static const struct got_error * append_ct_diff(struct got_commitable *ct, int *diff_header_shown, FILE *diff_outfile, FILE *f1, FILE *f2, int dirfd, const char *de_name, int diff_staged, struct got_repository *repo, struct got_worktree *worktree) { const struct got_error *err = NULL; struct got_blob_object *blob1 = NULL; int fd = -1, fd1 = -1, fd2 = -1; FILE *ondisk_file = NULL; char *label1 = NULL; struct stat sb; off_t size1 = 0; int f2_exists = 0; char *id_str = NULL; memset(&sb, 0, sizeof(sb)); if (diff_staged) { if (ct->staged_status != GOT_STATUS_MODIFY && ct->staged_status != GOT_STATUS_ADD && ct->staged_status != GOT_STATUS_DELETE) return NULL; } else { if (ct->status != GOT_STATUS_MODIFY && ct->status != GOT_STATUS_ADD && ct->status != GOT_STATUS_DELETE && ct->status != GOT_STATUS_CONFLICT) return NULL; } err = got_opentemp_truncate(f1); if (err) return got_error_from_errno("got_opentemp_truncate"); err = got_opentemp_truncate(f2); if (err) return got_error_from_errno("got_opentemp_truncate"); if (!*diff_header_shown) { err = got_object_id_str(&id_str, worktree->base_commit_id); if (err) return err; fprintf(diff_outfile, "diff %s%s\n", diff_staged ? "-s " : "", got_worktree_get_root_path(worktree)); fprintf(diff_outfile, "commit - %s\n", id_str); fprintf(diff_outfile, "path + %s%s\n", got_worktree_get_root_path(worktree), diff_staged ? " (staged changes)" : ""); *diff_header_shown = 1; } if (diff_staged) { const char *label1 = NULL, *label2 = NULL; switch (ct->staged_status) { case GOT_STATUS_MODIFY: label1 = ct->path; label2 = ct->path; break; case GOT_STATUS_ADD: label2 = ct->path; break; case GOT_STATUS_DELETE: label1 = ct->path; break; default: return got_error(GOT_ERR_FILE_STATUS); } fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } err = got_diff_objects_as_blobs(NULL, NULL, f1, f2, fd1, fd2, ct->base_blob_id, ct->staged_blob_id, label1, label2, GOT_DIFF_ALGORITHM_PATIENCE, 3, 0, 0, NULL, repo, diff_outfile); goto done; } fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } if (ct->status != GOT_STATUS_ADD) { err = got_object_open_as_blob(&blob1, repo, ct->base_blob_id, 8192, fd1); if (err) goto done; } if (ct->status != GOT_STATUS_DELETE) { if (dirfd != -1) { fd = openat(dirfd, de_name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { if (!got_err_open_nofollow_on_symlink()) { err = got_error_from_errno2("openat", ct->ondisk_path); goto done; } err = get_symlink_target_file(&fd, dirfd, de_name, ct->ondisk_path); if (err) goto done; } } else { fd = open(ct->ondisk_path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { if (!got_err_open_nofollow_on_symlink()) { err = got_error_from_errno2("open", ct->ondisk_path); goto done; } err = get_symlink_target_file(&fd, dirfd, de_name, ct->ondisk_path); if (err) goto done; } } if (fstatat(fd, ct->ondisk_path, &sb, AT_SYMLINK_NOFOLLOW) == -1) { err = got_error_from_errno2("fstatat", ct->ondisk_path); goto done; } ondisk_file = fdopen(fd, "r"); if (ondisk_file == NULL) { err = got_error_from_errno2("fdopen", ct->ondisk_path); goto done; } fd = -1; f2_exists = 1; } if (blob1) { err = got_object_blob_dump_to_file(&size1, NULL, NULL, f1, blob1); if (err) goto done; } err = got_diff_blob_file(blob1, f1, size1, label1, ondisk_file ? ondisk_file : f2, f2_exists, &sb, ct->path, GOT_DIFF_ALGORITHM_PATIENCE, 3, 0, 0, NULL, diff_outfile); done: if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob1) got_object_blob_close(blob1); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (ondisk_file && fclose(ondisk_file) == EOF && err == NULL) err = got_error_from_errno("fclose"); return err; } static const struct got_error * collect_commitables(void *arg, unsigned char status, unsigned char staged_status, const char *relpath, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { struct collect_commitables_arg *a = arg; const struct got_error *err = NULL; struct got_commitable *ct = NULL; struct got_pathlist_entry *new = NULL; char *parent_path = NULL, *path = NULL; struct stat sb; if (a->have_staged_files) { if (staged_status != GOT_STATUS_MODIFY && staged_status != GOT_STATUS_ADD && staged_status != GOT_STATUS_DELETE) return NULL; } else { if (status == GOT_STATUS_CONFLICT && !a->commit_conflicts) { printf("C %s\n", relpath); return got_error(GOT_ERR_COMMIT_CONFLICT); } if (status != GOT_STATUS_MODIFY && status != GOT_STATUS_MODE_CHANGE && status != GOT_STATUS_ADD && status != GOT_STATUS_DELETE && status != GOT_STATUS_CONFLICT) return NULL; } if (asprintf(&path, "/%s", relpath) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (strcmp(path, "/") == 0) { parent_path = strdup(""); if (parent_path == NULL) return got_error_from_errno("strdup"); } else { err = got_path_dirname(&parent_path, path); if (err) return err; } ct = calloc(1, sizeof(*ct)); if (ct == NULL) { err = got_error_from_errno("calloc"); goto done; } if (asprintf(&ct->ondisk_path, "%s/%s", a->worktree->root_path, relpath) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (staged_status == GOT_STATUS_ADD || staged_status == GOT_STATUS_MODIFY) { struct got_fileindex_entry *ie; ie = got_fileindex_entry_get(a->fileindex, path, strlen(path)); switch (got_fileindex_entry_staged_filetype_get(ie)) { case GOT_FILEIDX_MODE_REGULAR_FILE: case GOT_FILEIDX_MODE_BAD_SYMLINK: ct->mode = S_IFREG; break; case GOT_FILEIDX_MODE_SYMLINK: ct->mode = S_IFLNK; break; default: err = got_error_path(path, GOT_ERR_BAD_FILETYPE); goto done; } ct->mode |= got_fileindex_entry_perms_get(ie); } else if (status != GOT_STATUS_DELETE && staged_status != GOT_STATUS_DELETE) { if (dirfd != -1) { if (fstatat(dirfd, de_name, &sb, AT_SYMLINK_NOFOLLOW) == -1) { err = got_error_from_errno2("fstatat", ct->ondisk_path); goto done; } } else if (lstat(ct->ondisk_path, &sb) == -1) { err = got_error_from_errno2("lstat", ct->ondisk_path); goto done; } ct->mode = sb.st_mode; } if (asprintf(&ct->in_repo_path, "%s%s%s", a->worktree->path_prefix, got_path_is_root_dir(a->worktree->path_prefix) ? "" : "/", relpath) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (S_ISLNK(ct->mode) && staged_status == GOT_STATUS_NO_CHANGE && status == GOT_STATUS_ADD && !a->allow_bad_symlinks) { int is_bad_symlink; char target_path[PATH_MAX]; ssize_t target_len; target_len = readlink(ct->ondisk_path, target_path, sizeof(target_path)); if (target_len == -1) { err = got_error_from_errno2("readlink", ct->ondisk_path); goto done; } err = is_bad_symlink_target(&is_bad_symlink, target_path, target_len, ct->ondisk_path, a->worktree->root_path); if (err) goto done; if (is_bad_symlink) { err = got_error_path(ct->ondisk_path, GOT_ERR_BAD_SYMLINK); goto done; } } ct->status = status; ct->staged_status = staged_status; ct->blob_id = NULL; /* will be filled in when blob gets created */ if (ct->status != GOT_STATUS_ADD && ct->staged_status != GOT_STATUS_ADD) { ct->base_blob_id = got_object_id_dup(blob_id); if (ct->base_blob_id == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } ct->base_commit_id = got_object_id_dup(commit_id); if (ct->base_commit_id == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } } if (ct->staged_status == GOT_STATUS_ADD || ct->staged_status == GOT_STATUS_MODIFY) { ct->staged_blob_id = got_object_id_dup(staged_blob_id); if (ct->staged_blob_id == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } } ct->path = strdup(path); if (ct->path == NULL) { err = got_error_from_errno("strdup"); goto done; } err = got_pathlist_insert(&new, a->commitable_paths, ct->path, ct); if (err) goto done; if (a->diff_outfile && ct && new != NULL) { err = append_ct_diff(ct, &a->diff_header_shown, a->diff_outfile, a->f1, a->f2, dirfd, de_name, a->have_staged_files, a->repo, a->worktree); if (err) goto done; } done: if (ct && (err || new == NULL)) free_commitable(ct); free(parent_path); free(path); return err; } static const struct got_error *write_tree(struct got_object_id **, int *, struct got_tree_object *, const char *, struct got_pathlist_head *, got_worktree_status_cb status_cb, void *status_arg, struct got_repository *); static const struct got_error * write_subtree(struct got_object_id **new_subtree_id, int *nentries, struct got_tree_entry *te, const char *parent_path, struct got_pathlist_head *commitable_paths, got_worktree_status_cb status_cb, void *status_arg, struct got_repository *repo) { const struct got_error *err = NULL; struct got_tree_object *subtree; char *subpath; if (asprintf(&subpath, "%s%s%s", parent_path, got_path_is_root_dir(parent_path) ? "" : "/", te->name) == -1) return got_error_from_errno("asprintf"); err = got_object_open_as_tree(&subtree, repo, &te->id); if (err) return err; err = write_tree(new_subtree_id, nentries, subtree, subpath, commitable_paths, status_cb, status_arg, repo); got_object_tree_close(subtree); free(subpath); return err; } static const struct got_error * match_ct_parent_path(int *match, struct got_commitable *ct, const char *path) { const struct got_error *err = NULL; char *ct_parent_path = NULL; *match = 0; if (strchr(ct->in_repo_path, '/') == NULL) { *match = got_path_is_root_dir(path); return NULL; } err = got_path_dirname(&ct_parent_path, ct->in_repo_path); if (err) return err; *match = (strcmp(path, ct_parent_path) == 0); free(ct_parent_path); return err; } static mode_t get_ct_file_mode(struct got_commitable *ct) { if (S_ISLNK(ct->mode)) return S_IFLNK; return S_IFREG | (ct->mode & ((S_IRWXU | S_IRWXG | S_IRWXO))); } static const struct got_error * alloc_modified_blob_tree_entry(struct got_tree_entry **new_te, struct got_tree_entry *te, struct got_commitable *ct) { const struct got_error *err = NULL; *new_te = NULL; err = got_object_tree_entry_dup(new_te, te); if (err) goto done; (*new_te)->mode = get_ct_file_mode(ct); if (ct->staged_status == GOT_STATUS_MODIFY) memcpy(&(*new_te)->id, ct->staged_blob_id, sizeof((*new_te)->id)); else memcpy(&(*new_te)->id, ct->blob_id, sizeof((*new_te)->id)); done: if (err && *new_te) { free(*new_te); *new_te = NULL; } return err; } static const struct got_error * alloc_added_blob_tree_entry(struct got_tree_entry **new_te, struct got_commitable *ct) { const struct got_error *err = NULL; char *ct_name = NULL; *new_te = NULL; *new_te = calloc(1, sizeof(**new_te)); if (*new_te == NULL) return got_error_from_errno("calloc"); err = got_path_basename(&ct_name, ct->path); if (err) goto done; if (strlcpy((*new_te)->name, ct_name, sizeof((*new_te)->name)) >= sizeof((*new_te)->name)) { err = got_error(GOT_ERR_NO_SPACE); goto done; } (*new_te)->mode = get_ct_file_mode(ct); if (ct->staged_status == GOT_STATUS_ADD) memcpy(&(*new_te)->id, ct->staged_blob_id, sizeof((*new_te)->id)); else memcpy(&(*new_te)->id, ct->blob_id, sizeof((*new_te)->id)); done: free(ct_name); if (err && *new_te) { free(*new_te); *new_te = NULL; } return err; } static const struct got_error * insert_tree_entry(struct got_tree_entry *new_te, struct got_pathlist_head *paths) { const struct got_error *err = NULL; struct got_pathlist_entry *new_pe; err = got_pathlist_insert(&new_pe, paths, new_te->name, new_te); if (err) return err; if (new_pe == NULL) return got_error(GOT_ERR_TREE_DUP_ENTRY); return NULL; } static const struct got_error * report_ct_status(struct got_commitable *ct, got_worktree_status_cb status_cb, void *status_arg) { const char *ct_path = ct->path; unsigned char status; if (status_cb == NULL) /* no commit progress output desired */ return NULL; while (ct_path[0] == '/') ct_path++; if (ct->staged_status != GOT_STATUS_NO_CHANGE) status = ct->staged_status; else status = ct->status; return (*status_cb)(status_arg, status, GOT_STATUS_NO_CHANGE, ct_path, ct->blob_id, NULL, NULL, -1, NULL); } static const struct got_error * match_modified_subtree(int *modified, struct got_tree_entry *te, const char *base_tree_path, struct got_pathlist_head *commitable_paths) { const struct got_error *err = NULL; struct got_pathlist_entry *pe; char *te_path; *modified = 0; if (asprintf(&te_path, "%s%s%s", base_tree_path, got_path_is_root_dir(base_tree_path) ? "" : "/", te->name) == -1) return got_error_from_errno("asprintf"); TAILQ_FOREACH(pe, commitable_paths, entry) { struct got_commitable *ct = pe->data; *modified = got_path_is_child(ct->in_repo_path, te_path, strlen(te_path)); if (*modified) break; } free(te_path); return err; } static const struct got_error * match_deleted_or_modified_ct(struct got_commitable **ctp, struct got_tree_entry *te, const char *base_tree_path, struct got_pathlist_head *commitable_paths) { const struct got_error *err = NULL; struct got_pathlist_entry *pe; *ctp = NULL; TAILQ_FOREACH(pe, commitable_paths, entry) { struct got_commitable *ct = pe->data; char *ct_name = NULL; int path_matches; if (ct->staged_status == GOT_STATUS_NO_CHANGE) { if (ct->status != GOT_STATUS_MODIFY && ct->status != GOT_STATUS_MODE_CHANGE && ct->status != GOT_STATUS_DELETE && ct->status != GOT_STATUS_CONFLICT) continue; } else { if (ct->staged_status != GOT_STATUS_MODIFY && ct->staged_status != GOT_STATUS_DELETE) continue; } if (got_object_id_cmp(ct->base_blob_id, &te->id) != 0) continue; err = match_ct_parent_path(&path_matches, ct, base_tree_path); if (err) return err; if (!path_matches) continue; err = got_path_basename(&ct_name, pe->path); if (err) return err; if (strcmp(te->name, ct_name) != 0) { free(ct_name); continue; } free(ct_name); *ctp = ct; break; } return err; } static const struct got_error * make_subtree_for_added_blob(struct got_tree_entry **new_tep, const char *child_path, const char *path_base_tree, struct got_pathlist_head *commitable_paths, got_worktree_status_cb status_cb, void *status_arg, struct got_repository *repo) { const struct got_error *err = NULL; struct got_tree_entry *new_te; char *subtree_path; struct got_object_id *id = NULL; int nentries; *new_tep = NULL; if (asprintf(&subtree_path, "%s%s%s", path_base_tree, got_path_is_root_dir(path_base_tree) ? "" : "/", child_path) == -1) return got_error_from_errno("asprintf"); new_te = calloc(1, sizeof(*new_te)); if (new_te == NULL) return got_error_from_errno("calloc"); new_te->mode = S_IFDIR; if (strlcpy(new_te->name, child_path, sizeof(new_te->name)) >= sizeof(new_te->name)) { err = got_error(GOT_ERR_NO_SPACE); goto done; } err = write_tree(&id, &nentries, NULL, subtree_path, commitable_paths, status_cb, status_arg, repo); if (err) { free(new_te); goto done; } memcpy(&new_te->id, id, sizeof(new_te->id)); done: free(id); free(subtree_path); if (err == NULL) *new_tep = new_te; return err; } static const struct got_error * write_tree(struct got_object_id **new_tree_id, int *nentries, struct got_tree_object *base_tree, const char *path_base_tree, struct got_pathlist_head *commitable_paths, got_worktree_status_cb status_cb, void *status_arg, struct got_repository *repo) { const struct got_error *err = NULL; struct got_pathlist_head paths; struct got_tree_entry *te, *new_te = NULL; struct got_pathlist_entry *pe; TAILQ_INIT(&paths); *nentries = 0; /* Insert, and recurse into, newly added entries first. */ TAILQ_FOREACH(pe, commitable_paths, entry) { struct got_commitable *ct = pe->data; char *child_path = NULL, *slash; if ((ct->status != GOT_STATUS_ADD && ct->staged_status != GOT_STATUS_ADD) || (ct->flags & GOT_COMMITABLE_ADDED)) continue; if (!got_path_is_child(ct->in_repo_path, path_base_tree, strlen(path_base_tree))) continue; err = got_path_skip_common_ancestor(&child_path, path_base_tree, ct->in_repo_path); if (err) goto done; slash = strchr(child_path, '/'); if (slash == NULL) { err = alloc_added_blob_tree_entry(&new_te, ct); if (err) goto done; err = report_ct_status(ct, status_cb, status_arg); if (err) goto done; ct->flags |= GOT_COMMITABLE_ADDED; err = insert_tree_entry(new_te, &paths); if (err) goto done; (*nentries)++; } else { *slash = '\0'; /* trim trailing path components */ if (base_tree == NULL || got_object_tree_find_entry(base_tree, child_path) == NULL) { err = make_subtree_for_added_blob(&new_te, child_path, path_base_tree, commitable_paths, status_cb, status_arg, repo); if (err) goto done; err = insert_tree_entry(new_te, &paths); if (err) goto done; (*nentries)++; } } } if (base_tree) { int i, nbase_entries; /* Handle modified and deleted entries. */ nbase_entries = got_object_tree_get_nentries(base_tree); for (i = 0; i < nbase_entries; i++) { struct got_commitable *ct = NULL; te = got_object_tree_get_entry(base_tree, i); if (got_object_tree_entry_is_submodule(te)) { /* Entry is a submodule; just copy it. */ err = got_object_tree_entry_dup(&new_te, te); if (err) goto done; err = insert_tree_entry(new_te, &paths); if (err) goto done; (*nentries)++; continue; } if (S_ISDIR(te->mode)) { int modified; err = got_object_tree_entry_dup(&new_te, te); if (err) goto done; err = match_modified_subtree(&modified, te, path_base_tree, commitable_paths); if (err) goto done; /* Avoid recursion into unmodified subtrees. */ if (modified) { struct got_object_id *new_id; int nsubentries; err = write_subtree(&new_id, &nsubentries, te, path_base_tree, commitable_paths, status_cb, status_arg, repo); if (err) goto done; if (nsubentries == 0) { /* All entries were deleted. */ free(new_id); continue; } memcpy(&new_te->id, new_id, sizeof(new_te->id)); free(new_id); } err = insert_tree_entry(new_te, &paths); if (err) goto done; (*nentries)++; continue; } err = match_deleted_or_modified_ct(&ct, te, path_base_tree, commitable_paths); if (err) goto done; if (ct) { /* NB: Deleted entries get dropped here. */ if (ct->status == GOT_STATUS_MODIFY || ct->status == GOT_STATUS_MODE_CHANGE || ct->status == GOT_STATUS_CONFLICT || ct->staged_status == GOT_STATUS_MODIFY) { err = alloc_modified_blob_tree_entry( &new_te, te, ct); if (err) goto done; err = insert_tree_entry(new_te, &paths); if (err) goto done; (*nentries)++; } err = report_ct_status(ct, status_cb, status_arg); if (err) goto done; } else { /* Entry is unchanged; just copy it. */ err = got_object_tree_entry_dup(&new_te, te); if (err) goto done; err = insert_tree_entry(new_te, &paths); if (err) goto done; (*nentries)++; } } } /* Write new list of entries; deleted entries have been dropped. */ err = got_object_tree_create(new_tree_id, &paths, *nentries, repo); done: got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE); return err; } static const struct got_error * update_fileindex_after_commit(struct got_worktree *worktree, struct got_pathlist_head *commitable_paths, struct got_object_id *new_base_commit_id, struct got_fileindex *fileindex, int have_staged_files) { const struct got_error *err = NULL; struct got_pathlist_entry *pe; char *relpath = NULL; TAILQ_FOREACH(pe, commitable_paths, entry) { struct got_fileindex_entry *ie; struct got_commitable *ct = pe->data; ie = got_fileindex_entry_get(fileindex, pe->path, pe->path_len); err = got_path_skip_common_ancestor(&relpath, worktree->root_path, ct->ondisk_path); if (err) goto done; if (ie) { if (ct->status == GOT_STATUS_DELETE || ct->staged_status == GOT_STATUS_DELETE) { got_fileindex_entry_remove(fileindex, ie); } else if (ct->staged_status == GOT_STATUS_ADD || ct->staged_status == GOT_STATUS_MODIFY) { got_fileindex_entry_stage_set(ie, GOT_FILEIDX_STAGE_NONE); got_fileindex_entry_staged_filetype_set(ie, 0); err = got_fileindex_entry_update(ie, worktree->root_fd, relpath, ct->staged_blob_id->sha1, new_base_commit_id->sha1, !have_staged_files); } else err = got_fileindex_entry_update(ie, worktree->root_fd, relpath, ct->blob_id->sha1, new_base_commit_id->sha1, !have_staged_files); } else { err = got_fileindex_entry_alloc(&ie, pe->path); if (err) goto done; err = got_fileindex_entry_update(ie, worktree->root_fd, relpath, ct->blob_id->sha1, new_base_commit_id->sha1, 1); if (err) { got_fileindex_entry_free(ie); goto done; } err = got_fileindex_entry_add(fileindex, ie); if (err) { got_fileindex_entry_free(ie); goto done; } } free(relpath); relpath = NULL; } done: free(relpath); return err; } static const struct got_error * check_out_of_date(const char *in_repo_path, unsigned char status, unsigned char staged_status, struct got_object_id *base_blob_id, struct got_object_id *base_commit_id, struct got_object_id *head_commit_id, struct got_repository *repo, int ood_errcode) { const struct got_error *err = NULL; struct got_commit_object *commit = NULL; struct got_object_id *id = NULL; if (status != GOT_STATUS_ADD && staged_status != GOT_STATUS_ADD) { /* Trivial case: base commit == head commit */ if (got_object_id_cmp(base_commit_id, head_commit_id) == 0) return NULL; /* * Ensure file content which local changes were based * on matches file content in the branch head. */ err = got_object_open_as_commit(&commit, repo, head_commit_id); if (err) goto done; err = got_object_id_by_path(&id, repo, commit, in_repo_path); if (err) { if (err->code == GOT_ERR_NO_TREE_ENTRY) err = got_error(ood_errcode); goto done; } else if (got_object_id_cmp(id, base_blob_id) != 0) err = got_error(ood_errcode); } else { /* Require that added files don't exist in the branch head. */ err = got_object_open_as_commit(&commit, repo, head_commit_id); if (err) goto done; err = got_object_id_by_path(&id, repo, commit, in_repo_path); if (err && err->code != GOT_ERR_NO_TREE_ENTRY) goto done; err = id ? got_error(ood_errcode) : NULL; } done: free(id); if (commit) got_object_commit_close(commit); return err; } static const struct got_error * commit_worktree(struct got_object_id **new_commit_id, struct got_pathlist_head *commitable_paths, struct got_object_id *head_commit_id, struct got_object_id *parent_id2, struct got_worktree *worktree, const char *author, const char *committer, char *diff_path, got_worktree_commit_msg_cb commit_msg_cb, void *commit_arg, got_worktree_status_cb status_cb, void *status_arg, struct got_repository *repo) { const struct got_error *err = NULL; struct got_pathlist_entry *pe; struct got_commit_object *head_commit = NULL; struct got_tree_object *head_tree = NULL; struct got_object_id *new_tree_id = NULL; int nentries, nparents = 0; struct got_object_id_queue parent_ids; struct got_object_qid *pid = NULL; char *logmsg = NULL; time_t timestamp; *new_commit_id = NULL; STAILQ_INIT(&parent_ids); err = got_object_open_as_commit(&head_commit, repo, head_commit_id); if (err) goto done; err = got_object_open_as_tree(&head_tree, repo, head_commit->tree_id); if (err) goto done; if (commit_msg_cb != NULL) { err = commit_msg_cb(commitable_paths, diff_path, &logmsg, commit_arg); if (err) goto done; } if (logmsg == NULL || strlen(logmsg) == 0) { err = got_error(GOT_ERR_COMMIT_MSG_EMPTY); goto done; } /* Create blobs from added and modified files and record their IDs. */ TAILQ_FOREACH(pe, commitable_paths, entry) { struct got_commitable *ct = pe->data; char *ondisk_path; /* Blobs for staged files already exist. */ if (ct->staged_status == GOT_STATUS_ADD || ct->staged_status == GOT_STATUS_MODIFY) continue; if (ct->status != GOT_STATUS_ADD && ct->status != GOT_STATUS_MODIFY && ct->status != GOT_STATUS_MODE_CHANGE && ct->status != GOT_STATUS_CONFLICT) continue; if (asprintf(&ondisk_path, "%s/%s", worktree->root_path, pe->path) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_object_blob_create(&ct->blob_id, ondisk_path, repo); free(ondisk_path); if (err) goto done; } /* Recursively write new tree objects. */ err = write_tree(&new_tree_id, &nentries, head_tree, "/", commitable_paths, status_cb, status_arg, repo); if (err) goto done; err = got_object_qid_alloc(&pid, head_commit_id); if (err) goto done; STAILQ_INSERT_TAIL(&parent_ids, pid, entry); nparents++; if (parent_id2) { err = got_object_qid_alloc(&pid, parent_id2); if (err) goto done; STAILQ_INSERT_TAIL(&parent_ids, pid, entry); nparents++; } timestamp = time(NULL); err = got_object_commit_create(new_commit_id, new_tree_id, &parent_ids, nparents, author, timestamp, committer, timestamp, logmsg, repo); if (logmsg != NULL) free(logmsg); if (err) goto done; done: got_object_id_queue_free(&parent_ids); if (head_tree) got_object_tree_close(head_tree); if (head_commit) got_object_commit_close(head_commit); return err; } static const struct got_error * check_path_is_commitable(const char *path, struct got_pathlist_head *commitable_paths) { struct got_pathlist_entry *cpe = NULL; size_t path_len = strlen(path); TAILQ_FOREACH(cpe, commitable_paths, entry) { struct got_commitable *ct = cpe->data; const char *ct_path = ct->path; while (ct_path[0] == '/') ct_path++; if (strcmp(path, ct_path) == 0 || got_path_is_child(ct_path, path, path_len)) break; } if (cpe == NULL) return got_error_path(path, GOT_ERR_BAD_PATH); return NULL; } static const struct got_error * check_staged_file(void *arg, struct got_fileindex_entry *ie) { int *have_staged_files = arg; if (got_fileindex_entry_stage_get(ie) != GOT_FILEIDX_STAGE_NONE) { *have_staged_files = 1; return got_error(GOT_ERR_CANCELLED); } return NULL; } static const struct got_error * check_non_staged_files(struct got_fileindex *fileindex, struct got_pathlist_head *paths) { struct got_pathlist_entry *pe; struct got_fileindex_entry *ie; TAILQ_FOREACH(pe, paths, entry) { if (pe->path[0] == '\0') continue; ie = got_fileindex_entry_get(fileindex, pe->path, pe->path_len); if (ie == NULL) return got_error_path(pe->path, GOT_ERR_BAD_PATH); if (got_fileindex_entry_stage_get(ie) == GOT_FILEIDX_STAGE_NONE) return got_error_path(pe->path, GOT_ERR_FILE_NOT_STAGED); } return NULL; } static void print_load_info(int print_colored, int print_found, int print_trees, int ncolored, int nfound, int ntrees) { if (print_colored) { printf("%d commit%s colored", ncolored, ncolored == 1 ? "" : "s"); } if (print_found) { printf("%s%d object%s found", ncolored > 0 ? "; " : "", nfound, nfound == 1 ? "" : "s"); } if (print_trees) { printf("; %d tree%s scanned", ntrees, ntrees == 1 ? "" : "s"); } } struct got_send_progress_arg { char last_scaled_packsize[FMT_SCALED_STRSIZE]; int verbosity; int last_ncolored; int last_nfound; int last_ntrees; int loading_done; int last_ncommits; int last_nobj_total; int last_p_deltify; int last_p_written; int last_p_sent; int printed_something; int sent_something; struct got_pathlist_head *delete_branches; }; static const struct got_error * send_progress(void *arg, int ncolored, int nfound, int ntrees, off_t packfile_size, int ncommits, int nobj_total, int nobj_deltify, int nobj_written, off_t bytes_sent, const char *refname, const char *errmsg, int success) { struct got_send_progress_arg *a = arg; char scaled_packsize[FMT_SCALED_STRSIZE]; char scaled_sent[FMT_SCALED_STRSIZE]; int p_deltify = 0, p_written = 0, p_sent = 0; int print_colored = 0, print_found = 0, print_trees = 0; int print_searching = 0, print_total = 0; int print_deltify = 0, print_written = 0, print_sent = 0; if (a->verbosity < 0) return NULL; if (refname) { const char *status = success ? "accepted" : "rejected"; if (success) { struct got_pathlist_entry *pe; TAILQ_FOREACH(pe, a->delete_branches, entry) { const char *branchname = pe->path; if (got_path_cmp(branchname, refname, strlen(branchname), strlen(refname)) == 0) { status = "deleted"; a->sent_something = 1; break; } } } if (a->printed_something) putchar('\n'); printf("Server has %s %s", status, refname); if (errmsg) printf(": %s", errmsg); a->printed_something = 1; return NULL; } if (a->last_ncolored != ncolored) { print_colored = 1; a->last_ncolored = ncolored; } if (a->last_nfound != nfound) { print_colored = 1; print_found = 1; a->last_nfound = nfound; } if (a->last_ntrees != ntrees) { print_colored = 1; print_found = 1; print_trees = 1; a->last_ntrees = ntrees; } if ((print_colored || print_found || print_trees) && !a->loading_done) { printf("\r"); print_load_info(print_colored, print_found, print_trees, ncolored, nfound, ntrees); a->printed_something = 1; fflush(stdout); return NULL; } else if (!a->loading_done) { printf("\r"); print_load_info(1, 1, 1, ncolored, nfound, ntrees); printf("\n"); a->loading_done = 1; } if (fmt_scaled(packfile_size, scaled_packsize) == -1) return got_error_from_errno("fmt_scaled"); if (fmt_scaled(bytes_sent, scaled_sent) == -1) return got_error_from_errno("fmt_scaled"); if (a->last_ncommits != ncommits) { print_searching = 1; a->last_ncommits = ncommits; } if (a->last_nobj_total != nobj_total) { print_searching = 1; print_total = 1; a->last_nobj_total = nobj_total; } if (packfile_size > 0 && (a->last_scaled_packsize[0] == '\0' || strcmp(scaled_packsize, a->last_scaled_packsize)) != 0) { if (strlcpy(a->last_scaled_packsize, scaled_packsize, FMT_SCALED_STRSIZE) >= FMT_SCALED_STRSIZE) return got_error(GOT_ERR_NO_SPACE); } if (nobj_deltify > 0 || nobj_written > 0) { if (nobj_deltify > 0) { p_deltify = (nobj_deltify * 100) / nobj_total; if (p_deltify != a->last_p_deltify) { a->last_p_deltify = p_deltify; print_searching = 1; print_total = 1; print_deltify = 1; } } if (nobj_written > 0) { p_written = (nobj_written * 100) / nobj_total; if (p_written != a->last_p_written) { a->last_p_written = p_written; print_searching = 1; print_total = 1; print_deltify = 1; print_written = 1; } } } if (bytes_sent > 0) { p_sent = (bytes_sent * 100) / packfile_size; if (p_sent != a->last_p_sent) { a->last_p_sent = p_sent; print_searching = 1; print_total = 1; print_deltify = 1; print_written = 1; print_sent = 1; } a->sent_something = 1; } if (print_searching || print_total || print_deltify || print_written || print_sent) printf("\r"); if (print_searching) printf("packing %d reference%s", ncommits, ncommits == 1 ? "" : "s"); if (print_total) printf("; %d object%s", nobj_total, nobj_total == 1 ? "" : "s"); if (print_deltify) printf("; deltify: %d%%", p_deltify); if (print_sent) printf("; uploading pack: %*s %d%%", FMT_SCALED_STRSIZE - 2, scaled_packsize, p_sent); else if (print_written) printf("; writing pack: %*s %d%%", FMT_SCALED_STRSIZE - 2, scaled_packsize, p_written); if (print_searching || print_total || print_deltify || print_written || print_sent) { a->printed_something = 1; fflush(stdout); } return NULL; } struct got_fetch_progress_arg { char last_scaled_size[FMT_SCALED_STRSIZE]; int last_p_indexed; int last_p_resolved; int verbosity; struct got_repository *repo; }; static const struct got_error * fetch_progress(void *arg, const char *message, off_t packfile_size, int nobj_total, int nobj_indexed, int nobj_loose, int nobj_resolved) { struct got_fetch_progress_arg *a = arg; char scaled_size[FMT_SCALED_STRSIZE]; int p_indexed, p_resolved; int print_size = 0, print_indexed = 0, print_resolved = 0; if (a->verbosity < 0) return NULL; if (message && message[0] != '\0') { printf("\rserver: %s", message); fflush(stdout); return NULL; } if (packfile_size > 0 || nobj_indexed > 0) { if (fmt_scaled(packfile_size, scaled_size) == 0 && (a->last_scaled_size[0] == '\0' || strcmp(scaled_size, a->last_scaled_size)) != 0) { print_size = 1; if (strlcpy(a->last_scaled_size, scaled_size, FMT_SCALED_STRSIZE) >= FMT_SCALED_STRSIZE) return got_error(GOT_ERR_NO_SPACE); } if (nobj_indexed > 0) { p_indexed = (nobj_indexed * 100) / nobj_total; if (p_indexed != a->last_p_indexed) { a->last_p_indexed = p_indexed; print_indexed = 1; print_size = 1; } } if (nobj_resolved > 0) { p_resolved = (nobj_resolved * 100) / (nobj_total - nobj_loose); if (p_resolved != a->last_p_resolved) { a->last_p_resolved = p_resolved; print_resolved = 1; print_indexed = 1; print_size = 1; } } } if (print_size || print_indexed || print_resolved) printf("\r"); if (print_size) printf("%*s fetched", FMT_SCALED_STRSIZE - 2, scaled_size); if (print_indexed) printf("; indexing %d%%", p_indexed); if (print_resolved) printf("; resolving deltas %d%%", p_resolved); if (print_size || print_indexed || print_resolved) { putchar('\n'); fflush(stdout); } return NULL; } static const struct got_error * create_symref(const char *refname, struct got_reference *target_ref, int verbosity, struct got_repository *repo) { const struct got_error *err; struct got_reference *head_symref; err = got_ref_alloc_symref(&head_symref, refname, target_ref); if (err) return err; err = got_ref_write(head_symref, repo); if (err == NULL && verbosity > 0) { printf("Created reference %s: %s\n", GOT_REF_HEAD, got_ref_get_name(target_ref)); } got_ref_close(head_symref); return err; } static const struct got_error * create_ref(const char *refname, struct got_object_id *id, int verbosity, struct got_repository *repo) { const struct got_error *err = NULL; struct got_reference *ref; char *id_str; err = got_object_id_str(&id_str, id); if (err) return err; err = got_ref_alloc(&ref, refname, id); if (err) goto done; err = got_ref_write(ref, repo); got_ref_close(ref); if (err == NULL && verbosity >= 0) printf("Created reference %s: %s\n", refname, id_str); done: free(id_str); return err; } static const struct got_error * update_ref(struct got_reference *ref, struct got_object_id *new_id, int verbosity, struct got_repository *repo) { const struct got_error *err = NULL; char *new_id_str = NULL; struct got_object_id *old_id = NULL; err = got_object_id_str(&new_id_str, new_id); if (err) goto done; if (strncmp(got_ref_get_name(ref), "refs/tags/", 10) == 0) { err = got_ref_resolve(&old_id, repo, ref); if (err) goto done; if (got_object_id_cmp(old_id, new_id) == 0) goto done; if (verbosity >= 0) { printf("Rejecting update of existing tag %s: %s\n", got_ref_get_name(ref), new_id_str); } goto done; } if (got_ref_is_symbolic(ref)) { if (verbosity >= 0) { printf("Replacing reference %s: %s\n", got_ref_get_name(ref), got_ref_get_symref_target(ref)); } err = got_ref_change_symref_to_ref(ref, new_id); if (err) goto done; err = got_ref_write(ref, repo); if (err) goto done; } else { err = got_ref_resolve(&old_id, repo, ref); if (err) goto done; if (got_object_id_cmp(old_id, new_id) == 0) goto done; err = got_ref_change_ref(ref, new_id); if (err) goto done; err = got_ref_write(ref, repo); if (err) goto done; } if (verbosity >= 0) printf("Updated %s: %s\n", got_ref_get_name(ref), new_id_str); done: free(old_id); free(new_id_str); return err; } static const struct got_error * fetch_updated_remote(const char *proto, const char *host, const char *port, const char *server_path, int verbosity, const struct got_remote_repo *remote, struct got_repository *repo, struct got_reference *head_ref, const char *head_refname) { const struct got_error *err = NULL, *unlock_err = NULL; struct got_pathlist_entry *pe; struct got_pathlist_head learned_refs; struct got_pathlist_head symrefs; struct got_pathlist_head wanted_branches; struct got_pathlist_head wanted_refs; struct got_object_id *pack_hash; struct got_fetch_progress_arg fpa; int fetchfd = -1; pid_t fetchpid = -1; TAILQ_INIT(&learned_refs); TAILQ_INIT(&symrefs); TAILQ_INIT(&wanted_branches); TAILQ_INIT(&wanted_refs); err = got_pathlist_insert(NULL, &wanted_branches, head_refname, NULL); if (err) goto done; err = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port, server_path, verbosity); if (err) goto done; fpa.last_scaled_size[0] = '\0'; fpa.last_p_indexed = -1; fpa.last_p_resolved = -1; fpa.verbosity = verbosity; fpa.repo = repo; err = got_fetch_pack(&pack_hash, &learned_refs, &symrefs, remote->name, 1, 0, &wanted_branches, &wanted_refs, 0, verbosity, fetchfd, repo, head_refname, NULL, 0, fetch_progress, &fpa); if (err) goto done; /* Update references provided with the pack file. */ TAILQ_FOREACH(pe, &learned_refs, entry) { const char *refname = pe->path; struct got_object_id *id = pe->data; struct got_reference *ref; err = got_ref_open(&ref, repo, refname, 0); if (err) { if (err->code != GOT_ERR_NOT_REF) goto done; err = create_ref(refname, id, verbosity, repo); if (err) goto done; } else { err = update_ref(ref, id, verbosity, repo); unlock_err = got_ref_unlock(ref); if (unlock_err && err == NULL) err = unlock_err; got_ref_close(ref); if (err) goto done; } } /* Set the HEAD reference if the server provided one. */ TAILQ_FOREACH(pe, &symrefs, entry) { struct got_reference *target_ref; const char *refname = pe->path; const char *target = pe->data; char *remote_refname = NULL, *remote_target = NULL; if (strcmp(refname, GOT_REF_HEAD) != 0) continue; err = got_ref_open(&target_ref, repo, target, 0); if (err) { if (err->code == GOT_ERR_NOT_REF) { err = NULL; continue; } goto done; } err = create_symref(refname, target_ref, verbosity, repo); got_ref_close(target_ref); if (err) goto done; if (remote->mirror_references) continue; if (strncmp("refs/heads/", target, 11) != 0) continue; if (asprintf(&remote_refname, "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME, refname) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (asprintf(&remote_target, "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME, target + 11) == -1) { err = got_error_from_errno("asprintf"); free(remote_refname); goto done; } err = got_ref_open(&target_ref, repo, remote_target, 0); if (err) { free(remote_refname); free(remote_target); if (err->code == GOT_ERR_NOT_REF) { err = NULL; continue; } goto done; } err = create_symref(remote_refname, target_ref, verbosity - 1, repo); free(remote_refname); free(remote_target); got_ref_close(target_ref); if (err) goto done; } done: got_pathlist_free(&learned_refs, GOT_PATHLIST_FREE_NONE); got_pathlist_free(&symrefs, GOT_PATHLIST_FREE_NONE); got_pathlist_free(&wanted_branches, GOT_PATHLIST_FREE_NONE); got_pathlist_free(&wanted_refs, GOT_PATHLIST_FREE_NONE); return err; } const struct got_error * got_worktree_cvg_commit(struct got_object_id **new_commit_id, struct got_worktree *worktree, struct got_pathlist_head *paths, const char *author, const char *committer, int allow_bad_symlinks, int show_diff, int commit_conflicts, got_worktree_commit_msg_cb commit_msg_cb, void *commit_arg, got_worktree_status_cb status_cb, void *status_arg, const char *proto, const char *host, const char *port, const char *server_path, int verbosity, const struct got_remote_repo *remote, got_cancel_cb check_cancelled, struct got_repository *repo) { const struct got_error *err = NULL, *unlockerr = NULL, *sync_err; struct got_fileindex *fileindex = NULL; char *fileindex_path = NULL; struct got_pathlist_head commitable_paths; struct collect_commitables_arg cc_arg; struct got_pathlist_entry *pe; struct got_reference *head_ref = NULL, *head_ref2 = NULL; struct got_reference *commit_ref = NULL; struct got_object_id *head_commit_id = NULL; struct got_object_id *head_commit_id2 = NULL; char *head_refname = NULL; char *commit_refname = NULL; char *diff_path = NULL; int have_staged_files = 0; int sendfd = -1; pid_t sendpid = -1; struct got_send_progress_arg spa; struct got_pathlist_head commit_reflist; struct got_pathlist_head tag_names; struct got_pathlist_head delete_branches; *new_commit_id = NULL; memset(&cc_arg, 0, sizeof(cc_arg)); TAILQ_INIT(&commitable_paths); TAILQ_INIT(&commit_reflist); TAILQ_INIT(&tag_names); TAILQ_INIT(&delete_branches); err = lock_worktree(worktree, LOCK_EX); if (err) goto done; err = got_worktree_cvg_get_commit_ref_name(&commit_refname, worktree); if (err) goto done; head_refname = worktree->head_ref_name; err = got_ref_open(&head_ref, repo, head_refname, 0); if (err) goto done; err = got_ref_resolve(&head_commit_id, repo, head_ref); if (err) goto done; err = got_ref_alloc(&commit_ref, commit_refname, head_commit_id); if (err) goto done; err = got_ref_write(commit_ref, repo); if (err) goto done; err = open_fileindex(&fileindex, &fileindex_path, worktree); if (err) goto done; err = got_fileindex_for_each_entry_safe(fileindex, check_staged_file, &have_staged_files); if (err && err->code != GOT_ERR_CANCELLED) goto done; if (have_staged_files) { err = check_non_staged_files(fileindex, paths); if (err) goto done; } cc_arg.commitable_paths = &commitable_paths; cc_arg.worktree = worktree; cc_arg.fileindex = fileindex; cc_arg.repo = repo; cc_arg.have_staged_files = have_staged_files; cc_arg.allow_bad_symlinks = allow_bad_symlinks; cc_arg.diff_header_shown = 0; cc_arg.commit_conflicts = commit_conflicts; if (show_diff) { err = got_opentemp_named(&diff_path, &cc_arg.diff_outfile, GOT_TMPDIR_STR "/got", ".diff"); if (err) goto done; cc_arg.f1 = got_opentemp(); if (cc_arg.f1 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } cc_arg.f2 = got_opentemp(); if (cc_arg.f2 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } } TAILQ_FOREACH(pe, paths, entry) { err = worktree_status(worktree, pe->path, fileindex, repo, collect_commitables, &cc_arg, NULL, NULL, 0, 0); if (err) goto done; } if (show_diff) { if (fflush(cc_arg.diff_outfile) == EOF) { err = got_error_from_errno("fflush"); goto done; } } if (TAILQ_EMPTY(&commitable_paths)) { err = got_error(GOT_ERR_COMMIT_NO_CHANGES); goto done; } TAILQ_FOREACH(pe, paths, entry) { err = check_path_is_commitable(pe->path, &commitable_paths); if (err) goto done; } TAILQ_FOREACH(pe, &commitable_paths, entry) { struct got_commitable *ct = pe->data; const char *ct_path = ct->in_repo_path; while (ct_path[0] == '/') ct_path++; err = check_out_of_date(ct_path, ct->status, ct->staged_status, ct->base_blob_id, ct->base_commit_id, head_commit_id, repo, GOT_ERR_COMMIT_OUT_OF_DATE); if (err) goto done; } err = commit_worktree(new_commit_id, &commitable_paths, head_commit_id, NULL, worktree, author, committer, (diff_path && cc_arg.diff_header_shown) ? diff_path : NULL, commit_msg_cb, commit_arg, status_cb, status_arg, repo); if (err) goto done; /* * Check if a concurrent commit to our branch has occurred. * Lock the reference here to prevent concurrent modification. */ err = got_ref_open(&head_ref2, repo, head_refname, 1); if (err) goto done; err = got_ref_resolve(&head_commit_id2, repo, head_ref2); if (err) goto done; if (got_object_id_cmp(head_commit_id, head_commit_id2) != 0) { err = got_error(GOT_ERR_COMMIT_HEAD_CHANGED); goto done; } err = got_pathlist_append(&commit_reflist, commit_refname, head_refname); if (err) goto done; /* Update commit ref in repository. */ err = got_ref_change_ref(commit_ref, *new_commit_id); if (err) goto done; err = got_ref_write(commit_ref, repo); if (err) goto done; if (verbosity >= 0) { printf("Connecting to \"%s\" %s://%s%s%s%s%s\n", remote->name, proto, host, port ? ":" : "", port ? port : "", *server_path == '/' ? "" : "/", server_path); } /* Attempt send to remote branch. */ err = got_send_connect(&sendpid, &sendfd, proto, host, port, server_path, verbosity); if (err) goto done; memset(&spa, 0, sizeof(spa)); spa.last_scaled_packsize[0] = '\0'; spa.last_p_deltify = -1; spa.last_p_written = -1; spa.verbosity = verbosity; spa.delete_branches = &delete_branches; err = got_send_pack(remote->name, &commit_reflist, &tag_names, &delete_branches, verbosity, 0, sendfd, repo, send_progress, &spa, check_cancelled, NULL); if (spa.printed_something) putchar('\n'); if (err != NULL && err->code == GOT_ERR_SEND_ANCESTRY) { /* * Fetch new changes since remote has diverged. * No trivial-rebase yet; require update to be run manually. */ err = fetch_updated_remote(proto, host, port, server_path, verbosity, remote, repo, head_ref, head_refname); if (err == NULL) goto done; err = got_error(GOT_ERR_COMMIT_OUT_OF_DATE); goto done; /* XXX: Rebase commit over fetched remote branch. */ } if (err) { goto done; } /* Update branch head in repository. */ err = got_ref_change_ref(head_ref2, *new_commit_id); if (err) goto done; err = got_ref_write(head_ref2, repo); if (err) goto done; err = got_worktree_set_base_commit_id(worktree, repo, *new_commit_id); if (err) goto done; err = ref_base_commit(worktree, repo); if (err) goto done; /* XXX: fileindex must be updated for other fetched changes? */ err = update_fileindex_after_commit(worktree, &commitable_paths, *new_commit_id, fileindex, have_staged_files); sync_err = sync_fileindex(fileindex, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: if (head_ref2) { unlockerr = got_ref_unlock(head_ref2); if (unlockerr && err == NULL) err = unlockerr; got_ref_close(head_ref2); } if (commit_ref) got_ref_close(commit_ref); if (fileindex) got_fileindex_free(fileindex); unlockerr = lock_worktree(worktree, LOCK_SH); if (unlockerr && err == NULL) err = unlockerr; TAILQ_FOREACH(pe, &commitable_paths, entry) { struct got_commitable *ct = pe->data; free_commitable(ct); } got_pathlist_free(&commitable_paths, GOT_PATHLIST_FREE_NONE); if (diff_path && unlink(diff_path) == -1 && err == NULL) err = got_error_from_errno2("unlink", diff_path); if (cc_arg.diff_outfile && fclose(cc_arg.diff_outfile) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(head_commit_id); free(head_commit_id2); free(commit_refname); free(fileindex_path); free(diff_path); return err; } const struct got_error * got_worktree_cvg_get_commit_ref_name(char **refname, struct got_worktree *worktree) { return get_ref_name(refname, worktree, GOT_WORKTREE_COMMIT_REF_PREFIX); } got-portable-0.101/lib/got_lib_pack_create.h0000644000175100017510000001377614644143163014500 /* * Copyright (c) 2021 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Write pack file data into the provided open packfile handle, for all * objects reachable via the commits listed in 'ours'. * Exclude any objects for commits listed in 'theirs' if 'theirs' is not NULL. * Return the SHA1 digest of the resulting pack file in pack_sha1 which must * be pre-allocated by the caller with at least SHA1_DIGEST_LENGTH bytes. */ const struct got_error *got_pack_create(uint8_t *pack_sha1, int packfd, FILE *delta_cache, struct got_object_id **theirs, int ntheirs, struct got_object_id **ours, int nours, struct got_repository *repo, int loose_obj_only, int allow_empty, int force_refdelta, got_pack_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *, got_cancel_cb cancel_cb, void *cancel_arg); const struct got_error * got_pack_cache_pack_for_packidx(struct got_pack **pack, struct got_packidx *packidx, struct got_repository *repo); const struct got_error * got_pack_find_pack_for_commit_painting(struct got_packidx **best_packidx, struct got_object_id_queue *ids, int nids, struct got_repository *repo); const struct got_error *got_pack_find_pack_for_reuse( struct got_packidx **best_packidx, struct got_repository *repo); struct got_ratelimit; const struct got_error *got_pack_paint_commits(int *ncolored, struct got_object_id_queue *ids, int nids, struct got_object_idset *keep, struct got_object_idset *drop, struct got_object_idset *skip, struct got_repository *repo, got_pack_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl, got_cancel_cb cancel_cb, void *cancel_arg); enum got_pack_findtwixt_color { COLOR_KEEP = 0, COLOR_DROP, COLOR_SKIP, COLOR_MAX, }; const struct got_error *got_pack_paint_commit(struct got_object_qid *qid, intptr_t color); const struct got_error *got_pack_queue_commit_id( struct got_object_id_queue *ids, struct got_object_id *id, intptr_t color, struct got_repository *repo); struct got_pack_metavec { struct got_pack_meta **meta; int nmeta; int metasz; }; struct got_pack_meta { struct got_object_id id; uint32_t path_hash; int obj_type; off_t size; time_t mtime; /* The best delta we picked */ struct got_pack_meta *head; struct got_pack_meta *prev; unsigned char *delta_buf; /* if encoded in memory (compressed) */ off_t delta_offset; /* offset in delta cache file (compressed) */ off_t delta_len; /* encoded delta length */ off_t delta_compressed_len; /* encoded+compressed delta length */ int nchain; off_t reused_delta_offset; /* offset of delta in reused pack file */ struct got_object_id *base_obj_id; /* Only used for delta window */ struct got_delta_table *dtab; /* Only used for writing offset deltas */ off_t off; }; const struct got_error *got_pack_add_meta(struct got_pack_meta *m, struct got_pack_metavec *v); const struct got_error * got_pack_search_deltas(struct got_packidx **packidx, struct got_pack **pack, struct got_pack_metavec *v, struct got_object_idset *idset, int ncolored, int nfound, int ntrees, int ncommits, struct got_repository *repo, got_pack_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl, got_cancel_cb cancel_cb, void *cancel_arg); const struct got_error * got_pack_report_progress(got_pack_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl, int ncolored, int nfound, int ntrees, off_t packfile_size, int ncommits, int nobj_total, int obj_deltify, int nobj_written); const struct got_error * got_pack_load_packed_object_ids(int *found_all_objects, struct got_object_id **ours, int nours, struct got_object_id **theirs, int ntheirs, int want_meta, uint32_t seed, struct got_object_idset *idset, struct got_object_idset *idset_exclude, int loose_obj_only, struct got_repository *repo, struct got_packidx *packidx, int *ncolored, int *nfound, int *ntrees, got_pack_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl, got_cancel_cb cancel_cb, void *cancel_arg); const struct got_error * got_pack_load_tree_entries(struct got_object_id_queue *ids, int want_meta, struct got_object_idset *idset, struct got_object_idset *idset_exclude, struct got_tree_object *tree, const char *dpath, time_t mtime, uint32_t seed, struct got_repository *repo, int loose_obj_only, int *ncolored, int *nfound, int *ntrees, got_pack_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl, got_cancel_cb cancel_cb, void *cancel_arg); const struct got_error * got_pack_load_tree(int want_meta, struct got_object_idset *idset, struct got_object_idset *idset_exclude, struct got_object_id *tree_id, const char *dpath, time_t mtime, uint32_t seed, struct got_repository *repo, int loose_obj_only, int *ncolored, int *nfound, int *ntrees, got_pack_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl, got_cancel_cb cancel_cb, void *cancel_arg); const struct got_error * got_pack_add_object(int want_meta, struct got_object_idset *idset, struct got_object_id *id, const char *path, int obj_type, time_t mtime, uint32_t seed, int loose_obj_only, struct got_repository *repo, int *ncolored, int *nfound, int *ntrees, got_pack_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl); got-portable-0.101/lib/pack.c0000664000175100017510000015102214644144735011444 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_lib_hash.h" #include "got_lib_delta.h" #include "got_lib_delta_cache.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_qid.h" #include "got_lib_object_parse.h" #include "got_lib_privsep.h" #include "got_lib_pack.h" #ifndef nitems #define nitems(_a) (sizeof(_a) / sizeof((_a)[0])) #endif #ifndef MIN #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) #endif static const struct got_error * verify_fanout_table(uint32_t *fanout_table) { int i; for (i = 0; i < 0xff - 1; i++) { if (be32toh(fanout_table[i]) > be32toh(fanout_table[i + 1])) return got_error(GOT_ERR_BAD_PACKIDX); } return NULL; } const struct got_error * got_packidx_init_hdr(struct got_packidx *p, int verify, off_t packfile_size) { const struct got_error *err = NULL; enum got_hash_algorithm algo = GOT_HASH_SHA1; struct got_packidx_v2_hdr *h; struct got_hash ctx; uint8_t hash[GOT_HASH_DIGEST_MAXLEN]; size_t nobj, len_fanout, len_ids, offset, remain; ssize_t n; int i; got_hash_init(&ctx, algo); h = &p->hdr; offset = 0; remain = p->len; if (remain < sizeof(*h->magic)) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } if (p->map) h->magic = (uint32_t *)(p->map + offset); else { h->magic = malloc(sizeof(*h->magic)); if (h->magic == NULL) { err = got_error_from_errno("malloc"); goto done; } n = read(p->fd, h->magic, sizeof(*h->magic)); if (n < 0) { err = got_error_from_errno("read"); goto done; } else if (n != sizeof(*h->magic)) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } } if (*h->magic != htobe32(GOT_PACKIDX_V2_MAGIC)) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } offset += sizeof(*h->magic); remain -= sizeof(*h->magic); if (verify) got_hash_update(&ctx, h->magic, sizeof(*h->magic)); if (remain < sizeof(*h->version)) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } if (p->map) h->version = (uint32_t *)(p->map + offset); else { h->version = malloc(sizeof(*h->version)); if (h->version == NULL) { err = got_error_from_errno("malloc"); goto done; } n = read(p->fd, h->version, sizeof(*h->version)); if (n < 0) { err = got_error_from_errno("read"); goto done; } else if (n != sizeof(*h->version)) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } } if (*h->version != htobe32(GOT_PACKIDX_VERSION)) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } offset += sizeof(*h->version); remain -= sizeof(*h->version); if (verify) got_hash_update(&ctx, h->version, sizeof(*h->version)); len_fanout = sizeof(*h->fanout_table) * GOT_PACKIDX_V2_FANOUT_TABLE_ITEMS; if (remain < len_fanout) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } if (p->map) h->fanout_table = (uint32_t *)(p->map + offset); else { h->fanout_table = malloc(len_fanout); if (h->fanout_table == NULL) { err = got_error_from_errno("malloc"); goto done; } n = read(p->fd, h->fanout_table, len_fanout); if (n < 0) { err = got_error_from_errno("read"); goto done; } else if (n != len_fanout) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } } err = verify_fanout_table(h->fanout_table); if (err) goto done; if (verify) got_hash_update(&ctx, h->fanout_table, len_fanout); offset += len_fanout; remain -= len_fanout; nobj = be32toh(h->fanout_table[0xff]); len_ids = nobj * sizeof(*h->sorted_ids); if (len_ids <= nobj || len_ids > remain) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } if (p->map) h->sorted_ids = (struct got_packidx_object_id *)((uint8_t*)(p->map + offset)); else { h->sorted_ids = malloc(len_ids); if (h->sorted_ids == NULL) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } n = read(p->fd, h->sorted_ids, len_ids); if (n < 0) err = got_error_from_errno("read"); else if (n != len_ids) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } } if (verify) got_hash_update(&ctx, h->sorted_ids, len_ids); offset += len_ids; remain -= len_ids; if (remain < nobj * sizeof(*h->crc32)) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } if (p->map) h->crc32 = (uint32_t *)((uint8_t*)(p->map + offset)); else { h->crc32 = malloc(nobj * sizeof(*h->crc32)); if (h->crc32 == NULL) { err = got_error_from_errno("malloc"); goto done; } n = read(p->fd, h->crc32, nobj * sizeof(*h->crc32)); if (n < 0) err = got_error_from_errno("read"); else if (n != nobj * sizeof(*h->crc32)) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } } if (verify) got_hash_update(&ctx, h->crc32, nobj * sizeof(*h->crc32)); remain -= nobj * sizeof(*h->crc32); offset += nobj * sizeof(*h->crc32); if (remain < nobj * sizeof(*h->offsets)) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } if (p->map) h->offsets = (uint32_t *)((uint8_t*)(p->map + offset)); else { h->offsets = malloc(nobj * sizeof(*h->offsets)); if (h->offsets == NULL) { err = got_error_from_errno("malloc"); goto done; } n = read(p->fd, h->offsets, nobj * sizeof(*h->offsets)); if (n < 0) err = got_error_from_errno("read"); else if (n != nobj * sizeof(*h->offsets)) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } } if (verify) got_hash_update(&ctx, h->offsets, nobj * sizeof(*h->offsets)); remain -= nobj * sizeof(*h->offsets); offset += nobj * sizeof(*h->offsets); /* Large file offsets are contained only in files > 2GB. */ if (verify || packfile_size > 0x7fffffff) { for (i = 0; i < nobj; i++) { uint32_t o = h->offsets[i]; if (o & htobe32(GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX)) p->nlargeobj++; } } if (p->nlargeobj == 0) goto checksum; else if (packfile_size <= 0x7fffffff) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } if (remain < p->nlargeobj * sizeof(*h->large_offsets)) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } if (p->map) h->large_offsets = (uint64_t *)((uint8_t*)(p->map + offset)); else { h->large_offsets = malloc(p->nlargeobj * sizeof(*h->large_offsets)); if (h->large_offsets == NULL) { err = got_error_from_errno("malloc"); goto done; } n = read(p->fd, h->large_offsets, p->nlargeobj * sizeof(*h->large_offsets)); if (n < 0) err = got_error_from_errno("read"); else if (n != p->nlargeobj * sizeof(*h->large_offsets)) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } } if (verify) got_hash_update(&ctx, h->large_offsets, p->nlargeobj * sizeof(*h->large_offsets)); remain -= p->nlargeobj * sizeof(*h->large_offsets); offset += p->nlargeobj * sizeof(*h->large_offsets); checksum: if (remain < sizeof(*h->trailer)) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } if (p->map) h->trailer = (struct got_packidx_trailer *)((uint8_t*)(p->map + offset)); else { h->trailer = malloc(sizeof(*h->trailer)); if (h->trailer == NULL) { err = got_error_from_errno("malloc"); goto done; } n = read(p->fd, h->trailer, sizeof(*h->trailer)); if (n < 0) err = got_error_from_errno("read"); else if (n != sizeof(*h->trailer)) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } } if (verify) { got_hash_update(&ctx, h->trailer->packfile_sha1, SHA1_DIGEST_LENGTH); got_hash_final(&ctx, hash); if (got_hash_cmp(ctx.algo, hash, h->trailer->packidx_sha1) != 0) err = got_error(GOT_ERR_PACKIDX_CSUM); } done: return err; } const struct got_error * got_packidx_open(struct got_packidx **packidx, int dir_fd, const char *relpath, int verify) { const struct got_error *err = NULL; struct got_packidx *p = NULL; char *pack_relpath; struct stat idx_sb, pack_sb; *packidx = NULL; err = got_packidx_get_packfile_path(&pack_relpath, relpath); if (err) return err; /* * Ensure that a corresponding pack file exists. * Some Git repositories have this problem. Git seems to ignore * the existence of lonely pack index files but we do not. */ if (fstatat(dir_fd, pack_relpath, &pack_sb, 0) == -1) { if (errno == ENOENT) { err = got_error_fmt(GOT_ERR_LONELY_PACKIDX, "%s", relpath); } else err = got_error_from_errno2("fstatat", pack_relpath); goto done; } p = calloc(1, sizeof(*p)); if (p == NULL) { err = got_error_from_errno("calloc"); goto done; } p->fd = openat(dir_fd, relpath, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (p->fd == -1) { err = got_error_from_errno2("openat", relpath); goto done; } if (fstat(p->fd, &idx_sb) != 0) { err = got_error_from_errno2("fstat", relpath); goto done; } p->len = idx_sb.st_size; if (p->len < sizeof(p->hdr)) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } p->path_packidx = strdup(relpath); if (p->path_packidx == NULL) { err = got_error_from_errno("strdup"); goto done; } #ifndef GOT_PACK_NO_MMAP if (p->len > 0 && p->len <= SIZE_MAX) { p->map = mmap(NULL, p->len, PROT_READ, MAP_PRIVATE, p->fd, 0); if (p->map == MAP_FAILED) { if (errno != ENOMEM) { err = got_error_from_errno("mmap"); goto done; } p->map = NULL; /* fall back to read(2) */ } } #endif err = got_packidx_init_hdr(p, verify, pack_sb.st_size); done: if (err) { if (p) got_packidx_close(p); } else *packidx = p; free(pack_relpath); return err; } const struct got_error * got_packidx_close(struct got_packidx *packidx) { const struct got_error *err = NULL; free(packidx->path_packidx); if (packidx->map) { if (munmap(packidx->map, packidx->len) == -1) err = got_error_from_errno("munmap"); } else { free(packidx->hdr.magic); free(packidx->hdr.version); free(packidx->hdr.fanout_table); free(packidx->hdr.sorted_ids); free(packidx->hdr.crc32); free(packidx->hdr.offsets); free(packidx->hdr.large_offsets); free(packidx->hdr.trailer); } if (close(packidx->fd) == -1 && err == NULL) err = got_error_from_errno("close"); free(packidx->sorted_offsets); free(packidx->sorted_large_offsets); free(packidx); return err; } const struct got_error * got_packidx_get_packfile_path(char **path_packfile, const char *path_packidx) { size_t size; /* Packfile path contains ".pack" instead of ".idx", so add one byte. */ size = strlen(path_packidx) + 2; if (size < GOT_PACKFILE_NAMELEN + 1) return got_error_path(path_packidx, GOT_ERR_BAD_PATH); *path_packfile = malloc(size); if (*path_packfile == NULL) return got_error_from_errno("malloc"); /* Copy up to and excluding ".idx". */ if (strlcpy(*path_packfile, path_packidx, size - strlen(GOT_PACKIDX_SUFFIX) - 1) >= size) return got_error(GOT_ERR_NO_SPACE); if (strlcat(*path_packfile, GOT_PACKFILE_SUFFIX, size) >= size) return got_error(GOT_ERR_NO_SPACE); return NULL; } off_t got_packidx_get_object_offset(struct got_packidx *packidx, int idx) { uint32_t offset = be32toh(packidx->hdr.offsets[idx]); if (offset & GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX) { uint64_t loffset; idx = offset & GOT_PACKIDX_OFFSET_VAL_MASK; if (idx < 0 || idx >= packidx->nlargeobj || packidx->hdr.large_offsets == NULL) return -1; loffset = be64toh(packidx->hdr.large_offsets[idx]); return (loffset > INT64_MAX ? -1 : (off_t)loffset); } return (off_t)(offset & GOT_PACKIDX_OFFSET_VAL_MASK); } int got_packidx_get_object_idx(struct got_packidx *packidx, struct got_object_id *id) { u_int8_t id0 = id->sha1[0]; uint32_t totobj = be32toh(packidx->hdr.fanout_table[0xff]); int left = 0, right = totobj - 1; if (id0 > 0) left = be32toh(packidx->hdr.fanout_table[id0 - 1]); while (left <= right) { struct got_packidx_object_id *oid; int i, cmp; i = ((left + right) / 2); oid = &packidx->hdr.sorted_ids[i]; cmp = memcmp(id->sha1, oid->sha1, SHA1_DIGEST_LENGTH); if (cmp == 0) return i; else if (cmp > 0) left = i + 1; else if (cmp < 0) right = i - 1; } return -1; } static int offset_cmp(const void *pa, const void *pb) { const struct got_pack_offset_index *a, *b; a = (const struct got_pack_offset_index *)pa; b = (const struct got_pack_offset_index *)pb; if (a->offset < b->offset) return -1; else if (a->offset > b->offset) return 1; return 0; } static int large_offset_cmp(const void *pa, const void *pb) { const struct got_pack_large_offset_index *a, *b; a = (const struct got_pack_large_offset_index *)pa; b = (const struct got_pack_large_offset_index *)pb; if (a->offset < b->offset) return -1; else if (a->offset > b->offset) return 1; return 0; } static const struct got_error * build_offset_index(struct got_packidx *p) { uint32_t nobj = be32toh(p->hdr.fanout_table[0xff]); unsigned int i, j, k; p->sorted_offsets = calloc(nobj - p->nlargeobj, sizeof(p->sorted_offsets[0])); if (p->sorted_offsets == NULL) return got_error_from_errno("calloc"); if (p->nlargeobj > 0) { p->sorted_large_offsets = calloc(p->nlargeobj, sizeof(p->sorted_large_offsets[0])); if (p->sorted_large_offsets == NULL) return got_error_from_errno("calloc"); } j = 0; k = 0; for (i = 0; i < nobj; i++) { uint32_t offset = be32toh(p->hdr.offsets[i]); if (offset & GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX) { uint64_t loffset; uint32_t idx; idx = offset & GOT_PACKIDX_OFFSET_VAL_MASK; if (idx >= p->nlargeobj || p->nlargeobj == 0 || p->hdr.large_offsets == NULL) return got_error(GOT_ERR_BAD_PACKIDX); loffset = be64toh(p->hdr.large_offsets[idx]); p->sorted_large_offsets[j].offset = loffset; p->sorted_large_offsets[j].idx = i; j++; } else { p->sorted_offsets[k].offset = offset; p->sorted_offsets[k].idx = i; k++; } } if (j != p->nlargeobj || k != nobj - p->nlargeobj) return got_error(GOT_ERR_BAD_PACKIDX); qsort(p->sorted_offsets, nobj - p->nlargeobj, sizeof(p->sorted_offsets[0]), offset_cmp); if (p->sorted_large_offsets) qsort(p->sorted_large_offsets, p->nlargeobj, sizeof(p->sorted_large_offsets[0]), large_offset_cmp); return NULL; } const struct got_error * got_packidx_get_offset_idx(int *idx, struct got_packidx *packidx, off_t offset) { const struct got_error *err; uint32_t totobj = be32toh(packidx->hdr.fanout_table[0xff]); int i, left, right; *idx = -1; if (packidx->sorted_offsets == NULL) { err = build_offset_index(packidx); if (err) return err; } if (offset >= 0x7fffffff) { uint64_t lo; left = 0, right = packidx->nlargeobj - 1; while (left <= right) { i = ((left + right) / 2); lo = packidx->sorted_large_offsets[i].offset; if (lo == offset) { *idx = packidx->sorted_large_offsets[i].idx; break; } else if (offset > lo) left = i + 1; else if (offset < lo) right = i - 1; } } else { uint32_t o; left = 0, right = totobj - packidx->nlargeobj - 1; while (left <= right) { i = ((left + right) / 2); o = packidx->sorted_offsets[i].offset; if (o == offset) { *idx = packidx->sorted_offsets[i].idx; break; } else if (offset > o) left = i + 1; else if (offset < o) right = i - 1; } } return NULL; } const struct got_error * got_packidx_get_object_id(struct got_object_id *id, struct got_packidx *packidx, int idx) { uint32_t totobj = be32toh(packidx->hdr.fanout_table[0xff]); struct got_packidx_object_id *oid; if (idx < 0 || idx >= totobj) return got_error(GOT_ERR_NO_OBJ); oid = &packidx->hdr.sorted_ids[idx]; memcpy(id->sha1, oid->sha1, SHA1_DIGEST_LENGTH); return NULL; } const struct got_error * got_packidx_match_id_str_prefix(struct got_object_id_queue *matched_ids, struct got_packidx *packidx, const char *id_str_prefix) { const struct got_error *err = NULL; u_int8_t id0; uint32_t totobj = be32toh(packidx->hdr.fanout_table[0xff]); char hex[3]; size_t prefix_len = strlen(id_str_prefix); struct got_packidx_object_id *oid; uint32_t i = 0; if (prefix_len < 2) return got_error_path(id_str_prefix, GOT_ERR_BAD_OBJ_ID_STR); hex[0] = id_str_prefix[0]; hex[1] = id_str_prefix[1]; hex[2] = '\0'; if (!got_parse_xdigit(&id0, hex)) return got_error_path(id_str_prefix, GOT_ERR_BAD_OBJ_ID_STR); if (id0 > 0) i = be32toh(packidx->hdr.fanout_table[id0 - 1]); oid = &packidx->hdr.sorted_ids[i]; while (i < totobj && oid->sha1[0] == id0) { char id_str[SHA1_DIGEST_STRING_LENGTH]; struct got_object_qid *qid; int cmp; if (!got_sha1_digest_to_str(oid->sha1, id_str, sizeof(id_str))) return got_error(GOT_ERR_NO_SPACE); cmp = strncmp(id_str, id_str_prefix, prefix_len); if (cmp < 0) { oid = &packidx->hdr.sorted_ids[++i]; continue; } else if (cmp > 0) break; err = got_object_qid_alloc_partial(&qid); if (err) return err; memcpy(qid->id.sha1, oid->sha1, SHA1_DIGEST_LENGTH); STAILQ_INSERT_TAIL(matched_ids, qid, entry); oid = &packidx->hdr.sorted_ids[++i]; } return NULL; } static void set_max_datasize(void) { struct rlimit rl; if (getrlimit(RLIMIT_DATA, &rl) != 0) return; rl.rlim_cur = rl.rlim_max; setrlimit(RLIMIT_DATA, &rl); } const struct got_error * got_pack_start_privsep_child(struct got_pack *pack, struct got_packidx *packidx) { const struct got_error *err = NULL; int imsg_fds[2]; pid_t pid; struct imsgbuf *ibuf; ibuf = calloc(1, sizeof(*ibuf)); if (ibuf == NULL) return got_error_from_errno("calloc"); pack->privsep_child = calloc(1, sizeof(*pack->privsep_child)); if (pack->privsep_child == NULL) { err = got_error_from_errno("calloc"); free(ibuf); return err; } pack->child_has_tempfiles = 0; pack->child_has_delta_outfd = 0; if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) { err = got_error_from_errno("socketpair"); goto done; } pid = fork(); if (pid == -1) { err = got_error_from_errno("fork"); goto done; } else if (pid == 0) { set_max_datasize(); got_privsep_exec_child(imsg_fds, GOT_PATH_PROG_READ_PACK, pack->path_packfile); /* not reached */ } if (close(imsg_fds[1]) == -1) return got_error_from_errno("close"); pack->privsep_child->imsg_fd = imsg_fds[0]; pack->privsep_child->pid = pid; imsg_init(ibuf, imsg_fds[0]); pack->privsep_child->ibuf = ibuf; err = got_privsep_init_pack_child(ibuf, pack, packidx); if (err) { const struct got_error *child_err; err = got_privsep_send_stop(pack->privsep_child->imsg_fd); child_err = got_privsep_wait_for_child( pack->privsep_child->pid); if (child_err && err == NULL) err = child_err; } done: if (err) { free(ibuf); free(pack->privsep_child); pack->privsep_child = NULL; } return err; } static const struct got_error * pack_stop_privsep_child(struct got_pack *pack) { const struct got_error *err = NULL, *close_err = NULL; if (pack->privsep_child == NULL) return NULL; err = got_privsep_send_stop(pack->privsep_child->imsg_fd); if (err) return err; if (close(pack->privsep_child->imsg_fd) == -1) close_err = got_error_from_errno("close"); err = got_privsep_wait_for_child(pack->privsep_child->pid); if (close_err && err == NULL) err = close_err; imsg_clear(pack->privsep_child->ibuf); free(pack->privsep_child->ibuf); free(pack->privsep_child); pack->privsep_child = NULL; return err; } const struct got_error * got_pack_close(struct got_pack *pack) { const struct got_error *err = NULL; err = pack_stop_privsep_child(pack); if (pack->map && munmap(pack->map, pack->filesize) == -1 && !err) err = got_error_from_errno("munmap"); if (pack->fd != -1 && close(pack->fd) == -1 && err == NULL) err = got_error_from_errno("close"); pack->fd = -1; free(pack->path_packfile); pack->path_packfile = NULL; pack->filesize = 0; if (pack->delta_cache) { got_delta_cache_free(pack->delta_cache); pack->delta_cache = NULL; } /* * Leave accumfd and basefd alone. They are managed by the * repository layer and can be reused. */ return err; } const struct got_error * got_pack_parse_object_type_and_size(uint8_t *type, uint64_t *size, size_t *len, struct got_pack *pack, off_t offset) { uint8_t t = 0; uint64_t s = 0; uint8_t sizeN; size_t mapoff = 0; int i = 0; *len = 0; if (offset >= pack->filesize) return got_error(GOT_ERR_PACK_OFFSET); if (pack->map) { if (offset > SIZE_MAX) { return got_error_fmt(GOT_ERR_PACK_OFFSET, "offset %lld overflows size_t", (long long)offset); } mapoff = (size_t)offset; } else { if (lseek(pack->fd, offset, SEEK_SET) == -1) return got_error_from_errno("lseek"); } do { /* We do not support size values which don't fit in 64 bit. */ if (i > 9) return got_error_fmt(GOT_ERR_OBJ_TOO_LARGE, "packfile offset %lld", (long long)offset); if (pack->map) { if (mapoff + sizeof(sizeN) >= pack->filesize) return got_error(GOT_ERR_BAD_PACKFILE); sizeN = *(pack->map + mapoff); mapoff += sizeof(sizeN); } else { ssize_t n = read(pack->fd, &sizeN, sizeof(sizeN)); if (n < 0) return got_error_from_errno("read"); if (n != sizeof(sizeN)) return got_error(GOT_ERR_BAD_PACKFILE); } *len += sizeof(sizeN); if (i == 0) { t = (sizeN & GOT_PACK_OBJ_SIZE0_TYPE_MASK) >> GOT_PACK_OBJ_SIZE0_TYPE_MASK_SHIFT; s = (sizeN & GOT_PACK_OBJ_SIZE0_VAL_MASK); } else { size_t shift = 4 + 7 * (i - 1); s |= ((sizeN & GOT_PACK_OBJ_SIZE_VAL_MASK) << shift); } i++; } while (sizeN & GOT_PACK_OBJ_SIZE_MORE); *type = t; *size = s; return NULL; } static const struct got_error * open_plain_object(struct got_object **obj, struct got_object_id *id, uint8_t type, off_t offset, size_t size, int idx) { *obj = calloc(1, sizeof(**obj)); if (*obj == NULL) return got_error_from_errno("calloc"); (*obj)->type = type; (*obj)->flags = GOT_OBJ_FLAG_PACKED; (*obj)->pack_idx = idx; (*obj)->hdrlen = 0; (*obj)->size = size; memcpy(&(*obj)->id, id, sizeof((*obj)->id)); (*obj)->pack_offset = offset; return NULL; } static const struct got_error * parse_negative_offset(int64_t *offset, size_t *len, struct got_pack *pack, off_t delta_offset) { int64_t o = 0; uint8_t offN; int i = 0; *offset = 0; *len = 0; do { /* We do not support offset values which don't fit in 64 bit. */ if (i > 8) return got_error(GOT_ERR_NO_SPACE); if (pack->map) { size_t mapoff; if (delta_offset > SIZE_MAX - *len) { return got_error_fmt(GOT_ERR_PACK_OFFSET, "mapoff %lld would overflow size_t", (long long)delta_offset + *len); } mapoff = (size_t)delta_offset + *len; if (mapoff + sizeof(offN) >= pack->filesize) return got_error(GOT_ERR_PACK_OFFSET); offN = *(pack->map + mapoff); } else { ssize_t n; n = read(pack->fd, &offN, sizeof(offN)); if (n < 0) return got_error_from_errno("read"); if (n != sizeof(offN)) return got_error(GOT_ERR_BAD_PACKFILE); } *len += sizeof(offN); if (i == 0) o = (offN & GOT_PACK_OBJ_DELTA_OFF_VAL_MASK); else { o++; o <<= 7; o += (offN & GOT_PACK_OBJ_DELTA_OFF_VAL_MASK); } i++; } while (offN & GOT_PACK_OBJ_DELTA_OFF_MORE); *offset = o; return NULL; } const struct got_error * got_pack_parse_offset_delta(off_t *base_offset, size_t *len, struct got_pack *pack, off_t offset, size_t tslen) { const struct got_error *err; int64_t negoffset; size_t negofflen; *len = 0; err = parse_negative_offset(&negoffset, &negofflen, pack, offset + tslen); if (err) return err; /* Compute the base object's offset (must be in the same pack file). */ *base_offset = (offset - negoffset); if (*base_offset <= 0) return got_error(GOT_ERR_BAD_PACKFILE); *len = negofflen; return NULL; } static const struct got_error * read_delta_data(uint8_t **delta_buf, size_t *delta_len, size_t *delta_compressed_len, size_t delta_data_offset, struct got_pack *pack) { const struct got_error *err = NULL; size_t consumed = 0; if (pack->map) { if (delta_data_offset >= pack->filesize) return got_error(GOT_ERR_PACK_OFFSET); err = got_inflate_to_mem_mmap(delta_buf, delta_len, &consumed, NULL, pack->map, delta_data_offset, pack->filesize - delta_data_offset); if (err) return err; } else { if (lseek(pack->fd, delta_data_offset, SEEK_SET) == -1) return got_error_from_errno("lseek"); err = got_inflate_to_mem_fd(delta_buf, delta_len, &consumed, NULL, 0, pack->fd); if (err) return err; } if (delta_compressed_len) *delta_compressed_len = consumed; return NULL; } static const struct got_error * add_delta(struct got_delta_chain *deltas, off_t delta_offset, size_t tslen, int delta_type, size_t delta_size, off_t delta_data_offset) { struct got_delta *delta; delta = got_delta_open(delta_offset, tslen, delta_type, delta_size, delta_data_offset); if (delta == NULL) return got_error_from_errno("got_delta_open"); /* delta is freed in got_object_close() */ deltas->nentries++; STAILQ_INSERT_HEAD(&deltas->entries, delta, entry); return NULL; } static const struct got_error * resolve_offset_delta(struct got_delta_chain *deltas, struct got_packidx *packidx, struct got_pack *pack, off_t delta_offset, size_t tslen, int delta_type, size_t delta_size, unsigned int recursion) { const struct got_error *err; off_t base_offset; uint8_t base_type; uint64_t base_size; size_t base_tslen; off_t delta_data_offset; size_t consumed; err = got_pack_parse_offset_delta(&base_offset, &consumed, pack, delta_offset, tslen); if (err) return err; delta_data_offset = delta_offset + tslen + consumed; if (delta_data_offset >= pack->filesize) return got_error(GOT_ERR_PACK_OFFSET); if (pack->map == NULL) { delta_data_offset = lseek(pack->fd, 0, SEEK_CUR); if (delta_data_offset == -1) return got_error_from_errno("lseek"); } err = add_delta(deltas, delta_offset, tslen, delta_type, delta_size, delta_data_offset); if (err) return err; /* An offset delta must be in the same packfile. */ if (base_offset >= pack->filesize) return got_error(GOT_ERR_PACK_OFFSET); err = got_pack_parse_object_type_and_size(&base_type, &base_size, &base_tslen, pack, base_offset); if (err) return err; return got_pack_resolve_delta_chain(deltas, packidx, pack, base_offset, base_tslen, base_type, base_size, recursion - 1); } const struct got_error * got_pack_parse_ref_delta(struct got_object_id *id, struct got_pack *pack, off_t delta_offset, int tslen) { if (pack->map) { size_t mapoff; if (delta_offset > SIZE_MAX - tslen) { return got_error_fmt(GOT_ERR_PACK_OFFSET, "mapoff %lld would overflow size_t", (long long)delta_offset + tslen); } mapoff = delta_offset + tslen; if (mapoff + sizeof(*id) >= pack->filesize) return got_error(GOT_ERR_PACK_OFFSET); memcpy(id, pack->map + mapoff, sizeof(*id)); } else { ssize_t n; n = read(pack->fd, id, sizeof(*id)); if (n < 0) return got_error_from_errno("read"); if (n != sizeof(*id)) return got_error(GOT_ERR_BAD_PACKFILE); } return NULL; } static const struct got_error * resolve_ref_delta(struct got_delta_chain *deltas, struct got_packidx *packidx, struct got_pack *pack, off_t delta_offset, size_t tslen, int delta_type, size_t delta_size, unsigned int recursion) { const struct got_error *err; struct got_object_id id; int idx; off_t base_offset; uint8_t base_type; uint64_t base_size; size_t base_tslen; off_t delta_data_offset; if (delta_offset + tslen >= pack->filesize) return got_error(GOT_ERR_PACK_OFFSET); err = got_pack_parse_ref_delta(&id, pack, delta_offset, tslen); if (err) return err; if (pack->map) { delta_data_offset = delta_offset + tslen + SHA1_DIGEST_LENGTH; } else { delta_data_offset = lseek(pack->fd, 0, SEEK_CUR); if (delta_data_offset == -1) return got_error_from_errno("lseek"); } err = add_delta(deltas, delta_offset, tslen, delta_type, delta_size, delta_data_offset); if (err) return err; /* Delta base must be in the same pack file. */ idx = got_packidx_get_object_idx(packidx, &id); if (idx == -1) return got_error(GOT_ERR_NO_OBJ); base_offset = got_packidx_get_object_offset(packidx, idx); if (base_offset == -1) return got_error(GOT_ERR_BAD_PACKIDX); if (base_offset >= pack->filesize) return got_error(GOT_ERR_PACK_OFFSET); err = got_pack_parse_object_type_and_size(&base_type, &base_size, &base_tslen, pack, base_offset); if (err) return err; return got_pack_resolve_delta_chain(deltas, packidx, pack, base_offset, base_tslen, base_type, base_size, recursion - 1); } const struct got_error * got_pack_resolve_delta_chain(struct got_delta_chain *deltas, struct got_packidx *packidx, struct got_pack *pack, off_t delta_offset, size_t tslen, int delta_type, size_t delta_size, unsigned int recursion) { const struct got_error *err = NULL; if (--recursion == 0) return got_error(GOT_ERR_RECURSION); switch (delta_type) { case GOT_OBJ_TYPE_COMMIT: case GOT_OBJ_TYPE_TREE: case GOT_OBJ_TYPE_BLOB: case GOT_OBJ_TYPE_TAG: /* Plain types are the final delta base. Recursion ends. */ err = add_delta(deltas, delta_offset, tslen, delta_type, delta_size, 0); break; case GOT_OBJ_TYPE_OFFSET_DELTA: err = resolve_offset_delta(deltas, packidx, pack, delta_offset, tslen, delta_type, delta_size, recursion - 1); break; case GOT_OBJ_TYPE_REF_DELTA: err = resolve_ref_delta(deltas, packidx, pack, delta_offset, tslen, delta_type, delta_size, recursion - 1); break; default: return got_error(GOT_ERR_OBJ_TYPE); } return err; } static const struct got_error * open_delta_object(struct got_object **obj, struct got_packidx *packidx, struct got_pack *pack, struct got_object_id *id, off_t offset, size_t tslen, int delta_type, size_t delta_size, int idx) { const struct got_error *err = NULL; int resolved_type; *obj = calloc(1, sizeof(**obj)); if (*obj == NULL) return got_error_from_errno("calloc"); (*obj)->flags = 0; (*obj)->hdrlen = 0; (*obj)->size = 0; /* Not known because deltas aren't applied yet. */ memcpy(&(*obj)->id, id, sizeof((*obj)->id)); (*obj)->pack_offset = offset + tslen; STAILQ_INIT(&(*obj)->deltas.entries); (*obj)->flags |= GOT_OBJ_FLAG_DELTIFIED; (*obj)->flags |= GOT_OBJ_FLAG_PACKED; (*obj)->pack_idx = idx; err = got_pack_resolve_delta_chain(&(*obj)->deltas, packidx, pack, offset, tslen, delta_type, delta_size, GOT_DELTA_CHAIN_RECURSION_MAX); if (err) goto done; err = got_delta_chain_get_base_type(&resolved_type, &(*obj)->deltas); if (err) goto done; (*obj)->type = resolved_type; done: if (err) { got_object_close(*obj); *obj = NULL; } return err; } const struct got_error * got_packfile_open_object(struct got_object **obj, struct got_pack *pack, struct got_packidx *packidx, int idx, struct got_object_id *id) { const struct got_error *err = NULL; off_t offset; uint8_t type; uint64_t size; size_t tslen; *obj = NULL; offset = got_packidx_get_object_offset(packidx, idx); if (offset == -1) return got_error(GOT_ERR_BAD_PACKIDX); err = got_pack_parse_object_type_and_size(&type, &size, &tslen, pack, offset); if (err) return err; switch (type) { case GOT_OBJ_TYPE_COMMIT: case GOT_OBJ_TYPE_TREE: case GOT_OBJ_TYPE_BLOB: case GOT_OBJ_TYPE_TAG: err = open_plain_object(obj, id, type, offset + tslen, size, idx); break; case GOT_OBJ_TYPE_OFFSET_DELTA: case GOT_OBJ_TYPE_REF_DELTA: err = open_delta_object(obj, packidx, pack, id, offset, tslen, type, size, idx); break; default: err = got_error(GOT_ERR_OBJ_TYPE); break; } return err; } const struct got_error * got_pack_get_delta_chain_max_size(uint64_t *max_size, struct got_delta_chain *deltas, struct got_pack *pack) { struct got_delta *delta; uint64_t base_size = 0, result_size = 0; *max_size = 0; STAILQ_FOREACH(delta, &deltas->entries, entry) { /* Plain object types are the delta base. */ if (delta->type != GOT_OBJ_TYPE_COMMIT && delta->type != GOT_OBJ_TYPE_TREE && delta->type != GOT_OBJ_TYPE_BLOB && delta->type != GOT_OBJ_TYPE_TAG) { const struct got_error *err; uint8_t *delta_buf = NULL; size_t delta_len; int cached = 1; if (pack->delta_cache) { got_delta_cache_get(&delta_buf, &delta_len, NULL, NULL, pack->delta_cache, delta->data_offset); } if (delta_buf == NULL) { cached = 0; err = read_delta_data(&delta_buf, &delta_len, NULL, delta->data_offset, pack); if (err) return err; } if (pack->delta_cache && !cached) { err = got_delta_cache_add(pack->delta_cache, delta->data_offset, delta_buf, delta_len); if (err == NULL) cached = 1; else if (err->code != GOT_ERR_NO_SPACE) { free(delta_buf); return err; } } err = got_delta_get_sizes(&base_size, &result_size, delta_buf, delta_len); if (!cached) free(delta_buf); if (err) return err; } else base_size = delta->size; if (base_size > *max_size) *max_size = base_size; if (result_size > *max_size) *max_size = result_size; } return NULL; } const struct got_error * got_pack_get_max_delta_object_size(uint64_t *size, struct got_object *obj, struct got_pack *pack) { if ((obj->flags & GOT_OBJ_FLAG_DELTIFIED) == 0) return got_error(GOT_ERR_OBJ_TYPE); return got_pack_get_delta_chain_max_size(size, &obj->deltas, pack); } const struct got_error * got_pack_dump_delta_chain_to_file(size_t *result_size, struct got_delta_chain *deltas, struct got_pack *pack, FILE *outfile, FILE *base_file, FILE *accum_file) { const struct got_error *err = NULL; struct got_delta *delta; uint8_t *base_buf = NULL, *accum_buf = NULL; size_t base_bufsz = 0, accum_bufsz = 0, accum_size = 0; /* We process small enough files entirely in memory for speed. */ const size_t max_bufsize = GOT_DELTA_RESULT_SIZE_CACHED_MAX; uint64_t max_size = 0; int n = 0; *result_size = 0; if (STAILQ_EMPTY(&deltas->entries)) return got_error(GOT_ERR_BAD_DELTA_CHAIN); if (pack->delta_cache) { uint8_t *delta_buf = NULL, *fulltext = NULL; size_t delta_len, fulltext_len; delta = STAILQ_LAST(&deltas->entries, got_delta, entry); got_delta_cache_get(&delta_buf, &delta_len, &fulltext, &fulltext_len, pack->delta_cache, delta->data_offset); if (fulltext) { size_t w; w = fwrite(fulltext, 1, fulltext_len, outfile); if (w != fulltext_len) return got_ferror(outfile, GOT_ERR_IO); if (fflush(outfile) != 0) return got_error_from_errno("fflush"); *result_size = fulltext_len; return NULL; } } if (fseeko(base_file, 0L, SEEK_SET) == -1) return got_error_from_errno("fseeko"); if (fseeko(accum_file, 0L, SEEK_SET) == -1) return got_error_from_errno("fseeko"); /* Deltas are ordered in ascending order. */ STAILQ_FOREACH(delta, &deltas->entries, entry) { uint8_t *delta_buf = NULL, *fulltext = NULL; size_t delta_len, fulltext_len; uint64_t base_size, result_size = 0; int cached = 1; if (n == 0) { size_t mapoff; off_t delta_data_offset; /* Plain object types are the delta base. */ if (delta->type != GOT_OBJ_TYPE_COMMIT && delta->type != GOT_OBJ_TYPE_TREE && delta->type != GOT_OBJ_TYPE_BLOB && delta->type != GOT_OBJ_TYPE_TAG) { err = got_error(GOT_ERR_BAD_DELTA_CHAIN); goto done; } delta_data_offset = delta->offset + delta->tslen; if (delta_data_offset >= pack->filesize) { err = got_error(GOT_ERR_PACK_OFFSET); goto done; } if (pack->map == NULL) { if (lseek(pack->fd, delta_data_offset, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } } if (delta->size > max_size) max_size = delta->size; if (max_size > max_bufsize) { if (pack->map) { if (delta_data_offset > SIZE_MAX) { return got_error_fmt( GOT_ERR_RANGE, "delta offset %lld " "overflows size_t", (long long) delta_data_offset); } mapoff = delta_data_offset; err = got_inflate_to_file_mmap( &base_bufsz, NULL, NULL, pack->map, mapoff, pack->filesize - mapoff, base_file); } else err = got_inflate_to_file_fd( &base_bufsz, NULL, NULL, pack->fd, base_file); } else { accum_buf = malloc(max_size); if (accum_buf == NULL) { err = got_error_from_errno("malloc"); goto done; } accum_bufsz = max_size; if (pack->map) { if (delta_data_offset > SIZE_MAX) { err = got_error_fmt( GOT_ERR_RANGE, "delta offset %lld " "overflows size_t", (long long) delta_data_offset); goto done; } mapoff = delta_data_offset; err = got_inflate_to_mem_mmap(&base_buf, &base_bufsz, NULL, NULL, pack->map, mapoff, pack->filesize - mapoff); } else err = got_inflate_to_mem_fd(&base_buf, &base_bufsz, NULL, NULL, max_size, pack->fd); } if (err) goto done; n++; if (base_buf == NULL) rewind(base_file); else if (pack->delta_cache && fulltext == NULL) { err = got_delta_cache_add(pack->delta_cache, delta_data_offset, NULL, 0); if (err) { if (err->code != GOT_ERR_NO_SPACE) goto done; err = NULL; } else { err = got_delta_cache_add_fulltext( pack->delta_cache, delta_data_offset, base_buf, base_bufsz); if (err && err->code != GOT_ERR_NO_SPACE) goto done; err = NULL; } } continue; } if (pack->delta_cache) { got_delta_cache_get(&delta_buf, &delta_len, &fulltext, &fulltext_len, pack->delta_cache, delta->data_offset); } if (delta_buf == NULL) { cached = 0; err = read_delta_data(&delta_buf, &delta_len, NULL, delta->data_offset, pack); if (err) goto done; } if (pack->delta_cache && !cached) { err = got_delta_cache_add(pack->delta_cache, delta->data_offset, delta_buf, delta_len); if (err == NULL) cached = 1; else if (err->code != GOT_ERR_NO_SPACE) { free(delta_buf); goto done; } } err = got_delta_get_sizes(&base_size, &result_size, delta_buf, delta_len); if (err) { if (!cached) free(delta_buf); goto done; } if (base_size > max_size) max_size = base_size; if (result_size > max_size) max_size = result_size; if (fulltext_len > max_size) max_size = fulltext_len; if (base_buf && max_size > max_bufsize) { /* Switch from buffers to temporary files. */ size_t w = fwrite(base_buf, 1, base_bufsz, base_file); if (w != base_bufsz) { err = got_ferror(outfile, GOT_ERR_IO); if (!cached) free(delta_buf); goto done; } free(base_buf); base_buf = NULL; free(accum_buf); accum_buf = NULL; } if (base_buf && max_size > base_bufsz) { uint8_t *p = realloc(base_buf, max_size); if (p == NULL) { err = got_error_from_errno("realloc"); if (!cached) free(delta_buf); goto done; } base_buf = p; base_bufsz = max_size; } if (accum_buf && max_size > accum_bufsz) { uint8_t *p = realloc(accum_buf, max_size); if (p == NULL) { err = got_error_from_errno("realloc"); if (!cached) free(delta_buf); goto done; } accum_buf = p; accum_bufsz = max_size; } if (base_buf) { if (fulltext) { memcpy(accum_buf, fulltext, fulltext_len); accum_size = fulltext_len; err = NULL; } else { err = got_delta_apply_in_mem(base_buf, base_bufsz, delta_buf, delta_len, accum_buf, &accum_size, max_size); } n++; if (!cached) free(delta_buf); if (err) goto done; if (fulltext == NULL) { err = got_delta_cache_add_fulltext( pack->delta_cache, delta->data_offset, accum_buf, accum_size); if (err) { if (err->code != GOT_ERR_NO_SPACE) goto done; err = NULL; } } } else { err = got_delta_apply(base_file, delta_buf, delta_len, /* Final delta application writes to output file. */ ++n < deltas->nentries ? accum_file : outfile, &accum_size); if (!cached) free(delta_buf); if (err) goto done; } if (n < deltas->nentries) { /* Accumulated delta becomes the new base. */ if (base_buf) { uint8_t *tmp = accum_buf; size_t tmp_size = accum_bufsz; accum_buf = base_buf; accum_bufsz = base_bufsz; base_buf = tmp; base_bufsz = tmp_size; } else { FILE *tmp = accum_file; accum_file = base_file; base_file = tmp; rewind(base_file); rewind(accum_file); } } } done: free(base_buf); if (err) { free(accum_buf); accum_buf = NULL; } if (accum_buf) { size_t len = fwrite(accum_buf, 1, accum_size, outfile); free(accum_buf); if (len != accum_size) err = got_ferror(outfile, GOT_ERR_IO); } rewind(outfile); if (err == NULL) *result_size = accum_size; return err; } const struct got_error * got_pack_dump_delta_chain_to_mem(uint8_t **outbuf, size_t *outlen, struct got_delta_chain *deltas, struct got_pack *pack) { const struct got_error *err = NULL; struct got_delta *delta; uint8_t *base_buf = NULL, *accum_buf = NULL; size_t base_bufsz = 0, accum_bufsz = 0, accum_size = 0; uint64_t max_size = 0; int n = 0; *outbuf = NULL; *outlen = 0; if (STAILQ_EMPTY(&deltas->entries)) return got_error(GOT_ERR_BAD_DELTA_CHAIN); if (pack->delta_cache) { uint8_t *delta_buf = NULL, *fulltext = NULL; size_t delta_len, fulltext_len; delta = STAILQ_LAST(&deltas->entries, got_delta, entry); got_delta_cache_get(&delta_buf, &delta_len, &fulltext, &fulltext_len, pack->delta_cache, delta->data_offset); if (fulltext) { *outbuf = malloc(fulltext_len); if (*outbuf == NULL) return got_error_from_errno("malloc"); memcpy(*outbuf, fulltext, fulltext_len); *outlen = fulltext_len; return NULL; } } /* Deltas are ordered in ascending order. */ STAILQ_FOREACH(delta, &deltas->entries, entry) { uint8_t *delta_buf = NULL, *fulltext = NULL; size_t delta_len, fulltext_len = 0; uint64_t base_size, result_size = 0; int cached = 1; if (n == 0) { off_t delta_data_offset; /* Plain object types are the delta base. */ if (delta->type != GOT_OBJ_TYPE_COMMIT && delta->type != GOT_OBJ_TYPE_TREE && delta->type != GOT_OBJ_TYPE_BLOB && delta->type != GOT_OBJ_TYPE_TAG) { err = got_error(GOT_ERR_BAD_DELTA_CHAIN); goto done; } delta_data_offset = delta->offset + delta->tslen; if (delta_data_offset >= pack->filesize) { err = got_error(GOT_ERR_PACK_OFFSET); goto done; } if (pack->delta_cache) { got_delta_cache_get(&delta_buf, &delta_len, &fulltext, &fulltext_len, pack->delta_cache, delta_data_offset); } if (delta->size > max_size) max_size = delta->size; if (delta->size > fulltext_len) max_size = fulltext_len; if (fulltext) { base_buf = malloc(fulltext_len); if (base_buf == NULL) { err = got_error_from_errno("malloc"); goto done; } memcpy(base_buf, fulltext, fulltext_len); base_bufsz = fulltext_len; } else if (pack->map) { size_t mapoff; if (delta_data_offset > SIZE_MAX) { return got_error_fmt(GOT_ERR_RANGE, "delta %lld offset would " "overflow size_t", (long long)delta_data_offset); } mapoff = delta_data_offset; err = got_inflate_to_mem_mmap(&base_buf, &base_bufsz, NULL, NULL, pack->map, mapoff, pack->filesize - mapoff); } else { if (lseek(pack->fd, delta_data_offset, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } err = got_inflate_to_mem_fd(&base_buf, &base_bufsz, NULL, NULL, max_size, pack->fd); } if (err) goto done; n++; if (pack->delta_cache && fulltext == NULL) { err = got_delta_cache_add(pack->delta_cache, delta_data_offset, NULL, 0); if (err) { if (err->code != GOT_ERR_NO_SPACE) goto done; err = NULL; } else { err = got_delta_cache_add_fulltext( pack->delta_cache, delta_data_offset, base_buf, base_bufsz); if (err && err->code != GOT_ERR_NO_SPACE) goto done; err = NULL; } } continue; } if (pack->delta_cache) { got_delta_cache_get(&delta_buf, &delta_len, &fulltext, &fulltext_len, pack->delta_cache, delta->data_offset); } if (delta_buf == NULL) { cached = 0; err = read_delta_data(&delta_buf, &delta_len, NULL, delta->data_offset, pack); if (err) goto done; } if (pack->delta_cache && !cached) { err = got_delta_cache_add(pack->delta_cache, delta->data_offset, delta_buf, delta_len); if (err == NULL) cached = 1; else if (err->code != GOT_ERR_NO_SPACE) { free(delta_buf); goto done; } } err = got_delta_get_sizes(&base_size, &result_size, delta_buf, delta_len); if (err) { if (!cached) free(delta_buf); goto done; } if (base_size > max_size) max_size = base_size; if (result_size > max_size) max_size = result_size; if (fulltext_len > max_size) max_size = fulltext_len; if (max_size > base_bufsz) { uint8_t *p = realloc(base_buf, max_size); if (p == NULL) { err = got_error_from_errno("realloc"); if (!cached) free(delta_buf); goto done; } base_buf = p; base_bufsz = max_size; } if (max_size > accum_bufsz) { uint8_t *p = realloc(accum_buf, max_size); if (p == NULL) { err = got_error_from_errno("realloc"); if (!cached) free(delta_buf); goto done; } accum_buf = p; accum_bufsz = max_size; } if (fulltext) { memcpy(accum_buf, fulltext, fulltext_len); accum_size = fulltext_len; err = NULL; } else { err = got_delta_apply_in_mem(base_buf, base_bufsz, delta_buf, delta_len, accum_buf, &accum_size, max_size); } if (!cached) free(delta_buf); n++; if (err) goto done; if (fulltext == NULL) { err = got_delta_cache_add_fulltext(pack->delta_cache, delta->data_offset, accum_buf, accum_size); if (err) { if (err->code != GOT_ERR_NO_SPACE) goto done; err = NULL; } } if (n < deltas->nentries) { /* Accumulated delta becomes the new base. */ uint8_t *tmp = accum_buf; size_t tmp_size = accum_bufsz; accum_buf = base_buf; accum_bufsz = base_bufsz; base_buf = tmp; base_bufsz = tmp_size; } } done: free(base_buf); if (err) { free(accum_buf); *outbuf = NULL; *outlen = 0; } else { *outbuf = accum_buf; *outlen = accum_size; } return err; } const struct got_error * got_packfile_extract_object(struct got_pack *pack, struct got_object *obj, FILE *outfile, FILE *base_file, FILE *accum_file) { const struct got_error *err = NULL; if ((obj->flags & GOT_OBJ_FLAG_PACKED) == 0) return got_error(GOT_ERR_OBJ_NOT_PACKED); if ((obj->flags & GOT_OBJ_FLAG_DELTIFIED) == 0) { if (obj->pack_offset >= pack->filesize) return got_error(GOT_ERR_PACK_OFFSET); if (pack->map) { size_t mapoff; if (obj->pack_offset > SIZE_MAX) { return got_error_fmt(GOT_ERR_RANGE, "pack offset %lld would overflow size_t", (long long)obj->pack_offset); } mapoff = obj->pack_offset; err = got_inflate_to_file_mmap(&obj->size, NULL, NULL, pack->map, mapoff, pack->filesize - mapoff, outfile); } else { if (lseek(pack->fd, obj->pack_offset, SEEK_SET) == -1) return got_error_from_errno("lseek"); err = got_inflate_to_file_fd(&obj->size, NULL, NULL, pack->fd, outfile); } } else err = got_pack_dump_delta_chain_to_file(&obj->size, &obj->deltas, pack, outfile, base_file, accum_file); return err; } const struct got_error * got_packfile_extract_object_to_mem(uint8_t **buf, size_t *len, struct got_object *obj, struct got_pack *pack) { const struct got_error *err = NULL; if ((obj->flags & GOT_OBJ_FLAG_PACKED) == 0) return got_error(GOT_ERR_OBJ_NOT_PACKED); if ((obj->flags & GOT_OBJ_FLAG_DELTIFIED) == 0) { if (obj->pack_offset >= pack->filesize) return got_error(GOT_ERR_PACK_OFFSET); if (pack->map) { size_t mapoff; if (obj->pack_offset > SIZE_MAX) { return got_error_fmt(GOT_ERR_RANGE, "pack offset %lld would overflow size_t", (long long)obj->pack_offset); } mapoff = obj->pack_offset; err = got_inflate_to_mem_mmap(buf, len, NULL, NULL, pack->map, mapoff, pack->filesize - mapoff); } else { if (lseek(pack->fd, obj->pack_offset, SEEK_SET) == -1) return got_error_from_errno("lseek"); err = got_inflate_to_mem_fd(buf, len, NULL, NULL, obj->size, pack->fd); } } else err = got_pack_dump_delta_chain_to_mem(buf, len, &obj->deltas, pack); return err; } static const struct got_error * read_raw_delta_data(uint8_t **delta_buf, size_t *delta_len, size_t *delta_len_compressed, uint64_t *base_size, uint64_t *result_size, off_t delta_data_offset, struct got_pack *pack, struct got_packidx *packidx) { const struct got_error *err = NULL; /* Validate decompression and obtain the decompressed size. */ err = read_delta_data(delta_buf, delta_len, delta_len_compressed, delta_data_offset, pack); if (err) return err; /* Read delta base/result sizes from head of delta stream. */ err = got_delta_get_sizes(base_size, result_size, *delta_buf, *delta_len); if (err) goto done; /* Discard decompressed delta and read it again in compressed form. */ free(*delta_buf); *delta_buf = malloc(*delta_len_compressed); if (*delta_buf == NULL) { err = got_error_from_errno("malloc"); goto done; } if (pack->map) { if (delta_data_offset >= pack->filesize) { err = got_error(GOT_ERR_PACK_OFFSET); goto done; } memcpy(*delta_buf, pack->map + delta_data_offset, *delta_len_compressed); } else { ssize_t n; if (lseek(pack->fd, delta_data_offset, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } n = read(pack->fd, *delta_buf, *delta_len_compressed); if (n < 0) { err = got_error_from_errno("read"); goto done; } else if (n != *delta_len_compressed) { err = got_error(GOT_ERR_IO); goto done; } } done: if (err) { free(*delta_buf); *delta_buf = NULL; *delta_len = 0; *delta_len_compressed = 0; *base_size = 0; *result_size = 0; } return err; } const struct got_error * got_packfile_extract_raw_delta(uint8_t **delta_buf, size_t *delta_size, size_t *delta_compressed_size, off_t *delta_offset, off_t *delta_data_offset, off_t *base_offset, struct got_object_id *base_id, uint64_t *base_size, uint64_t *result_size, struct got_pack *pack, struct got_packidx *packidx, int idx) { const struct got_error *err = NULL; off_t offset; uint8_t type; uint64_t size; size_t tslen, delta_hdrlen; *delta_buf = NULL; *delta_size = 0; *delta_compressed_size = 0; *delta_offset = 0; *delta_data_offset = 0; *base_offset = 0; *base_size = 0; *result_size = 0; offset = got_packidx_get_object_offset(packidx, idx); if (offset == -1) return got_error(GOT_ERR_BAD_PACKIDX); if (offset >= pack->filesize) return got_error(GOT_ERR_PACK_OFFSET); err = got_pack_parse_object_type_and_size(&type, &size, &tslen, pack, offset); if (err) return err; if (tslen + size < tslen || offset + size < size || tslen + offset < tslen) return got_error(GOT_ERR_PACK_OFFSET); switch (type) { case GOT_OBJ_TYPE_OFFSET_DELTA: err = got_pack_parse_offset_delta(base_offset, &delta_hdrlen, pack, offset, tslen); if (err) return err; break; case GOT_OBJ_TYPE_REF_DELTA: err = got_pack_parse_ref_delta(base_id, pack, offset, tslen); if (err) return err; delta_hdrlen = SHA1_DIGEST_LENGTH; break; default: return got_error_fmt(GOT_ERR_OBJ_TYPE, "non-delta object type %d found at offset %lld", type, (long long)offset); } if (tslen + delta_hdrlen < delta_hdrlen || offset + delta_hdrlen < delta_hdrlen) return got_error(GOT_ERR_BAD_DELTA); *delta_data_offset = offset + tslen + delta_hdrlen; err = read_raw_delta_data(delta_buf, delta_size, delta_compressed_size, base_size, result_size, *delta_data_offset, pack, packidx); if (err) return err; if (*delta_size != size) { err = got_error(GOT_ERR_BAD_DELTA); goto done; } *delta_offset = offset; done: if (err) { free(*delta_buf); *delta_buf = NULL; *delta_size = 0; *delta_compressed_size = 0; *delta_offset = 0; *base_offset = 0; *base_size = 0; *result_size = 0; } return err; } got-portable-0.101/lib/dump.c0000664000175100017510000001052214644144735011472 /* * Copyright (c) 2023 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_cancel.h" #include "got_reference.h" #include "got_repository_admin.h" /* XXX for pack_progress */ #include "got_object.h" #include "got_opentemp.h" #include "got_repository_dump.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_object_idset.h" #include "got_lib_ratelimit.h" #include "got_lib_pack_create.h" #define GIT_BUNDLE_SIGNATURE_V2 "# v2 git bundle" struct idvec { struct got_object_id **ids; size_t len; size_t size; }; static const struct got_error * idvec_push(struct idvec *v, struct got_object_id *id) { size_t newsize; void *t; if (v->len == v->size) { newsize = v->size + 8; t = reallocarray(v->ids, newsize, sizeof(*v->ids)); if (t == NULL) return got_error_from_errno("reallocarray"); v->ids = t; v->size = newsize; } v->ids[v->len++] = id; return NULL; } static void idvec_free(struct idvec *v) { size_t i; for (i = 0; i < v->len; ++i) free(v->ids[i]); free(v->ids); } const struct got_error * got_repo_dump(FILE *out, struct got_reflist_head *include_refs, struct got_reflist_head *exclude_refs, struct got_repository *repo, got_pack_progress_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; struct got_ratelimit rl; uint8_t packsha[SHA1_DIGEST_LENGTH]; FILE *delta_cache = NULL; struct got_reflist_entry *e; struct got_object_id *id = NULL; struct got_commit_object *commit = NULL; struct idvec ours, theirs; char *nl, *s, *hex, *logmsg = NULL; const char *refname; int r; got_ratelimit_init(&rl, 0, 500); memset(&ours, 0, sizeof(ours)); memset(&theirs, 0, sizeof(theirs)); r = fprintf(out, "%s\n", GIT_BUNDLE_SIGNATURE_V2); if (r != strlen(GIT_BUNDLE_SIGNATURE_V2) + 1) return got_ferror(out, GOT_ERR_IO); TAILQ_FOREACH(e, exclude_refs, entry) { err = got_ref_resolve(&id, repo, e->ref); if (err) goto done; idvec_push(&theirs, id); if (err) goto done; err = got_object_open_as_commit(&commit, repo, id); if (err) goto done; err = got_object_commit_get_logmsg(&logmsg, commit); if (err) goto done; s = logmsg; while (isspace((unsigned char)*s)) s++; nl = strchr(s, '\n'); if (nl) *nl = '\0'; err = got_object_id_str(&hex, id); if (err) goto done; fprintf(out, "-%s %s\n", hex, s); free(hex); got_object_commit_close(commit); commit = NULL; free(logmsg); logmsg = NULL; } TAILQ_FOREACH(e, include_refs, entry) { err = got_ref_resolve(&id, repo, e->ref); if (err) goto done; err = idvec_push(&ours, id); if (err) goto done; refname = got_ref_get_name(e->ref); err = got_object_id_str(&hex, id); if (err) goto done; fprintf(out, "%s %s\n", hex, refname); free(hex); } if (fputc('\n', out) == EOF || fflush(out) == EOF) { err = got_ferror(out, GOT_ERR_IO); goto done; } delta_cache = got_opentemp(); if (delta_cache == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } err = got_pack_create(&packsha[0], fileno(out), delta_cache, theirs.ids, theirs.len, ours.ids, ours.len, repo, 0, 0, 0, progress_cb, progress_arg, &rl, cancel_cb, cancel_arg); done: idvec_free(&ours); idvec_free(&theirs); if (commit) got_object_commit_close(commit); if (delta_cache && fclose(delta_cache) == EOF && err == NULL) err = got_error_from_errno("fclose"); return err; } got-portable-0.101/lib/got_lib_delta_cache.h0000644000175100017510000000236214644143163014440 /* * Copyright (c) 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct got_delta_cache; const struct got_error *got_delta_cache_alloc(struct got_delta_cache **); void got_delta_cache_free(struct got_delta_cache *); const struct got_error *got_delta_cache_add(struct got_delta_cache *, off_t, uint8_t *, size_t); const struct got_error *got_delta_cache_add_fulltext(struct got_delta_cache *, off_t , uint8_t *, size_t); void got_delta_cache_get(uint8_t **, size_t *, uint8_t **, size_t *, struct got_delta_cache *, off_t); got-portable-0.101/lib/got_lib_deflate.h0000644000175100017510000000471314644143163013632 /* * Copyright (c) 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct got_deflate_checksum { /* If not NULL, mix output bytes into this CRC checksum. */ uint32_t *output_crc; /* If not NULL, mix output bytes into this hash context. */ struct got_hash *output_ctx; }; struct got_deflate_buf { z_stream z; uint8_t *inbuf; size_t inlen; uint8_t *outbuf; size_t outlen; int flags; #define GOT_DEFLATE_F_HAVE_MORE 0x01 #define GOT_DEFLATE_F_OWN_OUTBUF 0x02 }; #define GOT_DEFLATE_BUFSIZE 8192 const struct got_error *got_deflate_init(struct got_deflate_buf *, uint8_t *, size_t); const struct got_error *got_deflate_read(struct got_deflate_buf *, FILE *, off_t, size_t *, off_t *); const struct got_error *got_deflate_read_mmap(struct got_deflate_buf *, uint8_t *, size_t, size_t, size_t *, size_t *); void got_deflate_end(struct got_deflate_buf *); const struct got_error *got_deflate_to_fd(off_t *, FILE *, off_t, int, struct got_deflate_checksum *); const struct got_error *got_deflate_to_fd_mmap(off_t *, uint8_t *, size_t, size_t, int, struct got_deflate_checksum *); const struct got_error *got_deflate_to_file(off_t *, FILE *, off_t, FILE *, struct got_deflate_checksum *); const struct got_error *got_deflate_to_file_mmap(off_t *, uint8_t *, size_t, size_t, FILE *, struct got_deflate_checksum *); const struct got_error *got_deflate_flush(struct got_deflate_buf *, FILE *, struct got_deflate_checksum *, off_t *); const struct got_error *got_deflate_append_to_file_mmap( struct got_deflate_buf *, off_t *, uint8_t *, size_t, size_t, FILE *, struct got_deflate_checksum *); const struct got_error *got_deflate_to_mem_mmap(uint8_t **, size_t *, size_t *, struct got_deflate_checksum *, uint8_t *, size_t, size_t); got-portable-0.101/lib/got_lib_object.h0000644000175100017510000001320314644143163013466 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct got_object { int type; int flags; #define GOT_OBJ_FLAG_PACKED 0x01 #define GOT_OBJ_FLAG_DELTIFIED 0x02 size_t hdrlen; size_t size; struct got_object_id id; int pack_idx; /* if packed */ off_t pack_offset; /* if packed */ struct got_delta_chain deltas; /* if deltified */ int refcnt; /* > 0 if open and/or cached */ }; /* A callback function which is invoked when a raw object is closed. */ struct got_raw_object; typedef void (got_object_raw_close_cb)(struct got_raw_object *); struct got_raw_object { FILE *f; /* NULL if data buffer is being used */ int fd; /* -1 unless data buffer is memory-mapped */ int tempfile_idx; /* -1 unless using a repository-tempfile */ uint8_t *data; off_t size; size_t hdrlen; int refcnt; /* > 0 if open and/or cached */ got_object_raw_close_cb *close_cb; void *close_arg; }; struct got_commit_object { struct got_object_id *tree_id; unsigned int nparents; struct got_object_id_queue parent_ids; char *author; time_t author_time; /* UTC */ time_t author_gmtoff; char *committer; time_t committer_time; /* UTC */ time_t committer_gmtoff; char *logmsg; int refcnt; /* > 0 if open and/or cached */ int flags; #define GOT_COMMIT_FLAG_PACKED 0x01 }; struct got_tree_entry { mode_t mode; char name[NAME_MAX + 1 /* NUL */]; struct got_object_id id; int idx; }; struct got_tree_object { int nentries; struct got_tree_entry *entries; int refcnt; }; struct got_blob_object { FILE *f; uint8_t *data; size_t hdrlen; size_t blocksize; uint8_t *read_buf; struct got_object_id id; }; struct got_tag_object { struct got_object_id id; int obj_type; char *tag; time_t tagger_time; time_t tagger_gmtoff; char *tagger; char *tagmsg; int refcnt; /* > 0 if open and/or cached */ }; struct got_object_id *got_object_get_id(struct got_object *); const struct got_error *got_object_get_id_str(char **, struct got_object *); const struct got_error *got_object_get_path(char **, struct got_object_id *, struct got_repository *); const struct got_error *got_object_open_loose_fd(int *, struct got_object_id *, struct got_repository *); const struct got_error *got_object_open_packed(struct got_object **, struct got_object_id *, struct got_repository *); struct got_pack; struct got_packidx; const struct got_error *got_object_open_from_packfile(struct got_object **, struct got_object_id *, struct got_pack *, struct got_packidx *, int, struct got_repository *); const struct got_error *got_object_read_raw_delta(uint64_t *, uint64_t *, off_t *, off_t *, off_t *, off_t *, struct got_object_id **, int, struct got_packidx *, int, struct got_object_id *, struct got_repository *); const struct got_error *got_object_prepare_delta_reuse(struct got_pack **, struct got_packidx *, int, struct got_repository *); const struct got_error *got_object_read_header_privsep(struct got_object **, struct got_object_id *, struct got_repository *, int); const struct got_error *got_object_open(struct got_object **, struct got_repository *, struct got_object_id *); const struct got_error *got_object_raw_open(struct got_raw_object **, int *, struct got_repository *, struct got_object_id *); const struct got_error *got_object_raw_close(struct got_raw_object *); const struct got_error *got_object_open_by_id_str(struct got_object **, struct got_repository *, const char *); void got_object_close(struct got_object *); const struct got_error *got_object_commit_open(struct got_commit_object **, struct got_repository *, struct got_object *); const struct got_error *got_object_tree_open(struct got_tree_object **, struct got_repository *, struct got_object *); const struct got_error *got_object_blob_open(struct got_blob_object **, struct got_repository *, struct got_object *, size_t, int); char *got_object_blob_id_str(struct got_blob_object*, char *, size_t); const struct got_error *got_object_tag_open(struct got_tag_object **, struct got_repository *, struct got_object *); const struct got_error *got_object_tree_entry_dup(struct got_tree_entry **, struct got_tree_entry *); const struct got_error *got_traverse_packed_commits( struct got_object_id_queue *, struct got_object_id *, const char *, struct got_repository *); typedef const struct got_error *(*got_object_enumerate_commit_cb)(void *, time_t, struct got_object_id *, struct got_repository *); typedef const struct got_error *(*got_object_enumerate_tree_cb)(void *, struct got_tree_object *, time_t, struct got_object_id *, const char *, struct got_repository *); const struct got_error *got_object_enumerate(int *, got_object_enumerate_commit_cb, got_object_enumerate_tree_cb, void *, struct got_object_id **, int, struct got_object_id **, int, struct got_packidx *, struct got_repository *); const struct got_error *got_object_raw_alloc(struct got_raw_object **, uint8_t *, int *, size_t, size_t, off_t); got-portable-0.101/lib/worktree.c0000664000175100017510000102532314644144735012375 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_repository.h" #include "got_reference.h" #include "got_object.h" #include "got_path.h" #include "got_cancel.h" #include "got_worktree.h" #include "got_opentemp.h" #include "got_diff.h" #include "got_lib_worktree.h" #include "got_lib_hash.h" #include "got_lib_fileindex.h" #include "got_lib_inflate.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_object_create.h" #include "got_lib_object_idset.h" #include "got_lib_diff.h" #include "got_lib_gotconfig.h" #ifndef MIN #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) #endif #define GOT_MERGE_LABEL_MERGED "merged change" #define GOT_MERGE_LABEL_BASE "3-way merge base" static mode_t apply_umask(mode_t mode) { mode_t um; um = umask(000); umask(um); return mode & ~um; } static const struct got_error * create_meta_file(const char *path_got, const char *name, const char *content) { const struct got_error *err = NULL; char *path; if (asprintf(&path, "%s/%s", path_got, name) == -1) return got_error_from_errno("asprintf"); err = got_path_create_file(path, content); free(path); return err; } static const struct got_error * update_meta_file(const char *path_got, const char *name, const char *content) { const struct got_error *err = NULL; FILE *tmpfile = NULL; char *tmppath = NULL; char *path = NULL; if (asprintf(&path, "%s/%s", path_got, name) == -1) { err = got_error_from_errno("asprintf"); path = NULL; goto done; } err = got_opentemp_named(&tmppath, &tmpfile, path, ""); if (err) goto done; if (content) { int len = fprintf(tmpfile, "%s\n", content); if (len != strlen(content) + 1) { err = got_error_from_errno2("fprintf", tmppath); goto done; } } if (rename(tmppath, path) != 0) { err = got_error_from_errno3("rename", tmppath, path); unlink(tmppath); goto done; } done: if (fclose(tmpfile) == EOF && err == NULL) err = got_error_from_errno2("fclose", tmppath); free(tmppath); return err; } static const struct got_error * write_head_ref(const char *path_got, struct got_reference *head_ref) { const struct got_error *err = NULL; char *refstr = NULL; if (got_ref_is_symbolic(head_ref)) { refstr = got_ref_to_str(head_ref); if (refstr == NULL) return got_error_from_errno("got_ref_to_str"); } else { refstr = strdup(got_ref_get_name(head_ref)); if (refstr == NULL) return got_error_from_errno("strdup"); } err = update_meta_file(path_got, GOT_WORKTREE_HEAD_REF, refstr); free(refstr); return err; } const struct got_error * got_worktree_init(const char *path, struct got_reference *head_ref, const char *prefix, const char *meta_dir, struct got_repository *repo) { const struct got_error *err = NULL; struct got_object_id *commit_id = NULL; uuid_t uuid; uint32_t uuid_status; int obj_type; char *path_got = NULL; char *formatstr = NULL; char *absprefix = NULL; char *basestr = NULL; char *uuidstr = NULL; if (strcmp(path, got_repo_get_path(repo)) == 0) { err = got_error(GOT_ERR_WORKTREE_REPO); goto done; } err = got_ref_resolve(&commit_id, repo, head_ref); if (err) return err; err = got_object_get_type(&obj_type, repo, commit_id); if (err) return err; if (obj_type != GOT_OBJ_TYPE_COMMIT) return got_error(GOT_ERR_OBJ_TYPE); if (!got_path_is_absolute(prefix)) { if (asprintf(&absprefix, "/%s", prefix) == -1) return got_error_from_errno("asprintf"); } /* Create top-level directory (may already exist). */ if (mkdir(path, GOT_DEFAULT_DIR_MODE) == -1 && errno != EEXIST) { err = got_error_from_errno2("mkdir", path); goto done; } /* Create .got/.cvg directory (may already exist). */ if (asprintf(&path_got, "%s/%s", path, meta_dir) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (mkdir(path_got, GOT_DEFAULT_DIR_MODE) == -1 && errno != EEXIST) { err = got_error_from_errno2("mkdir", path_got); goto done; } /* Create an empty lock file. */ err = create_meta_file(path_got, GOT_WORKTREE_LOCK, NULL); if (err) goto done; /* Create an empty file index. */ err = create_meta_file(path_got, GOT_WORKTREE_FILE_INDEX, NULL); if (err) goto done; /* Write the HEAD reference. */ err = write_head_ref(path_got, head_ref); if (err) goto done; /* Record our base commit. */ err = got_object_id_str(&basestr, commit_id); if (err) goto done; err = create_meta_file(path_got, GOT_WORKTREE_BASE_COMMIT, basestr); if (err) goto done; /* Store path to repository. */ err = create_meta_file(path_got, GOT_WORKTREE_REPOSITORY, got_repo_get_path(repo)); if (err) goto done; /* Store in-repository path prefix. */ err = create_meta_file(path_got, GOT_WORKTREE_PATH_PREFIX, absprefix ? absprefix : prefix); if (err) goto done; /* Generate UUID. */ uuid_create(&uuid, &uuid_status); if (uuid_status != uuid_s_ok) { err = got_error_uuid(uuid_status, "uuid_create"); goto done; } uuid_to_string(&uuid, &uuidstr, &uuid_status); if (uuid_status != uuid_s_ok) { err = got_error_uuid(uuid_status, "uuid_to_string"); goto done; } err = create_meta_file(path_got, GOT_WORKTREE_UUID, uuidstr); if (err) goto done; /* Stamp work tree with format file. */ if (asprintf(&formatstr, "%d", GOT_WORKTREE_FORMAT_VERSION) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = create_meta_file(path_got, GOT_WORKTREE_FORMAT, formatstr); if (err) goto done; done: free(commit_id); free(path_got); free(formatstr); free(absprefix); free(basestr); free(uuidstr); return err; } const struct got_error * got_worktree_match_path_prefix(int *match, struct got_worktree *worktree, const char *path_prefix) { char *absprefix = NULL; if (!got_path_is_absolute(path_prefix)) { if (asprintf(&absprefix, "/%s", path_prefix) == -1) return got_error_from_errno("asprintf"); } *match = (strcmp(absprefix ? absprefix : path_prefix, worktree->path_prefix) == 0); free(absprefix); return NULL; } const char * got_worktree_get_head_ref_name(struct got_worktree *worktree) { return worktree->head_ref_name; } const struct got_error * got_worktree_set_head_ref(struct got_worktree *worktree, struct got_reference *head_ref) { const struct got_error *err = NULL; char *path_got = NULL, *head_ref_name = NULL; if (asprintf(&path_got, "%s/%s", worktree->root_path, worktree->meta_dir) == -1) { err = got_error_from_errno("asprintf"); path_got = NULL; goto done; } head_ref_name = strdup(got_ref_get_name(head_ref)); if (head_ref_name == NULL) { err = got_error_from_errno("strdup"); goto done; } err = write_head_ref(path_got, head_ref); if (err) goto done; free(worktree->head_ref_name); worktree->head_ref_name = head_ref_name; done: free(path_got); if (err) free(head_ref_name); return err; } struct got_object_id * got_worktree_get_base_commit_id(struct got_worktree *worktree) { return worktree->base_commit_id; } const struct got_error * got_worktree_set_base_commit_id(struct got_worktree *worktree, struct got_repository *repo, struct got_object_id *commit_id) { const struct got_error *err; struct got_object *obj = NULL; char *id_str = NULL; char *path_got = NULL; if (asprintf(&path_got, "%s/%s", worktree->root_path, worktree->meta_dir) == -1) { err = got_error_from_errno("asprintf"); path_got = NULL; goto done; } err = got_object_open(&obj, repo, commit_id); if (err) return err; if (obj->type != GOT_OBJ_TYPE_COMMIT) { err = got_error(GOT_ERR_OBJ_TYPE); goto done; } /* Record our base commit. */ err = got_object_id_str(&id_str, commit_id); if (err) goto done; err = update_meta_file(path_got, GOT_WORKTREE_BASE_COMMIT, id_str); if (err) goto done; free(worktree->base_commit_id); worktree->base_commit_id = got_object_id_dup(commit_id); if (worktree->base_commit_id == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } done: if (obj) got_object_close(obj); free(id_str); free(path_got); return err; } const struct got_gotconfig * got_worktree_get_gotconfig(struct got_worktree *worktree) { return worktree->gotconfig; } static const struct got_error * lock_worktree(struct got_worktree *worktree, int operation) { if (flock(worktree->lockfd, operation | LOCK_NB) == -1) return (errno == EWOULDBLOCK ? got_error(GOT_ERR_WORKTREE_BUSY) : got_error_from_errno2("flock", got_worktree_get_root_path(worktree))); return NULL; } static const struct got_error * add_dir_on_disk(struct got_worktree *worktree, const char *path) { const struct got_error *err = NULL; char *abspath; /* We only accept worktree-relative paths here. */ if (got_path_is_absolute(path)) { return got_error_fmt(GOT_ERR_BAD_PATH, "%s does not accept absolute paths: %s", __func__, path); } if (asprintf(&abspath, "%s/%s", worktree->root_path, path) == -1) return got_error_from_errno("asprintf"); err = got_path_mkdir(abspath); if (err && err->code == GOT_ERR_ERRNO && errno == EEXIST) { struct stat sb; err = NULL; if (lstat(abspath, &sb) == -1) { err = got_error_from_errno2("lstat", abspath); } else if (!S_ISDIR(sb.st_mode)) { /* TODO directory is obstructed; do something */ err = got_error_path(abspath, GOT_ERR_FILE_OBSTRUCTED); } } free(abspath); return err; } static const struct got_error * check_file_contents_equal(int *same, FILE *f1, FILE *f2) { const struct got_error *err = NULL; uint8_t fbuf1[8192]; uint8_t fbuf2[8192]; size_t flen1 = 0, flen2 = 0; *same = 1; for (;;) { flen1 = fread(fbuf1, 1, sizeof(fbuf1), f1); if (flen1 == 0 && ferror(f1)) { err = got_error_from_errno("fread"); break; } flen2 = fread(fbuf2, 1, sizeof(fbuf2), f2); if (flen2 == 0 && ferror(f2)) { err = got_error_from_errno("fread"); break; } if (flen1 == 0) { if (flen2 != 0) *same = 0; break; } else if (flen2 == 0) { if (flen1 != 0) *same = 0; break; } else if (flen1 == flen2) { if (memcmp(fbuf1, fbuf2, flen2) != 0) { *same = 0; break; } } else { *same = 0; break; } } return err; } static const struct got_error * check_files_equal(int *same, FILE *f1, FILE *f2) { struct stat sb; size_t size1, size2; *same = 1; if (fstat(fileno(f1), &sb) != 0) return got_error_from_errno("fstat"); size1 = sb.st_size; if (fstat(fileno(f2), &sb) != 0) return got_error_from_errno("fstat"); size2 = sb.st_size; if (size1 != size2) { *same = 0; return NULL; } if (fseek(f1, 0L, SEEK_SET) == -1) return got_ferror(f1, GOT_ERR_IO); if (fseek(f2, 0L, SEEK_SET) == -1) return got_ferror(f2, GOT_ERR_IO); return check_file_contents_equal(same, f1, f2); } static const struct got_error * copy_file_to_fd(off_t *outsize, FILE *f, int outfd) { uint8_t fbuf[65536]; size_t flen; ssize_t outlen; *outsize = 0; if (fseek(f, 0L, SEEK_SET) == -1) return got_ferror(f, GOT_ERR_IO); for (;;) { flen = fread(fbuf, 1, sizeof(fbuf), f); if (flen == 0) { if (ferror(f)) return got_error_from_errno("fread"); if (feof(f)) break; } outlen = write(outfd, fbuf, flen); if (outlen == -1) return got_error_from_errno("write"); if (outlen != flen) return got_error(GOT_ERR_IO); *outsize += outlen; } return NULL; } static const struct got_error * merge_binary_file(int *overlapcnt, int merged_fd, FILE *f_deriv, FILE *f_orig, FILE *f_deriv2, const char *label_deriv, const char *label_orig, const char *label_deriv2, const char *ondisk_path) { const struct got_error *err = NULL; int same_content, changed_deriv, changed_deriv2; int fd_orig = -1, fd_deriv = -1, fd_deriv2 = -1; off_t size_orig = 0, size_deriv = 0, size_deriv2 = 0; char *path_orig = NULL, *path_deriv = NULL, *path_deriv2 = NULL; char *base_path_orig = NULL, *base_path_deriv = NULL; char *base_path_deriv2 = NULL; *overlapcnt = 0; err = check_files_equal(&same_content, f_deriv, f_deriv2); if (err) return err; if (same_content) return copy_file_to_fd(&size_deriv, f_deriv, merged_fd); err = check_files_equal(&same_content, f_deriv, f_orig); if (err) return err; changed_deriv = !same_content; err = check_files_equal(&same_content, f_deriv2, f_orig); if (err) return err; changed_deriv2 = !same_content; if (changed_deriv && changed_deriv2) { *overlapcnt = 1; if (asprintf(&base_path_orig, "%s-orig", ondisk_path) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (asprintf(&base_path_deriv, "%s-1", ondisk_path) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (asprintf(&base_path_deriv2, "%s-2", ondisk_path) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_opentemp_named_fd(&path_orig, &fd_orig, base_path_orig, ""); if (err) goto done; err = got_opentemp_named_fd(&path_deriv, &fd_deriv, base_path_deriv, ""); if (err) goto done; err = got_opentemp_named_fd(&path_deriv2, &fd_deriv2, base_path_deriv2, ""); if (err) goto done; err = copy_file_to_fd(&size_orig, f_orig, fd_orig); if (err) goto done; err = copy_file_to_fd(&size_deriv, f_deriv, fd_deriv); if (err) goto done; err = copy_file_to_fd(&size_deriv2, f_deriv2, fd_deriv2); if (err) goto done; if (dprintf(merged_fd, "Binary files differ and cannot be " "merged automatically:\n") < 0) { err = got_error_from_errno("dprintf"); goto done; } if (dprintf(merged_fd, "%s%s%s\nfile %s\n", GOT_DIFF_CONFLICT_MARKER_BEGIN, label_deriv ? " " : "", label_deriv ? label_deriv : "", path_deriv) < 0) { err = got_error_from_errno("dprintf"); goto done; } if (size_orig > 0) { if (dprintf(merged_fd, "%s%s%s\nfile %s\n", GOT_DIFF_CONFLICT_MARKER_ORIG, label_orig ? " " : "", label_orig ? label_orig : "", path_orig) < 0) { err = got_error_from_errno("dprintf"); goto done; } } if (dprintf(merged_fd, "%s\nfile %s\n%s%s%s\n", GOT_DIFF_CONFLICT_MARKER_SEP, path_deriv2, GOT_DIFF_CONFLICT_MARKER_END, label_deriv2 ? " " : "", label_deriv2 ? label_deriv2 : "") < 0) { err = got_error_from_errno("dprintf"); goto done; } } else if (changed_deriv) err = copy_file_to_fd(&size_deriv, f_deriv, merged_fd); else if (changed_deriv2) err = copy_file_to_fd(&size_deriv2, f_deriv2, merged_fd); done: if (size_orig == 0 && path_orig && unlink(path_orig) == -1 && err == NULL) err = got_error_from_errno2("unlink", path_orig); if (fd_orig != -1 && close(fd_orig) == -1 && err == NULL) err = got_error_from_errno2("close", path_orig); if (fd_deriv != -1 && close(fd_deriv) == -1 && err == NULL) err = got_error_from_errno2("close", path_deriv); if (fd_deriv2 != -1 && close(fd_deriv2) == -1 && err == NULL) err = got_error_from_errno2("close", path_deriv2); free(path_orig); free(path_deriv); free(path_deriv2); free(base_path_orig); free(base_path_deriv); free(base_path_deriv2); return err; } /* * Perform a 3-way merge where the file f_orig acts as the common * ancestor, the file f_deriv acts as the first derived version, * and the file f_deriv2 acts as the second derived version. * The merge result will be written to a new file at ondisk_path; any * existing file at this path will be replaced. */ static const struct got_error * merge_file(int *local_changes_subsumed, struct got_worktree *worktree, FILE *f_orig, FILE *f_deriv, FILE *f_deriv2, const char *ondisk_path, const char *path, uint16_t st_mode, const char *label_orig, const char *label_deriv, const char *label_deriv2, enum got_diff_algorithm diff_algo, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg) { const struct got_error *err = NULL; int merged_fd = -1; FILE *f_merged = NULL; char *merged_path = NULL, *base_path = NULL; int overlapcnt = 0; char *parent = NULL; *local_changes_subsumed = 0; err = got_path_dirname(&parent, ondisk_path); if (err) return err; if (asprintf(&base_path, "%s/got-merged", parent) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_opentemp_named_fd(&merged_path, &merged_fd, base_path, ""); if (err) goto done; err = got_merge_diff3(&overlapcnt, merged_fd, f_deriv, f_orig, f_deriv2, label_deriv, label_orig, label_deriv2, diff_algo); if (err) { if (err->code != GOT_ERR_FILE_BINARY) goto done; err = merge_binary_file(&overlapcnt, merged_fd, f_deriv, f_orig, f_deriv2, label_deriv, label_orig, label_deriv2, ondisk_path); if (err) goto done; } err = (*progress_cb)(progress_arg, overlapcnt > 0 ? GOT_STATUS_CONFLICT : GOT_STATUS_MERGE, path); if (err) goto done; if (fsync(merged_fd) != 0) { err = got_error_from_errno("fsync"); goto done; } f_merged = fdopen(merged_fd, "r"); if (f_merged == NULL) { err = got_error_from_errno("fdopen"); goto done; } merged_fd = -1; /* Check if a clean merge has subsumed all local changes. */ if (overlapcnt == 0) { err = check_files_equal(local_changes_subsumed, f_deriv, f_merged); if (err) goto done; } if (fchmod(fileno(f_merged), apply_umask(st_mode)) != 0) { err = got_error_from_errno2("fchmod", merged_path); goto done; } if (rename(merged_path, ondisk_path) != 0) { err = got_error_from_errno3("rename", merged_path, ondisk_path); goto done; } done: if (err) { if (merged_path) unlink(merged_path); } if (merged_fd != -1 && close(merged_fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (f_merged && fclose(f_merged) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(merged_path); free(base_path); free(parent); return err; } static const struct got_error * update_symlink(const char *ondisk_path, const char *target_path, size_t target_len) { /* This is not atomic but matches what 'ln -sf' does. */ if (unlink(ondisk_path) == -1) return got_error_from_errno2("unlink", ondisk_path); if (symlink(target_path, ondisk_path) == -1) return got_error_from_errno3("symlink", target_path, ondisk_path); return NULL; } /* * Overwrite a symlink (or a regular file in case there was a "bad" symlink) * in the work tree with a file that contains conflict markers and the * conflicting target paths of the original version, a "derived version" * of a symlink from an incoming change, and a local version of the symlink. * * The original versions's target path can be NULL if it is not available, * such as if both derived versions added a new symlink at the same path. * * The incoming derived symlink target is NULL in case the incoming change * has deleted this symlink. */ static const struct got_error * install_symlink_conflict(const char *deriv_target, struct got_object_id *deriv_base_commit_id, const char *orig_target, const char *label_orig, const char *local_target, const char *ondisk_path) { const struct got_error *err; char *id_str = NULL, *label_deriv = NULL, *path = NULL; FILE *f = NULL; err = got_object_id_str(&id_str, deriv_base_commit_id); if (err) return got_error_from_errno("asprintf"); if (asprintf(&label_deriv, "%s: commit %s", GOT_MERGE_LABEL_MERGED, id_str) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_opentemp_named(&path, &f, "got-symlink-conflict", ""); if (err) goto done; if (fchmod(fileno(f), apply_umask(GOT_DEFAULT_FILE_MODE)) == -1) { err = got_error_from_errno2("fchmod", path); goto done; } if (fprintf(f, "%s %s\n%s\n%s%s%s%s%s\n%s\n%s\n", GOT_DIFF_CONFLICT_MARKER_BEGIN, label_deriv, deriv_target ? deriv_target : "(symlink was deleted)", orig_target ? label_orig : "", orig_target ? "\n" : "", orig_target ? orig_target : "", orig_target ? "\n" : "", GOT_DIFF_CONFLICT_MARKER_SEP, local_target, GOT_DIFF_CONFLICT_MARKER_END) < 0) { err = got_error_from_errno2("fprintf", path); goto done; } if (unlink(ondisk_path) == -1) { err = got_error_from_errno2("unlink", ondisk_path); goto done; } if (rename(path, ondisk_path) == -1) { err = got_error_from_errno3("rename", path, ondisk_path); goto done; } done: if (f != NULL && fclose(f) == EOF && err == NULL) err = got_error_from_errno2("fclose", path); free(path); free(id_str); free(label_deriv); return err; } /* forward declaration */ static const struct got_error * merge_blob(int *, struct got_worktree *, struct got_blob_object *, const char *, const char *, uint16_t, const char *, struct got_blob_object *, struct got_object_id *, struct got_repository *, got_worktree_checkout_cb, void *); /* * Merge a symlink into the work tree, where blob_orig acts as the common * ancestor, deriv_target is the link target of the first derived version, * and the symlink on disk acts as the second derived version. * Assume that contents of both blobs represent symlinks. */ static const struct got_error * merge_symlink(struct got_worktree *worktree, struct got_blob_object *blob_orig, const char *ondisk_path, const char *path, const char *label_orig, const char *deriv_target, struct got_object_id *deriv_base_commit_id, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg) { const struct got_error *err = NULL; char *ancestor_target = NULL; struct stat sb; ssize_t ondisk_len, deriv_len; char ondisk_target[PATH_MAX]; int have_local_change = 0; int have_incoming_change = 0; if (lstat(ondisk_path, &sb) == -1) return got_error_from_errno2("lstat", ondisk_path); ondisk_len = readlink(ondisk_path, ondisk_target, sizeof(ondisk_target)); if (ondisk_len == -1) { err = got_error_from_errno2("readlink", ondisk_path); goto done; } ondisk_target[ondisk_len] = '\0'; if (blob_orig) { err = got_object_blob_read_to_str(&ancestor_target, blob_orig); if (err) goto done; } if (ancestor_target == NULL || (ondisk_len != strlen(ancestor_target) || memcmp(ondisk_target, ancestor_target, ondisk_len) != 0)) have_local_change = 1; deriv_len = strlen(deriv_target); if (ancestor_target == NULL || (deriv_len != strlen(ancestor_target) || memcmp(deriv_target, ancestor_target, deriv_len) != 0)) have_incoming_change = 1; if (!have_local_change && !have_incoming_change) { if (ancestor_target) { /* Both sides made the same change. */ err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE, path); } else if (deriv_len == ondisk_len && memcmp(ondisk_target, deriv_target, deriv_len) == 0) { /* Both sides added the same symlink. */ err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE, path); } else { /* Both sides added symlinks which don't match. */ err = install_symlink_conflict(deriv_target, deriv_base_commit_id, ancestor_target, label_orig, ondisk_target, ondisk_path); if (err) goto done; err = (*progress_cb)(progress_arg, GOT_STATUS_CONFLICT, path); } } else if (!have_local_change && have_incoming_change) { /* Apply the incoming change. */ err = update_symlink(ondisk_path, deriv_target, strlen(deriv_target)); if (err) goto done; err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE, path); } else if (have_local_change && have_incoming_change) { if (deriv_len == ondisk_len && memcmp(deriv_target, ondisk_target, deriv_len) == 0) { /* Both sides made the same change. */ err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE, path); } else { err = install_symlink_conflict(deriv_target, deriv_base_commit_id, ancestor_target, label_orig, ondisk_target, ondisk_path); if (err) goto done; err = (*progress_cb)(progress_arg, GOT_STATUS_CONFLICT, path); } } done: free(ancestor_target); return err; } static const struct got_error * dump_symlink_target_path_to_file(FILE **outfile, const char *ondisk_path) { const struct got_error *err = NULL; char target_path[PATH_MAX]; ssize_t target_len; size_t n; FILE *f; *outfile = NULL; f = got_opentemp(); if (f == NULL) return got_error_from_errno("got_opentemp"); target_len = readlink(ondisk_path, target_path, sizeof(target_path)); if (target_len == -1) { err = got_error_from_errno2("readlink", ondisk_path); goto done; } n = fwrite(target_path, 1, target_len, f); if (n != target_len) { err = got_ferror(f, GOT_ERR_IO); goto done; } if (fflush(f) == EOF) { err = got_error_from_errno("fflush"); goto done; } if (fseek(f, 0L, SEEK_SET) == -1) { err = got_ferror(f, GOT_ERR_IO); goto done; } done: if (err) fclose(f); else *outfile = f; return err; } /* * Perform a 3-way merge where blob_orig acts as the common ancestor, * blob_deriv acts as the first derived version, and the file on disk * acts as the second derived version. */ static const struct got_error * merge_blob(int *local_changes_subsumed, struct got_worktree *worktree, struct got_blob_object *blob_orig, const char *ondisk_path, const char *path, uint16_t st_mode, const char *label_orig, struct got_blob_object *blob_deriv, struct got_object_id *deriv_base_commit_id, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg) { const struct got_error *err = NULL; FILE *f_orig = NULL, *f_deriv = NULL, *f_deriv2 = NULL; char *blob_orig_path = NULL; char *blob_deriv_path = NULL, *base_path = NULL, *id_str = NULL; char *label_deriv = NULL, *parent = NULL; *local_changes_subsumed = 0; err = got_path_dirname(&parent, ondisk_path); if (err) return err; if (blob_orig) { if (asprintf(&base_path, "%s/got-merge-blob-orig", parent) == -1) { err = got_error_from_errno("asprintf"); base_path = NULL; goto done; } err = got_opentemp_named(&blob_orig_path, &f_orig, base_path, ""); if (err) goto done; err = got_object_blob_dump_to_file(NULL, NULL, NULL, f_orig, blob_orig); if (err) goto done; free(base_path); } else { /* * No common ancestor exists. This is an "add vs add" conflict * and we simply use an empty ancestor file to make both files * appear in the merged result in their entirety. */ f_orig = got_opentemp(); if (f_orig == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } } if (asprintf(&base_path, "%s/got-merge-blob-deriv", parent) == -1) { err = got_error_from_errno("asprintf"); base_path = NULL; goto done; } err = got_opentemp_named(&blob_deriv_path, &f_deriv, base_path, ""); if (err) goto done; err = got_object_blob_dump_to_file(NULL, NULL, NULL, f_deriv, blob_deriv); if (err) goto done; err = got_object_id_str(&id_str, deriv_base_commit_id); if (err) goto done; if (asprintf(&label_deriv, "%s: commit %s", GOT_MERGE_LABEL_MERGED, id_str) == -1) { err = got_error_from_errno("asprintf"); goto done; } /* * In order the run a 3-way merge with a symlink we copy the symlink's * target path into a temporary file and use that file with diff3. */ if (S_ISLNK(st_mode)) { err = dump_symlink_target_path_to_file(&f_deriv2, ondisk_path); if (err) goto done; } else { int fd; fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { err = got_error_from_errno2("open", ondisk_path); goto done; } f_deriv2 = fdopen(fd, "r"); if (f_deriv2 == NULL) { err = got_error_from_errno2("fdopen", ondisk_path); close(fd); goto done; } } err = merge_file(local_changes_subsumed, worktree, f_orig, f_deriv, f_deriv2, ondisk_path, path, st_mode, label_orig, label_deriv, NULL, GOT_DIFF_ALGORITHM_MYERS, repo, progress_cb, progress_arg); done: if (f_orig && fclose(f_orig) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (f_deriv && fclose(f_deriv) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (f_deriv2 && fclose(f_deriv2) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(base_path); if (blob_orig_path) { unlink(blob_orig_path); free(blob_orig_path); } if (blob_deriv_path) { unlink(blob_deriv_path); free(blob_deriv_path); } free(id_str); free(label_deriv); free(parent); return err; } static const struct got_error * create_fileindex_entry(struct got_fileindex_entry **new_iep, struct got_fileindex *fileindex, struct got_object_id *base_commit_id, int wt_fd, const char *path, struct got_object_id *blob_id, int update_timestamps) { const struct got_error *err = NULL; struct got_fileindex_entry *new_ie; *new_iep = NULL; err = got_fileindex_entry_alloc(&new_ie, path); if (err) return err; err = got_fileindex_entry_update(new_ie, wt_fd, path, blob_id->sha1, base_commit_id->sha1, update_timestamps); if (err) goto done; err = got_fileindex_entry_add(fileindex, new_ie); done: if (err) got_fileindex_entry_free(new_ie); else *new_iep = new_ie; return err; } static mode_t get_ondisk_perms(int executable, mode_t st_mode) { mode_t xbits = S_IXUSR; if (executable) { /* Map read bits to execute bits. */ if (st_mode & S_IRGRP) xbits |= S_IXGRP; if (st_mode & S_IROTH) xbits |= S_IXOTH; return st_mode | xbits; } return st_mode; } /* forward declaration */ static const struct got_error * install_blob(struct got_worktree *worktree, const char *ondisk_path, const char *path, mode_t te_mode, mode_t st_mode, struct got_blob_object *blob, int restoring_missing_file, int reverting_versioned_file, int installing_bad_symlink, int path_is_unversioned, int *update_timestamps, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg); /* * This function assumes that the provided symlink target points at a * safe location in the work tree! */ static const struct got_error * replace_existing_symlink(int *did_something, const char *ondisk_path, const char *target_path, size_t target_len) { const struct got_error *err = NULL; ssize_t elen; char etarget[PATH_MAX]; int fd; *did_something = 0; /* * "Bad" symlinks (those pointing outside the work tree or into the * .got directory) are installed in the work tree as a regular file * which contains the bad symlink target path. * The new symlink target has already been checked for safety by our * caller. If we can successfully open a regular file then we simply * replace this file with a symlink below. */ fd = open(ondisk_path, O_RDWR | O_EXCL | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { if (!got_err_open_nofollow_on_symlink()) return got_error_from_errno2("open", ondisk_path); /* We are updating an existing on-disk symlink. */ elen = readlink(ondisk_path, etarget, sizeof(etarget)); if (elen == -1) return got_error_from_errno2("readlink", ondisk_path); if (elen == target_len && memcmp(etarget, target_path, target_len) == 0) return NULL; /* nothing to do */ } *did_something = 1; err = update_symlink(ondisk_path, target_path, target_len); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno2("close", ondisk_path); return err; } static const struct got_error * is_bad_symlink_target(int *is_bad_symlink, const char *target_path, size_t target_len, const char *ondisk_path, const char *wtroot_path, const char *meta_dir) { const struct got_error *err = NULL; char canonpath[PATH_MAX]; char *path_got = NULL; *is_bad_symlink = 0; if (target_len >= sizeof(canonpath)) { *is_bad_symlink = 1; return NULL; } /* * We do not use realpath(3) to resolve the symlink's target * path because we don't want to resolve symlinks recursively. * Instead we make the path absolute and then canonicalize it. * Relative symlink target lookup should begin at the directory * in which the blob object is being installed. */ if (!got_path_is_absolute(target_path)) { char *abspath, *parent; err = got_path_dirname(&parent, ondisk_path); if (err) return err; if (asprintf(&abspath, "%s/%s", parent, target_path) == -1) { free(parent); return got_error_from_errno("asprintf"); } free(parent); if (strlen(abspath) >= sizeof(canonpath)) { err = got_error_path(abspath, GOT_ERR_BAD_PATH); free(abspath); return err; } err = got_canonpath(abspath, canonpath, sizeof(canonpath)); free(abspath); if (err) return err; } else { err = got_canonpath(target_path, canonpath, sizeof(canonpath)); if (err) return err; } /* Only allow symlinks pointing at paths within the work tree. */ if (!got_path_is_child(canonpath, wtroot_path, strlen(wtroot_path))) { *is_bad_symlink = 1; return NULL; } /* Do not allow symlinks pointing into the meta directory. */ if (asprintf(&path_got, "%s/%s", wtroot_path, meta_dir) == -1) return got_error_from_errno("asprintf"); if (got_path_is_child(canonpath, path_got, strlen(path_got))) *is_bad_symlink = 1; free(path_got); return NULL; } static const struct got_error * install_symlink(int *is_bad_symlink, struct got_worktree *worktree, const char *ondisk_path, const char *path, struct got_blob_object *blob, int restoring_missing_file, int reverting_versioned_file, int path_is_unversioned, int allow_bad_symlinks, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg) { const struct got_error *err = NULL; char target_path[PATH_MAX]; size_t len, target_len = 0; const uint8_t *buf = got_object_blob_get_read_buf(blob); size_t hdrlen = got_object_blob_get_hdrlen(blob); *is_bad_symlink = 0; /* * Blob object content specifies the target path of the link. * If a symbolic link cannot be installed we instead create * a regular file which contains the link target path stored * in the blob object. */ do { err = got_object_blob_read_block(&len, blob); if (err) return err; if (len + target_len >= sizeof(target_path)) { /* Path too long; install as a regular file. */ *is_bad_symlink = 1; got_object_blob_rewind(blob); return install_blob(worktree, ondisk_path, path, GOT_DEFAULT_FILE_MODE, GOT_DEFAULT_FILE_MODE, blob, restoring_missing_file, reverting_versioned_file, 1, path_is_unversioned, NULL, repo, progress_cb, progress_arg); } if (len > 0) { /* Skip blob object header first time around. */ memcpy(target_path + target_len, buf + hdrlen, len - hdrlen); target_len += len - hdrlen; hdrlen = 0; } } while (len != 0); target_path[target_len] = '\0'; err = is_bad_symlink_target(is_bad_symlink, target_path, target_len, ondisk_path, worktree->root_path, worktree->meta_dir); if (err) return err; if (*is_bad_symlink && !allow_bad_symlinks) { /* install as a regular file */ got_object_blob_rewind(blob); err = install_blob(worktree, ondisk_path, path, GOT_DEFAULT_FILE_MODE, GOT_DEFAULT_FILE_MODE, blob, restoring_missing_file, reverting_versioned_file, 1, path_is_unversioned, NULL, repo, progress_cb, progress_arg); return err; } if (symlink(target_path, ondisk_path) == -1) { if (errno == EEXIST) { int symlink_replaced; if (path_is_unversioned) { err = (*progress_cb)(progress_arg, GOT_STATUS_UNVERSIONED, path); return err; } err = replace_existing_symlink(&symlink_replaced, ondisk_path, target_path, target_len); if (err) return err; if (progress_cb) { if (symlink_replaced) { err = (*progress_cb)(progress_arg, reverting_versioned_file ? GOT_STATUS_REVERT : GOT_STATUS_UPDATE, path); } else { err = (*progress_cb)(progress_arg, GOT_STATUS_EXISTS, path); } } return err; /* Nothing else to do. */ } if (errno == ENOENT) { char *parent; err = got_path_dirname(&parent, ondisk_path); if (err) return err; err = got_path_mkdir(parent); free(parent); if (err) return err; /* * Retry, and fall through to error handling * below if this second attempt fails. */ if (symlink(target_path, ondisk_path) != -1) { err = NULL; /* success */ if (progress_cb) { err = (*progress_cb)(progress_arg, reverting_versioned_file ? GOT_STATUS_REVERT : GOT_STATUS_ADD, path); } return err; } } /* Handle errors from first or second creation attempt. */ if (errno == ENAMETOOLONG) { /* bad target path; install as a regular file */ *is_bad_symlink = 1; got_object_blob_rewind(blob); err = install_blob(worktree, ondisk_path, path, GOT_DEFAULT_FILE_MODE, GOT_DEFAULT_FILE_MODE, blob, restoring_missing_file, reverting_versioned_file, 1, path_is_unversioned, NULL, repo, progress_cb, progress_arg); } else if (errno == ENOTDIR) { err = got_error_path(ondisk_path, GOT_ERR_FILE_OBSTRUCTED); } else { err = got_error_from_errno3("symlink", target_path, ondisk_path); } } else if (progress_cb) err = (*progress_cb)(progress_arg, reverting_versioned_file ? GOT_STATUS_REVERT : GOT_STATUS_ADD, path); return err; } static const struct got_error * install_blob(struct got_worktree *worktree, const char *ondisk_path, const char *path, mode_t te_mode, mode_t st_mode, struct got_blob_object *blob, int restoring_missing_file, int reverting_versioned_file, int installing_bad_symlink, int path_is_unversioned, int *update_timestamps, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg) { const struct got_error *err = NULL; int fd = -1; size_t len, hdrlen; int update = 0; char *tmppath = NULL; mode_t mode; if (update_timestamps) *update_timestamps = 1; mode = get_ondisk_perms(te_mode & S_IXUSR, GOT_DEFAULT_FILE_MODE); fd = open(ondisk_path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC, mode); if (fd == -1) { if (errno == ENOENT || errno == ENOTDIR) { char *parent; err = got_path_dirname(&parent, path); if (err) return err; err = add_dir_on_disk(worktree, parent); if (err && err->code == GOT_ERR_FILE_OBSTRUCTED) err = got_error_path(path, err->code); free(parent); if (err) return err; fd = open(ondisk_path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC, mode); if (fd == -1) return got_error_from_errno2("open", ondisk_path); } else if (errno == EEXIST) { if (path_is_unversioned) { if (update_timestamps) *update_timestamps = 0; err = (*progress_cb)(progress_arg, GOT_STATUS_EXISTS, path); goto done; } if (!(S_ISLNK(st_mode) && S_ISREG(te_mode)) && !S_ISREG(st_mode) && !installing_bad_symlink) { /* TODO file is obstructed; do something */ err = got_error_path(ondisk_path, GOT_ERR_FILE_OBSTRUCTED); goto done; } else { err = got_opentemp_named_fd(&tmppath, &fd, ondisk_path, ""); if (err) goto done; update = 1; if (fchmod(fd, apply_umask(mode)) == -1) { err = got_error_from_errno2("fchmod", tmppath); goto done; } } } else return got_error_from_errno2("open", ondisk_path); } if (progress_cb) { if (restoring_missing_file) err = (*progress_cb)(progress_arg, GOT_STATUS_MISSING, path); else if (reverting_versioned_file) err = (*progress_cb)(progress_arg, GOT_STATUS_REVERT, path); else err = (*progress_cb)(progress_arg, update ? GOT_STATUS_UPDATE : GOT_STATUS_ADD, path); if (err) goto done; } hdrlen = got_object_blob_get_hdrlen(blob); do { const uint8_t *buf = got_object_blob_get_read_buf(blob); err = got_object_blob_read_block(&len, blob); if (err) break; if (len > 0) { /* Skip blob object header first time around. */ ssize_t outlen = write(fd, buf + hdrlen, len - hdrlen); if (outlen == -1) { err = got_error_from_errno("write"); goto done; } else if (outlen != len - hdrlen) { err = got_error(GOT_ERR_IO); goto done; } hdrlen = 0; } } while (len != 0); if (fsync(fd) != 0) { err = got_error_from_errno("fsync"); goto done; } if (update) { if (S_ISLNK(st_mode) && unlink(ondisk_path) == -1) { err = got_error_from_errno2("unlink", ondisk_path); goto done; } if (rename(tmppath, ondisk_path) != 0) { err = got_error_from_errno3("rename", tmppath, ondisk_path); goto done; } free(tmppath); tmppath = NULL; } done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (tmppath != NULL && unlink(tmppath) == -1 && err == NULL) err = got_error_from_errno2("unlink", tmppath); free(tmppath); return err; } /* * Upgrade STATUS_MODIFY to STATUS_CONFLICT if a * conflict marker is found in newly added lines only. */ static const struct got_error * get_modified_file_content_status(unsigned char *status, struct got_blob_object *blob, const char *path, struct stat *sb, FILE *ondisk_file) { const struct got_error *err, *free_err; const char *markers[3] = { GOT_DIFF_CONFLICT_MARKER_BEGIN, GOT_DIFF_CONFLICT_MARKER_SEP, GOT_DIFF_CONFLICT_MARKER_END }; FILE *f1 = NULL; struct got_diffreg_result *diffreg_result = NULL; struct diff_result *r; int nchunks_parsed, n, i = 0, ln = 0; char *line = NULL; size_t linesize = 0; ssize_t linelen; if (*status != GOT_STATUS_MODIFY) return NULL; f1 = got_opentemp(); if (f1 == NULL) return got_error_from_errno("got_opentemp"); if (blob) { got_object_blob_rewind(blob); err = got_object_blob_dump_to_file(NULL, NULL, NULL, f1, blob); if (err) goto done; } err = got_diff_files(&diffreg_result, f1, 1, NULL, ondisk_file, 1, NULL, 0, 0, 1, NULL, GOT_DIFF_ALGORITHM_MYERS); if (err) goto done; r = diffreg_result->result; for (n = 0; n < r->chunks.len; n += nchunks_parsed) { struct diff_chunk *c; struct diff_chunk_context cc = {}; off_t pos; /* * We can optimise a little by advancing straight * to the next chunk if this one has no added lines. */ c = diff_chunk_get(r, n); if (diff_chunk_type(c) != CHUNK_PLUS) { nchunks_parsed = 1; continue; /* removed or unchanged lines */ } pos = diff_chunk_get_right_start_pos(c); if (fseek(ondisk_file, pos, SEEK_SET) == -1) { err = got_ferror(ondisk_file, GOT_ERR_IO); goto done; } diff_chunk_context_load_change(&cc, &nchunks_parsed, r, n, 0); ln = cc.right.start; while (ln < cc.right.end) { linelen = getline(&line, &linesize, ondisk_file); if (linelen == -1) { if (feof(ondisk_file)) break; err = got_ferror(ondisk_file, GOT_ERR_IO); break; } if (line && strncmp(line, markers[i], strlen(markers[i])) == 0) { if (strcmp(markers[i], GOT_DIFF_CONFLICT_MARKER_END) == 0) { *status = GOT_STATUS_CONFLICT; goto done; } else i++; } ++ln; } } done: free(line); if (f1 != NULL && fclose(f1) == EOF && err == NULL) err = got_error_from_errno("fclose"); free_err = got_diffreg_result_free(diffreg_result); if (err == NULL) err = free_err; return err; } static int xbit_differs(struct got_fileindex_entry *ie, uint16_t st_mode) { mode_t ie_mode = got_fileindex_perms_to_st(ie); return ((ie_mode & S_IXUSR) != (st_mode & S_IXUSR)); } static int stat_info_differs(struct got_fileindex_entry *ie, struct stat *sb) { return !(ie->ctime_sec == sb->st_ctim.tv_sec && ie->ctime_nsec == sb->st_ctim.tv_nsec && ie->mtime_sec == sb->st_mtim.tv_sec && ie->mtime_nsec == sb->st_mtim.tv_nsec && ie->size == (sb->st_size & 0xffffffff) && !xbit_differs(ie, sb->st_mode)); } static unsigned char get_staged_status(struct got_fileindex_entry *ie) { switch (got_fileindex_entry_stage_get(ie)) { case GOT_FILEIDX_STAGE_ADD: return GOT_STATUS_ADD; case GOT_FILEIDX_STAGE_DELETE: return GOT_STATUS_DELETE; case GOT_FILEIDX_STAGE_MODIFY: return GOT_STATUS_MODIFY; default: return GOT_STATUS_NO_CHANGE; } } static const struct got_error * get_symlink_modification_status(unsigned char *status, struct got_fileindex_entry *ie, const char *abspath, int dirfd, const char *de_name, struct got_blob_object *blob) { const struct got_error *err = NULL; char target_path[PATH_MAX]; char etarget[PATH_MAX]; ssize_t elen; size_t len, target_len = 0; const uint8_t *buf = got_object_blob_get_read_buf(blob); size_t hdrlen = got_object_blob_get_hdrlen(blob); *status = GOT_STATUS_NO_CHANGE; /* Blob object content specifies the target path of the link. */ do { err = got_object_blob_read_block(&len, blob); if (err) return err; if (len + target_len >= sizeof(target_path)) { /* * Should not happen. The blob contents were OK * when this symlink was installed. */ return got_error(GOT_ERR_NO_SPACE); } if (len > 0) { /* Skip blob object header first time around. */ memcpy(target_path + target_len, buf + hdrlen, len - hdrlen); target_len += len - hdrlen; hdrlen = 0; } } while (len != 0); target_path[target_len] = '\0'; if (dirfd != -1) { elen = readlinkat(dirfd, de_name, etarget, sizeof(etarget)); if (elen == -1) return got_error_from_errno2("readlinkat", abspath); } else { elen = readlink(abspath, etarget, sizeof(etarget)); if (elen == -1) return got_error_from_errno2("readlink", abspath); } if (elen != target_len || memcmp(etarget, target_path, target_len) != 0) *status = GOT_STATUS_MODIFY; return NULL; } static const struct got_error * get_file_status(unsigned char *status, struct stat *sb, struct got_fileindex_entry *ie, const char *abspath, int dirfd, const char *de_name, struct got_repository *repo) { const struct got_error *err = NULL; struct got_object_id id; size_t hdrlen; int fd = -1, fd1 = -1; FILE *f = NULL; uint8_t fbuf[8192]; struct got_blob_object *blob = NULL; size_t flen, blen; unsigned char staged_status; staged_status = get_staged_status(ie); *status = GOT_STATUS_NO_CHANGE; memset(sb, 0, sizeof(*sb)); /* * Whenever the caller provides a directory descriptor and a * directory entry name for the file, use them! This prevents * race conditions if filesystem paths change beneath our feet. */ if (dirfd != -1) { if (fstatat(dirfd, de_name, sb, AT_SYMLINK_NOFOLLOW) == -1) { if (errno == ENOENT) { if (got_fileindex_entry_has_file_on_disk(ie)) *status = GOT_STATUS_MISSING; else *status = GOT_STATUS_DELETE; goto done; } err = got_error_from_errno2("fstatat", abspath); goto done; } } else { fd = open(abspath, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1 && errno != ENOENT && !got_err_open_nofollow_on_symlink()) return got_error_from_errno2("open", abspath); else if (fd == -1 && got_err_open_nofollow_on_symlink()) { if (lstat(abspath, sb) == -1) return got_error_from_errno2("lstat", abspath); } else if (fd == -1 || fstat(fd, sb) == -1) { if (errno == ENOENT) { if (got_fileindex_entry_has_file_on_disk(ie)) *status = GOT_STATUS_MISSING; else *status = GOT_STATUS_DELETE; goto done; } err = got_error_from_errno2("fstat", abspath); goto done; } } if (!S_ISREG(sb->st_mode) && !S_ISLNK(sb->st_mode)) { *status = GOT_STATUS_OBSTRUCTED; goto done; } if (!got_fileindex_entry_has_file_on_disk(ie)) { *status = GOT_STATUS_DELETE; goto done; } else if (!got_fileindex_entry_has_blob(ie) && staged_status != GOT_STATUS_ADD) { *status = GOT_STATUS_ADD; goto done; } if (!stat_info_differs(ie, sb)) goto done; if (S_ISLNK(sb->st_mode) && got_fileindex_entry_filetype_get(ie) != GOT_FILEIDX_MODE_SYMLINK) { *status = GOT_STATUS_MODIFY; goto done; } if (staged_status == GOT_STATUS_MODIFY || staged_status == GOT_STATUS_ADD) got_fileindex_entry_get_staged_blob_id(&id, ie); else got_fileindex_entry_get_blob_id(&id, ie); fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } err = got_object_open_as_blob(&blob, repo, &id, sizeof(fbuf), fd1); if (err) goto done; if (S_ISLNK(sb->st_mode)) { err = get_symlink_modification_status(status, ie, abspath, dirfd, de_name, blob); goto done; } if (dirfd != -1) { fd = openat(dirfd, de_name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { err = got_error_from_errno2("openat", abspath); goto done; } } f = fdopen(fd, "r"); if (f == NULL) { err = got_error_from_errno2("fdopen", abspath); goto done; } fd = -1; hdrlen = got_object_blob_get_hdrlen(blob); for (;;) { const uint8_t *bbuf = got_object_blob_get_read_buf(blob); err = got_object_blob_read_block(&blen, blob); if (err) goto done; /* Skip length of blob object header first time around. */ flen = fread(fbuf, 1, sizeof(fbuf) - hdrlen, f); if (flen == 0 && ferror(f)) { err = got_error_from_errno("fread"); goto done; } if (blen - hdrlen == 0) { if (flen != 0) *status = GOT_STATUS_MODIFY; break; } else if (flen == 0) { if (blen - hdrlen != 0) *status = GOT_STATUS_MODIFY; break; } else if (blen - hdrlen == flen) { /* Skip blob object header first time around. */ if (memcmp(bbuf + hdrlen, fbuf, flen) != 0) { *status = GOT_STATUS_MODIFY; break; } } else { *status = GOT_STATUS_MODIFY; break; } hdrlen = 0; } if (*status == GOT_STATUS_MODIFY) { rewind(f); err = get_modified_file_content_status(status, blob, ie->path, sb, f); } else if (xbit_differs(ie, sb->st_mode)) *status = GOT_STATUS_MODE_CHANGE; done: if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob) got_object_blob_close(blob); if (f != NULL && fclose(f) == EOF && err == NULL) err = got_error_from_errno2("fclose", abspath); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno2("close", abspath); return err; } /* * Update timestamps in the file index if a file is unmodified and * we had to run a full content comparison to find out. */ static const struct got_error * sync_timestamps(int wt_fd, const char *path, unsigned char status, struct got_fileindex_entry *ie, struct stat *sb) { if (status == GOT_STATUS_NO_CHANGE && stat_info_differs(ie, sb)) return got_fileindex_entry_update(ie, wt_fd, path, ie->blob_sha1, ie->commit_sha1, 1); return NULL; } static const struct got_error *remove_ondisk_file(const char *, const char *); static const struct got_error * update_blob(struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_fileindex_entry *ie, struct got_tree_entry *te, const char *path, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg) { const struct got_error *err = NULL; struct got_blob_object *blob = NULL; char *ondisk_path = NULL; unsigned char status = GOT_STATUS_NO_CHANGE; struct stat sb; int fd1 = -1, fd2 = -1; int update_timestamps = 0; if (asprintf(&ondisk_path, "%s/%s", worktree->root_path, path) == -1) return got_error_from_errno("asprintf"); if (ie) { if (get_staged_status(ie) != GOT_STATUS_NO_CHANGE) { err = got_error_path(ie->path, GOT_ERR_FILE_STAGED); goto done; } err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, repo); if (err) goto done; if (status == GOT_STATUS_MISSING || status == GOT_STATUS_DELETE) sb.st_mode = got_fileindex_perms_to_st(ie); } else { if (stat(ondisk_path, &sb) == -1) { if (errno != ENOENT && errno != ENOTDIR) { err = got_error_from_errno2("stat", ondisk_path); goto done; } sb.st_mode = GOT_DEFAULT_FILE_MODE; status = GOT_STATUS_UNVERSIONED; } else { if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) status = GOT_STATUS_UNVERSIONED; else status = GOT_STATUS_OBSTRUCTED; } } if (status == GOT_STATUS_OBSTRUCTED) { if (ie) got_fileindex_entry_mark_skipped(ie); err = (*progress_cb)(progress_arg, status, path); goto done; } if (status == GOT_STATUS_CONFLICT) { if (ie) got_fileindex_entry_mark_skipped(ie); err = (*progress_cb)(progress_arg, GOT_STATUS_CANNOT_UPDATE, path); goto done; } if (S_ISDIR(te->mode)) { /* file changing into a directory */ if (status == GOT_STATUS_UNVERSIONED) { err = (*progress_cb)(progress_arg, status, path); } else if (status != GOT_STATUS_NO_CHANGE && status != GOT_STATUS_DELETE && status != GOT_STATUS_NONEXISTENT && status != GOT_STATUS_MISSING) { err = (*progress_cb)(progress_arg, GOT_STATUS_CANNOT_DELETE, path); } else if (ie) { if (status != GOT_STATUS_DELETE && status != GOT_STATUS_NONEXISTENT && status != GOT_STATUS_MISSING) { err = remove_ondisk_file(worktree->root_path, ie->path); if (err && !(err->code == GOT_ERR_ERRNO && errno == ENOENT)) goto done; } got_fileindex_entry_remove(fileindex, ie); err = (*progress_cb)(progress_arg, GOT_STATUS_DELETE, ie->path); } goto done; /* nothing else to do */ } if (ie && status != GOT_STATUS_MISSING && S_ISREG(sb.st_mode) && (S_ISLNK(te->mode) || (te->mode & S_IXUSR) == (sb.st_mode & S_IXUSR))) { /* * This is a regular file or an installed bad symlink. * If the file index indicates that this file is already * up-to-date with respect to the repository we can skip * updating contents of this file. */ if (got_fileindex_entry_has_commit(ie) && memcmp(ie->commit_sha1, worktree->base_commit_id->sha1, SHA1_DIGEST_LENGTH) == 0) { /* Same commit. */ err = sync_timestamps(worktree->root_fd, path, status, ie, &sb); if (err) goto done; err = (*progress_cb)(progress_arg, GOT_STATUS_EXISTS, path); goto done; } if (got_fileindex_entry_has_blob(ie) && memcmp(ie->blob_sha1, te->id.sha1, SHA1_DIGEST_LENGTH) == 0) { /* Different commit but the same blob. */ if (got_fileindex_entry_has_commit(ie)) { /* Update the base commit ID of this file. */ memcpy(ie->commit_sha1, worktree->base_commit_id->sha1, sizeof(ie->commit_sha1)); } err = sync_timestamps(worktree->root_fd, path, status, ie, &sb); if (err) goto done; err = (*progress_cb)(progress_arg, GOT_STATUS_EXISTS, path); goto done; } } fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } err = got_object_open_as_blob(&blob, repo, &te->id, 8192, fd1); if (err) goto done; if (status == GOT_STATUS_MODIFY || status == GOT_STATUS_ADD) { struct got_blob_object *blob2 = NULL; char *label_orig = NULL; if (got_fileindex_entry_has_blob(ie)) { fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } struct got_object_id id2; got_fileindex_entry_get_blob_id(&id2, ie); err = got_object_open_as_blob(&blob2, repo, &id2, 8192, fd2); if (err) goto done; } if (got_fileindex_entry_has_commit(ie)) { char id_str[SHA1_DIGEST_STRING_LENGTH]; if (got_sha1_digest_to_str(ie->commit_sha1, id_str, sizeof(id_str)) == NULL) { err = got_error_path(id_str, GOT_ERR_BAD_OBJ_ID_STR); goto done; } if (asprintf(&label_orig, "%s: commit %s", GOT_MERGE_LABEL_BASE, id_str) == -1) { err = got_error_from_errno("asprintf"); goto done; } } if (S_ISLNK(te->mode) && S_ISLNK(sb.st_mode)) { char *link_target; err = got_object_blob_read_to_str(&link_target, blob); if (err) goto done; err = merge_symlink(worktree, blob2, ondisk_path, path, label_orig, link_target, worktree->base_commit_id, repo, progress_cb, progress_arg); free(link_target); } else { err = merge_blob(&update_timestamps, worktree, blob2, ondisk_path, path, sb.st_mode, label_orig, blob, worktree->base_commit_id, repo, progress_cb, progress_arg); } free(label_orig); if (fd2 != -1 && close(fd2) == -1 && err == NULL) { err = got_error_from_errno("close"); goto done; } if (blob2) got_object_blob_close(blob2); if (err) goto done; /* * Do not update timestamps of files with local changes. * Otherwise, a future status walk would treat them as * unmodified files again. */ err = got_fileindex_entry_update(ie, worktree->root_fd, path, blob->id.sha1, worktree->base_commit_id->sha1, update_timestamps); } else if (status == GOT_STATUS_MODE_CHANGE) { err = got_fileindex_entry_update(ie, worktree->root_fd, path, blob->id.sha1, worktree->base_commit_id->sha1, 0); } else if (status == GOT_STATUS_DELETE) { err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE, path); if (err) goto done; err = got_fileindex_entry_update(ie, worktree->root_fd, path, blob->id.sha1, worktree->base_commit_id->sha1, 0); if (err) goto done; } else { int is_bad_symlink = 0; if (S_ISLNK(te->mode)) { err = install_symlink(&is_bad_symlink, worktree, ondisk_path, path, blob, status == GOT_STATUS_MISSING, 0, status == GOT_STATUS_UNVERSIONED, 0, repo, progress_cb, progress_arg); } else { err = install_blob(worktree, ondisk_path, path, te->mode, sb.st_mode, blob, status == GOT_STATUS_MISSING, 0, 0, status == GOT_STATUS_UNVERSIONED, &update_timestamps, repo, progress_cb, progress_arg); } if (err) goto done; if (ie) { err = got_fileindex_entry_update(ie, worktree->root_fd, path, blob->id.sha1, worktree->base_commit_id->sha1, 1); } else { err = create_fileindex_entry(&ie, fileindex, worktree->base_commit_id, worktree->root_fd, path, &blob->id, update_timestamps); } if (err) goto done; if (is_bad_symlink) { got_fileindex_entry_filetype_set(ie, GOT_FILEIDX_MODE_BAD_SYMLINK); } } if (fd1 != -1 && close(fd1) == -1 && err == NULL) { err = got_error_from_errno("close"); goto done; } got_object_blob_close(blob); done: free(ondisk_path); return err; } static const struct got_error * remove_ondisk_file(const char *root_path, const char *path) { const struct got_error *err = NULL; char *ondisk_path = NULL, *parent = NULL; if (asprintf(&ondisk_path, "%s/%s", root_path, path) == -1) return got_error_from_errno("asprintf"); if (unlink(ondisk_path) == -1) { if (errno != ENOENT) err = got_error_from_errno2("unlink", ondisk_path); } else { size_t root_len = strlen(root_path); err = got_path_dirname(&parent, ondisk_path); if (err) goto done; while (got_path_cmp(parent, root_path, strlen(parent), root_len) != 0) { free(ondisk_path); ondisk_path = parent; parent = NULL; if (rmdir(ondisk_path) == -1) { if (errno != ENOTEMPTY) err = got_error_from_errno2("rmdir", ondisk_path); break; } err = got_path_dirname(&parent, ondisk_path); if (err) break; } } done: free(ondisk_path); free(parent); return err; } static const struct got_error * delete_blob(struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_fileindex_entry *ie, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg) { const struct got_error *err = NULL; unsigned char status; struct stat sb; char *ondisk_path; if (get_staged_status(ie) != GOT_STATUS_NO_CHANGE) return got_error_path(ie->path, GOT_ERR_FILE_STAGED); if (asprintf(&ondisk_path, "%s/%s", worktree->root_path, ie->path) == -1) return got_error_from_errno("asprintf"); err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, repo); if (err) goto done; if (S_ISLNK(sb.st_mode) && status != GOT_STATUS_NO_CHANGE) { char ondisk_target[PATH_MAX]; ssize_t ondisk_len = readlink(ondisk_path, ondisk_target, sizeof(ondisk_target)); if (ondisk_len == -1) { err = got_error_from_errno2("readlink", ondisk_path); goto done; } ondisk_target[ondisk_len] = '\0'; err = install_symlink_conflict(NULL, worktree->base_commit_id, NULL, NULL, /* XXX pass common ancestor info? */ ondisk_target, ondisk_path); if (err) goto done; err = (*progress_cb)(progress_arg, GOT_STATUS_CONFLICT, ie->path); goto done; } if (status == GOT_STATUS_MODIFY || status == GOT_STATUS_CONFLICT || status == GOT_STATUS_ADD) { err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE, ie->path); if (err) goto done; /* * Preserve the working file and change the deleted blob's * entry into a schedule-add entry. */ err = got_fileindex_entry_update(ie, worktree->root_fd, ie->path, NULL, NULL, 0); } else { err = (*progress_cb)(progress_arg, GOT_STATUS_DELETE, ie->path); if (err) goto done; if (status == GOT_STATUS_NO_CHANGE) { err = remove_ondisk_file(worktree->root_path, ie->path); if (err) goto done; } got_fileindex_entry_remove(fileindex, ie); } done: free(ondisk_path); return err; } struct diff_cb_arg { struct got_fileindex *fileindex; struct got_worktree *worktree; struct got_repository *repo; got_worktree_checkout_cb progress_cb; void *progress_arg; got_cancel_cb cancel_cb; void *cancel_arg; }; static const struct got_error * diff_old_new(void *arg, struct got_fileindex_entry *ie, struct got_tree_entry *te, const char *parent_path) { const struct got_error *err = NULL; struct diff_cb_arg *a = arg; if (a->cancel_cb) { err = a->cancel_cb(a->cancel_arg); if (err) return err; } return update_blob(a->worktree, a->fileindex, ie, te, ie->path, a->repo, a->progress_cb, a->progress_arg); } static const struct got_error * diff_old(void *arg, struct got_fileindex_entry *ie, const char *parent_path) { const struct got_error *err = NULL; struct diff_cb_arg *a = arg; if (a->cancel_cb) { err = a->cancel_cb(a->cancel_arg); if (err) return err; } return delete_blob(a->worktree, a->fileindex, ie, a->repo, a->progress_cb, a->progress_arg); } static const struct got_error * diff_new(void *arg, struct got_tree_entry *te, const char *parent_path) { const struct got_error *err = NULL; struct diff_cb_arg *a = arg; char *path; if (a->cancel_cb) { err = a->cancel_cb(a->cancel_arg); if (err) return err; } if (got_object_tree_entry_is_submodule(te)) return NULL; if (!S_ISREG(te->mode) && !S_ISLNK(te->mode)) return NULL; if (asprintf(&path, "%s%s%s", parent_path, parent_path[0] ? "/" : "", te->name) == -1) return got_error_from_errno("asprintf"); err = update_blob(a->worktree, a->fileindex, NULL, te, path, a->repo, a->progress_cb, a->progress_arg); free(path); return err; } const struct got_error * got_worktree_get_uuid(char **uuidstr, struct got_worktree *worktree) { uint32_t uuid_status; uuid_to_string(&worktree->uuid, uuidstr, &uuid_status); if (uuid_status != uuid_s_ok) { *uuidstr = NULL; return got_error_uuid(uuid_status, "uuid_to_string"); } return NULL; } static const struct got_error * get_ref_name(char **refname, struct got_worktree *worktree, const char *prefix) { const struct got_error *err = NULL; char *uuidstr = NULL; *refname = NULL; err = got_worktree_get_uuid(&uuidstr, worktree); if (err) return err; if (asprintf(refname, "%s-%s", prefix, uuidstr) == -1) { err = got_error_from_errno("asprintf"); *refname = NULL; } free(uuidstr); return err; } const struct got_error * got_worktree_get_logmsg_ref_name(char **refname, struct got_worktree *worktree, const char *prefix) { return get_ref_name(refname, worktree, prefix); } static const struct got_error * get_base_ref_name(char **refname, struct got_worktree *worktree) { return get_ref_name(refname, worktree, GOT_WORKTREE_BASE_REF_PREFIX); } static const struct got_error * get_rebase_tmp_ref_name(char **refname, struct got_worktree *worktree) { return get_ref_name(refname, worktree, GOT_WORKTREE_REBASE_TMP_REF_PREFIX); } static const struct got_error * get_newbase_symref_name(char **refname, struct got_worktree *worktree) { return get_ref_name(refname, worktree, GOT_WORKTREE_NEWBASE_REF_PREFIX); } static const struct got_error * get_rebase_branch_symref_name(char **refname, struct got_worktree *worktree) { return get_ref_name(refname, worktree, GOT_WORKTREE_REBASE_BRANCH_REF_PREFIX); } static const struct got_error * get_rebase_commit_ref_name(char **refname, struct got_worktree *worktree) { return get_ref_name(refname, worktree, GOT_WORKTREE_REBASE_COMMIT_REF_PREFIX); } static const struct got_error * get_histedit_tmp_ref_name(char **refname, struct got_worktree *worktree) { return get_ref_name(refname, worktree, GOT_WORKTREE_HISTEDIT_TMP_REF_PREFIX); } static const struct got_error * get_histedit_branch_symref_name(char **refname, struct got_worktree *worktree) { return get_ref_name(refname, worktree, GOT_WORKTREE_HISTEDIT_BRANCH_REF_PREFIX); } static const struct got_error * get_histedit_base_commit_ref_name(char **refname, struct got_worktree *worktree) { return get_ref_name(refname, worktree, GOT_WORKTREE_HISTEDIT_BASE_COMMIT_REF_PREFIX); } static const struct got_error * get_histedit_commit_ref_name(char **refname, struct got_worktree *worktree) { return get_ref_name(refname, worktree, GOT_WORKTREE_HISTEDIT_COMMIT_REF_PREFIX); } const struct got_error * got_worktree_get_histedit_script_path(char **path, struct got_worktree *worktree) { if (asprintf(path, "%s/%s/%s", worktree->root_path, worktree->meta_dir, GOT_WORKTREE_HISTEDIT_SCRIPT) == -1) { *path = NULL; return got_error_from_errno("asprintf"); } return NULL; } static const struct got_error * get_merge_branch_ref_name(char **refname, struct got_worktree *worktree) { return get_ref_name(refname, worktree, GOT_WORKTREE_MERGE_BRANCH_REF_PREFIX); } static const struct got_error * get_merge_commit_ref_name(char **refname, struct got_worktree *worktree) { return get_ref_name(refname, worktree, GOT_WORKTREE_MERGE_COMMIT_REF_PREFIX); } /* * Prevent Git's garbage collector from deleting our base commit by * setting a reference to our base commit's ID. */ static const struct got_error * ref_base_commit(struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err = NULL; struct got_reference *ref = NULL; char *refname; err = get_base_ref_name(&refname, worktree); if (err) return err; err = got_ref_alloc(&ref, refname, worktree->base_commit_id); if (err) goto done; err = got_ref_write(ref, repo); done: free(refname); if (ref) got_ref_close(ref); return err; } static const struct got_error * get_fileindex_path(char **fileindex_path, struct got_worktree *worktree) { const struct got_error *err = NULL; if (asprintf(fileindex_path, "%s/%s/%s", worktree->root_path, worktree->meta_dir, GOT_WORKTREE_FILE_INDEX) == -1) { err = got_error_from_errno("asprintf"); *fileindex_path = NULL; } return err; } static const struct got_error * open_fileindex(struct got_fileindex **fileindex, char **fileindex_path, struct got_worktree *worktree) { const struct got_error *err = NULL; FILE *index = NULL; *fileindex_path = NULL; *fileindex = got_fileindex_alloc(); if (*fileindex == NULL) return got_error_from_errno("got_fileindex_alloc"); err = get_fileindex_path(fileindex_path, worktree); if (err) goto done; index = fopen(*fileindex_path, "rbe"); if (index == NULL) { if (errno != ENOENT) err = got_error_from_errno2("fopen", *fileindex_path); } else { err = got_fileindex_read(*fileindex, index); if (fclose(index) == EOF && err == NULL) err = got_error_from_errno("fclose"); } done: if (err) { free(*fileindex_path); *fileindex_path = NULL; got_fileindex_free(*fileindex); *fileindex = NULL; } return err; } struct bump_base_commit_id_arg { struct got_object_id *base_commit_id; const char *path; size_t path_len; const char *entry_name; got_worktree_checkout_cb progress_cb; void *progress_arg; }; static const struct got_error * bump_base_commit_id(void *arg, struct got_fileindex_entry *ie) { const struct got_error *err; struct bump_base_commit_id_arg *a = arg; if (a->entry_name) { if (strcmp(ie->path, a->path) != 0) return NULL; } else if (!got_path_is_child(ie->path, a->path, a->path_len)) return NULL; if (got_fileindex_entry_was_skipped(ie)) return NULL; if (memcmp(ie->commit_sha1, a->base_commit_id->sha1, SHA1_DIGEST_LENGTH) == 0) return NULL; if (a->progress_cb) { err = (*a->progress_cb)(a->progress_arg, GOT_STATUS_BUMP_BASE, ie->path); if (err) return err; } memcpy(ie->commit_sha1, a->base_commit_id->sha1, SHA1_DIGEST_LENGTH); return NULL; } /* Bump base commit ID of all files within an updated part of the work tree. */ static const struct got_error * bump_base_commit_id_everywhere(struct got_worktree *worktree, struct got_fileindex *fileindex, got_worktree_checkout_cb progress_cb, void *progress_arg) { struct bump_base_commit_id_arg bbc_arg; bbc_arg.base_commit_id = worktree->base_commit_id; bbc_arg.entry_name = NULL; bbc_arg.path = ""; bbc_arg.path_len = 0; bbc_arg.progress_cb = progress_cb; bbc_arg.progress_arg = progress_arg; return got_fileindex_for_each_entry_safe(fileindex, bump_base_commit_id, &bbc_arg); } static const struct got_error * sync_fileindex(struct got_fileindex *fileindex, const char *fileindex_path) { const struct got_error *err = NULL; char *new_fileindex_path = NULL; FILE *new_index = NULL; struct timespec timeout; err = got_opentemp_named(&new_fileindex_path, &new_index, fileindex_path, ""); if (err) goto done; err = got_fileindex_write(fileindex, new_index); if (err) goto done; if (rename(new_fileindex_path, fileindex_path) != 0) { err = got_error_from_errno3("rename", new_fileindex_path, fileindex_path); unlink(new_fileindex_path); } /* * Sleep for a short amount of time to ensure that files modified after * this program exits have a different time stamp from the one which * was recorded in the file index. */ timeout.tv_sec = 0; timeout.tv_nsec = 1; nanosleep(&timeout, NULL); done: if (new_index) fclose(new_index); free(new_fileindex_path); return err; } static const struct got_error * find_tree_entry_for_checkout(int *entry_type, char **tree_relpath, struct got_object_id **tree_id, const char *wt_relpath, struct got_commit_object *base_commit, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err = NULL; struct got_object_id *id = NULL; char *in_repo_path = NULL; int is_root_wt = got_path_is_root_dir(worktree->path_prefix); *entry_type = GOT_OBJ_TYPE_ANY; *tree_relpath = NULL; *tree_id = NULL; if (wt_relpath[0] == '\0') { /* Check out all files within the work tree. */ *entry_type = GOT_OBJ_TYPE_TREE; *tree_relpath = strdup(""); if (*tree_relpath == NULL) { err = got_error_from_errno("strdup"); goto done; } err = got_object_id_by_path(tree_id, repo, base_commit, worktree->path_prefix); if (err) goto done; return NULL; } /* Check out a subset of files in the work tree. */ if (asprintf(&in_repo_path, "%s%s%s", worktree->path_prefix, is_root_wt ? "" : "/", wt_relpath) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_object_id_by_path(&id, repo, base_commit, in_repo_path); if (err) goto done; free(in_repo_path); in_repo_path = NULL; err = got_object_get_type(entry_type, repo, id); if (err) goto done; if (*entry_type == GOT_OBJ_TYPE_BLOB) { /* Check out a single file. */ if (strchr(wt_relpath, '/') == NULL) { /* Check out a single file in work tree's root dir. */ in_repo_path = strdup(worktree->path_prefix); if (in_repo_path == NULL) { err = got_error_from_errno("strdup"); goto done; } *tree_relpath = strdup(""); if (*tree_relpath == NULL) { err = got_error_from_errno("strdup"); goto done; } } else { /* Check out a single file in a subdirectory. */ err = got_path_dirname(tree_relpath, wt_relpath); if (err) return err; if (asprintf(&in_repo_path, "%s%s%s", worktree->path_prefix, is_root_wt ? "" : "/", *tree_relpath) == -1) { err = got_error_from_errno("asprintf"); goto done; } } err = got_object_id_by_path(tree_id, repo, base_commit, in_repo_path); } else { /* Check out all files within a subdirectory. */ *tree_id = got_object_id_dup(id); if (*tree_id == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } *tree_relpath = strdup(wt_relpath); if (*tree_relpath == NULL) { err = got_error_from_errno("strdup"); goto done; } } done: free(id); free(in_repo_path); if (err) { *entry_type = GOT_OBJ_TYPE_ANY; free(*tree_relpath); *tree_relpath = NULL; free(*tree_id); *tree_id = NULL; } return err; } static const struct got_error * checkout_files(struct got_worktree *worktree, struct got_fileindex *fileindex, const char *relpath, struct got_object_id *tree_id, const char *entry_name, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; struct got_commit_object *commit = NULL; struct got_tree_object *tree = NULL; struct got_fileindex_diff_tree_cb diff_cb; struct diff_cb_arg arg; err = ref_base_commit(worktree, repo); if (err) { if (!(err->code == GOT_ERR_ERRNO && (errno == EACCES || errno == EROFS))) goto done; err = (*progress_cb)(progress_arg, GOT_STATUS_BASE_REF_ERR, worktree->root_path); if (err) return err; } err = got_object_open_as_commit(&commit, repo, worktree->base_commit_id); if (err) goto done; err = got_object_open_as_tree(&tree, repo, tree_id); if (err) goto done; if (entry_name && got_object_tree_find_entry(tree, entry_name) == NULL) { err = got_error_path(entry_name, GOT_ERR_NO_TREE_ENTRY); goto done; } diff_cb.diff_old_new = diff_old_new; diff_cb.diff_old = diff_old; diff_cb.diff_new = diff_new; arg.fileindex = fileindex; arg.worktree = worktree; arg.repo = repo; arg.progress_cb = progress_cb; arg.progress_arg = progress_arg; arg.cancel_cb = cancel_cb; arg.cancel_arg = cancel_arg; err = got_fileindex_diff_tree(fileindex, tree, relpath, entry_name, repo, &diff_cb, &arg); done: if (tree) got_object_tree_close(tree); if (commit) got_object_commit_close(commit); return err; } const struct got_error * got_worktree_checkout_files(struct got_worktree *worktree, struct got_pathlist_head *paths, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL, *sync_err, *unlockerr; struct got_commit_object *commit = NULL; struct got_tree_object *tree = NULL; struct got_fileindex *fileindex = NULL; char *fileindex_path = NULL; struct got_pathlist_entry *pe; struct tree_path_data { STAILQ_ENTRY(tree_path_data) entry; struct got_object_id *tree_id; int entry_type; char *relpath; char *entry_name; } *tpd = NULL; STAILQ_HEAD(tree_paths, tree_path_data) tree_paths; STAILQ_INIT(&tree_paths); err = lock_worktree(worktree, LOCK_EX); if (err) return err; err = got_object_open_as_commit(&commit, repo, worktree->base_commit_id); if (err) goto done; /* Map all specified paths to in-repository trees. */ TAILQ_FOREACH(pe, paths, entry) { tpd = malloc(sizeof(*tpd)); if (tpd == NULL) { err = got_error_from_errno("malloc"); goto done; } err = find_tree_entry_for_checkout(&tpd->entry_type, &tpd->relpath, &tpd->tree_id, pe->path, commit, worktree, repo); if (err) { free(tpd); goto done; } if (tpd->entry_type == GOT_OBJ_TYPE_BLOB) { err = got_path_basename(&tpd->entry_name, pe->path); if (err) { free(tpd->relpath); free(tpd->tree_id); free(tpd); goto done; } } else tpd->entry_name = NULL; STAILQ_INSERT_TAIL(&tree_paths, tpd, entry); } /* * Read the file index. * Checking out files is supposed to be an idempotent operation. * If the on-disk file index is incomplete we will try to complete it. */ err = open_fileindex(&fileindex, &fileindex_path, worktree); if (err) goto done; tpd = STAILQ_FIRST(&tree_paths); TAILQ_FOREACH(pe, paths, entry) { struct bump_base_commit_id_arg bbc_arg; err = checkout_files(worktree, fileindex, tpd->relpath, tpd->tree_id, tpd->entry_name, repo, progress_cb, progress_arg, cancel_cb, cancel_arg); if (err) break; bbc_arg.base_commit_id = worktree->base_commit_id; bbc_arg.entry_name = tpd->entry_name; bbc_arg.path = pe->path; bbc_arg.path_len = pe->path_len; bbc_arg.progress_cb = progress_cb; bbc_arg.progress_arg = progress_arg; err = got_fileindex_for_each_entry_safe(fileindex, bump_base_commit_id, &bbc_arg); if (err) break; tpd = STAILQ_NEXT(tpd, entry); } sync_err = sync_fileindex(fileindex, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: free(fileindex_path); if (tree) got_object_tree_close(tree); if (commit) got_object_commit_close(commit); if (fileindex) got_fileindex_free(fileindex); while (!STAILQ_EMPTY(&tree_paths)) { tpd = STAILQ_FIRST(&tree_paths); STAILQ_REMOVE_HEAD(&tree_paths, entry); free(tpd->relpath); free(tpd->tree_id); free(tpd); } unlockerr = lock_worktree(worktree, LOCK_SH); if (unlockerr && err == NULL) err = unlockerr; return err; } static const struct got_error * add_file(struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_fileindex_entry *ie, const char *ondisk_path, const char *path2, struct got_blob_object *blob2, mode_t mode2, int restoring_missing_file, int reverting_versioned_file, int path_is_unversioned, int allow_bad_symlinks, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg) { const struct got_error *err = NULL; int is_bad_symlink = 0; if (S_ISLNK(mode2)) { err = install_symlink(&is_bad_symlink, worktree, ondisk_path, path2, blob2, restoring_missing_file, reverting_versioned_file, path_is_unversioned, allow_bad_symlinks, repo, progress_cb, progress_arg); } else { err = install_blob(worktree, ondisk_path, path2, mode2, GOT_DEFAULT_FILE_MODE, blob2, restoring_missing_file, reverting_versioned_file, 0, path_is_unversioned, NULL, repo, progress_cb, progress_arg); } if (err) return err; if (ie == NULL) { /* Adding an unversioned file. */ err = got_fileindex_entry_alloc(&ie, path2); if (err) return err; err = got_fileindex_entry_update(ie, worktree->root_fd, path2, NULL, NULL, 1); if (err) { got_fileindex_entry_free(ie); return err; } err = got_fileindex_entry_add(fileindex, ie); if (err) { got_fileindex_entry_free(ie); return err; } } else { /* Re-adding a locally deleted file. */ err = got_fileindex_entry_update(ie, worktree->root_fd, path2, ie->blob_sha1, worktree->base_commit_id->sha1, 0); if (err) return err; } if (is_bad_symlink) { got_fileindex_entry_filetype_set(ie, GOT_FILEIDX_MODE_BAD_SYMLINK); } return NULL; } struct merge_file_cb_arg { struct got_worktree *worktree; struct got_fileindex *fileindex; got_worktree_checkout_cb progress_cb; void *progress_arg; got_cancel_cb cancel_cb; void *cancel_arg; const char *label_orig; struct got_object_id *commit_id2; int allow_bad_symlinks; }; static const struct got_error * merge_file_cb(void *arg, struct got_blob_object *blob1, struct got_blob_object *blob2, FILE *f1, FILE *f2, struct got_object_id *id1, struct got_object_id *id2, const char *path1, const char *path2, mode_t mode1, mode_t mode2, struct got_repository *repo) { static const struct got_error *err = NULL; struct merge_file_cb_arg *a = arg; struct got_fileindex_entry *ie; char *ondisk_path = NULL; struct stat sb; unsigned char status; int local_changes_subsumed; FILE *f_orig = NULL, *f_deriv = NULL, *f_deriv2 = NULL; char *id_str = NULL, *label_deriv2 = NULL; struct got_object_id *id = NULL; if (blob1 && blob2) { ie = got_fileindex_entry_get(a->fileindex, path2, strlen(path2)); if (ie == NULL) return (*a->progress_cb)(a->progress_arg, GOT_STATUS_MISSING, path2); if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, path2) == -1) return got_error_from_errno("asprintf"); err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, repo); if (err) goto done; if (status == GOT_STATUS_DELETE) { err = (*a->progress_cb)(a->progress_arg, GOT_STATUS_MERGE, path2); goto done; } if (status != GOT_STATUS_NO_CHANGE && status != GOT_STATUS_MODIFY && status != GOT_STATUS_CONFLICT && status != GOT_STATUS_ADD) { err = (*a->progress_cb)(a->progress_arg, status, path2); goto done; } if (S_ISLNK(mode1) && S_ISLNK(mode2)) { char *link_target2; err = got_object_blob_read_to_str(&link_target2, blob2); if (err) goto done; err = merge_symlink(a->worktree, blob1, ondisk_path, path2, a->label_orig, link_target2, a->commit_id2, repo, a->progress_cb, a->progress_arg); free(link_target2); } else { int fd; f_orig = got_opentemp(); if (f_orig == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } err = got_object_blob_dump_to_file(NULL, NULL, NULL, f_orig, blob1); if (err) goto done; f_deriv2 = got_opentemp(); if (f_deriv2 == NULL) goto done; err = got_object_blob_dump_to_file(NULL, NULL, NULL, f_deriv2, blob2); if (err) goto done; fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { err = got_error_from_errno2("open", ondisk_path); goto done; } f_deriv = fdopen(fd, "r"); if (f_deriv == NULL) { err = got_error_from_errno2("fdopen", ondisk_path); close(fd); goto done; } err = got_object_id_str(&id_str, a->commit_id2); if (err) goto done; if (asprintf(&label_deriv2, "%s: commit %s", GOT_MERGE_LABEL_MERGED, id_str) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = merge_file(&local_changes_subsumed, a->worktree, f_orig, f_deriv, f_deriv2, ondisk_path, path2, mode2, a->label_orig, NULL, label_deriv2, GOT_DIFF_ALGORITHM_PATIENCE, repo, a->progress_cb, a->progress_arg); } } else if (blob1) { ie = got_fileindex_entry_get(a->fileindex, path1, strlen(path1)); if (ie == NULL) return (*a->progress_cb)(a->progress_arg, GOT_STATUS_MISSING, path1); if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, path1) == -1) return got_error_from_errno("asprintf"); err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, repo); if (err) goto done; switch (status) { case GOT_STATUS_NO_CHANGE: err = (*a->progress_cb)(a->progress_arg, GOT_STATUS_DELETE, path1); if (err) goto done; err = remove_ondisk_file(a->worktree->root_path, path1); if (err) goto done; if (ie) got_fileindex_entry_mark_deleted_from_disk(ie); break; case GOT_STATUS_DELETE: case GOT_STATUS_MISSING: err = (*a->progress_cb)(a->progress_arg, GOT_STATUS_DELETE, path1); if (err) goto done; if (ie) got_fileindex_entry_mark_deleted_from_disk(ie); break; case GOT_STATUS_MODIFY: { FILE *blob1_f; off_t blob1_size; int obj_type; /* * Delete the file only if its content already * exists in the repository. */ err = got_object_blob_file_create(&id, &blob1_f, &blob1_size, path1); if (err) goto done; if (fclose(blob1_f) == EOF) { err = got_error_from_errno("fclose"); goto done; } /* Implied existence check. */ err = got_object_get_type(&obj_type, repo, id); if (err) { if (err->code != GOT_ERR_NO_OBJ) goto done; err = (*a->progress_cb)(a->progress_arg, GOT_STATUS_CANNOT_DELETE, path1); goto done; } else if (obj_type != GOT_OBJ_TYPE_BLOB) { err = (*a->progress_cb)(a->progress_arg, GOT_STATUS_CANNOT_DELETE, path1); goto done; } err = (*a->progress_cb)(a->progress_arg, GOT_STATUS_DELETE, path1); if (err) goto done; err = remove_ondisk_file(a->worktree->root_path, path1); if (err) goto done; if (ie) got_fileindex_entry_mark_deleted_from_disk(ie); break; } case GOT_STATUS_ADD: { FILE *blob1_f; off_t blob1_size; /* * Delete the file only if its content already * exists in the repository. */ err = got_object_blob_file_create(&id, &blob1_f, &blob1_size, path1); if (err) goto done; if (fclose(blob1_f) == EOF) { err = got_error_from_errno("fclose"); goto done; } if (got_object_id_cmp(id, id1) == 0) { err = (*a->progress_cb)(a->progress_arg, GOT_STATUS_DELETE, path1); if (err) goto done; err = remove_ondisk_file(a->worktree->root_path, path1); if (err) goto done; if (ie) got_fileindex_entry_remove(a->fileindex, ie); } else { err = (*a->progress_cb)(a->progress_arg, GOT_STATUS_CANNOT_DELETE, path1); } if (err) goto done; break; } case GOT_STATUS_CONFLICT: err = (*a->progress_cb)(a->progress_arg, GOT_STATUS_CANNOT_DELETE, path1); if (err) goto done; break; case GOT_STATUS_OBSTRUCTED: err = (*a->progress_cb)(a->progress_arg, status, path1); if (err) goto done; break; default: break; } } else if (blob2) { if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, path2) == -1) return got_error_from_errno("asprintf"); ie = got_fileindex_entry_get(a->fileindex, path2, strlen(path2)); if (ie) { err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, repo); if (err) goto done; if (status != GOT_STATUS_NO_CHANGE && status != GOT_STATUS_MODIFY && status != GOT_STATUS_CONFLICT && status != GOT_STATUS_ADD && status != GOT_STATUS_DELETE) { err = (*a->progress_cb)(a->progress_arg, status, path2); goto done; } if (S_ISLNK(mode2) && S_ISLNK(sb.st_mode)) { char *link_target2; err = got_object_blob_read_to_str(&link_target2, blob2); if (err) goto done; err = merge_symlink(a->worktree, NULL, ondisk_path, path2, a->label_orig, link_target2, a->commit_id2, repo, a->progress_cb, a->progress_arg); free(link_target2); } else if (S_ISREG(sb.st_mode)) { err = merge_blob(&local_changes_subsumed, a->worktree, NULL, ondisk_path, path2, sb.st_mode, a->label_orig, blob2, a->commit_id2, repo, a->progress_cb, a->progress_arg); } else if (status != GOT_STATUS_DELETE) { err = got_error_path(ondisk_path, GOT_ERR_FILE_OBSTRUCTED); } if (err) goto done; if (status == GOT_STATUS_DELETE) { /* Re-add file with content from new blob. */ err = add_file(a->worktree, a->fileindex, ie, ondisk_path, path2, blob2, mode2, 0, 0, 0, a->allow_bad_symlinks, repo, a->progress_cb, a->progress_arg); if (err) goto done; } } else { err = add_file(a->worktree, a->fileindex, NULL, ondisk_path, path2, blob2, mode2, 0, 0, 1, a->allow_bad_symlinks, repo, a->progress_cb, a->progress_arg); if (err) goto done; } } done: if (f_orig && fclose(f_orig) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (f_deriv && fclose(f_deriv) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (f_deriv2 && fclose(f_deriv2) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(id_str); free(id); free(label_deriv2); free(ondisk_path); return err; } struct check_mixed_commits_args { struct got_worktree *worktree; got_cancel_cb cancel_cb; void *cancel_arg; }; static const struct got_error * check_mixed_commits(void *arg, struct got_fileindex_entry *ie) { const struct got_error *err = NULL; struct check_mixed_commits_args *a = arg; if (a->cancel_cb) { err = a->cancel_cb(a->cancel_arg); if (err) return err; } /* Reject merges into a work tree with mixed base commits. */ if (got_fileindex_entry_has_commit(ie) && memcmp(ie->commit_sha1, a->worktree->base_commit_id->sha1, SHA1_DIGEST_LENGTH) != 0) return got_error(GOT_ERR_MIXED_COMMITS); return NULL; } const struct got_error * got_worktree_get_state(char *state, struct got_repository *repo, struct got_worktree *worktree, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err; struct got_object_id *base_id, *head_id = NULL; struct got_reference *head_ref; struct got_fileindex *fileindex = NULL; char *fileindex_path = NULL; struct check_mixed_commits_args cma; if (worktree == NULL) return got_error(GOT_ERR_NOT_WORKTREE); err = got_ref_open(&head_ref, repo, got_worktree_get_head_ref_name(worktree), 0); if (err) return err; err = got_ref_resolve(&head_id, repo, head_ref); if (err) goto done; *state = GOT_WORKTREE_STATE_UNKNOWN; base_id = got_worktree_get_base_commit_id(worktree); cma.worktree = worktree; cma.cancel_cb = cancel_cb; cma.cancel_arg = cancel_arg; if (got_object_id_cmp(base_id, head_id) == 0) { err = open_fileindex(&fileindex, &fileindex_path, worktree); if (err) goto done; err = got_fileindex_for_each_entry_safe(fileindex, check_mixed_commits, &cma); if (err == NULL) *state = GOT_WORKTREE_STATE_UPTODATE; else if (err->code == GOT_ERR_MIXED_COMMITS) { *state = GOT_WORKTREE_STATE_OUTOFDATE; err = NULL; } } else *state = GOT_WORKTREE_STATE_OUTOFDATE; done: free(head_id); free(fileindex_path); got_ref_close(head_ref); if (fileindex != NULL) got_fileindex_free(fileindex); return err; } struct check_merge_conflicts_arg { struct got_worktree *worktree; struct got_fileindex *fileindex; struct got_repository *repo; }; static const struct got_error * check_merge_conflicts(void *arg, struct got_blob_object *blob1, struct got_blob_object *blob2, FILE *f1, FILE *f2, struct got_object_id *id1, struct got_object_id *id2, const char *path1, const char *path2, mode_t mode1, mode_t mode2, struct got_repository *repo) { const struct got_error *err = NULL; struct check_merge_conflicts_arg *a = arg; unsigned char status; struct stat sb; struct got_fileindex_entry *ie; const char *path = path2 ? path2 : path1; struct got_object_id *id = id2 ? id2 : id1; char *ondisk_path; if (id == NULL) return NULL; ie = got_fileindex_entry_get(a->fileindex, path, strlen(path)); if (ie == NULL) return NULL; if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, ie->path) == -1) return got_error_from_errno("asprintf"); /* Reject merges into a work tree with conflicted files. */ err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, a->repo); free(ondisk_path); if (err) return err; if (status == GOT_STATUS_CONFLICT) return got_error(GOT_ERR_CONFLICTS); return NULL; } static const struct got_error * merge_files(struct got_worktree *worktree, struct got_fileindex *fileindex, const char *fileindex_path, struct got_object_id *commit_id1, struct got_object_id *commit_id2, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL, *sync_err; struct got_object_id *tree_id1 = NULL, *tree_id2 = NULL; struct got_tree_object *tree1 = NULL, *tree2 = NULL; struct got_commit_object *commit1 = NULL, *commit2 = NULL; struct check_merge_conflicts_arg cmc_arg; struct merge_file_cb_arg arg; char *label_orig = NULL; FILE *f1 = NULL, *f2 = NULL; int fd1 = -1, fd2 = -1; if (commit_id1) { err = got_object_open_as_commit(&commit1, repo, commit_id1); if (err) goto done; err = got_object_id_by_path(&tree_id1, repo, commit1, worktree->path_prefix); if (err && err->code != GOT_ERR_NO_TREE_ENTRY) goto done; } if (tree_id1) { char *id_str; err = got_object_open_as_tree(&tree1, repo, tree_id1); if (err) goto done; err = got_object_id_str(&id_str, commit_id1); if (err) goto done; if (asprintf(&label_orig, "%s: commit %s", GOT_MERGE_LABEL_BASE, id_str) == -1) { err = got_error_from_errno("asprintf"); free(id_str); goto done; } free(id_str); f1 = got_opentemp(); if (f1 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } } err = got_object_open_as_commit(&commit2, repo, commit_id2); if (err) goto done; err = got_object_id_by_path(&tree_id2, repo, commit2, worktree->path_prefix); if (err) goto done; err = got_object_open_as_tree(&tree2, repo, tree_id2); if (err) goto done; f2 = got_opentemp(); if (f2 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } cmc_arg.worktree = worktree; cmc_arg.fileindex = fileindex; cmc_arg.repo = repo; err = got_diff_tree(tree1, tree2, f1, f2, fd1, fd2, "", "", repo, check_merge_conflicts, &cmc_arg, 0); if (err) goto done; arg.worktree = worktree; arg.fileindex = fileindex; arg.progress_cb = progress_cb; arg.progress_arg = progress_arg; arg.cancel_cb = cancel_cb; arg.cancel_arg = cancel_arg; arg.label_orig = label_orig; arg.commit_id2 = commit_id2; arg.allow_bad_symlinks = 1; /* preserve bad symlinks across merges */ err = got_diff_tree(tree1, tree2, f1, f2, fd1, fd2, "", "", repo, merge_file_cb, &arg, 1); sync_err = sync_fileindex(fileindex, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: if (commit1) got_object_commit_close(commit1); if (commit2) got_object_commit_close(commit2); if (tree1) got_object_tree_close(tree1); if (tree2) got_object_tree_close(tree2); if (f1 && fclose(f1) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (f2 && fclose(f2) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno("close"); free(label_orig); return err; } const struct got_error * got_worktree_merge_files(struct got_worktree *worktree, struct got_object_id *commit_id1, struct got_object_id *commit_id2, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err, *unlockerr; char *fileindex_path = NULL; struct got_fileindex *fileindex = NULL; struct check_mixed_commits_args cma; err = lock_worktree(worktree, LOCK_EX); if (err) return err; err = open_fileindex(&fileindex, &fileindex_path, worktree); if (err) goto done; cma.worktree = worktree; cma.cancel_cb = cancel_cb; cma.cancel_arg = cancel_arg; err = got_fileindex_for_each_entry_safe(fileindex, check_mixed_commits, &cma); if (err) goto done; err = merge_files(worktree, fileindex, fileindex_path, commit_id1, commit_id2, repo, progress_cb, progress_arg, cancel_cb, cancel_arg); done: if (fileindex) got_fileindex_free(fileindex); free(fileindex_path); unlockerr = lock_worktree(worktree, LOCK_SH); if (unlockerr && err == NULL) err = unlockerr; return err; } struct diff_dir_cb_arg { struct got_fileindex *fileindex; struct got_worktree *worktree; const char *status_path; size_t status_path_len; struct got_repository *repo; got_worktree_status_cb status_cb; void *status_arg; got_cancel_cb cancel_cb; void *cancel_arg; /* A pathlist containing per-directory pathlists of ignore patterns. */ struct got_pathlist_head *ignores; int report_unchanged; int no_ignores; }; static const struct got_error * report_file_status(struct got_fileindex_entry *ie, const char *abspath, int dirfd, const char *de_name, got_worktree_status_cb status_cb, void *status_arg, struct got_repository *repo, int report_unchanged) { const struct got_error *err = NULL; unsigned char status = GOT_STATUS_NO_CHANGE; unsigned char staged_status; struct stat sb; struct got_object_id blob_id, commit_id, staged_blob_id; struct got_object_id *blob_idp = NULL, *commit_idp = NULL; struct got_object_id *staged_blob_idp = NULL; staged_status = get_staged_status(ie); err = get_file_status(&status, &sb, ie, abspath, dirfd, de_name, repo); if (err) return err; if (status == GOT_STATUS_NO_CHANGE && staged_status == GOT_STATUS_NO_CHANGE && !report_unchanged) return NULL; if (got_fileindex_entry_has_blob(ie)) blob_idp = got_fileindex_entry_get_blob_id(&blob_id, ie); if (got_fileindex_entry_has_commit(ie)) commit_idp = got_fileindex_entry_get_commit_id(&commit_id, ie); if (staged_status == GOT_STATUS_ADD || staged_status == GOT_STATUS_MODIFY) { staged_blob_idp = got_fileindex_entry_get_staged_blob_id( &staged_blob_id, ie); } return (*status_cb)(status_arg, status, staged_status, ie->path, blob_idp, staged_blob_idp, commit_idp, dirfd, de_name); } static const struct got_error * status_old_new(void *arg, struct got_fileindex_entry *ie, struct dirent *de, const char *parent_path, int dirfd) { const struct got_error *err = NULL; struct diff_dir_cb_arg *a = arg; char *abspath; if (a->cancel_cb) { err = a->cancel_cb(a->cancel_arg); if (err) return err; } if (got_path_cmp(parent_path, a->status_path, strlen(parent_path), a->status_path_len) != 0 && !got_path_is_child(parent_path, a->status_path, a->status_path_len)) return NULL; if (parent_path[0]) { if (asprintf(&abspath, "%s/%s/%s", a->worktree->root_path, parent_path, de->d_name) == -1) return got_error_from_errno("asprintf"); } else { if (asprintf(&abspath, "%s/%s", a->worktree->root_path, de->d_name) == -1) return got_error_from_errno("asprintf"); } err = report_file_status(ie, abspath, dirfd, de->d_name, a->status_cb, a->status_arg, a->repo, a->report_unchanged); free(abspath); return err; } static const struct got_error * status_old(void *arg, struct got_fileindex_entry *ie, const char *parent_path) { const struct got_error *err; struct diff_dir_cb_arg *a = arg; struct got_object_id blob_id, commit_id; unsigned char status; if (a->cancel_cb) { err = a->cancel_cb(a->cancel_arg); if (err) return err; } if (!got_path_is_child(ie->path, a->status_path, a->status_path_len)) return NULL; got_fileindex_entry_get_blob_id(&blob_id, ie); got_fileindex_entry_get_commit_id(&commit_id, ie); if (got_fileindex_entry_has_file_on_disk(ie)) status = GOT_STATUS_MISSING; else status = GOT_STATUS_DELETE; return (*a->status_cb)(a->status_arg, status, get_staged_status(ie), ie->path, &blob_id, NULL, &commit_id, -1, NULL); } static void free_ignores(struct got_pathlist_head *ignores) { struct got_pathlist_entry *pe; TAILQ_FOREACH(pe, ignores, entry) { struct got_pathlist_head *ignorelist = pe->data; got_pathlist_free(ignorelist, GOT_PATHLIST_FREE_PATH); } got_pathlist_free(ignores, GOT_PATHLIST_FREE_ALL); } static const struct got_error * read_ignores(struct got_pathlist_head *ignores, const char *path, FILE *f) { const struct got_error *err = NULL; struct got_pathlist_entry *pe = NULL; struct got_pathlist_head *ignorelist; char *line = NULL, *pattern, *dirpath = NULL; size_t linesize = 0; ssize_t linelen; ignorelist = calloc(1, sizeof(*ignorelist)); if (ignorelist == NULL) return got_error_from_errno("calloc"); TAILQ_INIT(ignorelist); while ((linelen = getline(&line, &linesize, f)) != -1) { if (linelen > 0 && line[linelen - 1] == '\n') line[linelen - 1] = '\0'; /* Git's ignores may contain comments. */ if (line[0] == '#') continue; /* Git's negated patterns are not (yet?) supported. */ if (line[0] == '!') continue; if (asprintf(&pattern, "%s%s%s", path, path[0] ? "/" : "", line) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_pathlist_insert(NULL, ignorelist, pattern, NULL); if (err) goto done; } if (ferror(f)) { err = got_error_from_errno("getline"); goto done; } dirpath = strdup(path); if (dirpath == NULL) { err = got_error_from_errno("strdup"); goto done; } err = got_pathlist_insert(&pe, ignores, dirpath, ignorelist); done: free(line); if (err || pe == NULL) { free(dirpath); got_pathlist_free(ignorelist, GOT_PATHLIST_FREE_PATH); free(ignorelist); } return err; } static int match_path(const char *pattern, size_t pattern_len, const char *path, int flags) { char buf[PATH_MAX]; /* * Trailing slashes signify directories. * Append a * to make such patterns conform to fnmatch rules. */ if (pattern_len > 0 && pattern[pattern_len - 1] == '/') { if (snprintf(buf, sizeof(buf), "%s*", pattern) >= sizeof(buf)) return FNM_NOMATCH; /* XXX */ return fnmatch(buf, path, flags); } return fnmatch(pattern, path, flags); } static int match_ignores(struct got_pathlist_head *ignores, const char *path) { struct got_pathlist_entry *pe; /* Handle patterns which match in all directories. */ TAILQ_FOREACH(pe, ignores, entry) { struct got_pathlist_head *ignorelist = pe->data; struct got_pathlist_entry *pi; TAILQ_FOREACH(pi, ignorelist, entry) { const char *p; if (pi->path_len < 3 || strncmp(pi->path, "**/", 3) != 0) continue; p = path; while (*p) { if (match_path(pi->path + 3, pi->path_len - 3, p, FNM_PATHNAME | FNM_LEADING_DIR)) { /* Retry in next directory. */ while (*p && *p != '/') p++; while (*p == '/') p++; continue; } return 1; } } } /* * The ignores pathlist contains ignore lists from children before * parents, so we can find the most specific ignorelist by walking * ignores backwards. */ pe = TAILQ_LAST(ignores, got_pathlist_head); while (pe) { if (got_path_is_child(path, pe->path, pe->path_len)) { struct got_pathlist_head *ignorelist = pe->data; struct got_pathlist_entry *pi; TAILQ_FOREACH(pi, ignorelist, entry) { int flags = FNM_LEADING_DIR; if (strstr(pi->path, "/**/") == NULL) flags |= FNM_PATHNAME; if (match_path(pi->path, pi->path_len, path, flags)) continue; return 1; } } pe = TAILQ_PREV(pe, got_pathlist_head, entry); } return 0; } static const struct got_error * add_ignores(struct got_pathlist_head *ignores, const char *root_path, const char *path, int dirfd, const char *ignores_filename) { const struct got_error *err = NULL; char *ignorespath; int fd = -1; FILE *ignoresfile = NULL; if (asprintf(&ignorespath, "%s/%s%s%s", root_path, path, path[0] ? "/" : "", ignores_filename) == -1) return got_error_from_errno("asprintf"); if (dirfd != -1) { fd = openat(dirfd, ignores_filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { if (errno != ENOENT && errno != EACCES) err = got_error_from_errno2("openat", ignorespath); } else { ignoresfile = fdopen(fd, "r"); if (ignoresfile == NULL) err = got_error_from_errno2("fdopen", ignorespath); else { fd = -1; err = read_ignores(ignores, path, ignoresfile); } } } else { ignoresfile = fopen(ignorespath, "re"); if (ignoresfile == NULL) { if (errno != ENOENT && errno != EACCES) err = got_error_from_errno2("fopen", ignorespath); } else err = read_ignores(ignores, path, ignoresfile); } if (ignoresfile && fclose(ignoresfile) == EOF && err == NULL) err = got_error_from_errno2("fclose", path); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno2("close", path); free(ignorespath); return err; } static const struct got_error * status_new(int *ignore, void *arg, struct dirent *de, const char *parent_path, int dirfd) { const struct got_error *err = NULL; struct diff_dir_cb_arg *a = arg; char *path = NULL; if (ignore != NULL) *ignore = 0; if (a->cancel_cb) { err = a->cancel_cb(a->cancel_arg); if (err) return err; } if (parent_path[0]) { if (asprintf(&path, "%s/%s", parent_path, de->d_name) == -1) return got_error_from_errno("asprintf"); } else { path = de->d_name; } if (de->d_type == DT_DIR) { if (!a->no_ignores && ignore != NULL && match_ignores(a->ignores, path)) *ignore = 1; } else if (!match_ignores(a->ignores, path) && got_path_is_child(path, a->status_path, a->status_path_len)) err = (*a->status_cb)(a->status_arg, GOT_STATUS_UNVERSIONED, GOT_STATUS_NO_CHANGE, path, NULL, NULL, NULL, -1, NULL); if (parent_path[0]) free(path); return err; } static const struct got_error * status_traverse(void *arg, const char *path, int dirfd) { const struct got_error *err = NULL; struct diff_dir_cb_arg *a = arg; if (a->no_ignores) return NULL; err = add_ignores(a->ignores, a->worktree->root_path, path, dirfd, ".cvsignore"); if (err) return err; err = add_ignores(a->ignores, a->worktree->root_path, path, dirfd, ".gitignore"); return err; } static const struct got_error * report_single_file_status(const char *path, const char *ondisk_path, struct got_fileindex *fileindex, got_worktree_status_cb status_cb, void *status_arg, struct got_repository *repo, int report_unchanged, struct got_pathlist_head *ignores, int no_ignores) { struct got_fileindex_entry *ie; struct stat sb; ie = got_fileindex_entry_get(fileindex, path, strlen(path)); if (ie) return report_file_status(ie, ondisk_path, -1, NULL, status_cb, status_arg, repo, report_unchanged); if (lstat(ondisk_path, &sb) == -1) { if (errno != ENOENT) return got_error_from_errno2("lstat", ondisk_path); return (*status_cb)(status_arg, GOT_STATUS_NONEXISTENT, GOT_STATUS_NO_CHANGE, path, NULL, NULL, NULL, -1, NULL); } if (!no_ignores && match_ignores(ignores, path)) return NULL; if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) return (*status_cb)(status_arg, GOT_STATUS_UNVERSIONED, GOT_STATUS_NO_CHANGE, path, NULL, NULL, NULL, -1, NULL); return NULL; } static const struct got_error * add_ignores_from_parent_paths(struct got_pathlist_head *ignores, const char *root_path, const char *path) { const struct got_error *err; char *parent_path, *next_parent_path = NULL; err = add_ignores(ignores, root_path, "", -1, ".cvsignore"); if (err) return err; err = add_ignores(ignores, root_path, "", -1, ".gitignore"); if (err) return err; err = got_path_dirname(&parent_path, path); if (err) { if (err->code == GOT_ERR_BAD_PATH) return NULL; /* cannot traverse parent */ return err; } for (;;) { err = add_ignores(ignores, root_path, parent_path, -1, ".cvsignore"); if (err) break; err = add_ignores(ignores, root_path, parent_path, -1, ".gitignore"); if (err) break; err = got_path_dirname(&next_parent_path, parent_path); if (err) { if (err->code == GOT_ERR_BAD_PATH) err = NULL; /* traversed everything */ break; } if (got_path_is_root_dir(parent_path)) break; free(parent_path); parent_path = next_parent_path; next_parent_path = NULL; } free(parent_path); free(next_parent_path); return err; } struct find_missing_children_args { const char *parent_path; size_t parent_len; struct got_pathlist_head *children; got_cancel_cb cancel_cb; void *cancel_arg; }; static const struct got_error * find_missing_children(void *arg, struct got_fileindex_entry *ie) { const struct got_error *err = NULL; struct find_missing_children_args *a = arg; if (a->cancel_cb) { err = a->cancel_cb(a->cancel_arg); if (err) return err; } if (got_path_is_child(ie->path, a->parent_path, a->parent_len)) err = got_pathlist_append(a->children, ie->path, NULL); return err; } static const struct got_error * report_children(struct got_pathlist_head *children, struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_repository *repo, int is_root_dir, int report_unchanged, struct got_pathlist_head *ignores, int no_ignores, got_worktree_status_cb status_cb, void *status_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; struct got_pathlist_entry *pe; char *ondisk_path = NULL; TAILQ_FOREACH(pe, children, entry) { if (cancel_cb) { err = cancel_cb(cancel_arg); if (err) break; } if (asprintf(&ondisk_path, "%s%s%s", worktree->root_path, !is_root_dir ? "/" : "", pe->path) == -1) { err = got_error_from_errno("asprintf"); ondisk_path = NULL; break; } err = report_single_file_status(pe->path, ondisk_path, fileindex, status_cb, status_arg, repo, report_unchanged, ignores, no_ignores); if (err) break; free(ondisk_path); ondisk_path = NULL; } free(ondisk_path); return err; } static const struct got_error * worktree_status(struct got_worktree *worktree, const char *path, struct got_fileindex *fileindex, struct got_repository *repo, got_worktree_status_cb status_cb, void *status_arg, got_cancel_cb cancel_cb, void *cancel_arg, int no_ignores, int report_unchanged) { const struct got_error *err = NULL; int fd = -1; struct got_fileindex_diff_dir_cb fdiff_cb; struct diff_dir_cb_arg arg; char *ondisk_path = NULL; struct got_pathlist_head ignores, missing_children; struct got_fileindex_entry *ie; TAILQ_INIT(&ignores); TAILQ_INIT(&missing_children); if (asprintf(&ondisk_path, "%s%s%s", worktree->root_path, path[0] ? "/" : "", path) == -1) return got_error_from_errno("asprintf"); ie = got_fileindex_entry_get(fileindex, path, strlen(path)); if (ie) { err = report_single_file_status(path, ondisk_path, fileindex, status_cb, status_arg, repo, report_unchanged, &ignores, no_ignores); goto done; } else { struct find_missing_children_args fmca; fmca.parent_path = path; fmca.parent_len = strlen(path); fmca.children = &missing_children; fmca.cancel_cb = cancel_cb; fmca.cancel_arg = cancel_arg; err = got_fileindex_for_each_entry_safe(fileindex, find_missing_children, &fmca); if (err) goto done; } fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC); if (fd == -1) { if (errno != ENOTDIR && errno != ENOENT && errno != EACCES && !got_err_open_nofollow_on_symlink()) err = got_error_from_errno2("open", ondisk_path); else { if (!no_ignores) { err = add_ignores_from_parent_paths(&ignores, worktree->root_path, ondisk_path); if (err) goto done; } if (TAILQ_EMPTY(&missing_children)) { err = report_single_file_status(path, ondisk_path, fileindex, status_cb, status_arg, repo, report_unchanged, &ignores, no_ignores); if (err) goto done; } else { err = report_children(&missing_children, worktree, fileindex, repo, (path[0] == '\0'), report_unchanged, &ignores, no_ignores, status_cb, status_arg, cancel_cb, cancel_arg); if (err) goto done; } } } else { fdiff_cb.diff_old_new = status_old_new; fdiff_cb.diff_old = status_old; fdiff_cb.diff_new = status_new; fdiff_cb.diff_traverse = status_traverse; arg.fileindex = fileindex; arg.worktree = worktree; arg.status_path = path; arg.status_path_len = strlen(path); arg.repo = repo; arg.status_cb = status_cb; arg.status_arg = status_arg; arg.cancel_cb = cancel_cb; arg.cancel_arg = cancel_arg; arg.report_unchanged = report_unchanged; arg.no_ignores = no_ignores; if (!no_ignores) { err = add_ignores_from_parent_paths(&ignores, worktree->root_path, path); if (err) goto done; } arg.ignores = &ignores; err = got_fileindex_diff_dir(fileindex, fd, worktree->root_path, path, repo, &fdiff_cb, &arg); } done: free_ignores(&ignores); got_pathlist_free(&missing_children, GOT_PATHLIST_FREE_NONE); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); free(ondisk_path); return err; } const struct got_error * got_worktree_status(struct got_worktree *worktree, struct got_pathlist_head *paths, struct got_repository *repo, int no_ignores, got_worktree_status_cb status_cb, void *status_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; char *fileindex_path = NULL; struct got_fileindex *fileindex = NULL; struct got_pathlist_entry *pe; err = open_fileindex(&fileindex, &fileindex_path, worktree); if (err) return err; TAILQ_FOREACH(pe, paths, entry) { err = worktree_status(worktree, pe->path, fileindex, repo, status_cb, status_arg, cancel_cb, cancel_arg, no_ignores, 0); if (err) break; } free(fileindex_path); got_fileindex_free(fileindex); return err; } const struct got_error * got_worktree_resolve_path(char **wt_path, struct got_worktree *worktree, const char *arg) { const struct got_error *err = NULL; char *resolved = NULL, *cwd = NULL, *path = NULL; size_t len; struct stat sb; char *abspath = NULL; char canonpath[PATH_MAX]; *wt_path = NULL; cwd = getcwd(NULL, 0); if (cwd == NULL) return got_error_from_errno("getcwd"); if (lstat(arg, &sb) == -1) { if (errno != ENOENT) { err = got_error_from_errno2("lstat", arg); goto done; } sb.st_mode = 0; } if (S_ISLNK(sb.st_mode)) { /* * We cannot use realpath(3) with symlinks since we want to * operate on the symlink itself. * But we can make the path absolute, assuming it is relative * to the current working directory, and then canonicalize it. */ if (!got_path_is_absolute(arg)) { if (asprintf(&abspath, "%s/%s", cwd, arg) == -1) { err = got_error_from_errno("asprintf"); goto done; } } err = got_canonpath(abspath ? abspath : arg, canonpath, sizeof(canonpath)); if (err) goto done; resolved = strdup(canonpath); if (resolved == NULL) { err = got_error_from_errno("strdup"); goto done; } } else { resolved = realpath(arg, NULL); if (resolved == NULL) { if (errno != ENOENT) { err = got_error_from_errno2("realpath", arg); goto done; } if (asprintf(&abspath, "%s/%s", cwd, arg) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_canonpath(abspath, canonpath, sizeof(canonpath)); if (err) goto done; resolved = strdup(canonpath); if (resolved == NULL) { err = got_error_from_errno("strdup"); goto done; } } } if (strncmp(got_worktree_get_root_path(worktree), resolved, strlen(got_worktree_get_root_path(worktree)))) { err = got_error_path(resolved, GOT_ERR_BAD_PATH); goto done; } if (strlen(resolved) > strlen(got_worktree_get_root_path(worktree))) { err = got_path_skip_common_ancestor(&path, got_worktree_get_root_path(worktree), resolved); if (err) goto done; } else { path = strdup(""); if (path == NULL) { err = got_error_from_errno("strdup"); goto done; } } /* XXX status walk can't deal with trailing slash! */ len = strlen(path); while (len > 0 && path[len - 1] == '/') { path[len - 1] = '\0'; len--; } done: free(abspath); free(resolved); free(cwd); if (err == NULL) *wt_path = path; else free(path); return err; } struct schedule_addition_args { struct got_worktree *worktree; struct got_fileindex *fileindex; got_worktree_checkout_cb progress_cb; void *progress_arg; struct got_repository *repo; }; static int add_noop_status(unsigned char status) { return (status == GOT_STATUS_ADD || status == GOT_STATUS_MODIFY || status == GOT_STATUS_CONFLICT || status == GOT_STATUS_MODE_CHANGE || status == GOT_STATUS_NO_CHANGE); } static const struct got_error * schedule_addition(void *arg, unsigned char status, unsigned char staged_status, const char *relpath, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { struct schedule_addition_args *a = arg; const struct got_error *err = NULL; struct got_fileindex_entry *ie; struct stat sb; char *ondisk_path; if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, relpath) == -1) return got_error_from_errno("asprintf"); ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath)); if (ie) { err = get_file_status(&status, &sb, ie, ondisk_path, dirfd, de_name, a->repo); if (err) goto done; /* Re-adding an existing entry is a no-op. */ if (staged_status == GOT_STATUS_NO_CHANGE && add_noop_status(status)) goto done; err = got_error_path(relpath, GOT_ERR_FILE_STATUS); if (err) goto done; } if (status != GOT_STATUS_UNVERSIONED) { if (status == GOT_STATUS_NONEXISTENT) err = got_error_set_errno(ENOENT, ondisk_path); else err = got_error_path(ondisk_path, GOT_ERR_FILE_STATUS); goto done; } err = got_fileindex_entry_alloc(&ie, relpath); if (err) goto done; err = got_fileindex_entry_update(ie, a->worktree->root_fd, relpath, NULL, NULL, 1); if (err) { got_fileindex_entry_free(ie); goto done; } err = got_fileindex_entry_add(a->fileindex, ie); if (err) { got_fileindex_entry_free(ie); goto done; } done: free(ondisk_path); if (err) return err; if (staged_status == GOT_STATUS_NO_CHANGE && add_noop_status(status)) return NULL; return (*a->progress_cb)(a->progress_arg, GOT_STATUS_ADD, relpath); } const struct got_error * got_worktree_schedule_add(struct got_worktree *worktree, struct got_pathlist_head *paths, got_worktree_checkout_cb progress_cb, void *progress_arg, struct got_repository *repo, int no_ignores) { struct got_fileindex *fileindex = NULL; char *fileindex_path = NULL; const struct got_error *err = NULL, *sync_err, *unlockerr; struct got_pathlist_entry *pe; struct schedule_addition_args saa; err = lock_worktree(worktree, LOCK_EX); if (err) return err; err = open_fileindex(&fileindex, &fileindex_path, worktree); if (err) goto done; saa.worktree = worktree; saa.fileindex = fileindex; saa.progress_cb = progress_cb; saa.progress_arg = progress_arg; saa.repo = repo; TAILQ_FOREACH(pe, paths, entry) { err = worktree_status(worktree, pe->path, fileindex, repo, schedule_addition, &saa, NULL, NULL, no_ignores, 0); if (err) break; } sync_err = sync_fileindex(fileindex, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: free(fileindex_path); if (fileindex) got_fileindex_free(fileindex); unlockerr = lock_worktree(worktree, LOCK_SH); if (unlockerr && err == NULL) err = unlockerr; return err; } struct schedule_deletion_args { struct got_worktree *worktree; struct got_fileindex *fileindex; got_worktree_delete_cb progress_cb; void *progress_arg; struct got_repository *repo; int delete_local_mods; int keep_on_disk; int ignore_missing_paths; const char *status_path; size_t status_path_len; const char *status_codes; }; static const struct got_error * schedule_for_deletion(void *arg, unsigned char status, unsigned char staged_status, const char *relpath, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { struct schedule_deletion_args *a = arg; const struct got_error *err = NULL; struct got_fileindex_entry *ie = NULL; struct stat sb; char *ondisk_path; if (status == GOT_STATUS_NONEXISTENT) { if (a->ignore_missing_paths) return NULL; return got_error_set_errno(ENOENT, relpath); } ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath)); if (ie == NULL) return got_error_path(relpath, GOT_ERR_FILE_STATUS); staged_status = get_staged_status(ie); if (staged_status != GOT_STATUS_NO_CHANGE) { if (staged_status == GOT_STATUS_DELETE) return NULL; return got_error_path(relpath, GOT_ERR_FILE_STAGED); } if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, relpath) == -1) return got_error_from_errno("asprintf"); err = get_file_status(&status, &sb, ie, ondisk_path, dirfd, de_name, a->repo); if (err) goto done; if (a->status_codes) { size_t ncodes = strlen(a->status_codes); int i; for (i = 0; i < ncodes ; i++) { if (status == a->status_codes[i]) break; } if (i == ncodes) { /* Do not delete files in non-matching status. */ free(ondisk_path); return NULL; } if (a->status_codes[i] != GOT_STATUS_MODIFY && a->status_codes[i] != GOT_STATUS_MISSING) { static char msg[64]; snprintf(msg, sizeof(msg), "invalid status code '%c'", a->status_codes[i]); err = got_error_msg(GOT_ERR_FILE_STATUS, msg); goto done; } } if (status != GOT_STATUS_NO_CHANGE) { if (status == GOT_STATUS_DELETE) goto done; if (status == GOT_STATUS_MODIFY && !a->delete_local_mods) { err = got_error_path(relpath, GOT_ERR_FILE_MODIFIED); goto done; } if (status == GOT_STATUS_MISSING && !a->ignore_missing_paths) { err = got_error_set_errno(ENOENT, relpath); goto done; } if (status != GOT_STATUS_MODIFY && status != GOT_STATUS_MISSING) { err = got_error_path(relpath, GOT_ERR_FILE_STATUS); goto done; } } if (!a->keep_on_disk && status != GOT_STATUS_MISSING) { size_t root_len; if (dirfd != -1) { if (unlinkat(dirfd, de_name, 0) == -1) { err = got_error_from_errno2("unlinkat", ondisk_path); goto done; } } else if (unlink(ondisk_path) == -1) { err = got_error_from_errno2("unlink", ondisk_path); goto done; } root_len = strlen(a->worktree->root_path); do { char *parent; err = got_path_dirname(&parent, ondisk_path); if (err) goto done; free(ondisk_path); ondisk_path = parent; if (got_path_cmp(ondisk_path, a->status_path, strlen(ondisk_path), a->status_path_len) != 0 && !got_path_is_child(ondisk_path, a->status_path, a->status_path_len)) break; if (rmdir(ondisk_path) == -1) { if (errno != ENOTEMPTY) err = got_error_from_errno2("rmdir", ondisk_path); break; } } while (got_path_cmp(ondisk_path, a->worktree->root_path, strlen(ondisk_path), root_len) != 0); } if (got_fileindex_entry_has_blob(ie)) got_fileindex_entry_mark_deleted_from_disk(ie); else got_fileindex_entry_remove(a->fileindex, ie); done: free(ondisk_path); if (err) return err; if (status == GOT_STATUS_DELETE) return NULL; return (*a->progress_cb)(a->progress_arg, GOT_STATUS_DELETE, staged_status, relpath); } const struct got_error * got_worktree_schedule_delete(struct got_worktree *worktree, struct got_pathlist_head *paths, int delete_local_mods, const char *status_codes, got_worktree_delete_cb progress_cb, void *progress_arg, struct got_repository *repo, int keep_on_disk, int ignore_missing_paths) { struct got_fileindex *fileindex = NULL; char *fileindex_path = NULL; const struct got_error *err = NULL, *sync_err, *unlockerr; struct got_pathlist_entry *pe; struct schedule_deletion_args sda; err = lock_worktree(worktree, LOCK_EX); if (err) return err; err = open_fileindex(&fileindex, &fileindex_path, worktree); if (err) goto done; sda.worktree = worktree; sda.fileindex = fileindex; sda.progress_cb = progress_cb; sda.progress_arg = progress_arg; sda.repo = repo; sda.delete_local_mods = delete_local_mods; sda.keep_on_disk = keep_on_disk; sda.ignore_missing_paths = ignore_missing_paths; sda.status_codes = status_codes; TAILQ_FOREACH(pe, paths, entry) { char *ondisk_status_path; if (asprintf(&ondisk_status_path, "%s%s%s", got_worktree_get_root_path(worktree), pe->path[0] == '\0' ? "" : "/", pe->path) == -1) { err = got_error_from_errno("asprintf"); goto done; } sda.status_path = ondisk_status_path; sda.status_path_len = strlen(ondisk_status_path); err = worktree_status(worktree, pe->path, fileindex, repo, schedule_for_deletion, &sda, NULL, NULL, 1, 1); free(ondisk_status_path); if (err) break; } sync_err = sync_fileindex(fileindex, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: free(fileindex_path); if (fileindex) got_fileindex_free(fileindex); unlockerr = lock_worktree(worktree, LOCK_SH); if (unlockerr && err == NULL) err = unlockerr; return err; } static const struct got_error * copy_one_line(FILE *infile, FILE *outfile, FILE *rejectfile) { const struct got_error *err = NULL; char *line = NULL; size_t linesize = 0, n; ssize_t linelen; linelen = getline(&line, &linesize, infile); if (linelen == -1) { if (ferror(infile)) { err = got_error_from_errno("getline"); goto done; } return NULL; } if (outfile) { n = fwrite(line, 1, linelen, outfile); if (n != linelen) { err = got_ferror(outfile, GOT_ERR_IO); goto done; } } if (rejectfile) { n = fwrite(line, 1, linelen, rejectfile); if (n != linelen) err = got_ferror(rejectfile, GOT_ERR_IO); } done: free(line); return err; } static const struct got_error * skip_one_line(FILE *f) { char *line = NULL; size_t linesize = 0; ssize_t linelen; linelen = getline(&line, &linesize, f); if (linelen == -1) { if (ferror(f)) return got_error_from_errno("getline"); return NULL; } free(line); return NULL; } static const struct got_error * copy_change(FILE *f1, FILE *f2, int *line_cur1, int *line_cur2, int start_old, int end_old, int start_new, int end_new, FILE *outfile, FILE *rejectfile) { const struct got_error *err; /* Copy old file's lines leading up to patch. */ while (!feof(f1) && *line_cur1 < start_old) { err = copy_one_line(f1, outfile, NULL); if (err) return err; (*line_cur1)++; } /* Skip new file's lines leading up to patch. */ while (!feof(f2) && *line_cur2 < start_new) { if (rejectfile) err = copy_one_line(f2, NULL, rejectfile); else err = skip_one_line(f2); if (err) return err; (*line_cur2)++; } /* Copy patched lines. */ while (!feof(f2) && *line_cur2 <= end_new) { err = copy_one_line(f2, outfile, NULL); if (err) return err; (*line_cur2)++; } /* Skip over old file's replaced lines. */ while (!feof(f1) && *line_cur1 <= end_old) { if (rejectfile) err = copy_one_line(f1, NULL, rejectfile); else err = skip_one_line(f1); if (err) return err; (*line_cur1)++; } return NULL; } static const struct got_error * copy_remaining_content(FILE *f1, FILE *f2, int *line_cur1, int *line_cur2, FILE *outfile, FILE *rejectfile) { const struct got_error *err; if (outfile) { /* Copy old file's lines until EOF. */ while (!feof(f1)) { err = copy_one_line(f1, outfile, NULL); if (err) return err; (*line_cur1)++; } } if (rejectfile) { /* Copy new file's lines until EOF. */ while (!feof(f2)) { err = copy_one_line(f2, NULL, rejectfile); if (err) return err; (*line_cur2)++; } } return NULL; } static const struct got_error * apply_or_reject_change(int *choice, int *nchunks_used, struct diff_result *diff_result, int n, const char *relpath, FILE *f1, FILE *f2, int *line_cur1, int *line_cur2, FILE *outfile, FILE *rejectfile, int changeno, int nchanges, got_worktree_patch_cb patch_cb, void *patch_arg) { const struct got_error *err = NULL; struct diff_chunk_context cc = {}; int start_old, end_old, start_new, end_new; FILE *hunkfile; struct diff_output_unidiff_state *diff_state; struct diff_input_info diff_info; int rc; *choice = GOT_PATCH_CHOICE_NONE; /* Get changed line numbers without context lines for copy_change(). */ diff_chunk_context_load_change(&cc, NULL, diff_result, n, 0); start_old = cc.left.start; end_old = cc.left.end; start_new = cc.right.start; end_new = cc.right.end; /* Get the same change with context lines for display. */ memset(&cc, 0, sizeof(cc)); diff_chunk_context_load_change(&cc, nchunks_used, diff_result, n, 3); memset(&diff_info, 0, sizeof(diff_info)); diff_info.left_path = relpath; diff_info.right_path = relpath; diff_state = diff_output_unidiff_state_alloc(); if (diff_state == NULL) return got_error_set_errno(ENOMEM, "diff_output_unidiff_state_alloc"); hunkfile = got_opentemp(); if (hunkfile == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } rc = diff_output_unidiff_chunk(NULL, hunkfile, diff_state, &diff_info, diff_result, &cc); if (rc != DIFF_RC_OK) { err = got_error_set_errno(rc, "diff_output_unidiff_chunk"); goto done; } if (fseek(hunkfile, 0L, SEEK_SET) == -1) { err = got_ferror(hunkfile, GOT_ERR_IO); goto done; } err = (*patch_cb)(choice, patch_arg, GOT_STATUS_MODIFY, relpath, hunkfile, changeno, nchanges); if (err) goto done; switch (*choice) { case GOT_PATCH_CHOICE_YES: err = copy_change(f1, f2, line_cur1, line_cur2, start_old, end_old, start_new, end_new, outfile, rejectfile); break; case GOT_PATCH_CHOICE_NO: err = copy_change(f1, f2, line_cur1, line_cur2, start_old, end_old, start_new, end_new, rejectfile, outfile); break; case GOT_PATCH_CHOICE_QUIT: break; default: err = got_error(GOT_ERR_PATCH_CHOICE); break; } done: diff_output_unidiff_state_free(diff_state); if (hunkfile && fclose(hunkfile) == EOF && err == NULL) err = got_error_from_errno("fclose"); return err; } struct revert_file_args { struct got_worktree *worktree; struct got_fileindex *fileindex; got_worktree_checkout_cb progress_cb; void *progress_arg; got_worktree_patch_cb patch_cb; void *patch_arg; struct got_repository *repo; int unlink_added_files; struct got_pathlist_head *added_files_to_unlink; }; static const struct got_error * create_patched_content(char **path_outfile, int reverse_patch, struct got_object_id *blob_id, const char *path2, int dirfd2, const char *de_name2, const char *relpath, struct got_repository *repo, got_worktree_patch_cb patch_cb, void *patch_arg) { const struct got_error *err, *free_err; struct got_blob_object *blob = NULL; FILE *f1 = NULL, *f2 = NULL, *outfile = NULL; int fd = -1, fd2 = -1; char link_target[PATH_MAX]; ssize_t link_len = 0; char *path1 = NULL, *id_str = NULL; struct stat sb2; struct got_diffreg_result *diffreg_result = NULL; int line_cur1 = 1, line_cur2 = 1, have_content = 0; int i = 0, n = 0, nchunks_used = 0, nchanges = 0; *path_outfile = NULL; err = got_object_id_str(&id_str, blob_id); if (err) return err; if (dirfd2 != -1) { fd2 = openat(dirfd2, de_name2, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd2 == -1) { if (!got_err_open_nofollow_on_symlink()) { err = got_error_from_errno2("openat", path2); goto done; } link_len = readlinkat(dirfd2, de_name2, link_target, sizeof(link_target)); if (link_len == -1) { return got_error_from_errno2("readlinkat", path2); } sb2.st_mode = S_IFLNK; sb2.st_size = link_len; } } else { fd2 = open(path2, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd2 == -1) { if (!got_err_open_nofollow_on_symlink()) { err = got_error_from_errno2("open", path2); goto done; } link_len = readlink(path2, link_target, sizeof(link_target)); if (link_len == -1) return got_error_from_errno2("readlink", path2); sb2.st_mode = S_IFLNK; sb2.st_size = link_len; } } if (fd2 != -1) { if (fstat(fd2, &sb2) == -1) { err = got_error_from_errno2("fstat", path2); goto done; } f2 = fdopen(fd2, "r"); if (f2 == NULL) { err = got_error_from_errno2("fdopen", path2); goto done; } fd2 = -1; } else { size_t n; f2 = got_opentemp(); if (f2 == NULL) { err = got_error_from_errno2("got_opentemp", path2); goto done; } n = fwrite(link_target, 1, link_len, f2); if (n != link_len) { err = got_ferror(f2, GOT_ERR_IO); goto done; } if (fflush(f2) == EOF) { err = got_error_from_errno("fflush"); goto done; } rewind(f2); } fd = got_opentempfd(); if (fd == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } err = got_object_open_as_blob(&blob, repo, blob_id, 8192, fd); if (err) goto done; err = got_opentemp_named(&path1, &f1, "got-patched-blob", ""); if (err) goto done; err = got_object_blob_dump_to_file(NULL, NULL, NULL, f1, blob); if (err) goto done; err = got_diff_files(&diffreg_result, f1, 1, id_str, f2, 1, path2, 3, 0, 1, NULL, GOT_DIFF_ALGORITHM_MYERS); if (err) goto done; err = got_opentemp_named(path_outfile, &outfile, "got-patched-content", ""); if (err) goto done; if (fseek(f1, 0L, SEEK_SET) == -1) return got_ferror(f1, GOT_ERR_IO); if (fseek(f2, 0L, SEEK_SET) == -1) return got_ferror(f2, GOT_ERR_IO); /* Count the number of actual changes in the diff result. */ for (n = 0; n < diffreg_result->result->chunks.len; n += nchunks_used) { struct diff_chunk_context cc = {}; diff_chunk_context_load_change(&cc, &nchunks_used, diffreg_result->result, n, 0); nchanges++; } for (n = 0; n < diffreg_result->result->chunks.len; n += nchunks_used) { int choice; err = apply_or_reject_change(&choice, &nchunks_used, diffreg_result->result, n, relpath, f1, f2, &line_cur1, &line_cur2, reverse_patch ? NULL : outfile, reverse_patch ? outfile : NULL, ++i, nchanges, patch_cb, patch_arg); if (err) goto done; if (choice == GOT_PATCH_CHOICE_YES) have_content = 1; else if (choice == GOT_PATCH_CHOICE_QUIT) break; } if (have_content) { err = copy_remaining_content(f1, f2, &line_cur1, &line_cur2, reverse_patch ? NULL : outfile, reverse_patch ? outfile : NULL); if (err) goto done; if (!S_ISLNK(sb2.st_mode)) { mode_t mode; mode = apply_umask(sb2.st_mode); if (fchmod(fileno(outfile), mode) == -1) { err = got_error_from_errno2("fchmod", path2); goto done; } } } done: free(id_str); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob) got_object_blob_close(blob); free_err = got_diffreg_result_free(diffreg_result); if (err == NULL) err = free_err; if (f1 && fclose(f1) == EOF && err == NULL) err = got_error_from_errno2("fclose", path1); if (f2 && fclose(f2) == EOF && err == NULL) err = got_error_from_errno2("fclose", path2); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno2("close", path2); if (outfile && fclose(outfile) == EOF && err == NULL) err = got_error_from_errno2("fclose", *path_outfile); if (path1 && unlink(path1) == -1 && err == NULL) err = got_error_from_errno2("unlink", path1); if (err || !have_content) { if (*path_outfile && unlink(*path_outfile) == -1 && err == NULL) err = got_error_from_errno2("unlink", *path_outfile); free(*path_outfile); *path_outfile = NULL; } free(path1); return err; } static const struct got_error * revert_file(void *arg, unsigned char status, unsigned char staged_status, const char *relpath, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { struct revert_file_args *a = arg; const struct got_error *err = NULL; char *parent_path = NULL; struct got_fileindex_entry *ie; struct got_commit_object *base_commit = NULL; struct got_tree_object *tree = NULL; struct got_object_id *tree_id = NULL; const struct got_tree_entry *te = NULL; char *tree_path = NULL, *te_name; char *ondisk_path = NULL, *path_content = NULL; struct got_blob_object *blob = NULL; int fd = -1; /* Reverting a staged deletion is a no-op. */ if (status == GOT_STATUS_DELETE && staged_status != GOT_STATUS_NO_CHANGE) return NULL; if (status == GOT_STATUS_UNVERSIONED) return (*a->progress_cb)(a->progress_arg, GOT_STATUS_UNVERSIONED, relpath); ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath)); if (ie == NULL) return got_error_path(relpath, GOT_ERR_BAD_PATH); /* Construct in-repository path of tree which contains this blob. */ err = got_path_dirname(&parent_path, ie->path); if (err) { if (err->code != GOT_ERR_BAD_PATH) goto done; parent_path = strdup("/"); if (parent_path == NULL) { err = got_error_from_errno("strdup"); goto done; } } if (got_path_is_root_dir(a->worktree->path_prefix)) { tree_path = strdup(parent_path); if (tree_path == NULL) { err = got_error_from_errno("strdup"); goto done; } } else { if (got_path_is_root_dir(parent_path)) { tree_path = strdup(a->worktree->path_prefix); if (tree_path == NULL) { err = got_error_from_errno("strdup"); goto done; } } else { if (asprintf(&tree_path, "%s/%s", a->worktree->path_prefix, parent_path) == -1) { err = got_error_from_errno("asprintf"); goto done; } } } err = got_object_open_as_commit(&base_commit, a->repo, a->worktree->base_commit_id); if (err) goto done; err = got_object_id_by_path(&tree_id, a->repo, base_commit, tree_path); if (err) { if (!(err->code == GOT_ERR_NO_TREE_ENTRY && (status == GOT_STATUS_ADD || staged_status == GOT_STATUS_ADD))) goto done; } else { err = got_object_open_as_tree(&tree, a->repo, tree_id); if (err) goto done; err = got_path_basename(&te_name, ie->path); if (err) goto done; te = got_object_tree_find_entry(tree, te_name); free(te_name); if (te == NULL && status != GOT_STATUS_ADD && staged_status != GOT_STATUS_ADD) { err = got_error_path(ie->path, GOT_ERR_NO_TREE_ENTRY); goto done; } } switch (status) { case GOT_STATUS_ADD: if (a->patch_cb) { int choice = GOT_PATCH_CHOICE_NONE; err = (*a->patch_cb)(&choice, a->patch_arg, status, ie->path, NULL, 1, 1); if (err) goto done; if (choice != GOT_PATCH_CHOICE_YES) break; } err = (*a->progress_cb)(a->progress_arg, GOT_STATUS_REVERT, ie->path); if (err) goto done; got_fileindex_entry_remove(a->fileindex, ie); if (a->unlink_added_files) { int do_unlink = a->added_files_to_unlink ? 0 : 1; if (a->added_files_to_unlink) { struct got_pathlist_entry *pe; TAILQ_FOREACH(pe, a->added_files_to_unlink, entry) { if (got_path_cmp(pe->path, relpath, pe->path_len, strlen(relpath))) continue; do_unlink = 1; break; } } if (do_unlink) { if (asprintf(&ondisk_path, "%s/%s", got_worktree_get_root_path(a->worktree), relpath) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (unlink(ondisk_path) == -1) { err = got_error_from_errno2("unlink", ondisk_path); break; } } } break; case GOT_STATUS_DELETE: if (a->patch_cb) { int choice = GOT_PATCH_CHOICE_NONE; err = (*a->patch_cb)(&choice, a->patch_arg, status, ie->path, NULL, 1, 1); if (err) goto done; if (choice != GOT_PATCH_CHOICE_YES) break; } /* fall through */ case GOT_STATUS_MODIFY: case GOT_STATUS_MODE_CHANGE: case GOT_STATUS_CONFLICT: case GOT_STATUS_MISSING: { struct got_object_id id; if (staged_status == GOT_STATUS_ADD || staged_status == GOT_STATUS_MODIFY) got_fileindex_entry_get_staged_blob_id(&id, ie); else got_fileindex_entry_get_blob_id(&id, ie); fd = got_opentempfd(); if (fd == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } err = got_object_open_as_blob(&blob, a->repo, &id, 8192, fd); if (err) goto done; if (asprintf(&ondisk_path, "%s/%s", got_worktree_get_root_path(a->worktree), relpath) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (a->patch_cb && (status == GOT_STATUS_MODIFY || status == GOT_STATUS_CONFLICT)) { int is_bad_symlink = 0; err = create_patched_content(&path_content, 1, &id, ondisk_path, dirfd, de_name, ie->path, a->repo, a->patch_cb, a->patch_arg); if (err || path_content == NULL) break; if (te && S_ISLNK(te->mode)) { if (unlink(path_content) == -1) { err = got_error_from_errno2("unlink", path_content); break; } err = install_symlink(&is_bad_symlink, a->worktree, ondisk_path, ie->path, blob, 0, 1, 0, 0, a->repo, a->progress_cb, a->progress_arg); } else { if (rename(path_content, ondisk_path) == -1) { err = got_error_from_errno3("rename", path_content, ondisk_path); goto done; } } } else { int is_bad_symlink = 0; if (te && S_ISLNK(te->mode)) { err = install_symlink(&is_bad_symlink, a->worktree, ondisk_path, ie->path, blob, 0, 1, 0, 0, a->repo, a->progress_cb, a->progress_arg); } else { err = install_blob(a->worktree, ondisk_path, ie->path, te ? te->mode : GOT_DEFAULT_FILE_MODE, got_fileindex_perms_to_st(ie), blob, 0, 1, 0, 0, NULL, a->repo, a->progress_cb, a->progress_arg); } if (err) goto done; if (status == GOT_STATUS_DELETE || status == GOT_STATUS_MODE_CHANGE) { err = got_fileindex_entry_update(ie, a->worktree->root_fd, relpath, blob->id.sha1, a->worktree->base_commit_id->sha1, 1); if (err) goto done; } if (is_bad_symlink) { got_fileindex_entry_filetype_set(ie, GOT_FILEIDX_MODE_BAD_SYMLINK); } } break; } default: break; } done: free(ondisk_path); free(path_content); free(parent_path); free(tree_path); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob) got_object_blob_close(blob); if (tree) got_object_tree_close(tree); free(tree_id); if (base_commit) got_object_commit_close(base_commit); return err; } const struct got_error * got_worktree_revert(struct got_worktree *worktree, struct got_pathlist_head *paths, got_worktree_checkout_cb progress_cb, void *progress_arg, got_worktree_patch_cb patch_cb, void *patch_arg, struct got_repository *repo) { struct got_fileindex *fileindex = NULL; char *fileindex_path = NULL; const struct got_error *err = NULL, *unlockerr = NULL; const struct got_error *sync_err = NULL; struct got_pathlist_entry *pe; struct revert_file_args rfa; err = lock_worktree(worktree, LOCK_EX); if (err) return err; err = open_fileindex(&fileindex, &fileindex_path, worktree); if (err) goto done; rfa.worktree = worktree; rfa.fileindex = fileindex; rfa.progress_cb = progress_cb; rfa.progress_arg = progress_arg; rfa.patch_cb = patch_cb; rfa.patch_arg = patch_arg; rfa.repo = repo; rfa.unlink_added_files = 0; TAILQ_FOREACH(pe, paths, entry) { err = worktree_status(worktree, pe->path, fileindex, repo, revert_file, &rfa, NULL, NULL, 1, 0); if (err) break; } sync_err = sync_fileindex(fileindex, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: free(fileindex_path); if (fileindex) got_fileindex_free(fileindex); unlockerr = lock_worktree(worktree, LOCK_SH); if (unlockerr && err == NULL) err = unlockerr; return err; } static void free_commitable(struct got_commitable *ct) { free(ct->path); free(ct->in_repo_path); free(ct->ondisk_path); free(ct->blob_id); free(ct->base_blob_id); free(ct->staged_blob_id); free(ct->base_commit_id); free(ct); } struct collect_commitables_arg { struct got_pathlist_head *commitable_paths; struct got_repository *repo; struct got_worktree *worktree; struct got_fileindex *fileindex; int have_staged_files; int allow_bad_symlinks; int diff_header_shown; int commit_conflicts; FILE *diff_outfile; FILE *f1; FILE *f2; }; /* * Create a file which contains the target path of a symlink so we can feed * it as content to the diff engine. */ static const struct got_error * get_symlink_target_file(int *fd, int dirfd, const char *de_name, const char *abspath) { const struct got_error *err = NULL; char target_path[PATH_MAX]; ssize_t target_len, outlen; *fd = -1; if (dirfd != -1) { target_len = readlinkat(dirfd, de_name, target_path, PATH_MAX); if (target_len == -1) return got_error_from_errno2("readlinkat", abspath); } else { target_len = readlink(abspath, target_path, PATH_MAX); if (target_len == -1) return got_error_from_errno2("readlink", abspath); } *fd = got_opentempfd(); if (*fd == -1) return got_error_from_errno("got_opentempfd"); outlen = write(*fd, target_path, target_len); if (outlen == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } if (lseek(*fd, 0, SEEK_SET) == -1) { err = got_error_from_errno2("lseek", abspath); goto done; } done: if (err) { close(*fd); *fd = -1; } return err; } static const struct got_error * append_ct_diff(struct got_commitable *ct, int *diff_header_shown, FILE *diff_outfile, FILE *f1, FILE *f2, int dirfd, const char *de_name, int diff_staged, struct got_repository *repo, struct got_worktree *worktree) { const struct got_error *err = NULL; struct got_blob_object *blob1 = NULL; int fd = -1, fd1 = -1, fd2 = -1; FILE *ondisk_file = NULL; char *label1 = NULL; struct stat sb; off_t size1 = 0; int f2_exists = 0; char *id_str = NULL; memset(&sb, 0, sizeof(sb)); if (diff_staged) { if (ct->staged_status != GOT_STATUS_MODIFY && ct->staged_status != GOT_STATUS_ADD && ct->staged_status != GOT_STATUS_DELETE) return NULL; } else { if (ct->status != GOT_STATUS_MODIFY && ct->status != GOT_STATUS_ADD && ct->status != GOT_STATUS_DELETE && ct->status != GOT_STATUS_CONFLICT) return NULL; } err = got_opentemp_truncate(f1); if (err) return got_error_from_errno("got_opentemp_truncate"); err = got_opentemp_truncate(f2); if (err) return got_error_from_errno("got_opentemp_truncate"); if (!*diff_header_shown) { err = got_object_id_str(&id_str, worktree->base_commit_id); if (err) return err; fprintf(diff_outfile, "diff %s%s\n", diff_staged ? "-s " : "", got_worktree_get_root_path(worktree)); fprintf(diff_outfile, "commit - %s\n", id_str); fprintf(diff_outfile, "path + %s%s\n", got_worktree_get_root_path(worktree), diff_staged ? " (staged changes)" : ""); *diff_header_shown = 1; } if (diff_staged) { const char *label1 = NULL, *label2 = NULL; switch (ct->staged_status) { case GOT_STATUS_MODIFY: label1 = ct->path; label2 = ct->path; break; case GOT_STATUS_ADD: label2 = ct->path; break; case GOT_STATUS_DELETE: label1 = ct->path; break; default: return got_error(GOT_ERR_FILE_STATUS); } fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } err = got_diff_objects_as_blobs(NULL, NULL, f1, f2, fd1, fd2, ct->base_blob_id, ct->staged_blob_id, label1, label2, GOT_DIFF_ALGORITHM_PATIENCE, 3, 0, 0, NULL, repo, diff_outfile); goto done; } fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } if (ct->status != GOT_STATUS_ADD) { err = got_object_open_as_blob(&blob1, repo, ct->base_blob_id, 8192, fd1); if (err) goto done; } if (ct->status != GOT_STATUS_DELETE) { if (dirfd != -1) { fd = openat(dirfd, de_name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { if (!got_err_open_nofollow_on_symlink()) { err = got_error_from_errno2("openat", ct->ondisk_path); goto done; } err = get_symlink_target_file(&fd, dirfd, de_name, ct->ondisk_path); if (err) goto done; } } else { fd = open(ct->ondisk_path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { if (!got_err_open_nofollow_on_symlink()) { err = got_error_from_errno2("open", ct->ondisk_path); goto done; } err = get_symlink_target_file(&fd, dirfd, de_name, ct->ondisk_path); if (err) goto done; } } if (fstatat(fd, ct->ondisk_path, &sb, AT_SYMLINK_NOFOLLOW) == -1) { err = got_error_from_errno2("fstatat", ct->ondisk_path); goto done; } ondisk_file = fdopen(fd, "r"); if (ondisk_file == NULL) { err = got_error_from_errno2("fdopen", ct->ondisk_path); goto done; } fd = -1; f2_exists = 1; } if (blob1) { err = got_object_blob_dump_to_file(&size1, NULL, NULL, f1, blob1); if (err) goto done; } err = got_diff_blob_file(blob1, f1, size1, label1, ondisk_file ? ondisk_file : f2, f2_exists, &sb, ct->path, GOT_DIFF_ALGORITHM_PATIENCE, 3, 0, 0, NULL, diff_outfile); done: if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob1) got_object_blob_close(blob1); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (ondisk_file && fclose(ondisk_file) == EOF && err == NULL) err = got_error_from_errno("fclose"); return err; } static const struct got_error * collect_commitables(void *arg, unsigned char status, unsigned char staged_status, const char *relpath, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { struct collect_commitables_arg *a = arg; const struct got_error *err = NULL; struct got_commitable *ct = NULL; struct got_pathlist_entry *new = NULL; char *parent_path = NULL, *path = NULL; struct stat sb; if (a->have_staged_files) { if (staged_status != GOT_STATUS_MODIFY && staged_status != GOT_STATUS_ADD && staged_status != GOT_STATUS_DELETE) return NULL; } else { if (status == GOT_STATUS_CONFLICT && !a->commit_conflicts) { printf("C %s\n", relpath); return got_error(GOT_ERR_COMMIT_CONFLICT); } if (status != GOT_STATUS_MODIFY && status != GOT_STATUS_MODE_CHANGE && status != GOT_STATUS_ADD && status != GOT_STATUS_DELETE && status != GOT_STATUS_CONFLICT) return NULL; } if (asprintf(&path, "/%s", relpath) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (strcmp(path, "/") == 0) { parent_path = strdup(""); if (parent_path == NULL) return got_error_from_errno("strdup"); } else { err = got_path_dirname(&parent_path, path); if (err) return err; } ct = calloc(1, sizeof(*ct)); if (ct == NULL) { err = got_error_from_errno("calloc"); goto done; } if (asprintf(&ct->ondisk_path, "%s/%s", a->worktree->root_path, relpath) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (staged_status == GOT_STATUS_ADD || staged_status == GOT_STATUS_MODIFY) { struct got_fileindex_entry *ie; ie = got_fileindex_entry_get(a->fileindex, path, strlen(path)); switch (got_fileindex_entry_staged_filetype_get(ie)) { case GOT_FILEIDX_MODE_REGULAR_FILE: case GOT_FILEIDX_MODE_BAD_SYMLINK: ct->mode = S_IFREG; break; case GOT_FILEIDX_MODE_SYMLINK: ct->mode = S_IFLNK; break; default: err = got_error_path(path, GOT_ERR_BAD_FILETYPE); goto done; } ct->mode |= got_fileindex_entry_perms_get(ie); } else if (status != GOT_STATUS_DELETE && staged_status != GOT_STATUS_DELETE) { if (dirfd != -1) { if (fstatat(dirfd, de_name, &sb, AT_SYMLINK_NOFOLLOW) == -1) { err = got_error_from_errno2("fstatat", ct->ondisk_path); goto done; } } else if (lstat(ct->ondisk_path, &sb) == -1) { err = got_error_from_errno2("lstat", ct->ondisk_path); goto done; } ct->mode = sb.st_mode; } if (asprintf(&ct->in_repo_path, "%s%s%s", a->worktree->path_prefix, got_path_is_root_dir(a->worktree->path_prefix) ? "" : "/", relpath) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (S_ISLNK(ct->mode) && staged_status == GOT_STATUS_NO_CHANGE && status == GOT_STATUS_ADD && !a->allow_bad_symlinks) { int is_bad_symlink; char target_path[PATH_MAX]; ssize_t target_len; target_len = readlink(ct->ondisk_path, target_path, sizeof(target_path)); if (target_len == -1) { err = got_error_from_errno2("readlink", ct->ondisk_path); goto done; } err = is_bad_symlink_target(&is_bad_symlink, target_path, target_len, ct->ondisk_path, a->worktree->root_path, a->worktree->meta_dir); if (err) goto done; if (is_bad_symlink) { err = got_error_path(ct->ondisk_path, GOT_ERR_BAD_SYMLINK); goto done; } } ct->status = status; ct->staged_status = staged_status; ct->blob_id = NULL; /* will be filled in when blob gets created */ if (ct->status != GOT_STATUS_ADD && ct->staged_status != GOT_STATUS_ADD) { ct->base_blob_id = got_object_id_dup(blob_id); if (ct->base_blob_id == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } ct->base_commit_id = got_object_id_dup(commit_id); if (ct->base_commit_id == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } } if (ct->staged_status == GOT_STATUS_ADD || ct->staged_status == GOT_STATUS_MODIFY) { ct->staged_blob_id = got_object_id_dup(staged_blob_id); if (ct->staged_blob_id == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } } ct->path = strdup(path); if (ct->path == NULL) { err = got_error_from_errno("strdup"); goto done; } if (a->diff_outfile) { err = append_ct_diff(ct, &a->diff_header_shown, a->diff_outfile, a->f1, a->f2, dirfd, de_name, a->have_staged_files, a->repo, a->worktree); if (err) goto done; } err = got_pathlist_insert(&new, a->commitable_paths, ct->path, ct); done: if (ct && (err || new == NULL)) free_commitable(ct); free(parent_path); free(path); return err; } static const struct got_error *write_tree(struct got_object_id **, int *, struct got_tree_object *, const char *, struct got_pathlist_head *, got_worktree_status_cb status_cb, void *status_arg, struct got_repository *); static const struct got_error * write_subtree(struct got_object_id **new_subtree_id, int *nentries, struct got_tree_entry *te, const char *parent_path, struct got_pathlist_head *commitable_paths, got_worktree_status_cb status_cb, void *status_arg, struct got_repository *repo) { const struct got_error *err = NULL; struct got_tree_object *subtree; char *subpath; if (asprintf(&subpath, "%s%s%s", parent_path, got_path_is_root_dir(parent_path) ? "" : "/", te->name) == -1) return got_error_from_errno("asprintf"); err = got_object_open_as_tree(&subtree, repo, &te->id); if (err) return err; err = write_tree(new_subtree_id, nentries, subtree, subpath, commitable_paths, status_cb, status_arg, repo); got_object_tree_close(subtree); free(subpath); return err; } static const struct got_error * match_ct_parent_path(int *match, struct got_commitable *ct, const char *path) { const struct got_error *err = NULL; char *ct_parent_path = NULL; *match = 0; if (strchr(ct->in_repo_path, '/') == NULL) { *match = got_path_is_root_dir(path); return NULL; } err = got_path_dirname(&ct_parent_path, ct->in_repo_path); if (err) return err; *match = (strcmp(path, ct_parent_path) == 0); free(ct_parent_path); return err; } static mode_t get_ct_file_mode(struct got_commitable *ct) { if (S_ISLNK(ct->mode)) return S_IFLNK; return S_IFREG | (ct->mode & ((S_IRWXU | S_IRWXG | S_IRWXO))); } static const struct got_error * alloc_modified_blob_tree_entry(struct got_tree_entry **new_te, struct got_tree_entry *te, struct got_commitable *ct) { const struct got_error *err = NULL; *new_te = NULL; err = got_object_tree_entry_dup(new_te, te); if (err) goto done; (*new_te)->mode = get_ct_file_mode(ct); if (ct->staged_status == GOT_STATUS_MODIFY) memcpy(&(*new_te)->id, ct->staged_blob_id, sizeof((*new_te)->id)); else memcpy(&(*new_te)->id, ct->blob_id, sizeof((*new_te)->id)); done: if (err && *new_te) { free(*new_te); *new_te = NULL; } return err; } static const struct got_error * alloc_added_blob_tree_entry(struct got_tree_entry **new_te, struct got_commitable *ct) { const struct got_error *err = NULL; char *ct_name = NULL; *new_te = NULL; *new_te = calloc(1, sizeof(**new_te)); if (*new_te == NULL) return got_error_from_errno("calloc"); err = got_path_basename(&ct_name, ct->path); if (err) goto done; if (strlcpy((*new_te)->name, ct_name, sizeof((*new_te)->name)) >= sizeof((*new_te)->name)) { err = got_error(GOT_ERR_NO_SPACE); goto done; } (*new_te)->mode = get_ct_file_mode(ct); if (ct->staged_status == GOT_STATUS_ADD) memcpy(&(*new_te)->id, ct->staged_blob_id, sizeof((*new_te)->id)); else memcpy(&(*new_te)->id, ct->blob_id, sizeof((*new_te)->id)); done: free(ct_name); if (err && *new_te) { free(*new_te); *new_te = NULL; } return err; } static const struct got_error * insert_tree_entry(struct got_tree_entry *new_te, struct got_pathlist_head *paths) { const struct got_error *err = NULL; struct got_pathlist_entry *new_pe; err = got_pathlist_insert(&new_pe, paths, new_te->name, new_te); if (err) return err; if (new_pe == NULL) return got_error(GOT_ERR_TREE_DUP_ENTRY); return NULL; } static const struct got_error * report_ct_status(struct got_commitable *ct, got_worktree_status_cb status_cb, void *status_arg) { const char *ct_path = ct->path; unsigned char status; if (status_cb == NULL) /* no commit progress output desired */ return NULL; while (ct_path[0] == '/') ct_path++; if (ct->staged_status != GOT_STATUS_NO_CHANGE) status = ct->staged_status; else status = ct->status; return (*status_cb)(status_arg, status, GOT_STATUS_NO_CHANGE, ct_path, ct->blob_id, NULL, NULL, -1, NULL); } static const struct got_error * match_modified_subtree(int *modified, struct got_tree_entry *te, const char *base_tree_path, struct got_pathlist_head *commitable_paths) { const struct got_error *err = NULL; struct got_pathlist_entry *pe; char *te_path; *modified = 0; if (asprintf(&te_path, "%s%s%s", base_tree_path, got_path_is_root_dir(base_tree_path) ? "" : "/", te->name) == -1) return got_error_from_errno("asprintf"); TAILQ_FOREACH(pe, commitable_paths, entry) { struct got_commitable *ct = pe->data; *modified = got_path_is_child(ct->in_repo_path, te_path, strlen(te_path)); if (*modified) break; } free(te_path); return err; } static const struct got_error * match_deleted_or_modified_ct(struct got_commitable **ctp, struct got_tree_entry *te, const char *base_tree_path, struct got_pathlist_head *commitable_paths) { const struct got_error *err = NULL; struct got_pathlist_entry *pe; *ctp = NULL; TAILQ_FOREACH(pe, commitable_paths, entry) { struct got_commitable *ct = pe->data; char *ct_name = NULL; int path_matches; if (ct->staged_status == GOT_STATUS_NO_CHANGE) { if (ct->status != GOT_STATUS_MODIFY && ct->status != GOT_STATUS_MODE_CHANGE && ct->status != GOT_STATUS_DELETE && ct->status != GOT_STATUS_CONFLICT) continue; } else { if (ct->staged_status != GOT_STATUS_MODIFY && ct->staged_status != GOT_STATUS_DELETE) continue; } if (got_object_id_cmp(ct->base_blob_id, &te->id) != 0) continue; err = match_ct_parent_path(&path_matches, ct, base_tree_path); if (err) return err; if (!path_matches) continue; err = got_path_basename(&ct_name, pe->path); if (err) return err; if (strcmp(te->name, ct_name) != 0) { free(ct_name); continue; } free(ct_name); *ctp = ct; break; } return err; } static const struct got_error * make_subtree_for_added_blob(struct got_tree_entry **new_tep, const char *child_path, const char *path_base_tree, struct got_pathlist_head *commitable_paths, got_worktree_status_cb status_cb, void *status_arg, struct got_repository *repo) { const struct got_error *err = NULL; struct got_tree_entry *new_te; char *subtree_path; struct got_object_id *id = NULL; int nentries; *new_tep = NULL; if (asprintf(&subtree_path, "%s%s%s", path_base_tree, got_path_is_root_dir(path_base_tree) ? "" : "/", child_path) == -1) return got_error_from_errno("asprintf"); new_te = calloc(1, sizeof(*new_te)); if (new_te == NULL) return got_error_from_errno("calloc"); new_te->mode = S_IFDIR; if (strlcpy(new_te->name, child_path, sizeof(new_te->name)) >= sizeof(new_te->name)) { err = got_error(GOT_ERR_NO_SPACE); goto done; } err = write_tree(&id, &nentries, NULL, subtree_path, commitable_paths, status_cb, status_arg, repo); if (err) { free(new_te); goto done; } memcpy(&new_te->id, id, sizeof(new_te->id)); done: free(id); free(subtree_path); if (err == NULL) *new_tep = new_te; return err; } static const struct got_error * write_tree(struct got_object_id **new_tree_id, int *nentries, struct got_tree_object *base_tree, const char *path_base_tree, struct got_pathlist_head *commitable_paths, got_worktree_status_cb status_cb, void *status_arg, struct got_repository *repo) { const struct got_error *err = NULL; struct got_pathlist_head paths; struct got_tree_entry *te, *new_te = NULL; struct got_pathlist_entry *pe; TAILQ_INIT(&paths); *nentries = 0; /* Insert, and recurse into, newly added entries first. */ TAILQ_FOREACH(pe, commitable_paths, entry) { struct got_commitable *ct = pe->data; char *child_path = NULL, *slash; if ((ct->status != GOT_STATUS_ADD && ct->staged_status != GOT_STATUS_ADD) || (ct->flags & GOT_COMMITABLE_ADDED)) continue; if (!got_path_is_child(ct->in_repo_path, path_base_tree, strlen(path_base_tree))) continue; err = got_path_skip_common_ancestor(&child_path, path_base_tree, ct->in_repo_path); if (err) goto done; slash = strchr(child_path, '/'); if (slash == NULL) { err = alloc_added_blob_tree_entry(&new_te, ct); if (err) goto done; err = report_ct_status(ct, status_cb, status_arg); if (err) goto done; ct->flags |= GOT_COMMITABLE_ADDED; err = insert_tree_entry(new_te, &paths); if (err) goto done; (*nentries)++; } else { *slash = '\0'; /* trim trailing path components */ if (base_tree == NULL || got_object_tree_find_entry(base_tree, child_path) == NULL) { err = make_subtree_for_added_blob(&new_te, child_path, path_base_tree, commitable_paths, status_cb, status_arg, repo); if (err) goto done; err = insert_tree_entry(new_te, &paths); if (err) goto done; (*nentries)++; } } } if (base_tree) { int i, nbase_entries; /* Handle modified and deleted entries. */ nbase_entries = got_object_tree_get_nentries(base_tree); for (i = 0; i < nbase_entries; i++) { struct got_commitable *ct = NULL; te = got_object_tree_get_entry(base_tree, i); if (got_object_tree_entry_is_submodule(te)) { /* Entry is a submodule; just copy it. */ err = got_object_tree_entry_dup(&new_te, te); if (err) goto done; err = insert_tree_entry(new_te, &paths); if (err) goto done; (*nentries)++; continue; } if (S_ISDIR(te->mode)) { int modified; err = got_object_tree_entry_dup(&new_te, te); if (err) goto done; err = match_modified_subtree(&modified, te, path_base_tree, commitable_paths); if (err) goto done; /* Avoid recursion into unmodified subtrees. */ if (modified) { struct got_object_id *new_id; int nsubentries; err = write_subtree(&new_id, &nsubentries, te, path_base_tree, commitable_paths, status_cb, status_arg, repo); if (err) goto done; if (nsubentries == 0) { /* All entries were deleted. */ free(new_id); continue; } memcpy(&new_te->id, new_id, sizeof(new_te->id)); free(new_id); } err = insert_tree_entry(new_te, &paths); if (err) goto done; (*nentries)++; continue; } err = match_deleted_or_modified_ct(&ct, te, path_base_tree, commitable_paths); if (err) goto done; if (ct) { /* NB: Deleted entries get dropped here. */ if (ct->status == GOT_STATUS_MODIFY || ct->status == GOT_STATUS_MODE_CHANGE || ct->status == GOT_STATUS_CONFLICT || ct->staged_status == GOT_STATUS_MODIFY) { err = alloc_modified_blob_tree_entry( &new_te, te, ct); if (err) goto done; err = insert_tree_entry(new_te, &paths); if (err) goto done; (*nentries)++; } err = report_ct_status(ct, status_cb, status_arg); if (err) goto done; } else { /* Entry is unchanged; just copy it. */ err = got_object_tree_entry_dup(&new_te, te); if (err) goto done; err = insert_tree_entry(new_te, &paths); if (err) goto done; (*nentries)++; } } } /* Write new list of entries; deleted entries have been dropped. */ err = got_object_tree_create(new_tree_id, &paths, *nentries, repo); done: got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE); return err; } static const struct got_error * update_fileindex_after_commit(struct got_worktree *worktree, struct got_pathlist_head *commitable_paths, struct got_object_id *new_base_commit_id, struct got_fileindex *fileindex, int have_staged_files) { const struct got_error *err = NULL; struct got_pathlist_entry *pe; char *relpath = NULL; TAILQ_FOREACH(pe, commitable_paths, entry) { struct got_fileindex_entry *ie; struct got_commitable *ct = pe->data; ie = got_fileindex_entry_get(fileindex, pe->path, pe->path_len); err = got_path_skip_common_ancestor(&relpath, worktree->root_path, ct->ondisk_path); if (err) goto done; if (ie) { if (ct->status == GOT_STATUS_DELETE || ct->staged_status == GOT_STATUS_DELETE) { got_fileindex_entry_remove(fileindex, ie); } else if (ct->staged_status == GOT_STATUS_ADD || ct->staged_status == GOT_STATUS_MODIFY) { got_fileindex_entry_stage_set(ie, GOT_FILEIDX_STAGE_NONE); got_fileindex_entry_staged_filetype_set(ie, 0); err = got_fileindex_entry_update(ie, worktree->root_fd, relpath, ct->staged_blob_id->sha1, new_base_commit_id->sha1, !have_staged_files); } else err = got_fileindex_entry_update(ie, worktree->root_fd, relpath, ct->blob_id->sha1, new_base_commit_id->sha1, !have_staged_files); } else { err = got_fileindex_entry_alloc(&ie, pe->path); if (err) goto done; err = got_fileindex_entry_update(ie, worktree->root_fd, relpath, ct->blob_id->sha1, new_base_commit_id->sha1, 1); if (err) { got_fileindex_entry_free(ie); goto done; } err = got_fileindex_entry_add(fileindex, ie); if (err) { got_fileindex_entry_free(ie); goto done; } } free(relpath); relpath = NULL; } done: free(relpath); return err; } static const struct got_error * check_out_of_date(const char *in_repo_path, unsigned char status, unsigned char staged_status, struct got_object_id *base_blob_id, struct got_object_id *base_commit_id, struct got_object_id *head_commit_id, struct got_repository *repo, int ood_errcode) { const struct got_error *err = NULL; struct got_commit_object *commit = NULL; struct got_object_id *id = NULL; if (status != GOT_STATUS_ADD && staged_status != GOT_STATUS_ADD) { /* Trivial case: base commit == head commit */ if (got_object_id_cmp(base_commit_id, head_commit_id) == 0) return NULL; /* * Ensure file content which local changes were based * on matches file content in the branch head. */ err = got_object_open_as_commit(&commit, repo, head_commit_id); if (err) goto done; err = got_object_id_by_path(&id, repo, commit, in_repo_path); if (err) { if (err->code == GOT_ERR_NO_TREE_ENTRY) err = got_error(ood_errcode); goto done; } else if (got_object_id_cmp(id, base_blob_id) != 0) err = got_error(ood_errcode); } else { /* Require that added files don't exist in the branch head. */ err = got_object_open_as_commit(&commit, repo, head_commit_id); if (err) goto done; err = got_object_id_by_path(&id, repo, commit, in_repo_path); if (err && err->code != GOT_ERR_NO_TREE_ENTRY) goto done; err = id ? got_error(ood_errcode) : NULL; } done: free(id); if (commit) got_object_commit_close(commit); return err; } static const struct got_error * commit_worktree(struct got_object_id **new_commit_id, struct got_pathlist_head *commitable_paths, struct got_object_id *head_commit_id, struct got_object_id *parent_id2, struct got_worktree *worktree, const char *author, const char *committer, char *diff_path, got_worktree_commit_msg_cb commit_msg_cb, void *commit_arg, got_worktree_status_cb status_cb, void *status_arg, struct got_repository *repo) { const struct got_error *err = NULL, *unlockerr = NULL; struct got_pathlist_entry *pe; const char *head_ref_name = NULL; struct got_commit_object *head_commit = NULL; struct got_reference *head_ref2 = NULL; struct got_object_id *head_commit_id2 = NULL; struct got_tree_object *head_tree = NULL; struct got_object_id *new_tree_id = NULL; int nentries, nparents = 0; struct got_object_id_queue parent_ids; struct got_object_qid *pid = NULL; char *logmsg = NULL; time_t timestamp; *new_commit_id = NULL; STAILQ_INIT(&parent_ids); err = got_object_open_as_commit(&head_commit, repo, head_commit_id); if (err) goto done; err = got_object_open_as_tree(&head_tree, repo, head_commit->tree_id); if (err) goto done; if (commit_msg_cb != NULL) { err = commit_msg_cb(commitable_paths, diff_path, &logmsg, commit_arg); if (err) goto done; } if (logmsg == NULL || strlen(logmsg) == 0) { err = got_error(GOT_ERR_COMMIT_MSG_EMPTY); goto done; } /* Create blobs from added and modified files and record their IDs. */ TAILQ_FOREACH(pe, commitable_paths, entry) { struct got_commitable *ct = pe->data; char *ondisk_path; /* Blobs for staged files already exist. */ if (ct->staged_status == GOT_STATUS_ADD || ct->staged_status == GOT_STATUS_MODIFY) continue; if (ct->status != GOT_STATUS_ADD && ct->status != GOT_STATUS_MODIFY && ct->status != GOT_STATUS_MODE_CHANGE && ct->status != GOT_STATUS_CONFLICT) continue; if (asprintf(&ondisk_path, "%s/%s", worktree->root_path, pe->path) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_object_blob_create(&ct->blob_id, ondisk_path, repo); free(ondisk_path); if (err) goto done; } /* Recursively write new tree objects. */ err = write_tree(&new_tree_id, &nentries, head_tree, "/", commitable_paths, status_cb, status_arg, repo); if (err) goto done; err = got_object_qid_alloc(&pid, head_commit_id); if (err) goto done; STAILQ_INSERT_TAIL(&parent_ids, pid, entry); nparents++; if (parent_id2) { err = got_object_qid_alloc(&pid, parent_id2); if (err) goto done; STAILQ_INSERT_TAIL(&parent_ids, pid, entry); nparents++; } timestamp = time(NULL); err = got_object_commit_create(new_commit_id, new_tree_id, &parent_ids, nparents, author, timestamp, committer, timestamp, logmsg, repo); if (logmsg != NULL) free(logmsg); if (err) goto done; /* Check if a concurrent commit to our branch has occurred. */ head_ref_name = got_worktree_get_head_ref_name(worktree); if (head_ref_name == NULL) { err = got_error_from_errno("got_worktree_get_head_ref_name"); goto done; } /* Lock the reference here to prevent concurrent modification. */ err = got_ref_open(&head_ref2, repo, head_ref_name, 1); if (err) goto done; err = got_ref_resolve(&head_commit_id2, repo, head_ref2); if (err) goto done; if (got_object_id_cmp(head_commit_id, head_commit_id2) != 0) { err = got_error(GOT_ERR_COMMIT_HEAD_CHANGED); goto done; } /* Update branch head in repository. */ err = got_ref_change_ref(head_ref2, *new_commit_id); if (err) goto done; err = got_ref_write(head_ref2, repo); if (err) goto done; err = got_worktree_set_base_commit_id(worktree, repo, *new_commit_id); if (err) goto done; err = ref_base_commit(worktree, repo); if (err) goto done; done: got_object_id_queue_free(&parent_ids); if (head_tree) got_object_tree_close(head_tree); if (head_commit) got_object_commit_close(head_commit); free(head_commit_id2); if (head_ref2) { unlockerr = got_ref_unlock(head_ref2); if (unlockerr && err == NULL) err = unlockerr; got_ref_close(head_ref2); } return err; } static const struct got_error * check_path_is_commitable(const char *path, struct got_pathlist_head *commitable_paths) { struct got_pathlist_entry *cpe = NULL; size_t path_len = strlen(path); TAILQ_FOREACH(cpe, commitable_paths, entry) { struct got_commitable *ct = cpe->data; const char *ct_path = ct->path; while (ct_path[0] == '/') ct_path++; if (strcmp(path, ct_path) == 0 || got_path_is_child(ct_path, path, path_len)) break; } if (cpe == NULL) return got_error_path(path, GOT_ERR_COMMIT_NO_CHANGES); return NULL; } static const struct got_error * check_staged_file(void *arg, struct got_fileindex_entry *ie) { int *have_staged_files = arg; if (got_fileindex_entry_stage_get(ie) != GOT_FILEIDX_STAGE_NONE) { *have_staged_files = 1; return got_error(GOT_ERR_CANCELLED); } return NULL; } static const struct got_error * check_non_staged_files(struct got_fileindex *fileindex, struct got_pathlist_head *paths) { struct got_pathlist_entry *pe; struct got_fileindex_entry *ie; TAILQ_FOREACH(pe, paths, entry) { if (pe->path[0] == '\0') continue; ie = got_fileindex_entry_get(fileindex, pe->path, pe->path_len); if (ie == NULL) return got_error_path(pe->path, GOT_ERR_BAD_PATH); if (got_fileindex_entry_stage_get(ie) == GOT_FILEIDX_STAGE_NONE) return got_error_path(pe->path, GOT_ERR_FILE_NOT_STAGED); } return NULL; } const struct got_error * got_worktree_commit(struct got_object_id **new_commit_id, struct got_worktree *worktree, struct got_pathlist_head *paths, const char *author, const char *committer, int allow_bad_symlinks, int show_diff, int commit_conflicts, got_worktree_commit_msg_cb commit_msg_cb, void *commit_arg, got_worktree_status_cb status_cb, void *status_arg, struct got_repository *repo) { const struct got_error *err = NULL, *unlockerr = NULL, *sync_err; struct got_fileindex *fileindex = NULL; char *fileindex_path = NULL; struct got_pathlist_head commitable_paths; struct collect_commitables_arg cc_arg; struct got_pathlist_entry *pe; struct got_reference *head_ref = NULL; struct got_object_id *head_commit_id = NULL; char *diff_path = NULL; int have_staged_files = 0; *new_commit_id = NULL; memset(&cc_arg, 0, sizeof(cc_arg)); TAILQ_INIT(&commitable_paths); err = lock_worktree(worktree, LOCK_EX); if (err) goto done; err = got_ref_open(&head_ref, repo, worktree->head_ref_name, 0); if (err) goto done; err = got_ref_resolve(&head_commit_id, repo, head_ref); if (err) goto done; err = open_fileindex(&fileindex, &fileindex_path, worktree); if (err) goto done; err = got_fileindex_for_each_entry_safe(fileindex, check_staged_file, &have_staged_files); if (err && err->code != GOT_ERR_CANCELLED) goto done; if (have_staged_files) { err = check_non_staged_files(fileindex, paths); if (err) goto done; } cc_arg.commitable_paths = &commitable_paths; cc_arg.worktree = worktree; cc_arg.fileindex = fileindex; cc_arg.repo = repo; cc_arg.have_staged_files = have_staged_files; cc_arg.allow_bad_symlinks = allow_bad_symlinks; cc_arg.diff_header_shown = 0; cc_arg.commit_conflicts = commit_conflicts; if (show_diff) { err = got_opentemp_named(&diff_path, &cc_arg.diff_outfile, GOT_TMPDIR_STR "/got", ".diff"); if (err) goto done; cc_arg.f1 = got_opentemp(); if (cc_arg.f1 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } cc_arg.f2 = got_opentemp(); if (cc_arg.f2 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } } TAILQ_FOREACH(pe, paths, entry) { err = worktree_status(worktree, pe->path, fileindex, repo, collect_commitables, &cc_arg, NULL, NULL, 0, 0); if (err) goto done; } if (show_diff) { if (fflush(cc_arg.diff_outfile) == EOF) { err = got_error_from_errno("fflush"); goto done; } } if (TAILQ_EMPTY(&commitable_paths)) { err = got_error(GOT_ERR_COMMIT_NO_CHANGES); goto done; } TAILQ_FOREACH(pe, paths, entry) { err = check_path_is_commitable(pe->path, &commitable_paths); if (err) goto done; } TAILQ_FOREACH(pe, &commitable_paths, entry) { struct got_commitable *ct = pe->data; const char *ct_path = ct->in_repo_path; while (ct_path[0] == '/') ct_path++; err = check_out_of_date(ct_path, ct->status, ct->staged_status, ct->base_blob_id, ct->base_commit_id, head_commit_id, repo, GOT_ERR_COMMIT_OUT_OF_DATE); if (err) goto done; } err = commit_worktree(new_commit_id, &commitable_paths, head_commit_id, NULL, worktree, author, committer, (diff_path && cc_arg.diff_header_shown) ? diff_path : NULL, commit_msg_cb, commit_arg, status_cb, status_arg, repo); if (err) goto done; err = update_fileindex_after_commit(worktree, &commitable_paths, *new_commit_id, fileindex, have_staged_files); sync_err = sync_fileindex(fileindex, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: if (fileindex) got_fileindex_free(fileindex); free(fileindex_path); unlockerr = lock_worktree(worktree, LOCK_SH); if (unlockerr && err == NULL) err = unlockerr; TAILQ_FOREACH(pe, &commitable_paths, entry) { struct got_commitable *ct = pe->data; free_commitable(ct); } got_pathlist_free(&commitable_paths, GOT_PATHLIST_FREE_NONE); if (diff_path && unlink(diff_path) == -1 && err == NULL) err = got_error_from_errno2("unlink", diff_path); free(diff_path); if (cc_arg.diff_outfile && fclose(cc_arg.diff_outfile) == EOF && err == NULL) err = got_error_from_errno("fclose"); return err; } const char * got_commitable_get_path(struct got_commitable *ct) { return ct->path; } unsigned int got_commitable_get_status(struct got_commitable *ct) { return ct->status; } struct check_rebase_ok_arg { struct got_worktree *worktree; struct got_repository *repo; }; static const struct got_error * check_rebase_ok(void *arg, struct got_fileindex_entry *ie) { const struct got_error *err = NULL; struct check_rebase_ok_arg *a = arg; unsigned char status; struct stat sb; char *ondisk_path; /* Reject rebase of a work tree with mixed base commits. */ if (memcmp(ie->commit_sha1, a->worktree->base_commit_id->sha1, SHA1_DIGEST_LENGTH)) return got_error(GOT_ERR_MIXED_COMMITS); if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, ie->path) == -1) return got_error_from_errno("asprintf"); /* Reject rebase of a work tree with modified or staged files. */ err = get_file_status(&status, &sb, ie, ondisk_path, -1, NULL, a->repo); free(ondisk_path); if (err) return err; if (status != GOT_STATUS_NO_CHANGE) return got_error(GOT_ERR_MODIFIED); if (get_staged_status(ie) != GOT_STATUS_NO_CHANGE) return got_error_path(ie->path, GOT_ERR_FILE_STAGED); return NULL; } const struct got_error * got_worktree_rebase_prepare(struct got_reference **new_base_branch_ref, struct got_reference **tmp_branch, struct got_fileindex **fileindex, struct got_worktree *worktree, struct got_reference *branch, struct got_repository *repo) { const struct got_error *err = NULL; char *tmp_branch_name = NULL, *new_base_branch_ref_name = NULL; char *branch_ref_name = NULL; char *fileindex_path = NULL; struct check_rebase_ok_arg ok_arg; struct got_reference *wt_branch = NULL, *branch_ref = NULL; struct got_object_id *wt_branch_tip = NULL; *new_base_branch_ref = NULL; *tmp_branch = NULL; *fileindex = NULL; err = lock_worktree(worktree, LOCK_EX); if (err) return err; err = open_fileindex(fileindex, &fileindex_path, worktree); if (err) goto done; ok_arg.worktree = worktree; ok_arg.repo = repo; err = got_fileindex_for_each_entry_safe(*fileindex, check_rebase_ok, &ok_arg); if (err) goto done; err = get_rebase_tmp_ref_name(&tmp_branch_name, worktree); if (err) goto done; err = get_newbase_symref_name(&new_base_branch_ref_name, worktree); if (err) goto done; err = get_rebase_branch_symref_name(&branch_ref_name, worktree); if (err) goto done; err = got_ref_open(&wt_branch, repo, worktree->head_ref_name, 0); if (err) goto done; err = got_ref_resolve(&wt_branch_tip, repo, wt_branch); if (err) goto done; if (got_object_id_cmp(worktree->base_commit_id, wt_branch_tip) != 0) { err = got_error(GOT_ERR_REBASE_OUT_OF_DATE); goto done; } err = got_ref_alloc_symref(new_base_branch_ref, new_base_branch_ref_name, wt_branch); if (err) goto done; err = got_ref_write(*new_base_branch_ref, repo); if (err) goto done; /* TODO Lock original branch's ref while rebasing? */ err = got_ref_alloc_symref(&branch_ref, branch_ref_name, branch); if (err) goto done; err = got_ref_write(branch_ref, repo); if (err) goto done; err = got_ref_alloc(tmp_branch, tmp_branch_name, worktree->base_commit_id); if (err) goto done; err = got_ref_write(*tmp_branch, repo); if (err) goto done; err = got_worktree_set_head_ref(worktree, *tmp_branch); if (err) goto done; done: free(fileindex_path); free(tmp_branch_name); free(new_base_branch_ref_name); free(branch_ref_name); if (branch_ref) got_ref_close(branch_ref); if (wt_branch) got_ref_close(wt_branch); free(wt_branch_tip); if (err) { if (*new_base_branch_ref) { got_ref_close(*new_base_branch_ref); *new_base_branch_ref = NULL; } if (*tmp_branch) { got_ref_close(*tmp_branch); *tmp_branch = NULL; } if (*fileindex) { got_fileindex_free(*fileindex); *fileindex = NULL; } lock_worktree(worktree, LOCK_SH); } return err; } const struct got_error * got_worktree_rebase_continue(struct got_object_id **commit_id, struct got_reference **new_base_branch, struct got_reference **tmp_branch, struct got_reference **branch, struct got_fileindex **fileindex, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; char *commit_ref_name = NULL, *new_base_branch_ref_name = NULL; char *tmp_branch_name = NULL, *branch_ref_name = NULL; struct got_reference *commit_ref = NULL, *branch_ref = NULL; char *fileindex_path = NULL; int have_staged_files = 0; *commit_id = NULL; *new_base_branch = NULL; *tmp_branch = NULL; *branch = NULL; *fileindex = NULL; err = lock_worktree(worktree, LOCK_EX); if (err) return err; err = open_fileindex(fileindex, &fileindex_path, worktree); if (err) goto done; err = got_fileindex_for_each_entry_safe(*fileindex, check_staged_file, &have_staged_files); if (err && err->code != GOT_ERR_CANCELLED) goto done; if (have_staged_files) { err = got_error(GOT_ERR_STAGED_PATHS); goto done; } err = get_rebase_tmp_ref_name(&tmp_branch_name, worktree); if (err) goto done; err = get_rebase_branch_symref_name(&branch_ref_name, worktree); if (err) goto done; err = get_rebase_commit_ref_name(&commit_ref_name, worktree); if (err) goto done; err = get_newbase_symref_name(&new_base_branch_ref_name, worktree); if (err) goto done; err = got_ref_open(&branch_ref, repo, branch_ref_name, 0); if (err) goto done; err = got_ref_open(branch, repo, got_ref_get_symref_target(branch_ref), 0); if (err) goto done; err = got_ref_open(&commit_ref, repo, commit_ref_name, 0); if (err) goto done; err = got_ref_resolve(commit_id, repo, commit_ref); if (err) goto done; err = got_ref_open(new_base_branch, repo, new_base_branch_ref_name, 0); if (err) goto done; err = got_ref_open(tmp_branch, repo, tmp_branch_name, 0); if (err) goto done; done: free(commit_ref_name); free(branch_ref_name); free(fileindex_path); if (commit_ref) got_ref_close(commit_ref); if (branch_ref) got_ref_close(branch_ref); if (err) { free(*commit_id); *commit_id = NULL; if (*tmp_branch) { got_ref_close(*tmp_branch); *tmp_branch = NULL; } if (*new_base_branch) { got_ref_close(*new_base_branch); *new_base_branch = NULL; } if (*branch) { got_ref_close(*branch); *branch = NULL; } if (*fileindex) { got_fileindex_free(*fileindex); *fileindex = NULL; } lock_worktree(worktree, LOCK_SH); } return err; } const struct got_error * got_worktree_rebase_in_progress(int *in_progress, struct got_worktree *worktree) { const struct got_error *err; char *tmp_branch_name = NULL; err = get_rebase_tmp_ref_name(&tmp_branch_name, worktree); if (err) return err; *in_progress = (strcmp(tmp_branch_name, worktree->head_ref_name) == 0); free(tmp_branch_name); return NULL; } const struct got_error * got_worktree_rebase_info(char **new_base_branch_name, char **branch_name, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; char *new_base_branch_ref_name = NULL; char *branch_ref_name = NULL; struct got_reference *branch_ref = NULL, *branch = NULL; struct got_reference *new_base_branch = NULL; *new_base_branch_name = NULL; *branch_name = NULL; err = get_rebase_branch_symref_name(&branch_ref_name, worktree); if (err) goto done; err = get_newbase_symref_name(&new_base_branch_ref_name, worktree); if (err) goto done; err = got_ref_open(&branch_ref, repo, branch_ref_name, 0); if (err) goto done; err = got_ref_open(&branch, repo, got_ref_get_symref_target(branch_ref), 0); if (err) goto done; err = got_ref_open(&new_base_branch, repo, new_base_branch_ref_name, 0); if (err) goto done; if (!got_ref_is_symbolic(new_base_branch)) { err = got_error_fmt(GOT_ERR_BAD_REF_TYPE, "%s is not a symbolic reference", got_ref_get_name(branch_ref)); goto done; } *new_base_branch_name = strdup(got_ref_get_symref_target( new_base_branch)); if (*new_base_branch_name == NULL) { err = got_error_from_errno("strdup"); goto done; } *branch_name = strdup(got_ref_get_name(branch)); if (*branch_name == NULL) { err = got_error_from_errno("strdup"); goto done; } done: free(branch_ref_name); if (branch_ref) got_ref_close(branch_ref); if (new_base_branch) got_ref_close(new_base_branch); if (branch) got_ref_close(branch); return err; } static const struct got_error * collect_rebase_commit_msg(struct got_pathlist_head *commitable_paths, const char *diff_path, char **logmsg, void *arg) { *logmsg = arg; return NULL; } static const struct got_error * rebase_status(void *arg, unsigned char status, unsigned char staged_status, const char *path, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { return NULL; } struct collect_merged_paths_arg { got_worktree_checkout_cb progress_cb; void *progress_arg; struct got_pathlist_head *merged_paths; }; static const struct got_error * collect_merged_paths(void *arg, unsigned char status, const char *path) { const struct got_error *err; struct collect_merged_paths_arg *a = arg; char *p; struct got_pathlist_entry *new; err = (*a->progress_cb)(a->progress_arg, status, path); if (err) return err; if (status != GOT_STATUS_MERGE && status != GOT_STATUS_ADD && status != GOT_STATUS_DELETE && status != GOT_STATUS_CONFLICT) return NULL; p = strdup(path); if (p == NULL) return got_error_from_errno("strdup"); err = got_pathlist_insert(&new, a->merged_paths, p, NULL); if (err || new == NULL) free(p); return err; } static const struct got_error * store_commit_id(const char *commit_ref_name, struct got_object_id *commit_id, int is_rebase, struct got_repository *repo) { const struct got_error *err; struct got_reference *commit_ref = NULL; err = got_ref_open(&commit_ref, repo, commit_ref_name, 0); if (err) { if (err->code != GOT_ERR_NOT_REF) goto done; err = got_ref_alloc(&commit_ref, commit_ref_name, commit_id); if (err) goto done; err = got_ref_write(commit_ref, repo); if (err) goto done; } else if (is_rebase) { struct got_object_id *stored_id; int cmp; err = got_ref_resolve(&stored_id, repo, commit_ref); if (err) goto done; cmp = got_object_id_cmp(commit_id, stored_id); free(stored_id); if (cmp != 0) { err = got_error(GOT_ERR_REBASE_COMMITID); goto done; } } done: if (commit_ref) got_ref_close(commit_ref); return err; } static const struct got_error * rebase_merge_files(struct got_pathlist_head *merged_paths, const char *commit_ref_name, struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_object_id *parent_commit_id, struct got_object_id *commit_id, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err; struct got_reference *commit_ref = NULL; struct collect_merged_paths_arg cmp_arg; char *fileindex_path; /* Work tree is locked/unlocked during rebase preparation/teardown. */ err = get_fileindex_path(&fileindex_path, worktree); if (err) return err; cmp_arg.progress_cb = progress_cb; cmp_arg.progress_arg = progress_arg; cmp_arg.merged_paths = merged_paths; err = merge_files(worktree, fileindex, fileindex_path, parent_commit_id, commit_id, repo, collect_merged_paths, &cmp_arg, cancel_cb, cancel_arg); if (commit_ref) got_ref_close(commit_ref); return err; } const struct got_error * got_worktree_rebase_merge_files(struct got_pathlist_head *merged_paths, struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_object_id *parent_commit_id, struct got_object_id *commit_id, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err; char *commit_ref_name; err = get_rebase_commit_ref_name(&commit_ref_name, worktree); if (err) return err; err = store_commit_id(commit_ref_name, commit_id, 1, repo); if (err) goto done; err = rebase_merge_files(merged_paths, commit_ref_name, worktree, fileindex, parent_commit_id, commit_id, repo, progress_cb, progress_arg, cancel_cb, cancel_arg); done: free(commit_ref_name); return err; } const struct got_error * got_worktree_histedit_merge_files(struct got_pathlist_head *merged_paths, struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_object_id *parent_commit_id, struct got_object_id *commit_id, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err; char *commit_ref_name; err = get_histedit_commit_ref_name(&commit_ref_name, worktree); if (err) return err; err = store_commit_id(commit_ref_name, commit_id, 0, repo); if (err) goto done; err = rebase_merge_files(merged_paths, commit_ref_name, worktree, fileindex, parent_commit_id, commit_id, repo, progress_cb, progress_arg, cancel_cb, cancel_arg); done: free(commit_ref_name); return err; } static const struct got_error * rebase_commit(struct got_object_id **new_commit_id, struct got_pathlist_head *merged_paths, struct got_reference *commit_ref, struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_reference *tmp_branch, const char *committer, struct got_commit_object *orig_commit, const char *new_logmsg, int allow_conflict, struct got_repository *repo) { const struct got_error *err, *sync_err; struct got_pathlist_head commitable_paths; struct collect_commitables_arg cc_arg; char *fileindex_path = NULL; struct got_reference *head_ref = NULL; struct got_object_id *head_commit_id = NULL; char *logmsg = NULL; memset(&cc_arg, 0, sizeof(cc_arg)); TAILQ_INIT(&commitable_paths); *new_commit_id = NULL; /* Work tree is locked/unlocked during rebase preparation/teardown. */ err = get_fileindex_path(&fileindex_path, worktree); if (err) return err; cc_arg.commitable_paths = &commitable_paths; cc_arg.worktree = worktree; cc_arg.repo = repo; cc_arg.have_staged_files = 0; cc_arg.commit_conflicts = allow_conflict; /* * If possible get the status of individual files directly to * avoid crawling the entire work tree once per rebased commit. * * Ideally, merged_paths would contain a list of commitables * we could use so we could skip worktree_status() entirely. * However, we would then need carefully keep track of cumulative * effects of operations such as file additions and deletions * in 'got histedit -f' (folding multiple commits into one), * and this extra complexity is not really worth it. */ if (merged_paths) { struct got_pathlist_entry *pe; TAILQ_FOREACH(pe, merged_paths, entry) { err = worktree_status(worktree, pe->path, fileindex, repo, collect_commitables, &cc_arg, NULL, NULL, 1, 0); if (err) goto done; } } else { err = worktree_status(worktree, "", fileindex, repo, collect_commitables, &cc_arg, NULL, NULL, 1, 0); if (err) goto done; } if (TAILQ_EMPTY(&commitable_paths)) { /* No-op change; commit will be elided. */ err = got_ref_delete(commit_ref, repo); if (err) goto done; err = got_error(GOT_ERR_COMMIT_NO_CHANGES); goto done; } err = got_ref_open(&head_ref, repo, worktree->head_ref_name, 0); if (err) goto done; err = got_ref_resolve(&head_commit_id, repo, head_ref); if (err) goto done; if (new_logmsg) { logmsg = strdup(new_logmsg); if (logmsg == NULL) { err = got_error_from_errno("strdup"); goto done; } } else { err = got_object_commit_get_logmsg(&logmsg, orig_commit); if (err) goto done; } /* NB: commit_worktree will call free(logmsg) */ err = commit_worktree(new_commit_id, &commitable_paths, head_commit_id, NULL, worktree, got_object_commit_get_author(orig_commit), committer ? committer : got_object_commit_get_committer(orig_commit), NULL, collect_rebase_commit_msg, logmsg, rebase_status, NULL, repo); if (err) goto done; err = got_ref_change_ref(tmp_branch, *new_commit_id); if (err) goto done; err = got_ref_delete(commit_ref, repo); if (err) goto done; err = update_fileindex_after_commit(worktree, &commitable_paths, *new_commit_id, fileindex, 0); sync_err = sync_fileindex(fileindex, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: free(fileindex_path); free(head_commit_id); if (head_ref) got_ref_close(head_ref); if (err) { free(*new_commit_id); *new_commit_id = NULL; } return err; } const struct got_error * got_worktree_rebase_commit(struct got_object_id **new_commit_id, struct got_pathlist_head *merged_paths, struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_reference *tmp_branch, const char *committer, struct got_commit_object *orig_commit, struct got_object_id *orig_commit_id, int allow_conflict, struct got_repository *repo) { const struct got_error *err; char *commit_ref_name; struct got_reference *commit_ref = NULL; struct got_object_id *commit_id = NULL; err = get_rebase_commit_ref_name(&commit_ref_name, worktree); if (err) return err; err = got_ref_open(&commit_ref, repo, commit_ref_name, 0); if (err) goto done; err = got_ref_resolve(&commit_id, repo, commit_ref); if (err) goto done; if (got_object_id_cmp(commit_id, orig_commit_id) != 0) { err = got_error(GOT_ERR_REBASE_COMMITID); goto done; } err = rebase_commit(new_commit_id, merged_paths, commit_ref, worktree, fileindex, tmp_branch, committer, orig_commit, NULL, allow_conflict, repo); done: if (commit_ref) got_ref_close(commit_ref); free(commit_ref_name); free(commit_id); return err; } const struct got_error * got_worktree_histedit_commit(struct got_object_id **new_commit_id, struct got_pathlist_head *merged_paths, struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_reference *tmp_branch, const char *committer, struct got_commit_object *orig_commit, struct got_object_id *orig_commit_id, const char *new_logmsg, int allow_conflict, struct got_repository *repo) { const struct got_error *err; char *commit_ref_name; struct got_reference *commit_ref = NULL; err = get_histedit_commit_ref_name(&commit_ref_name, worktree); if (err) return err; err = got_ref_open(&commit_ref, repo, commit_ref_name, 0); if (err) goto done; err = rebase_commit(new_commit_id, merged_paths, commit_ref, worktree, fileindex, tmp_branch, committer, orig_commit, new_logmsg, allow_conflict, repo); done: if (commit_ref) got_ref_close(commit_ref); free(commit_ref_name); return err; } const struct got_error * got_worktree_rebase_postpone(struct got_worktree *worktree, struct got_fileindex *fileindex) { if (fileindex) got_fileindex_free(fileindex); return lock_worktree(worktree, LOCK_SH); } static const struct got_error * delete_ref(const char *name, struct got_repository *repo) { const struct got_error *err; struct got_reference *ref; err = got_ref_open(&ref, repo, name, 0); if (err) { if (err->code == GOT_ERR_NOT_REF) return NULL; return err; } err = got_ref_delete(ref, repo); got_ref_close(ref); return err; } static const struct got_error * delete_rebase_refs(struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; char *tmp_branch_name = NULL, *new_base_branch_ref_name = NULL; char *branch_ref_name = NULL, *commit_ref_name = NULL; err = get_rebase_tmp_ref_name(&tmp_branch_name, worktree); if (err) goto done; err = delete_ref(tmp_branch_name, repo); if (err) goto done; err = get_newbase_symref_name(&new_base_branch_ref_name, worktree); if (err) goto done; err = delete_ref(new_base_branch_ref_name, repo); if (err) goto done; err = get_rebase_branch_symref_name(&branch_ref_name, worktree); if (err) goto done; err = delete_ref(branch_ref_name, repo); if (err) goto done; err = get_rebase_commit_ref_name(&commit_ref_name, worktree); if (err) goto done; err = delete_ref(commit_ref_name, repo); if (err) goto done; done: free(tmp_branch_name); free(new_base_branch_ref_name); free(branch_ref_name); free(commit_ref_name); return err; } static const struct got_error * create_backup_ref(const char *backup_ref_prefix, struct got_reference *branch, struct got_object_id *new_commit_id, struct got_repository *repo) { const struct got_error *err; struct got_reference *ref = NULL; struct got_object_id *old_commit_id = NULL; const char *branch_name = NULL; char *new_id_str = NULL; char *refname = NULL; branch_name = got_ref_get_name(branch); if (strncmp(branch_name, "refs/heads/", 11) != 0) return got_error(GOT_ERR_BAD_REF_NAME); /* should not happen */ branch_name += 11; err = got_object_id_str(&new_id_str, new_commit_id); if (err) return err; if (asprintf(&refname, "%s/%s/%s", backup_ref_prefix, branch_name, new_id_str) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_ref_resolve(&old_commit_id, repo, branch); if (err) goto done; err = got_ref_alloc(&ref, refname, old_commit_id); if (err) goto done; err = got_ref_write(ref, repo); done: free(new_id_str); free(refname); free(old_commit_id); if (ref) got_ref_close(ref); return err; } const struct got_error * got_worktree_rebase_complete(struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_reference *tmp_branch, struct got_reference *rebased_branch, struct got_repository *repo, int create_backup) { const struct got_error *err, *unlockerr, *sync_err; struct got_object_id *new_head_commit_id = NULL; char *fileindex_path = NULL; err = got_ref_resolve(&new_head_commit_id, repo, tmp_branch); if (err) return err; if (create_backup) { err = create_backup_ref(GOT_WORKTREE_REBASE_BACKUP_REF_PREFIX, rebased_branch, new_head_commit_id, repo); if (err) goto done; } err = got_ref_change_ref(rebased_branch, new_head_commit_id); if (err) goto done; err = got_ref_write(rebased_branch, repo); if (err) goto done; err = got_worktree_set_head_ref(worktree, rebased_branch); if (err) goto done; err = delete_rebase_refs(worktree, repo); if (err) goto done; err = get_fileindex_path(&fileindex_path, worktree); if (err) goto done; err = bump_base_commit_id_everywhere(worktree, fileindex, NULL, NULL); sync_err = sync_fileindex(fileindex, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: got_fileindex_free(fileindex); free(fileindex_path); free(new_head_commit_id); unlockerr = lock_worktree(worktree, LOCK_SH); if (unlockerr && err == NULL) err = unlockerr; return err; } static const struct got_error * get_paths_changed_between_commits(struct got_pathlist_head *paths, struct got_object_id *id1, struct got_object_id *id2, struct got_repository *repo) { const struct got_error *err; struct got_commit_object *commit1 = NULL, *commit2 = NULL; struct got_tree_object *tree1 = NULL, *tree2 = NULL; if (id1) { err = got_object_open_as_commit(&commit1, repo, id1); if (err) goto done; err = got_object_open_as_tree(&tree1, repo, got_object_commit_get_tree_id(commit1)); if (err) goto done; } if (id2) { err = got_object_open_as_commit(&commit2, repo, id2); if (err) goto done; err = got_object_open_as_tree(&tree2, repo, got_object_commit_get_tree_id(commit2)); if (err) goto done; } err = got_diff_tree(tree1, tree2, NULL, NULL, -1, -1, "", "", repo, got_diff_tree_collect_changed_paths, paths, 0); if (err) goto done; done: if (commit1) got_object_commit_close(commit1); if (commit2) got_object_commit_close(commit2); if (tree1) got_object_tree_close(tree1); if (tree2) got_object_tree_close(tree2); return err; } static const struct got_error * get_paths_added_between_commits(struct got_pathlist_head *added_paths, struct got_object_id *id1, struct got_object_id *id2, const char *path_prefix, struct got_repository *repo) { const struct got_error *err; struct got_pathlist_head merged_paths; struct got_pathlist_entry *pe; char *abspath = NULL, *wt_path = NULL; TAILQ_INIT(&merged_paths); err = get_paths_changed_between_commits(&merged_paths, id1, id2, repo); if (err) goto done; TAILQ_FOREACH(pe, &merged_paths, entry) { struct got_diff_changed_path *change = pe->data; if (change->status != GOT_STATUS_ADD) continue; if (got_path_is_root_dir(path_prefix)) { wt_path = strdup(pe->path); if (wt_path == NULL) { err = got_error_from_errno("strdup"); goto done; } } else { if (asprintf(&abspath, "/%s", pe->path) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_path_skip_common_ancestor(&wt_path, path_prefix, abspath); if (err) goto done; free(abspath); abspath = NULL; } err = got_pathlist_append(added_paths, wt_path, NULL); if (err) goto done; wt_path = NULL; } done: got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_ALL); free(abspath); free(wt_path); return err; } static const struct got_error * get_paths_added_in_commit(struct got_pathlist_head *added_paths, struct got_object_id *id, const char *path_prefix, struct got_repository *repo) { const struct got_error *err; struct got_commit_object *commit = NULL; struct got_object_qid *pid; err = got_object_open_as_commit(&commit, repo, id); if (err) goto done; pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); err = get_paths_added_between_commits(added_paths, pid ? &pid->id : NULL, id, path_prefix, repo); if (err) goto done; done: if (commit) got_object_commit_close(commit); return err; } const struct got_error * got_worktree_rebase_abort(struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_repository *repo, struct got_reference *new_base_branch, got_worktree_checkout_cb progress_cb, void *progress_arg) { const struct got_error *err, *unlockerr, *sync_err; struct got_reference *resolved = NULL; struct got_object_id *commit_id = NULL; struct got_object_id *merged_commit_id = NULL; struct got_commit_object *commit = NULL; char *fileindex_path = NULL; char *commit_ref_name = NULL; struct got_reference *commit_ref = NULL; struct revert_file_args rfa; struct got_object_id *tree_id = NULL; struct got_pathlist_head added_paths; TAILQ_INIT(&added_paths); err = lock_worktree(worktree, LOCK_EX); if (err) return err; err = get_rebase_commit_ref_name(&commit_ref_name, worktree); if (err) goto done; err = got_ref_open(&commit_ref, repo, commit_ref_name, 0); if (err) goto done; err = got_ref_resolve(&merged_commit_id, repo, commit_ref); if (err) goto done; /* * Determine which files in added status can be safely removed * from disk while reverting changes in the work tree. * We want to avoid deleting unrelated files which were added by * the user for conflict resolution purposes. */ err = get_paths_added_in_commit(&added_paths, merged_commit_id, got_worktree_get_path_prefix(worktree), repo); if (err) goto done; err = got_ref_open(&resolved, repo, got_ref_get_symref_target(new_base_branch), 0); if (err) goto done; err = got_worktree_set_head_ref(worktree, resolved); if (err) goto done; /* * XXX commits to the base branch could have happened while * we were busy rebasing; should we store the original commit ID * when rebase begins and read it back here? */ err = got_ref_resolve(&commit_id, repo, resolved); if (err) goto done; err = got_worktree_set_base_commit_id(worktree, repo, commit_id); if (err) goto done; err = got_object_open_as_commit(&commit, repo, worktree->base_commit_id); if (err) goto done; err = got_object_id_by_path(&tree_id, repo, commit, worktree->path_prefix); if (err) goto done; err = delete_rebase_refs(worktree, repo); if (err) goto done; err = get_fileindex_path(&fileindex_path, worktree); if (err) goto done; rfa.worktree = worktree; rfa.fileindex = fileindex; rfa.progress_cb = progress_cb; rfa.progress_arg = progress_arg; rfa.patch_cb = NULL; rfa.patch_arg = NULL; rfa.repo = repo; rfa.unlink_added_files = 1; rfa.added_files_to_unlink = &added_paths; err = worktree_status(worktree, "", fileindex, repo, revert_file, &rfa, NULL, NULL, 1, 0); if (err) goto sync; err = checkout_files(worktree, fileindex, "", tree_id, NULL, repo, progress_cb, progress_arg, NULL, NULL); sync: sync_err = sync_fileindex(fileindex, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: got_pathlist_free(&added_paths, GOT_PATHLIST_FREE_PATH); got_ref_close(resolved); free(tree_id); free(commit_id); free(merged_commit_id); if (commit) got_object_commit_close(commit); if (fileindex) got_fileindex_free(fileindex); free(fileindex_path); free(commit_ref_name); if (commit_ref) got_ref_close(commit_ref); unlockerr = lock_worktree(worktree, LOCK_SH); if (unlockerr && err == NULL) err = unlockerr; return err; } const struct got_error * got_worktree_histedit_prepare(struct got_reference **tmp_branch, struct got_reference **branch_ref, struct got_object_id **base_commit_id, struct got_fileindex **fileindex, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err = NULL; char *tmp_branch_name = NULL; char *branch_ref_name = NULL; char *base_commit_ref_name = NULL; char *fileindex_path = NULL; struct check_rebase_ok_arg ok_arg; struct got_reference *wt_branch = NULL; struct got_reference *base_commit_ref = NULL; *tmp_branch = NULL; *branch_ref = NULL; *base_commit_id = NULL; *fileindex = NULL; err = lock_worktree(worktree, LOCK_EX); if (err) return err; err = open_fileindex(fileindex, &fileindex_path, worktree); if (err) goto done; ok_arg.worktree = worktree; ok_arg.repo = repo; err = got_fileindex_for_each_entry_safe(*fileindex, check_rebase_ok, &ok_arg); if (err) goto done; err = get_histedit_tmp_ref_name(&tmp_branch_name, worktree); if (err) goto done; err = get_histedit_branch_symref_name(&branch_ref_name, worktree); if (err) goto done; err = get_histedit_base_commit_ref_name(&base_commit_ref_name, worktree); if (err) goto done; err = got_ref_open(&wt_branch, repo, worktree->head_ref_name, 0); if (err) goto done; err = got_ref_alloc_symref(branch_ref, branch_ref_name, wt_branch); if (err) goto done; err = got_ref_write(*branch_ref, repo); if (err) goto done; err = got_ref_alloc(&base_commit_ref, base_commit_ref_name, worktree->base_commit_id); if (err) goto done; err = got_ref_write(base_commit_ref, repo); if (err) goto done; *base_commit_id = got_object_id_dup(worktree->base_commit_id); if (*base_commit_id == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } err = got_ref_alloc(tmp_branch, tmp_branch_name, worktree->base_commit_id); if (err) goto done; err = got_ref_write(*tmp_branch, repo); if (err) goto done; err = got_worktree_set_head_ref(worktree, *tmp_branch); if (err) goto done; done: free(fileindex_path); free(tmp_branch_name); free(branch_ref_name); free(base_commit_ref_name); if (wt_branch) got_ref_close(wt_branch); if (err) { if (*branch_ref) { got_ref_close(*branch_ref); *branch_ref = NULL; } if (*tmp_branch) { got_ref_close(*tmp_branch); *tmp_branch = NULL; } free(*base_commit_id); if (*fileindex) { got_fileindex_free(*fileindex); *fileindex = NULL; } lock_worktree(worktree, LOCK_SH); } return err; } const struct got_error * got_worktree_histedit_postpone(struct got_worktree *worktree, struct got_fileindex *fileindex) { if (fileindex) got_fileindex_free(fileindex); return lock_worktree(worktree, LOCK_SH); } const struct got_error * got_worktree_histedit_in_progress(int *in_progress, struct got_worktree *worktree) { const struct got_error *err; char *tmp_branch_name = NULL; err = get_histedit_tmp_ref_name(&tmp_branch_name, worktree); if (err) return err; *in_progress = (strcmp(tmp_branch_name, worktree->head_ref_name) == 0); free(tmp_branch_name); return NULL; } const struct got_error * got_worktree_histedit_continue(struct got_object_id **commit_id, struct got_reference **tmp_branch, struct got_reference **branch_ref, struct got_object_id **base_commit_id, struct got_fileindex **fileindex, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; char *commit_ref_name = NULL, *base_commit_ref_name = NULL; char *tmp_branch_name = NULL, *branch_ref_name = NULL; struct got_reference *commit_ref = NULL; struct got_reference *base_commit_ref = NULL; char *fileindex_path = NULL; int have_staged_files = 0; *commit_id = NULL; *tmp_branch = NULL; *branch_ref = NULL; *base_commit_id = NULL; *fileindex = NULL; err = lock_worktree(worktree, LOCK_EX); if (err) return err; err = open_fileindex(fileindex, &fileindex_path, worktree); if (err) goto done; err = got_fileindex_for_each_entry_safe(*fileindex, check_staged_file, &have_staged_files); if (err && err->code != GOT_ERR_CANCELLED) goto done; if (have_staged_files) { err = got_error(GOT_ERR_STAGED_PATHS); goto done; } err = get_histedit_tmp_ref_name(&tmp_branch_name, worktree); if (err) goto done; err = get_histedit_branch_symref_name(&branch_ref_name, worktree); if (err) goto done; err = get_histedit_commit_ref_name(&commit_ref_name, worktree); if (err) goto done; err = get_histedit_base_commit_ref_name(&base_commit_ref_name, worktree); if (err) goto done; err = got_ref_open(branch_ref, repo, branch_ref_name, 0); if (err) goto done; err = got_ref_open(&commit_ref, repo, commit_ref_name, 0); if (err) goto done; err = got_ref_resolve(commit_id, repo, commit_ref); if (err) goto done; err = got_ref_open(&base_commit_ref, repo, base_commit_ref_name, 0); if (err) goto done; err = got_ref_resolve(base_commit_id, repo, base_commit_ref); if (err) goto done; err = got_ref_open(tmp_branch, repo, tmp_branch_name, 0); if (err) goto done; done: free(commit_ref_name); free(branch_ref_name); free(fileindex_path); if (commit_ref) got_ref_close(commit_ref); if (base_commit_ref) got_ref_close(base_commit_ref); if (err) { free(*commit_id); *commit_id = NULL; free(*base_commit_id); *base_commit_id = NULL; if (*tmp_branch) { got_ref_close(*tmp_branch); *tmp_branch = NULL; } if (*branch_ref) { got_ref_close(*branch_ref); *branch_ref = NULL; } if (*fileindex) { got_fileindex_free(*fileindex); *fileindex = NULL; } lock_worktree(worktree, LOCK_EX); } return err; } const struct got_error * got_worktree_histedit_info(char **branch_name, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; struct got_reference *branch_ref = NULL; char *branch_ref_name = NULL; *branch_name = NULL; err = get_histedit_branch_symref_name(&branch_ref_name, worktree); if (err) goto done; err = got_ref_open(&branch_ref, repo, branch_ref_name, 0); if (err) goto done; if (!got_ref_is_symbolic(branch_ref)) { err = got_error_fmt(GOT_ERR_BAD_REF_TYPE, "%s is not a symbolic reference", got_ref_get_name(branch_ref)); goto done; } *branch_name = strdup(got_ref_get_symref_target(branch_ref)); if (*branch_name == NULL) { err = got_error_from_errno("strdup"); goto done; } done: free(branch_ref_name); if (branch_ref) got_ref_close(branch_ref); if (err) { free(*branch_name); *branch_name = NULL; } return err; } static const struct got_error * delete_histedit_refs(struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; char *tmp_branch_name = NULL, *base_commit_ref_name = NULL; char *branch_ref_name = NULL, *commit_ref_name = NULL; err = get_histedit_tmp_ref_name(&tmp_branch_name, worktree); if (err) goto done; err = delete_ref(tmp_branch_name, repo); if (err) goto done; err = get_histedit_base_commit_ref_name(&base_commit_ref_name, worktree); if (err) goto done; err = delete_ref(base_commit_ref_name, repo); if (err) goto done; err = get_histedit_branch_symref_name(&branch_ref_name, worktree); if (err) goto done; err = delete_ref(branch_ref_name, repo); if (err) goto done; err = get_histedit_commit_ref_name(&commit_ref_name, worktree); if (err) goto done; err = delete_ref(commit_ref_name, repo); if (err) goto done; done: free(tmp_branch_name); free(base_commit_ref_name); free(branch_ref_name); free(commit_ref_name); return err; } const struct got_error * got_worktree_histedit_abort(struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_repository *repo, struct got_reference *branch, struct got_object_id *base_commit_id, got_worktree_checkout_cb progress_cb, void *progress_arg) { const struct got_error *err, *unlockerr, *sync_err; struct got_reference *resolved = NULL; char *fileindex_path = NULL; struct got_object_id *merged_commit_id = NULL; struct got_commit_object *commit = NULL; char *commit_ref_name = NULL; struct got_reference *commit_ref = NULL; struct got_object_id *tree_id = NULL; struct revert_file_args rfa; struct got_pathlist_head added_paths; TAILQ_INIT(&added_paths); err = lock_worktree(worktree, LOCK_EX); if (err) return err; err = get_histedit_commit_ref_name(&commit_ref_name, worktree); if (err) goto done; err = got_ref_open(&commit_ref, repo, commit_ref_name, 0); if (err) { if (err->code != GOT_ERR_NOT_REF) goto done; /* Can happen on early abort due to invalid histedit script. */ commit_ref = NULL; } if (commit_ref) { err = got_ref_resolve(&merged_commit_id, repo, commit_ref); if (err) goto done; /* * Determine which files in added status can be safely removed * from disk while reverting changes in the work tree. * We want to avoid deleting unrelated files added by the * user during conflict resolution or during histedit -e. */ err = get_paths_added_in_commit(&added_paths, merged_commit_id, got_worktree_get_path_prefix(worktree), repo); if (err) goto done; } err = got_ref_open(&resolved, repo, got_ref_get_symref_target(branch), 0); if (err) goto done; err = got_worktree_set_head_ref(worktree, resolved); if (err) goto done; err = got_worktree_set_base_commit_id(worktree, repo, base_commit_id); if (err) goto done; err = got_object_open_as_commit(&commit, repo, worktree->base_commit_id); if (err) goto done; err = got_object_id_by_path(&tree_id, repo, commit, worktree->path_prefix); if (err) goto done; err = delete_histedit_refs(worktree, repo); if (err) goto done; err = get_fileindex_path(&fileindex_path, worktree); if (err) goto done; rfa.worktree = worktree; rfa.fileindex = fileindex; rfa.progress_cb = progress_cb; rfa.progress_arg = progress_arg; rfa.patch_cb = NULL; rfa.patch_arg = NULL; rfa.repo = repo; rfa.unlink_added_files = 1; rfa.added_files_to_unlink = &added_paths; err = worktree_status(worktree, "", fileindex, repo, revert_file, &rfa, NULL, NULL, 1, 0); if (err) goto sync; err = checkout_files(worktree, fileindex, "", tree_id, NULL, repo, progress_cb, progress_arg, NULL, NULL); sync: sync_err = sync_fileindex(fileindex, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: if (resolved) got_ref_close(resolved); if (commit_ref) got_ref_close(commit_ref); free(merged_commit_id); free(tree_id); free(fileindex_path); free(commit_ref_name); unlockerr = lock_worktree(worktree, LOCK_SH); if (unlockerr && err == NULL) err = unlockerr; return err; } const struct got_error * got_worktree_histedit_complete(struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_reference *tmp_branch, struct got_reference *edited_branch, struct got_repository *repo) { const struct got_error *err, *unlockerr, *sync_err; struct got_object_id *new_head_commit_id = NULL; struct got_reference *resolved = NULL; char *fileindex_path = NULL; err = got_ref_resolve(&new_head_commit_id, repo, tmp_branch); if (err) return err; err = got_ref_open(&resolved, repo, got_ref_get_symref_target(edited_branch), 0); if (err) goto done; err = create_backup_ref(GOT_WORKTREE_HISTEDIT_BACKUP_REF_PREFIX, resolved, new_head_commit_id, repo); if (err) goto done; err = got_ref_change_ref(resolved, new_head_commit_id); if (err) goto done; err = got_ref_write(resolved, repo); if (err) goto done; err = got_worktree_set_head_ref(worktree, resolved); if (err) goto done; err = delete_histedit_refs(worktree, repo); if (err) goto done; err = get_fileindex_path(&fileindex_path, worktree); if (err) goto done; err = bump_base_commit_id_everywhere(worktree, fileindex, NULL, NULL); sync_err = sync_fileindex(fileindex, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: got_fileindex_free(fileindex); free(fileindex_path); free(new_head_commit_id); unlockerr = lock_worktree(worktree, LOCK_SH); if (unlockerr && err == NULL) err = unlockerr; return err; } const struct got_error * got_worktree_histedit_skip_commit(struct got_worktree *worktree, struct got_object_id *commit_id, struct got_repository *repo) { const struct got_error *err; char *commit_ref_name; err = get_histedit_commit_ref_name(&commit_ref_name, worktree); if (err) return err; err = store_commit_id(commit_ref_name, commit_id, 0, repo); if (err) goto done; err = delete_ref(commit_ref_name, repo); done: free(commit_ref_name); return err; } const struct got_error * got_worktree_integrate_prepare(struct got_fileindex **fileindex, struct got_reference **branch_ref, struct got_reference **base_branch_ref, struct got_worktree *worktree, const char *refname, struct got_repository *repo) { const struct got_error *err = NULL; char *fileindex_path = NULL; struct check_rebase_ok_arg ok_arg; *fileindex = NULL; *branch_ref = NULL; *base_branch_ref = NULL; err = lock_worktree(worktree, LOCK_EX); if (err) return err; if (strcmp(refname, got_worktree_get_head_ref_name(worktree)) == 0) { err = got_error_msg(GOT_ERR_SAME_BRANCH, "cannot integrate a branch into itself; " "update -b or different branch name required"); goto done; } err = open_fileindex(fileindex, &fileindex_path, worktree); if (err) goto done; /* Preconditions are the same as for rebase. */ ok_arg.worktree = worktree; ok_arg.repo = repo; err = got_fileindex_for_each_entry_safe(*fileindex, check_rebase_ok, &ok_arg); if (err) goto done; err = got_ref_open(branch_ref, repo, refname, 1); if (err) goto done; err = got_ref_open(base_branch_ref, repo, got_worktree_get_head_ref_name(worktree), 1); done: if (err) { if (*branch_ref) { got_ref_close(*branch_ref); *branch_ref = NULL; } if (*base_branch_ref) { got_ref_close(*base_branch_ref); *base_branch_ref = NULL; } if (*fileindex) { got_fileindex_free(*fileindex); *fileindex = NULL; } lock_worktree(worktree, LOCK_SH); } return err; } const struct got_error * got_worktree_integrate_continue(struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_repository *repo, struct got_reference *branch_ref, struct got_reference *base_branch_ref, got_worktree_checkout_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL, *sync_err, *unlockerr; char *fileindex_path = NULL; struct got_object_id *tree_id = NULL, *commit_id = NULL; struct got_commit_object *commit = NULL; err = get_fileindex_path(&fileindex_path, worktree); if (err) goto done; err = got_ref_resolve(&commit_id, repo, branch_ref); if (err) goto done; err = got_object_open_as_commit(&commit, repo, commit_id); if (err) goto done; err = got_object_id_by_path(&tree_id, repo, commit, worktree->path_prefix); if (err) goto done; err = got_worktree_set_base_commit_id(worktree, repo, commit_id); if (err) goto done; err = checkout_files(worktree, fileindex, "", tree_id, NULL, repo, progress_cb, progress_arg, cancel_cb, cancel_arg); if (err) goto sync; err = got_ref_change_ref(base_branch_ref, commit_id); if (err) goto sync; err = got_ref_write(base_branch_ref, repo); if (err) goto sync; err = bump_base_commit_id_everywhere(worktree, fileindex, NULL, NULL); sync: sync_err = sync_fileindex(fileindex, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: unlockerr = got_ref_unlock(branch_ref); if (unlockerr && err == NULL) err = unlockerr; got_ref_close(branch_ref); unlockerr = got_ref_unlock(base_branch_ref); if (unlockerr && err == NULL) err = unlockerr; got_ref_close(base_branch_ref); got_fileindex_free(fileindex); free(fileindex_path); free(tree_id); if (commit) got_object_commit_close(commit); unlockerr = lock_worktree(worktree, LOCK_SH); if (unlockerr && err == NULL) err = unlockerr; return err; } const struct got_error * got_worktree_integrate_abort(struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_repository *repo, struct got_reference *branch_ref, struct got_reference *base_branch_ref) { const struct got_error *err = NULL, *unlockerr = NULL; got_fileindex_free(fileindex); err = lock_worktree(worktree, LOCK_SH); unlockerr = got_ref_unlock(branch_ref); if (unlockerr && err == NULL) err = unlockerr; got_ref_close(branch_ref); unlockerr = got_ref_unlock(base_branch_ref); if (unlockerr && err == NULL) err = unlockerr; got_ref_close(base_branch_ref); return err; } const struct got_error * got_worktree_merge_postpone(struct got_worktree *worktree, struct got_fileindex *fileindex) { const struct got_error *err, *sync_err; char *fileindex_path = NULL; err = get_fileindex_path(&fileindex_path, worktree); if (err) goto done; sync_err = sync_fileindex(fileindex, fileindex_path); err = lock_worktree(worktree, LOCK_SH); if (sync_err && err == NULL) err = sync_err; done: got_fileindex_free(fileindex); free(fileindex_path); return err; } static const struct got_error * delete_merge_refs(struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; char *branch_refname = NULL, *commit_refname = NULL; err = get_merge_branch_ref_name(&branch_refname, worktree); if (err) goto done; err = delete_ref(branch_refname, repo); if (err) goto done; err = get_merge_commit_ref_name(&commit_refname, worktree); if (err) goto done; err = delete_ref(commit_refname, repo); if (err) goto done; done: free(branch_refname); free(commit_refname); return err; } struct merge_commit_msg_arg { struct got_worktree *worktree; const char *branch_name; }; static const struct got_error * merge_commit_msg_cb(struct got_pathlist_head *commitable_paths, const char *diff_path, char **logmsg, void *arg) { struct merge_commit_msg_arg *a = arg; if (asprintf(logmsg, "merge %s into %s\n", a->branch_name, got_worktree_get_head_ref_name(a->worktree)) == -1) return got_error_from_errno("asprintf"); return NULL; } const struct got_error * got_worktree_merge_branch(struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_object_id *yca_commit_id, struct got_object_id *branch_tip, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err; char *fileindex_path = NULL; struct check_mixed_commits_args cma; err = get_fileindex_path(&fileindex_path, worktree); if (err) goto done; cma.worktree = worktree; cma.cancel_cb = cancel_cb; cma.cancel_arg = cancel_arg; err = got_fileindex_for_each_entry_safe(fileindex, check_mixed_commits, &cma); if (err) goto done; err = merge_files(worktree, fileindex, fileindex_path, yca_commit_id, branch_tip, repo, progress_cb, progress_arg, cancel_cb, cancel_arg); done: free(fileindex_path); return err; } const struct got_error * got_worktree_merge_commit(struct got_object_id **new_commit_id, struct got_worktree *worktree, struct got_fileindex *fileindex, const char *author, const char *committer, int allow_bad_symlinks, struct got_object_id *branch_tip, const char *branch_name, int allow_conflict, struct got_repository *repo, got_worktree_status_cb status_cb, void *status_arg) { const struct got_error *err = NULL, *sync_err; struct got_pathlist_head commitable_paths; struct collect_commitables_arg cc_arg; struct got_pathlist_entry *pe; struct got_reference *head_ref = NULL; struct got_object_id *head_commit_id = NULL; int have_staged_files = 0; struct merge_commit_msg_arg mcm_arg; char *fileindex_path = NULL; memset(&cc_arg, 0, sizeof(cc_arg)); *new_commit_id = NULL; TAILQ_INIT(&commitable_paths); err = get_fileindex_path(&fileindex_path, worktree); if (err) goto done; err = got_ref_open(&head_ref, repo, worktree->head_ref_name, 0); if (err) goto done; err = got_ref_resolve(&head_commit_id, repo, head_ref); if (err) goto done; err = got_fileindex_for_each_entry_safe(fileindex, check_staged_file, &have_staged_files); if (err && err->code != GOT_ERR_CANCELLED) goto done; if (have_staged_files) { err = got_error(GOT_ERR_MERGE_STAGED_PATHS); goto done; } cc_arg.commitable_paths = &commitable_paths; cc_arg.worktree = worktree; cc_arg.fileindex = fileindex; cc_arg.repo = repo; cc_arg.have_staged_files = have_staged_files; cc_arg.allow_bad_symlinks = allow_bad_symlinks; cc_arg.commit_conflicts = allow_conflict; err = worktree_status(worktree, "", fileindex, repo, collect_commitables, &cc_arg, NULL, NULL, 1, 0); if (err) goto done; mcm_arg.worktree = worktree; mcm_arg.branch_name = branch_name; err = commit_worktree(new_commit_id, &commitable_paths, head_commit_id, branch_tip, worktree, author, committer, NULL, merge_commit_msg_cb, &mcm_arg, status_cb, status_arg, repo); if (err) goto done; err = update_fileindex_after_commit(worktree, &commitable_paths, *new_commit_id, fileindex, have_staged_files); sync_err = sync_fileindex(fileindex, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: TAILQ_FOREACH(pe, &commitable_paths, entry) { struct got_commitable *ct = pe->data; free_commitable(ct); } got_pathlist_free(&commitable_paths, GOT_PATHLIST_FREE_NONE); free(fileindex_path); return err; } const struct got_error * got_worktree_merge_complete(struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_repository *repo) { const struct got_error *err, *unlockerr, *sync_err; char *fileindex_path = NULL; err = delete_merge_refs(worktree, repo); if (err) goto done; err = get_fileindex_path(&fileindex_path, worktree); if (err) goto done; err = bump_base_commit_id_everywhere(worktree, fileindex, NULL, NULL); sync_err = sync_fileindex(fileindex, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: got_fileindex_free(fileindex); free(fileindex_path); unlockerr = lock_worktree(worktree, LOCK_SH); if (unlockerr && err == NULL) err = unlockerr; return err; } const struct got_error * got_worktree_merge_in_progress(int *in_progress, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; char *branch_refname = NULL; struct got_reference *branch_ref = NULL; *in_progress = 0; err = get_merge_branch_ref_name(&branch_refname, worktree); if (err) return err; err = got_ref_open(&branch_ref, repo, branch_refname, 0); free(branch_refname); if (err) { if (err->code != GOT_ERR_NOT_REF) return err; } else *in_progress = 1; return NULL; } const struct got_error *got_worktree_merge_prepare( struct got_fileindex **fileindex, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err = NULL; char *fileindex_path = NULL; struct got_reference *wt_branch = NULL; struct got_object_id *wt_branch_tip = NULL; struct check_rebase_ok_arg ok_arg; *fileindex = NULL; err = lock_worktree(worktree, LOCK_EX); if (err) return err; err = open_fileindex(fileindex, &fileindex_path, worktree); if (err) goto done; /* Preconditions are the same as for rebase. */ ok_arg.worktree = worktree; ok_arg.repo = repo; err = got_fileindex_for_each_entry_safe(*fileindex, check_rebase_ok, &ok_arg); if (err) goto done; err = got_ref_open(&wt_branch, repo, worktree->head_ref_name, 0); if (err) goto done; err = got_ref_resolve(&wt_branch_tip, repo, wt_branch); if (err) goto done; if (got_object_id_cmp(worktree->base_commit_id, wt_branch_tip) != 0) { err = got_error(GOT_ERR_MERGE_OUT_OF_DATE); goto done; } done: free(fileindex_path); if (wt_branch) got_ref_close(wt_branch); free(wt_branch_tip); if (err) { if (*fileindex) { got_fileindex_free(*fileindex); *fileindex = NULL; } lock_worktree(worktree, LOCK_SH); } return err; } const struct got_error *got_worktree_merge_write_refs( struct got_worktree *worktree, struct got_reference *branch, struct got_repository *repo) { const struct got_error *err = NULL; char *branch_refname = NULL, *commit_refname = NULL; struct got_reference *branch_ref = NULL, *commit_ref = NULL; struct got_object_id *branch_tip = NULL; err = get_merge_branch_ref_name(&branch_refname, worktree); if (err) return err; err = get_merge_commit_ref_name(&commit_refname, worktree); if (err) return err; err = got_ref_resolve(&branch_tip, repo, branch); if (err) goto done; err = got_ref_alloc_symref(&branch_ref, branch_refname, branch); if (err) goto done; err = got_ref_write(branch_ref, repo); if (err) goto done; err = got_ref_alloc(&commit_ref, commit_refname, branch_tip); if (err) goto done; err = got_ref_write(commit_ref, repo); if (err) goto done; done: free(branch_refname); free(commit_refname); if (branch_ref) got_ref_close(branch_ref); if (commit_ref) got_ref_close(commit_ref); free(branch_tip); return err; } const struct got_error * got_worktree_merge_continue(char **branch_name, struct got_object_id **branch_tip, struct got_fileindex **fileindex, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; char *commit_refname = NULL, *branch_refname = NULL; struct got_reference *commit_ref = NULL, *branch_ref = NULL; char *fileindex_path = NULL; int have_staged_files = 0; *branch_name = NULL; *branch_tip = NULL; *fileindex = NULL; err = lock_worktree(worktree, LOCK_EX); if (err) return err; err = open_fileindex(fileindex, &fileindex_path, worktree); if (err) goto done; err = got_fileindex_for_each_entry_safe(*fileindex, check_staged_file, &have_staged_files); if (err && err->code != GOT_ERR_CANCELLED) goto done; if (have_staged_files) { err = got_error(GOT_ERR_STAGED_PATHS); goto done; } err = get_merge_branch_ref_name(&branch_refname, worktree); if (err) goto done; err = get_merge_commit_ref_name(&commit_refname, worktree); if (err) goto done; err = got_ref_open(&branch_ref, repo, branch_refname, 0); if (err) goto done; if (!got_ref_is_symbolic(branch_ref)) { err = got_error_fmt(GOT_ERR_BAD_REF_TYPE, "%s is not a symbolic reference", got_ref_get_name(branch_ref)); goto done; } *branch_name = strdup(got_ref_get_symref_target(branch_ref)); if (*branch_name == NULL) { err = got_error_from_errno("strdup"); goto done; } err = got_ref_open(&commit_ref, repo, commit_refname, 0); if (err) goto done; err = got_ref_resolve(branch_tip, repo, commit_ref); if (err) goto done; done: free(commit_refname); free(branch_refname); free(fileindex_path); if (commit_ref) got_ref_close(commit_ref); if (branch_ref) got_ref_close(branch_ref); if (err) { if (*branch_name) { free(*branch_name); *branch_name = NULL; } free(*branch_tip); *branch_tip = NULL; if (*fileindex) { got_fileindex_free(*fileindex); *fileindex = NULL; } lock_worktree(worktree, LOCK_SH); } return err; } const struct got_error * got_worktree_merge_info(char **branch_name, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; char *branch_refname = NULL; struct got_reference *branch_ref = NULL; *branch_name = NULL; err = get_merge_branch_ref_name(&branch_refname, worktree); if (err) goto done; err = got_ref_open(&branch_ref, repo, branch_refname, 0); if (err) goto done; if (!got_ref_is_symbolic(branch_ref)) { err = got_error_fmt(GOT_ERR_BAD_REF_TYPE, "%s is not a symbolic reference", got_ref_get_name(branch_ref)); goto done; } *branch_name = strdup(got_ref_get_symref_target(branch_ref)); if (*branch_name == NULL) { err = got_error_from_errno("strdup"); goto done; } done: free(branch_refname); if (branch_ref) got_ref_close(branch_ref); if (err) { if (*branch_name) { free(*branch_name); *branch_name = NULL; } } return err; } const struct got_error * got_worktree_merge_abort(struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg) { const struct got_error *err, *unlockerr, *sync_err; struct got_commit_object *commit = NULL; char *fileindex_path = NULL; struct revert_file_args rfa; char *commit_ref_name = NULL; struct got_reference *commit_ref = NULL; struct got_object_id *merged_commit_id = NULL; struct got_object_id *tree_id = NULL; struct got_pathlist_head added_paths; TAILQ_INIT(&added_paths); err = get_merge_commit_ref_name(&commit_ref_name, worktree); if (err) goto done; err = got_ref_open(&commit_ref, repo, commit_ref_name, 0); if (err) goto done; err = got_ref_resolve(&merged_commit_id, repo, commit_ref); if (err) goto done; /* * Determine which files in added status can be safely removed * from disk while reverting changes in the work tree. * We want to avoid deleting unrelated files which were added by * the user for conflict resolution purposes. */ err = get_paths_added_between_commits(&added_paths, got_worktree_get_base_commit_id(worktree), merged_commit_id, got_worktree_get_path_prefix(worktree), repo); if (err) goto done; err = got_object_open_as_commit(&commit, repo, worktree->base_commit_id); if (err) goto done; err = got_object_id_by_path(&tree_id, repo, commit, worktree->path_prefix); if (err) goto done; err = delete_merge_refs(worktree, repo); if (err) goto done; err = get_fileindex_path(&fileindex_path, worktree); if (err) goto done; rfa.worktree = worktree; rfa.fileindex = fileindex; rfa.progress_cb = progress_cb; rfa.progress_arg = progress_arg; rfa.patch_cb = NULL; rfa.patch_arg = NULL; rfa.repo = repo; rfa.unlink_added_files = 1; rfa.added_files_to_unlink = &added_paths; err = worktree_status(worktree, "", fileindex, repo, revert_file, &rfa, NULL, NULL, 1, 0); if (err) goto sync; err = checkout_files(worktree, fileindex, "", tree_id, NULL, repo, progress_cb, progress_arg, NULL, NULL); sync: sync_err = sync_fileindex(fileindex, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: free(tree_id); free(merged_commit_id); if (commit) got_object_commit_close(commit); if (fileindex) got_fileindex_free(fileindex); free(fileindex_path); if (commit_ref) got_ref_close(commit_ref); free(commit_ref_name); unlockerr = lock_worktree(worktree, LOCK_SH); if (unlockerr && err == NULL) err = unlockerr; return err; } struct check_stage_ok_arg { struct got_object_id *head_commit_id; struct got_worktree *worktree; struct got_fileindex *fileindex; struct got_repository *repo; int have_changes; }; static const struct got_error * check_stage_ok(void *arg, unsigned char status, unsigned char staged_status, const char *relpath, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { struct check_stage_ok_arg *a = arg; const struct got_error *err = NULL; struct got_fileindex_entry *ie; struct got_object_id base_commit_id; struct got_object_id *base_commit_idp = NULL; char *in_repo_path = NULL, *p; if (status == GOT_STATUS_UNVERSIONED || status == GOT_STATUS_NO_CHANGE) return NULL; if (status == GOT_STATUS_NONEXISTENT) return got_error_set_errno(ENOENT, relpath); ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath)); if (ie == NULL) return got_error_path(relpath, GOT_ERR_FILE_STATUS); if (asprintf(&in_repo_path, "%s%s%s", a->worktree->path_prefix, got_path_is_root_dir(a->worktree->path_prefix) ? "" : "/", relpath) == -1) return got_error_from_errno("asprintf"); if (got_fileindex_entry_has_commit(ie)) { base_commit_idp = got_fileindex_entry_get_commit_id( &base_commit_id, ie); } if (status == GOT_STATUS_CONFLICT) { err = got_error_path(ie->path, GOT_ERR_STAGE_CONFLICT); goto done; } else if (status != GOT_STATUS_ADD && status != GOT_STATUS_MODIFY && status != GOT_STATUS_DELETE) { err = got_error_path(ie->path, GOT_ERR_FILE_STATUS); goto done; } a->have_changes = 1; p = in_repo_path; while (p[0] == '/') p++; err = check_out_of_date(p, status, staged_status, blob_id, base_commit_idp, a->head_commit_id, a->repo, GOT_ERR_STAGE_OUT_OF_DATE); done: free(in_repo_path); return err; } struct stage_path_arg { struct got_worktree *worktree; struct got_fileindex *fileindex; struct got_repository *repo; got_worktree_status_cb status_cb; void *status_arg; got_worktree_patch_cb patch_cb; void *patch_arg; int staged_something; int allow_bad_symlinks; }; static const struct got_error * stage_path(void *arg, unsigned char status, unsigned char staged_status, const char *relpath, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { struct stage_path_arg *a = arg; const struct got_error *err = NULL; struct got_fileindex_entry *ie; char *ondisk_path = NULL, *path_content = NULL; uint32_t stage; struct got_object_id *new_staged_blob_id = NULL; struct stat sb; if (status == GOT_STATUS_UNVERSIONED) return NULL; ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath)); if (ie == NULL) return got_error_path(relpath, GOT_ERR_FILE_STATUS); if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, relpath)== -1) return got_error_from_errno("asprintf"); switch (status) { case GOT_STATUS_ADD: case GOT_STATUS_MODIFY: /* XXX could sb.st_mode be passed in by our caller? */ if (lstat(ondisk_path, &sb) == -1) { err = got_error_from_errno2("lstat", ondisk_path); break; } if (a->patch_cb) { if (status == GOT_STATUS_ADD) { int choice = GOT_PATCH_CHOICE_NONE; err = (*a->patch_cb)(&choice, a->patch_arg, status, ie->path, NULL, 1, 1); if (err) break; if (choice != GOT_PATCH_CHOICE_YES) break; } else { err = create_patched_content(&path_content, 0, staged_blob_id ? staged_blob_id : blob_id, ondisk_path, dirfd, de_name, ie->path, a->repo, a->patch_cb, a->patch_arg); if (err || path_content == NULL) break; } } err = got_object_blob_create(&new_staged_blob_id, path_content ? path_content : ondisk_path, a->repo); if (err) break; memcpy(ie->staged_blob_sha1, new_staged_blob_id->sha1, SHA1_DIGEST_LENGTH); if (status == GOT_STATUS_ADD || staged_status == GOT_STATUS_ADD) stage = GOT_FILEIDX_STAGE_ADD; else stage = GOT_FILEIDX_STAGE_MODIFY; got_fileindex_entry_stage_set(ie, stage); if (S_ISLNK(sb.st_mode)) { int is_bad_symlink = 0; if (!a->allow_bad_symlinks) { char target_path[PATH_MAX]; ssize_t target_len; target_len = readlink(ondisk_path, target_path, sizeof(target_path)); if (target_len == -1) { err = got_error_from_errno2("readlink", ondisk_path); break; } err = is_bad_symlink_target(&is_bad_symlink, target_path, target_len, ondisk_path, a->worktree->root_path, a->worktree->meta_dir); if (err) break; if (is_bad_symlink) { err = got_error_path(ondisk_path, GOT_ERR_BAD_SYMLINK); break; } } if (is_bad_symlink) got_fileindex_entry_staged_filetype_set(ie, GOT_FILEIDX_MODE_BAD_SYMLINK); else got_fileindex_entry_staged_filetype_set(ie, GOT_FILEIDX_MODE_SYMLINK); } else { got_fileindex_entry_staged_filetype_set(ie, GOT_FILEIDX_MODE_REGULAR_FILE); } a->staged_something = 1; if (a->status_cb == NULL) break; err = (*a->status_cb)(a->status_arg, GOT_STATUS_NO_CHANGE, get_staged_status(ie), relpath, blob_id, new_staged_blob_id, NULL, dirfd, de_name); if (err) break; /* * When staging the reverse of the staged diff, * implicitly unstage the file. */ if (memcmp(ie->staged_blob_sha1, ie->blob_sha1, sizeof(ie->blob_sha1)) == 0) { got_fileindex_entry_stage_set(ie, GOT_FILEIDX_STAGE_NONE); } break; case GOT_STATUS_DELETE: if (staged_status == GOT_STATUS_DELETE) break; if (a->patch_cb) { int choice = GOT_PATCH_CHOICE_NONE; err = (*a->patch_cb)(&choice, a->patch_arg, status, ie->path, NULL, 1, 1); if (err) break; if (choice == GOT_PATCH_CHOICE_NO) break; if (choice != GOT_PATCH_CHOICE_YES) { err = got_error(GOT_ERR_PATCH_CHOICE); break; } } stage = GOT_FILEIDX_STAGE_DELETE; got_fileindex_entry_stage_set(ie, stage); a->staged_something = 1; if (a->status_cb == NULL) break; err = (*a->status_cb)(a->status_arg, GOT_STATUS_NO_CHANGE, get_staged_status(ie), relpath, NULL, NULL, NULL, dirfd, de_name); break; case GOT_STATUS_NO_CHANGE: break; case GOT_STATUS_CONFLICT: err = got_error_path(relpath, GOT_ERR_STAGE_CONFLICT); break; case GOT_STATUS_NONEXISTENT: err = got_error_set_errno(ENOENT, relpath); break; default: err = got_error_path(relpath, GOT_ERR_FILE_STATUS); break; } if (path_content && unlink(path_content) == -1 && err == NULL) err = got_error_from_errno2("unlink", path_content); free(path_content); free(ondisk_path); free(new_staged_blob_id); return err; } const struct got_error * got_worktree_stage(struct got_worktree *worktree, struct got_pathlist_head *paths, got_worktree_status_cb status_cb, void *status_arg, got_worktree_patch_cb patch_cb, void *patch_arg, int allow_bad_symlinks, struct got_repository *repo) { const struct got_error *err = NULL, *sync_err, *unlockerr; struct got_pathlist_entry *pe; struct got_fileindex *fileindex = NULL; char *fileindex_path = NULL; struct got_reference *head_ref = NULL; struct got_object_id *head_commit_id = NULL; struct check_stage_ok_arg oka; struct stage_path_arg spa; err = lock_worktree(worktree, LOCK_EX); if (err) return err; err = got_ref_open(&head_ref, repo, got_worktree_get_head_ref_name(worktree), 0); if (err) goto done; err = got_ref_resolve(&head_commit_id, repo, head_ref); if (err) goto done; err = open_fileindex(&fileindex, &fileindex_path, worktree); if (err) goto done; /* Check pre-conditions before staging anything. */ oka.head_commit_id = head_commit_id; oka.worktree = worktree; oka.fileindex = fileindex; oka.repo = repo; oka.have_changes = 0; TAILQ_FOREACH(pe, paths, entry) { err = worktree_status(worktree, pe->path, fileindex, repo, check_stage_ok, &oka, NULL, NULL, 1, 0); if (err) goto done; } if (!oka.have_changes) { err = got_error(GOT_ERR_STAGE_NO_CHANGE); goto done; } spa.worktree = worktree; spa.fileindex = fileindex; spa.repo = repo; spa.patch_cb = patch_cb; spa.patch_arg = patch_arg; spa.status_cb = status_cb; spa.status_arg = status_arg; spa.staged_something = 0; spa.allow_bad_symlinks = allow_bad_symlinks; TAILQ_FOREACH(pe, paths, entry) { err = worktree_status(worktree, pe->path, fileindex, repo, stage_path, &spa, NULL, NULL, 1, 0); if (err) goto done; } if (!spa.staged_something) { err = got_error(GOT_ERR_STAGE_NO_CHANGE); goto done; } sync_err = sync_fileindex(fileindex, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: if (head_ref) got_ref_close(head_ref); free(head_commit_id); free(fileindex_path); if (fileindex) got_fileindex_free(fileindex); unlockerr = lock_worktree(worktree, LOCK_SH); if (unlockerr && err == NULL) err = unlockerr; return err; } struct unstage_path_arg { struct got_worktree *worktree; struct got_fileindex *fileindex; struct got_repository *repo; got_worktree_checkout_cb progress_cb; void *progress_arg; got_worktree_patch_cb patch_cb; void *patch_arg; }; static const struct got_error * create_unstaged_content(char **path_unstaged_content, char **path_new_staged_content, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, const char *relpath, struct got_repository *repo, got_worktree_patch_cb patch_cb, void *patch_arg) { const struct got_error *err, *free_err; struct got_blob_object *blob = NULL, *staged_blob = NULL; FILE *f1 = NULL, *f2 = NULL, *outfile = NULL, *rejectfile = NULL; char *path1 = NULL, *path2 = NULL, *label1 = NULL; struct got_diffreg_result *diffreg_result = NULL; int line_cur1 = 1, line_cur2 = 1, n = 0, nchunks_used = 0; int have_content = 0, have_rejected_content = 0, i = 0, nchanges = 0; int fd1 = -1, fd2 = -1; *path_unstaged_content = NULL; *path_new_staged_content = NULL; err = got_object_id_str(&label1, blob_id); if (err) return err; fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } err = got_object_open_as_blob(&blob, repo, blob_id, 8192, fd1); if (err) goto done; err = got_opentemp_named(&path1, &f1, "got-unstage-blob-base", ""); if (err) goto done; err = got_object_blob_dump_to_file(NULL, NULL, NULL, f1, blob); if (err) goto done; err = got_object_open_as_blob(&staged_blob, repo, staged_blob_id, 8192, fd2); if (err) goto done; err = got_opentemp_named(&path2, &f2, "got-unstage-blob-staged", ""); if (err) goto done; err = got_object_blob_dump_to_file(NULL, NULL, NULL, f2, staged_blob); if (err) goto done; err = got_diff_files(&diffreg_result, f1, 1, label1, f2, 1, path2, 3, 0, 1, NULL, GOT_DIFF_ALGORITHM_MYERS); if (err) goto done; err = got_opentemp_named(path_unstaged_content, &outfile, "got-unstaged-content", ""); if (err) goto done; err = got_opentemp_named(path_new_staged_content, &rejectfile, "got-new-staged-content", ""); if (err) goto done; if (fseek(f1, 0L, SEEK_SET) == -1) { err = got_ferror(f1, GOT_ERR_IO); goto done; } if (fseek(f2, 0L, SEEK_SET) == -1) { err = got_ferror(f2, GOT_ERR_IO); goto done; } /* Count the number of actual changes in the diff result. */ for (n = 0; n < diffreg_result->result->chunks.len; n += nchunks_used) { struct diff_chunk_context cc = {}; diff_chunk_context_load_change(&cc, &nchunks_used, diffreg_result->result, n, 0); nchanges++; } for (n = 0; n < diffreg_result->result->chunks.len; n += nchunks_used) { int choice; err = apply_or_reject_change(&choice, &nchunks_used, diffreg_result->result, n, relpath, f1, f2, &line_cur1, &line_cur2, outfile, rejectfile, ++i, nchanges, patch_cb, patch_arg); if (err) goto done; if (choice == GOT_PATCH_CHOICE_YES) have_content = 1; else have_rejected_content = 1; if (choice == GOT_PATCH_CHOICE_QUIT) break; } if (have_content || have_rejected_content) err = copy_remaining_content(f1, f2, &line_cur1, &line_cur2, outfile, rejectfile); done: free(label1); if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob) got_object_blob_close(blob); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno("close"); if (staged_blob) got_object_blob_close(staged_blob); free_err = got_diffreg_result_free(diffreg_result); if (free_err && err == NULL) err = free_err; if (f1 && fclose(f1) == EOF && err == NULL) err = got_error_from_errno2("fclose", path1); if (f2 && fclose(f2) == EOF && err == NULL) err = got_error_from_errno2("fclose", path2); if (outfile && fclose(outfile) == EOF && err == NULL) err = got_error_from_errno2("fclose", *path_unstaged_content); if (rejectfile && fclose(rejectfile) == EOF && err == NULL) err = got_error_from_errno2("fclose", *path_new_staged_content); if (path1 && unlink(path1) == -1 && err == NULL) err = got_error_from_errno2("unlink", path1); if (path2 && unlink(path2) == -1 && err == NULL) err = got_error_from_errno2("unlink", path2); if (err || !have_content) { if (*path_unstaged_content && unlink(*path_unstaged_content) == -1 && err == NULL) err = got_error_from_errno2("unlink", *path_unstaged_content); free(*path_unstaged_content); *path_unstaged_content = NULL; } if (err || !have_content || !have_rejected_content) { if (*path_new_staged_content && unlink(*path_new_staged_content) == -1 && err == NULL) err = got_error_from_errno2("unlink", *path_new_staged_content); free(*path_new_staged_content); *path_new_staged_content = NULL; } free(path1); free(path2); return err; } static const struct got_error * unstage_hunks(struct got_object_id *staged_blob_id, struct got_blob_object *blob_base, struct got_object_id *blob_id, struct got_fileindex_entry *ie, const char *ondisk_path, const char *label_orig, struct got_worktree *worktree, struct got_repository *repo, got_worktree_patch_cb patch_cb, void *patch_arg, got_worktree_checkout_cb progress_cb, void *progress_arg) { const struct got_error *err = NULL; char *path_unstaged_content = NULL; char *path_new_staged_content = NULL; char *parent = NULL, *base_path = NULL; char *blob_base_path = NULL; struct got_object_id *new_staged_blob_id = NULL; FILE *f = NULL, *f_base = NULL, *f_deriv2 = NULL; struct stat sb; err = create_unstaged_content(&path_unstaged_content, &path_new_staged_content, blob_id, staged_blob_id, ie->path, repo, patch_cb, patch_arg); if (err) return err; if (path_unstaged_content == NULL) return NULL; if (path_new_staged_content) { err = got_object_blob_create(&new_staged_blob_id, path_new_staged_content, repo); if (err) goto done; } f = fopen(path_unstaged_content, "re"); if (f == NULL) { err = got_error_from_errno2("fopen", path_unstaged_content); goto done; } if (fstat(fileno(f), &sb) == -1) { err = got_error_from_errno2("fstat", path_unstaged_content); goto done; } if (got_fileindex_entry_staged_filetype_get(ie) == GOT_FILEIDX_MODE_SYMLINK && sb.st_size < PATH_MAX) { char link_target[PATH_MAX]; size_t r; r = fread(link_target, 1, sizeof(link_target), f); if (r == 0 && ferror(f)) { err = got_error_from_errno("fread"); goto done; } if (r >= sizeof(link_target)) { /* should not happen */ err = got_error(GOT_ERR_NO_SPACE); goto done; } link_target[r] = '\0'; err = merge_symlink(worktree, blob_base, ondisk_path, ie->path, label_orig, link_target, worktree->base_commit_id, repo, progress_cb, progress_arg); } else { int local_changes_subsumed; err = got_path_dirname(&parent, ondisk_path); if (err) return err; if (asprintf(&base_path, "%s/got-unstage-blob-orig", parent) == -1) { err = got_error_from_errno("asprintf"); base_path = NULL; goto done; } err = got_opentemp_named(&blob_base_path, &f_base, base_path, ""); if (err) goto done; err = got_object_blob_dump_to_file(NULL, NULL, NULL, f_base, blob_base); if (err) goto done; /* * In order the run a 3-way merge with a symlink we copy the symlink's * target path into a temporary file and use that file with diff3. */ if (S_ISLNK(got_fileindex_perms_to_st(ie))) { err = dump_symlink_target_path_to_file(&f_deriv2, ondisk_path); if (err) goto done; } else { int fd; fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { err = got_error_from_errno2("open", ondisk_path); goto done; } f_deriv2 = fdopen(fd, "r"); if (f_deriv2 == NULL) { err = got_error_from_errno2("fdopen", ondisk_path); close(fd); goto done; } } err = merge_file(&local_changes_subsumed, worktree, f_base, f, f_deriv2, ondisk_path, ie->path, got_fileindex_perms_to_st(ie), label_orig, "unstaged", NULL, GOT_DIFF_ALGORITHM_MYERS, repo, progress_cb, progress_arg); } if (err) goto done; if (new_staged_blob_id) { memcpy(ie->staged_blob_sha1, new_staged_blob_id->sha1, SHA1_DIGEST_LENGTH); } else { got_fileindex_entry_stage_set(ie, GOT_FILEIDX_STAGE_NONE); got_fileindex_entry_staged_filetype_set(ie, 0); } done: free(new_staged_blob_id); if (path_unstaged_content && unlink(path_unstaged_content) == -1 && err == NULL) err = got_error_from_errno2("unlink", path_unstaged_content); if (path_new_staged_content && unlink(path_new_staged_content) == -1 && err == NULL) err = got_error_from_errno2("unlink", path_new_staged_content); if (blob_base_path && unlink(blob_base_path) == -1 && err == NULL) err = got_error_from_errno2("unlink", blob_base_path); if (f_base && fclose(f_base) == EOF && err == NULL) err = got_error_from_errno2("fclose", path_unstaged_content); if (f && fclose(f) == EOF && err == NULL) err = got_error_from_errno2("fclose", path_unstaged_content); if (f_deriv2 && fclose(f_deriv2) == EOF && err == NULL) err = got_error_from_errno2("fclose", ondisk_path); free(path_unstaged_content); free(path_new_staged_content); free(blob_base_path); free(parent); free(base_path); return err; } static const struct got_error * unstage_path(void *arg, unsigned char status, unsigned char staged_status, const char *relpath, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { const struct got_error *err = NULL; struct unstage_path_arg *a = arg; struct got_fileindex_entry *ie; struct got_blob_object *blob_base = NULL, *blob_staged = NULL; char *ondisk_path = NULL; char *id_str = NULL, *label_orig = NULL; int local_changes_subsumed; struct stat sb; int fd1 = -1, fd2 = -1; if (staged_status != GOT_STATUS_ADD && staged_status != GOT_STATUS_MODIFY && staged_status != GOT_STATUS_DELETE) return NULL; ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath)); if (ie == NULL) return got_error_path(relpath, GOT_ERR_FILE_STATUS); if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, relpath) == -1) return got_error_from_errno("asprintf"); err = got_object_id_str(&id_str, commit_id ? commit_id : a->worktree->base_commit_id); if (err) goto done; if (asprintf(&label_orig, "%s: commit %s", GOT_MERGE_LABEL_BASE, id_str) == -1) { err = got_error_from_errno("asprintf"); goto done; } fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } switch (staged_status) { case GOT_STATUS_MODIFY: err = got_object_open_as_blob(&blob_base, a->repo, blob_id, 8192, fd1); if (err) break; /* fall through */ case GOT_STATUS_ADD: if (a->patch_cb) { if (staged_status == GOT_STATUS_ADD) { int choice = GOT_PATCH_CHOICE_NONE; err = (*a->patch_cb)(&choice, a->patch_arg, staged_status, ie->path, NULL, 1, 1); if (err) break; if (choice != GOT_PATCH_CHOICE_YES) break; } else { err = unstage_hunks(staged_blob_id, blob_base, blob_id, ie, ondisk_path, label_orig, a->worktree, a->repo, a->patch_cb, a->patch_arg, a->progress_cb, a->progress_arg); break; /* Done with this file. */ } } err = got_object_open_as_blob(&blob_staged, a->repo, staged_blob_id, 8192, fd2); if (err) break; switch (got_fileindex_entry_staged_filetype_get(ie)) { case GOT_FILEIDX_MODE_BAD_SYMLINK: case GOT_FILEIDX_MODE_REGULAR_FILE: err = merge_blob(&local_changes_subsumed, a->worktree, blob_base, ondisk_path, relpath, got_fileindex_perms_to_st(ie), label_orig, blob_staged, commit_id ? commit_id : a->worktree->base_commit_id, a->repo, a->progress_cb, a->progress_arg); break; case GOT_FILEIDX_MODE_SYMLINK: if (S_ISLNK(got_fileindex_perms_to_st(ie))) { char *staged_target; err = got_object_blob_read_to_str( &staged_target, blob_staged); if (err) goto done; err = merge_symlink(a->worktree, blob_base, ondisk_path, relpath, label_orig, staged_target, commit_id ? commit_id : a->worktree->base_commit_id, a->repo, a->progress_cb, a->progress_arg); free(staged_target); } else { err = merge_blob(&local_changes_subsumed, a->worktree, blob_base, ondisk_path, relpath, got_fileindex_perms_to_st(ie), label_orig, blob_staged, commit_id ? commit_id : a->worktree->base_commit_id, a->repo, a->progress_cb, a->progress_arg); } break; default: err = got_error_path(relpath, GOT_ERR_BAD_FILETYPE); break; } if (err == NULL) { got_fileindex_entry_stage_set(ie, GOT_FILEIDX_STAGE_NONE); got_fileindex_entry_staged_filetype_set(ie, 0); } break; case GOT_STATUS_DELETE: if (a->patch_cb) { int choice = GOT_PATCH_CHOICE_NONE; err = (*a->patch_cb)(&choice, a->patch_arg, staged_status, ie->path, NULL, 1, 1); if (err) break; if (choice == GOT_PATCH_CHOICE_NO) break; if (choice != GOT_PATCH_CHOICE_YES) { err = got_error(GOT_ERR_PATCH_CHOICE); break; } } got_fileindex_entry_stage_set(ie, GOT_FILEIDX_STAGE_NONE); got_fileindex_entry_staged_filetype_set(ie, 0); err = get_file_status(&status, &sb, ie, ondisk_path, dirfd, de_name, a->repo); if (err) break; err = (*a->progress_cb)(a->progress_arg, status, relpath); break; } done: free(ondisk_path); if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob_base) got_object_blob_close(blob_base); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob_staged) got_object_blob_close(blob_staged); free(id_str); free(label_orig); return err; } const struct got_error * got_worktree_unstage(struct got_worktree *worktree, struct got_pathlist_head *paths, got_worktree_checkout_cb progress_cb, void *progress_arg, got_worktree_patch_cb patch_cb, void *patch_arg, struct got_repository *repo) { const struct got_error *err = NULL, *sync_err, *unlockerr; struct got_pathlist_entry *pe; struct got_fileindex *fileindex = NULL; char *fileindex_path = NULL; struct unstage_path_arg upa; err = lock_worktree(worktree, LOCK_EX); if (err) return err; err = open_fileindex(&fileindex, &fileindex_path, worktree); if (err) goto done; upa.worktree = worktree; upa.fileindex = fileindex; upa.repo = repo; upa.progress_cb = progress_cb; upa.progress_arg = progress_arg; upa.patch_cb = patch_cb; upa.patch_arg = patch_arg; TAILQ_FOREACH(pe, paths, entry) { err = worktree_status(worktree, pe->path, fileindex, repo, unstage_path, &upa, NULL, NULL, 1, 0); if (err) goto done; } sync_err = sync_fileindex(fileindex, fileindex_path); if (sync_err && err == NULL) err = sync_err; done: free(fileindex_path); if (fileindex) got_fileindex_free(fileindex); unlockerr = lock_worktree(worktree, LOCK_SH); if (unlockerr && err == NULL) err = unlockerr; return err; } struct report_file_info_arg { struct got_worktree *worktree; got_worktree_path_info_cb info_cb; void *info_arg; struct got_pathlist_head *paths; got_cancel_cb cancel_cb; void *cancel_arg; }; static const struct got_error * report_file_info(void *arg, struct got_fileindex_entry *ie) { const struct got_error *err; struct report_file_info_arg *a = arg; struct got_pathlist_entry *pe; struct got_object_id blob_id, staged_blob_id, commit_id; struct got_object_id *blob_idp = NULL, *staged_blob_idp = NULL; struct got_object_id *commit_idp = NULL; int stage; if (a->cancel_cb) { err = a->cancel_cb(a->cancel_arg); if (err) return err; } TAILQ_FOREACH(pe, a->paths, entry) { if (pe->path_len == 0 || strcmp(pe->path, ie->path) == 0 || got_path_is_child(ie->path, pe->path, pe->path_len)) break; } if (pe == NULL) /* not found */ return NULL; if (got_fileindex_entry_has_blob(ie)) blob_idp = got_fileindex_entry_get_blob_id(&blob_id, ie); stage = got_fileindex_entry_stage_get(ie); if (stage == GOT_FILEIDX_STAGE_MODIFY || stage == GOT_FILEIDX_STAGE_ADD) { staged_blob_idp = got_fileindex_entry_get_staged_blob_id( &staged_blob_id, ie); } if (got_fileindex_entry_has_commit(ie)) commit_idp = got_fileindex_entry_get_commit_id(&commit_id, ie); return a->info_cb(a->info_arg, ie->path, got_fileindex_perms_to_st(ie), (time_t)ie->mtime_sec, blob_idp, staged_blob_idp, commit_idp); } const struct got_error * got_worktree_path_info(struct got_worktree *worktree, struct got_pathlist_head *paths, got_worktree_path_info_cb info_cb, void *info_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL, *unlockerr; struct got_fileindex *fileindex = NULL; char *fileindex_path = NULL; struct report_file_info_arg arg; err = lock_worktree(worktree, LOCK_SH); if (err) return err; err = open_fileindex(&fileindex, &fileindex_path, worktree); if (err) goto done; arg.worktree = worktree; arg.info_cb = info_cb; arg.info_arg = info_arg; arg.paths = paths; arg.cancel_cb = cancel_cb; arg.cancel_arg = cancel_arg; err = got_fileindex_for_each_entry_safe(fileindex, report_file_info, &arg); done: free(fileindex_path); if (fileindex) got_fileindex_free(fileindex); unlockerr = lock_worktree(worktree, LOCK_UN); if (unlockerr && err == NULL) err = unlockerr; return err; } static const struct got_error * patch_check_path(const char *p, char **path, unsigned char *status, unsigned char *staged_status, struct got_fileindex *fileindex, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; struct got_fileindex_entry *ie; struct stat sb; char *ondisk_path = NULL; err = got_worktree_resolve_path(path, worktree, p); if (err) return err; if (asprintf(&ondisk_path, "%s%s%s", worktree->root_path, *path[0] ? "/" : "", *path) == -1) return got_error_from_errno("asprintf"); ie = got_fileindex_entry_get(fileindex, *path, strlen(*path)); if (ie) { *staged_status = get_staged_status(ie); err = get_file_status(status, &sb, ie, ondisk_path, -1, NULL, repo); if (err) goto done; } else { *staged_status = GOT_STATUS_NO_CHANGE; *status = GOT_STATUS_UNVERSIONED; if (lstat(ondisk_path, &sb) == -1) { if (errno != ENOENT) { err = got_error_from_errno2("lstat", ondisk_path); goto done; } *status = GOT_STATUS_NONEXISTENT; } } done: free(ondisk_path); return err; } static const struct got_error * patch_can_rm(const char *path, unsigned char status, unsigned char staged_status) { if (status == GOT_STATUS_NONEXISTENT) return got_error_set_errno(ENOENT, path); if (status != GOT_STATUS_NO_CHANGE && status != GOT_STATUS_ADD && status != GOT_STATUS_MODIFY && status != GOT_STATUS_MODE_CHANGE) return got_error_path(path, GOT_ERR_FILE_STATUS); if (staged_status == GOT_STATUS_DELETE) return got_error_path(path, GOT_ERR_FILE_STATUS); return NULL; } static const struct got_error * patch_can_add(const char *path, unsigned char status) { if (status != GOT_STATUS_NONEXISTENT) return got_error_path(path, GOT_ERR_FILE_STATUS); return NULL; } static const struct got_error * patch_can_edit(const char *path, unsigned char status, unsigned char staged_status) { if (status == GOT_STATUS_NONEXISTENT) return got_error_set_errno(ENOENT, path); if (status != GOT_STATUS_NO_CHANGE && status != GOT_STATUS_ADD && status != GOT_STATUS_MODIFY) return got_error_path(path, GOT_ERR_FILE_STATUS); if (staged_status == GOT_STATUS_DELETE) return got_error_path(path, GOT_ERR_FILE_STATUS); return NULL; } const struct got_error * got_worktree_patch_prepare(struct got_fileindex **fileindex, char **fileindex_path, struct got_worktree *worktree) { return open_fileindex(fileindex, fileindex_path, worktree); } const struct got_error * got_worktree_patch_check_path(const char *old, const char *new, char **oldpath, char **newpath, struct got_worktree *worktree, struct got_repository *repo, struct got_fileindex *fileindex) { const struct got_error *err = NULL; int file_renamed = 0; unsigned char status_old, staged_status_old; unsigned char status_new, staged_status_new; *oldpath = NULL; *newpath = NULL; err = patch_check_path(old != NULL ? old : new, oldpath, &status_old, &staged_status_old, fileindex, worktree, repo); if (err) goto done; err = patch_check_path(new != NULL ? new : old, newpath, &status_new, &staged_status_new, fileindex, worktree, repo); if (err) goto done; if (old != NULL && new != NULL && strcmp(old, new) != 0) file_renamed = 1; if (old != NULL && new == NULL) err = patch_can_rm(*oldpath, status_old, staged_status_old); else if (file_renamed) { err = patch_can_rm(*oldpath, status_old, staged_status_old); if (err == NULL) err = patch_can_add(*newpath, status_new); } else if (old == NULL) err = patch_can_add(*newpath, status_new); else err = patch_can_edit(*newpath, status_new, staged_status_new); done: if (err) { free(*oldpath); *oldpath = NULL; free(*newpath); *newpath = NULL; } return err; } const struct got_error * got_worktree_patch_schedule_add(const char *path, struct got_repository *repo, struct got_worktree *worktree, struct got_fileindex *fileindex, got_worktree_checkout_cb progress_cb, void *progress_arg) { struct schedule_addition_args saa; memset(&saa, 0, sizeof(saa)); saa.worktree = worktree; saa.fileindex = fileindex; saa.progress_cb = progress_cb; saa.progress_arg = progress_arg; saa.repo = repo; return worktree_status(worktree, path, fileindex, repo, schedule_addition, &saa, NULL, NULL, 1, 0); } const struct got_error * got_worktree_patch_schedule_rm(const char *path, struct got_repository *repo, struct got_worktree *worktree, struct got_fileindex *fileindex, got_worktree_delete_cb progress_cb, void *progress_arg) { const struct got_error *err; struct schedule_deletion_args sda; char *ondisk_status_path; memset(&sda, 0, sizeof(sda)); sda.worktree = worktree; sda.fileindex = fileindex; sda.progress_cb = progress_cb; sda.progress_arg = progress_arg; sda.repo = repo; sda.delete_local_mods = 0; sda.keep_on_disk = 0; sda.ignore_missing_paths = 0; sda.status_codes = NULL; if (asprintf(&ondisk_status_path, "%s/%s", got_worktree_get_root_path(worktree), path) == -1) return got_error_from_errno("asprintf"); sda.status_path = ondisk_status_path; sda.status_path_len = strlen(ondisk_status_path); err = worktree_status(worktree, path, fileindex, repo, schedule_for_deletion, &sda, NULL, NULL, 1, 1); free(ondisk_status_path); return err; } const struct got_error * got_worktree_patch_complete(struct got_fileindex *fileindex, const char *fileindex_path) { const struct got_error *err = NULL; err = sync_fileindex(fileindex, fileindex_path); got_fileindex_free(fileindex); return err; } got-portable-0.101/lib/serve.c0000664000175100017510000010235314644144735011655 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_serve.h" #include "got_path.h" #include "got_version.h" #include "got_reference.h" #include "got_object.h" #include "got_lib_pkt.h" #include "got_lib_dial.h" #include "got_lib_gitproto.h" #include "got_lib_hash.h" #include "got_lib_poll.h" #include "gotd.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif /* * Number of seconds until we give up trying to read more * data from the client connection. */ static const int timeout = 60; static const struct got_capability read_capabilities[] = { { GOT_CAPA_AGENT, "got/" GOT_VERSION_STR }, { GOT_CAPA_OFS_DELTA, NULL }, { GOT_CAPA_SIDE_BAND_64K, NULL }, }; static const struct got_capability write_capabilities[] = { { GOT_CAPA_AGENT, "got/" GOT_VERSION_STR }, { GOT_CAPA_OFS_DELTA, NULL }, { GOT_CAPA_REPORT_STATUS, NULL }, { GOT_CAPA_NO_THIN, NULL }, { GOT_CAPA_DELETE_REFS, NULL }, }; static const struct got_error * append_read_capabilities(size_t *capalen, size_t len, const char *symrefstr, uint8_t *buf, size_t bufsize) { struct got_capability capa[nitems(read_capabilities) + 1]; size_t ncapa; memcpy(&capa, read_capabilities, sizeof(read_capabilities)); if (symrefstr) { capa[nitems(read_capabilities)].key = "symref"; capa[nitems(read_capabilities)].value = symrefstr; ncapa = nitems(capa); } else ncapa = nitems(read_capabilities); return got_gitproto_append_capabilities(capalen, buf, len, bufsize, capa, ncapa); } static const struct got_error * send_ref(int outfd, uint8_t *id, const char *refname, int send_capabilities, int client_is_reading, const char *symrefstr, int chattygot) { const struct got_error *err = NULL; char hex[SHA1_DIGEST_STRING_LENGTH]; char buf[GOT_PKT_MAX]; size_t len, capalen = 0; if (got_sha1_digest_to_str(id, hex, sizeof(hex)) == NULL) return got_error(GOT_ERR_BAD_OBJ_ID); len = snprintf(buf, sizeof(buf), "%s %s", hex, refname); if (len >= sizeof(buf)) return got_error(GOT_ERR_NO_SPACE); if (send_capabilities) { if (client_is_reading) { err = append_read_capabilities(&capalen, len, symrefstr, buf, sizeof(buf)); } else { err = got_gitproto_append_capabilities(&capalen, buf, len, sizeof(buf), write_capabilities, nitems(write_capabilities)); } if (err) return err; len += capalen; } if (len + 1 >= sizeof(buf)) return got_error(GOT_ERR_NO_SPACE); buf[len] = '\n'; len++; buf[len] = '\0'; return got_pkt_writepkt(outfd, buf, len, chattygot); } static const struct got_error * send_zero_refs(int outfd, int client_is_reading, int chattygot) { const struct got_error *err = NULL; const char *line = GOT_SHA1_STRING_ZERO " capabilities^{}"; char buf[GOT_PKT_MAX]; size_t len, capalen = 0; len = strlcpy(buf, line, sizeof(buf)); if (len >= sizeof(buf)) return got_error(GOT_ERR_NO_SPACE); if (client_is_reading) { err = got_gitproto_append_capabilities(&capalen, buf, len, sizeof(buf), read_capabilities, nitems(read_capabilities)); if (err) return err; } else { err = got_gitproto_append_capabilities(&capalen, buf, len, sizeof(buf), write_capabilities, nitems(write_capabilities)); if (err) return err; } return got_pkt_writepkt(outfd, buf, len + capalen, chattygot); } static void echo_error(const struct got_error *err, int outfd, int chattygot) { char buf[4 + GOT_ERR_MAX_MSG_SIZE]; size_t len; /* * Echo the error to the client on a pkt-line. * The client should then terminate its session. */ buf[0] = 'E'; buf[1] = 'R'; buf[2] = 'R'; buf[3] = ' '; buf[4] = '\0'; len = strlcat(buf, err->msg, sizeof(buf)); got_pkt_writepkt(outfd, buf, len, chattygot); } static const struct got_error * announce_refs(int outfd, struct imsgbuf *ibuf, int client_is_reading, const char *repo_path, int chattygot) { const struct got_error *err = NULL; struct imsg imsg; size_t datalen; struct gotd_imsg_list_refs lsref; struct gotd_imsg_reflist ireflist; struct gotd_imsg_ref iref; struct gotd_imsg_symref isymref; size_t nrefs = 0; int have_nrefs = 0, sent_capabilities = 0; char *symrefname = NULL, *symreftarget = NULL, *symrefstr = NULL; char *refname = NULL; memset(&imsg, 0, sizeof(imsg)); memset(&lsref, 0, sizeof(lsref)); if (strlcpy(lsref.repo_name, repo_path, sizeof(lsref.repo_name)) >= sizeof(lsref.repo_name)) return got_error(GOT_ERR_NO_SPACE); lsref.client_is_reading = client_is_reading; if (imsg_compose(ibuf, GOTD_IMSG_LIST_REFS, 0, 0, -1, &lsref, sizeof(lsref)) == -1) return got_error_from_errno("imsg_compose LIST_REFS"); err = gotd_imsg_flush(ibuf); if (err) return err; while (!have_nrefs || nrefs > 0) { err = gotd_imsg_poll_recv(&imsg, ibuf, 0); if (err) goto done; datalen = imsg.hdr.len - IMSG_HEADER_SIZE; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: err = gotd_imsg_recv_error(NULL, &imsg); goto done; case GOTD_IMSG_REFLIST: if (have_nrefs || nrefs > 0) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } if (datalen != sizeof(ireflist)) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } memcpy(&ireflist, imsg.data, sizeof(ireflist)); nrefs = ireflist.nrefs; have_nrefs = 1; if (nrefs == 0) err = send_zero_refs(outfd, client_is_reading, chattygot); break; case GOTD_IMSG_REF: if (!have_nrefs || nrefs == 0) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } if (datalen < sizeof(iref)) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } memcpy(&iref, imsg.data, sizeof(iref)); if (datalen != sizeof(iref) + iref.name_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } refname = strndup(imsg.data + sizeof(iref), iref.name_len); if (refname == NULL) { err = got_error_from_errno("strndup"); goto done; } err = send_ref(outfd, iref.id, refname, !sent_capabilities, client_is_reading, NULL, chattygot); free(refname); refname = NULL; if (err) goto done; sent_capabilities = 1; if (nrefs > 0) nrefs--; break; case GOTD_IMSG_SYMREF: if (!have_nrefs || nrefs == 0) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } if (datalen < sizeof(isymref)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&isymref, imsg.data, sizeof(isymref)); if (datalen != sizeof(isymref) + isymref.name_len + isymref.target_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } /* * For now, we only announce one symbolic ref, * as part of our capability advertisement. */ if (sent_capabilities || symrefstr != NULL || symrefname != NULL || symreftarget != NULL) break; symrefname = strndup(imsg.data + sizeof(isymref), isymref.name_len); if (symrefname == NULL) { err = got_error_from_errno("malloc"); goto done; } symreftarget = strndup( imsg.data + sizeof(isymref) + isymref.name_len, isymref.target_len); if (symreftarget == NULL) { err = got_error_from_errno("strndup"); goto done; } if (asprintf(&symrefstr, "%s:%s", symrefname, symreftarget) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = send_ref(outfd, isymref.target_id, symrefname, !sent_capabilities, client_is_reading, symrefstr, chattygot); free(refname); refname = NULL; if (err) goto done; sent_capabilities = 1; if (nrefs > 0) nrefs--; break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); } err = got_pkt_flushpkt(outfd, chattygot); if (err) goto done; done: free(symrefstr); free(symrefname); free(symreftarget); return err; } static const struct got_error * parse_want_line(char **common_capabilities, uint8_t *id, char *buf, size_t len) { const struct got_error *err; char *id_str = NULL, *client_capabilities = NULL; err = got_gitproto_parse_want_line(&id_str, &client_capabilities, buf, len); if (err) return err; if (!got_parse_hash_digest(id, id_str, GOT_HASH_SHA1)) { err = got_error_msg(GOT_ERR_BAD_PACKET, "want-line with bad object ID"); goto done; } if (client_capabilities) { err = got_gitproto_match_capabilities(common_capabilities, NULL, client_capabilities, read_capabilities, nitems(read_capabilities)); if (err) goto done; } done: free(id_str); free(client_capabilities); return err; } static const struct got_error * parse_have_line(uint8_t *id, char *buf, size_t len) { const struct got_error *err; char *id_str = NULL; err = got_gitproto_parse_have_line(&id_str, buf, len); if (err) return err; if (!got_parse_hash_digest(id, id_str, GOT_HASH_SHA1)) { err = got_error_msg(GOT_ERR_BAD_PACKET, "have-line with bad object ID"); goto done; } done: free(id_str); return err; } static const struct got_error * send_capability(struct got_capability *capa, struct imsgbuf *ibuf) { const struct got_error *err = NULL; struct gotd_imsg_capability icapa; size_t len; struct ibuf *wbuf; memset(&icapa, 0, sizeof(icapa)); icapa.key_len = strlen(capa->key); len = sizeof(icapa) + icapa.key_len; if (capa->value) { icapa.value_len = strlen(capa->value); len += icapa.value_len; } wbuf = imsg_create(ibuf, GOTD_IMSG_CAPABILITY, 0, 0, len); if (wbuf == NULL) { err = got_error_from_errno("imsg_create CAPABILITY"); return err; } if (imsg_add(wbuf, &icapa, sizeof(icapa)) == -1) return got_error_from_errno("imsg_add CAPABILITY"); if (imsg_add(wbuf, capa->key, icapa.key_len) == -1) return got_error_from_errno("imsg_add CAPABILITY"); if (capa->value) { if (imsg_add(wbuf, capa->value, icapa.value_len) == -1) return got_error_from_errno("imsg_add CAPABILITY"); } imsg_close(ibuf, wbuf); return NULL; } static const struct got_error * send_capabilities(int *use_sidebands, int *report_status, char *capabilities_str, struct imsgbuf *ibuf) { const struct got_error *err = NULL; struct gotd_imsg_capabilities icapas; struct got_capability *capa = NULL; size_t ncapa, i; err = got_gitproto_split_capabilities_str(&capa, &ncapa, capabilities_str); if (err) return err; icapas.ncapabilities = ncapa; if (imsg_compose(ibuf, GOTD_IMSG_CAPABILITIES, 0, 0, -1, &icapas, sizeof(icapas)) == -1) { err = got_error_from_errno("imsg_compose IMSG_CAPABILITIES"); goto done; } for (i = 0; i < ncapa; i++) { err = send_capability(&capa[i], ibuf); if (err) goto done; if (use_sidebands && strcmp(capa[i].key, GOT_CAPA_SIDE_BAND_64K) == 0) *use_sidebands = 1; if (report_status && strcmp(capa[i].key, GOT_CAPA_REPORT_STATUS) == 0) *report_status = 1; } done: free(capa); return err; } static const struct got_error * forward_flushpkt(struct imsgbuf *ibuf) { if (imsg_compose(ibuf, GOTD_IMSG_FLUSH, 0, 0, -1, NULL, 0) == -1) return got_error_from_errno("imsg_compose FLUSH"); return gotd_imsg_flush(ibuf); } static const struct got_error * recv_ack(struct imsg *imsg, uint8_t *expected_id) { struct gotd_imsg_ack iack; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(iack)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iack, imsg->data, sizeof(iack)); if (memcmp(iack.object_id, expected_id, SHA1_DIGEST_LENGTH) != 0) return got_error(GOT_ERR_BAD_OBJ_ID); return NULL; } static const struct got_error * recv_nak(struct imsg *imsg, uint8_t *expected_id) { struct gotd_imsg_ack inak; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(inak)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&inak, imsg->data, sizeof(inak)); if (memcmp(inak.object_id, expected_id, SHA1_DIGEST_LENGTH) != 0) return got_error(GOT_ERR_BAD_OBJ_ID); return NULL; } static const struct got_error * recv_want(int *use_sidebands, int outfd, struct imsgbuf *ibuf, char *buf, size_t len, int expect_capabilities, int chattygot) { const struct got_error *err; struct gotd_imsg_want iwant; char *capabilities_str; int done = 0; struct imsg imsg; memset(&iwant, 0, sizeof(iwant)); memset(&imsg, 0, sizeof(imsg)); err = parse_want_line(&capabilities_str, iwant.object_id, buf, len); if (err) return err; if (capabilities_str) { if (!expect_capabilities) { err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected capability announcement received"); goto done; } err = send_capabilities(use_sidebands, NULL, capabilities_str, ibuf); if (err) goto done; } if (imsg_compose(ibuf, GOTD_IMSG_WANT, 0, 0, -1, &iwant, sizeof(iwant)) == -1) { err = got_error_from_errno("imsg_compose WANT"); goto done; } err = gotd_imsg_flush(ibuf); if (err) goto done; /* * Wait for an ACK, or an error in case the desired object * does not exist. */ while (!done && err == NULL) { err = gotd_imsg_poll_recv(&imsg, ibuf, 0); if (err) break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: err = gotd_imsg_recv_error(NULL, &imsg); break; case GOTD_IMSG_ACK: err = recv_ack(&imsg, iwant.object_id); if (err) break; done = 1; break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); } done: free(capabilities_str); return err; } static const struct got_error * send_ack(int outfd, uint8_t *id, int chattygot) { char hex[SHA1_DIGEST_STRING_LENGTH]; char buf[GOT_PKT_MAX]; int len; if (got_sha1_digest_to_str(id, hex, sizeof(hex)) == NULL) return got_error(GOT_ERR_BAD_OBJ_ID); len = snprintf(buf, sizeof(buf), "ACK %s\n", hex); if (len >= sizeof(buf)) return got_error(GOT_ERR_NO_SPACE); return got_pkt_writepkt(outfd, buf, len, chattygot); } static const struct got_error * send_nak(int outfd, int chattygot) { char buf[5]; int len; len = snprintf(buf, sizeof(buf), "NAK\n"); if (len >= sizeof(buf)) return got_error(GOT_ERR_NO_SPACE); return got_pkt_writepkt(outfd, buf, len, chattygot); } static const struct got_error * recv_have(int *have_ack, int outfd, struct imsgbuf *ibuf, char *buf, size_t len, int chattygot) { const struct got_error *err; struct gotd_imsg_have ihave; int done = 0; struct imsg imsg; memset(&ihave, 0, sizeof(ihave)); memset(&imsg, 0, sizeof(imsg)); err = parse_have_line(ihave.object_id, buf, len); if (err) return err; if (imsg_compose(ibuf, GOTD_IMSG_HAVE, 0, 0, -1, &ihave, sizeof(ihave)) == -1) return got_error_from_errno("imsg_compose HAVE"); err = gotd_imsg_flush(ibuf); if (err) return err; /* * Wait for an ACK or a NAK, indicating whether a common * commit object has been found. */ while (!done && err == NULL) { err = gotd_imsg_poll_recv(&imsg, ibuf, 0); if (err) return err; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: err = gotd_imsg_recv_error(NULL, &imsg); break; case GOTD_IMSG_ACK: err = recv_ack(&imsg, ihave.object_id); if (err) break; if (!*have_ack) { err = send_ack(outfd, ihave.object_id, chattygot); if (err) return err; *have_ack = 1; } done = 1; break; case GOTD_IMSG_NAK: err = recv_nak(&imsg, ihave.object_id); if (err) break; done = 1; break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); } return err; } static const struct got_error * recv_done(int *packfd, int outfd, struct imsgbuf *ibuf, int chattygot) { const struct got_error *err; struct imsg imsg; int fd; *packfd = -1; if (imsg_compose(ibuf, GOTD_IMSG_DONE, 0, 0, -1, NULL, 0) == -1) return got_error_from_errno("imsg_compose DONE"); err = gotd_imsg_flush(ibuf); if (err) return err; while (*packfd == -1 && err == NULL) { err = gotd_imsg_poll_recv(&imsg, ibuf, 0); if (err) break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: err = gotd_imsg_recv_error(NULL, &imsg); break; case GOTD_IMSG_PACKFILE_PIPE: fd = imsg_get_fd(&imsg); if (fd != -1) *packfd = fd; else err = got_error(GOT_ERR_PRIVSEP_NO_FD); break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); } return err; } static const struct got_error * relay_progress_reports(struct imsgbuf *ibuf, int outfd, int chattygot) { const struct got_error *err = NULL; int pack_starting = 0; struct gotd_imsg_packfile_progress iprog; char buf[GOT_PKT_MAX]; struct imsg imsg; size_t datalen; int p_deltify = 0, n; const char *eol = "\r"; memset(&imsg, 0, sizeof(imsg)); while (!pack_starting && err == NULL) { err = gotd_imsg_poll_recv(&imsg, ibuf, 0); if (err) break; datalen = imsg.hdr.len - IMSG_HEADER_SIZE; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: err = gotd_imsg_recv_error(NULL, &imsg); break; case GOTD_IMSG_PACKFILE_READY: eol = "\n"; pack_starting = 1; /* fallthrough */ case GOTD_IMSG_PACKFILE_PROGRESS: if (datalen != sizeof(iprog)) { err = got_error(GOT_ERR_PRIVSEP_LEN); break; } memcpy(&iprog, imsg.data, sizeof(iprog)); if (iprog.nobj_total > 0) { p_deltify = (iprog.nobj_deltify * 100) / iprog.nobj_total; } buf[0] = GOT_SIDEBAND_PROGRESS_INFO; n = snprintf(&buf[1], sizeof(buf) - 1, "%d commits colored, " "%d objects found, " "deltify %d%%%s", iprog.ncolored, iprog.nfound, p_deltify, eol); if (n >= sizeof(buf) - 1) break; err = got_pkt_writepkt(outfd, buf, 1 + n, chattygot); break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); } return err; } static const struct got_error * serve_read(int infd, int outfd, int gotd_sock, const char *repo_path, int chattygot) { const struct got_error *err = NULL; char buf[GOT_PKT_MAX]; struct imsgbuf ibuf; enum protostate { STATE_EXPECT_WANT, STATE_EXPECT_MORE_WANT, STATE_EXPECT_HAVE_OR_DONE, STATE_DONE, }; enum protostate curstate = STATE_EXPECT_WANT; int have_ack = 0, use_sidebands = 0, seen_have = 0; int packfd = -1; size_t pack_chunksize; imsg_init(&ibuf, gotd_sock); err = announce_refs(outfd, &ibuf, 1, repo_path, chattygot); if (err) goto done; while (curstate != STATE_DONE) { int n; buf[0] = '\0'; err = got_pkt_readpkt(&n, infd, buf, sizeof(buf), chattygot, timeout); if (err) goto done; if (n == 0) { if (curstate != STATE_EXPECT_WANT && curstate != STATE_EXPECT_MORE_WANT && curstate != STATE_EXPECT_HAVE_OR_DONE) { err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected flush packet received"); goto done; } if (curstate == STATE_EXPECT_WANT) { ssize_t r; /* * If the client does not want to fetch * anything we should receive a flush * packet followed by EOF. */ r = read(infd, buf, sizeof(buf)); if (r == -1) { err = got_error_from_errno("read"); goto done; } if (r == 0) /* EOF */ goto done; /* Zero-length field followed by payload. */ err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected flush packet received"); goto done; } if (curstate == STATE_EXPECT_WANT || curstate == STATE_EXPECT_MORE_WANT || curstate == STATE_EXPECT_HAVE_OR_DONE) { err = forward_flushpkt(&ibuf); if (err) goto done; } if (curstate == STATE_EXPECT_HAVE_OR_DONE && !have_ack) { err = send_nak(outfd, chattygot); if (err) goto done; } if (curstate == STATE_EXPECT_MORE_WANT) curstate = STATE_EXPECT_HAVE_OR_DONE; } else if (n >= 5 && strncmp(buf, "want ", 5) == 0) { if (curstate != STATE_EXPECT_WANT && curstate != STATE_EXPECT_MORE_WANT) { err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected 'want' packet"); goto done; } err = recv_want(&use_sidebands, outfd, &ibuf, buf, n, curstate == STATE_EXPECT_WANT ? 1 : 0, chattygot); if (err) goto done; if (curstate == STATE_EXPECT_WANT) curstate = STATE_EXPECT_MORE_WANT; } else if (n >= 5 && strncmp(buf, "have ", 5) == 0) { if (curstate != STATE_EXPECT_HAVE_OR_DONE) { err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected 'have' packet"); goto done; } err = recv_have(&have_ack, outfd, &ibuf, buf, n, chattygot); if (err) goto done; seen_have = 1; } else if (n == 5 && strncmp(buf, "done\n", 5) == 0) { if (curstate != STATE_EXPECT_HAVE_OR_DONE) { err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected 'done' packet"); goto done; } err = recv_done(&packfd, outfd, &ibuf, chattygot); if (err) goto done; curstate = STATE_DONE; break; } else { err = got_error(GOT_ERR_BAD_PACKET); goto done; } } if (!seen_have) { err = send_nak(outfd, chattygot); if (err) goto done; } if (use_sidebands) { err = relay_progress_reports(&ibuf, outfd, chattygot); if (err) goto done; pack_chunksize = GOT_SIDEBAND_64K_PACKFILE_DATA_MAX; } else pack_chunksize = sizeof(buf); for (;;) { ssize_t r; r = read(packfd, use_sidebands ? &buf[1] : buf, pack_chunksize); if (r == -1) { err = got_error_from_errno("read"); break; } else if (r == 0) { err = got_pkt_flushpkt(outfd, chattygot); break; } if (use_sidebands) { buf[0] = GOT_SIDEBAND_PACKFILE_DATA; err = got_pkt_writepkt(outfd, buf, 1 + r, chattygot); if (err) break; } else { err = got_poll_write_full(outfd, buf, r); if (err) { if (err->code == GOT_ERR_EOF) err = NULL; break; } } } done: imsg_clear(&ibuf); if (packfd != -1 && close(packfd) == -1 && err == NULL) err = got_error_from_errno("close"); if (err) echo_error(err, outfd, chattygot); return err; } static const struct got_error * parse_ref_update_line(char **common_capabilities, char **refname, uint8_t *old_id, uint8_t *new_id, char *buf, size_t len) { const struct got_error *err; char *old_id_str = NULL, *new_id_str = NULL; char *client_capabilities = NULL; *refname = NULL; err = got_gitproto_parse_ref_update_line(&old_id_str, &new_id_str, refname, &client_capabilities, buf, len); if (err) return err; if (!got_parse_hash_digest(old_id, old_id_str, GOT_HASH_SHA1) || !got_parse_hash_digest(new_id, new_id_str, GOT_HASH_SHA1)) { err = got_error_msg(GOT_ERR_BAD_PACKET, "ref-update with bad object ID"); goto done; } if (!got_ref_name_is_valid(*refname)) { err = got_error_msg(GOT_ERR_BAD_PACKET, "ref-update with bad reference name"); goto done; } if (client_capabilities) { err = got_gitproto_match_capabilities(common_capabilities, NULL, client_capabilities, write_capabilities, nitems(write_capabilities)); if (err) goto done; } done: free(old_id_str); free(new_id_str); free(client_capabilities); if (err) { free(*refname); *refname = NULL; } return err; } static const struct got_error * recv_ref_update(int *report_status, int outfd, struct imsgbuf *ibuf, char *buf, size_t len, int expect_capabilities, int chattygot) { const struct got_error *err; struct gotd_imsg_ref_update iref; struct ibuf *wbuf; char *capabilities_str = NULL, *refname = NULL; int done = 0; struct imsg imsg; memset(&iref, 0, sizeof(iref)); memset(&imsg, 0, sizeof(imsg)); err = parse_ref_update_line(&capabilities_str, &refname, iref.old_id, iref.new_id, buf, len); if (err) return err; if (capabilities_str) { if (!expect_capabilities) { err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected capability announcement received"); goto done; } err = send_capabilities(NULL, report_status, capabilities_str, ibuf); if (err) goto done; } iref.name_len = strlen(refname); len = sizeof(iref) + iref.name_len; wbuf = imsg_create(ibuf, GOTD_IMSG_REF_UPDATE, 0, 0, len); if (wbuf == NULL) { err = got_error_from_errno("imsg_create REF_UPDATE"); goto done; } if (imsg_add(wbuf, &iref, sizeof(iref)) == -1) return got_error_from_errno("imsg_add REF_UPDATE"); if (imsg_add(wbuf, refname, iref.name_len) == -1) return got_error_from_errno("imsg_add REF_UPDATE"); imsg_close(ibuf, wbuf); err = gotd_imsg_flush(ibuf); if (err) goto done; /* Wait for ACK or an error. */ while (!done && err == NULL) { err = gotd_imsg_poll_recv(&imsg, ibuf, 0); if (err) break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: err = gotd_imsg_recv_error(NULL, &imsg); break; case GOTD_IMSG_ACK: err = recv_ack(&imsg, iref.new_id); if (err) break; done = 1; break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); } done: free(capabilities_str); free(refname); return err; } static const struct got_error * recv_packfile(struct imsg *imsg, int infd) { const struct got_error *err = NULL; size_t datalen; int packfd; char buf[GOT_PKT_MAX]; int pack_done = 0; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_MSG); packfd = imsg_get_fd(imsg); if (packfd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); while (!pack_done) { ssize_t r = 0; err = got_poll_fd(infd, POLLIN, 1); if (err) { if (err->code != GOT_ERR_TIMEOUT) break; err = NULL; } else { r = read(infd, buf, sizeof(buf)); if (r == -1) { err = got_error_from_errno("read"); break; } if (r == 0) { /* * Git clients hang up their side of the * connection after sending the pack file. */ err = NULL; pack_done = 1; break; } } if (r == 0) { /* Detect gotd(8) closing the pack pipe when done. */ err = got_poll_fd(packfd, 0, 1); if (err) { if (err->code != GOT_ERR_TIMEOUT && err->code != GOT_ERR_EOF) break; if (err->code == GOT_ERR_EOF) pack_done = 1; err = NULL; } } else { /* Write pack data and/or detect pipe being closed. */ err = got_poll_write_full(packfd, buf, r); if (err) { if (err->code == GOT_ERR_EOF) err = NULL; break; } } } close(packfd); return err; } static const struct got_error * report_unpack_status(struct imsg *imsg, int outfd, int chattygot) { const struct got_error *err = NULL; struct gotd_imsg_packfile_status istatus; char buf[GOT_PKT_MAX]; size_t datalen, len; char *reason = NULL; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(istatus)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&istatus, imsg->data, sizeof(istatus)); if (datalen != sizeof(istatus) + istatus.reason_len) return got_error(GOT_ERR_PRIVSEP_LEN); reason = strndup(imsg->data + sizeof(istatus), istatus.reason_len); if (reason == NULL) { err = got_error_from_errno("strndup"); goto done; } if (err == NULL) len = snprintf(buf, sizeof(buf), "unpack ok\n"); else len = snprintf(buf, sizeof(buf), "unpack %s\n", reason); if (len >= sizeof(buf)) { err = got_error(GOT_ERR_NO_SPACE); goto done; } err = got_pkt_writepkt(outfd, buf, len, chattygot); done: free(reason); return err; } static const struct got_error * recv_ref_update_ok(struct imsg *imsg, int outfd, int chattygot) { const struct got_error *err = NULL; struct gotd_imsg_ref_update_ok iok; size_t datalen, len; char buf[GOT_PKT_MAX]; char *refname = NULL; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(iok)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iok, imsg->data, sizeof(iok)); if (datalen != sizeof(iok) + iok.name_len) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iok, imsg->data, sizeof(iok)); refname = strndup(imsg->data + sizeof(iok), iok.name_len); if (refname == NULL) return got_error_from_errno("strndup"); len = snprintf(buf, sizeof(buf), "ok %s\n", refname); if (len >= sizeof(buf)) { err = got_error(GOT_ERR_NO_SPACE); goto done; } err = got_pkt_writepkt(outfd, buf, len, chattygot); done: free(refname); return err; } static const struct got_error * recv_ref_update_ng(struct imsg *imsg, int outfd, int chattygot) { const struct got_error *err = NULL; struct gotd_imsg_ref_update_ng ing; size_t datalen, len; char buf[GOT_PKT_MAX]; char *refname = NULL, *reason = NULL; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(ing)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ing, imsg->data, sizeof(ing)); if (datalen != sizeof(ing) + ing.name_len + ing.reason_len) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ing, imsg->data, sizeof(ing)); refname = strndup(imsg->data + sizeof(ing), ing.name_len); if (refname == NULL) return got_error_from_errno("strndup"); reason = strndup(imsg->data + sizeof(ing) + ing.name_len, ing.reason_len); if (reason == NULL) { err = got_error_from_errno("strndup"); goto done; } len = snprintf(buf, sizeof(buf), "ng %s %s\n", refname, reason); if (len >= sizeof(buf)) { err = got_error(GOT_ERR_NO_SPACE); goto done; } err = got_pkt_writepkt(outfd, buf, len, chattygot); done: free(refname); free(reason); return err; } static const struct got_error * serve_write(int infd, int outfd, int gotd_sock, const char *repo_path, int chattygot) { const struct got_error *err = NULL; char buf[GOT_PKT_MAX]; struct imsgbuf ibuf; enum protostate { STATE_EXPECT_REF_UPDATE, STATE_EXPECT_MORE_REF_UPDATES, STATE_EXPECT_PACKFILE, STATE_PACKFILE_RECEIVED, STATE_REFS_UPDATED, }; enum protostate curstate = STATE_EXPECT_REF_UPDATE; struct imsg imsg; int report_status = 0; imsg_init(&ibuf, gotd_sock); memset(&imsg, 0, sizeof(imsg)); err = announce_refs(outfd, &ibuf, 0, repo_path, chattygot); if (err) goto done; while (curstate != STATE_EXPECT_PACKFILE) { int n; buf[0] = '\0'; err = got_pkt_readpkt(&n, infd, buf, sizeof(buf), chattygot, timeout); if (err) goto done; if (n == 0) { if (curstate == STATE_EXPECT_REF_UPDATE) { /* The client will not send us anything. */ goto done; } else if (curstate != STATE_EXPECT_MORE_REF_UPDATES) { err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected flush packet received"); goto done; } err = forward_flushpkt(&ibuf); if (err) goto done; curstate = STATE_EXPECT_PACKFILE; } else if (n >= (SHA1_DIGEST_STRING_LENGTH * 2) + 2) { if (curstate != STATE_EXPECT_REF_UPDATE && curstate != STATE_EXPECT_MORE_REF_UPDATES) { err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected ref-update packet"); goto done; } if (curstate == STATE_EXPECT_REF_UPDATE) { err = recv_ref_update(&report_status, outfd, &ibuf, buf, n, 1, chattygot); } else { err = recv_ref_update(NULL, outfd, &ibuf, buf, n, 0, chattygot); } if (err) goto done; curstate = STATE_EXPECT_MORE_REF_UPDATES; } else { err = got_error(GOT_ERR_BAD_PACKET); goto done; } } while (curstate != STATE_PACKFILE_RECEIVED) { err = gotd_imsg_poll_recv(&imsg, &ibuf, 0); if (err) goto done; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: err = gotd_imsg_recv_error(NULL, &imsg); goto done; case GOTD_IMSG_PACKFILE_PIPE: err = recv_packfile(&imsg, infd); if (err) { if (err->code != GOT_ERR_EOF) goto done; /* * EOF is reported when the client hangs up, * which can happen with Git clients. * The socket should stay half-open so we * can still send our reports if requested. */ err = NULL; } curstate = STATE_PACKFILE_RECEIVED; break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); if (err) goto done; } while (curstate != STATE_REFS_UPDATED && err == NULL) { err = gotd_imsg_poll_recv(&imsg, &ibuf, 0); if (err) break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: err = gotd_imsg_recv_error(NULL, &imsg); break; case GOTD_IMSG_PACKFILE_STATUS: if (!report_status) break; err = report_unpack_status(&imsg, outfd, chattygot); break; case GOTD_IMSG_REF_UPDATE_OK: if (!report_status) break; err = recv_ref_update_ok(&imsg, outfd, chattygot); break; case GOTD_IMSG_REF_UPDATE_NG: if (!report_status) break; err = recv_ref_update_ng(&imsg, outfd, chattygot); break; case GOTD_IMSG_REFS_UPDATED: curstate = STATE_REFS_UPDATED; err = got_pkt_flushpkt(outfd, chattygot); break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); } done: imsg_clear(&ibuf); if (err) echo_error(err, outfd, chattygot); return err; } const struct got_error * got_serve(int infd, int outfd, const char *command, const char *repo_path, int gotd_sock, int chattygot) { const struct got_error *err = NULL; if (strcmp(command, GOT_DIAL_CMD_FETCH) == 0) err = serve_read(infd, outfd, gotd_sock, repo_path, chattygot); else if (strcmp(command, GOT_DIAL_CMD_SEND) == 0) err = serve_write(infd, outfd, gotd_sock, repo_path, chattygot); else err = got_error(GOT_ERR_BAD_PACKET); return err; } got-portable-0.101/lib/gotconfig.c0000664000175100017510000000405114644144735012504 /* * Copyright (c) 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_repository.h" #include "got_lib_gotconfig.h" #include "got_gotconfig.h" void got_gotconfig_free(struct got_gotconfig *conf) { int i; if (conf == NULL) return; free(conf->author); for (i = 0; i < conf->nremotes; i++) got_repo_free_remote_repo_data(&conf->remotes[i]); free(conf->remotes); free(conf); } const char * got_gotconfig_get_author(const struct got_gotconfig *conf) { return conf->author; } void got_gotconfig_get_remotes(int *nremotes, const struct got_remote_repo **remotes, const struct got_gotconfig *conf) { *nremotes = conf->nremotes; *remotes = conf->remotes; } const char * got_gotconfig_get_allowed_signers_file(const struct got_gotconfig *conf) { return conf->allowed_signers_file; } const char * got_gotconfig_get_revoked_signers_file(const struct got_gotconfig *conf) { return conf->revoked_signers_file; } const char * got_gotconfig_get_signer_id(const struct got_gotconfig *conf) { return conf->signer_id; } got-portable-0.101/lib/deltify.c0000664000175100017510000006305114644144735012172 /* * Copyright (c) 2020 Ori Bernstein * Copyright (c) 2021 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_lib_deltify.h" #include "murmurhash2.h" #ifndef MIN #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) #endif /* * The algorihm used here is FastCDC (Fast Content-Defined Chunking) * https://www.usenix.org/conference/atc16/technical-sessions/presentation/xia */ static const uint32_t geartab[256] = { 0x67ed26b7, 0x32da500c, 0x53d0fee0, 0xce387dc7, 0xcd406d90, 0x2e83a4d4, 0x9fc9a38d, 0xb67259dc, 0xca6b1722, 0x6d2ea08c, 0x235cea2e, 0x3149bb5f, 0x1beda787, 0x2a6b77d5, 0x2f22d9ac, 0x91fc0544, 0xe413acfa, 0x5a30ff7a, 0xad6fdde0, 0x444fd0f5, 0x7ad87864, 0x58c5ff05, 0x8d2ec336, 0x2371f853, 0x550f8572, 0x6aa448dd, 0x7c9ddbcf, 0x95221e14, 0x2a82ec33, 0xcbec5a78, 0xc6795a0d, 0x243995b7, 0x1c909a2f, 0x4fded51c, 0x635d334b, 0x0e2b9999, 0x2702968d, 0x856de1d5, 0x3325d60e, 0xeb6a7502, 0xec2a9844, 0x0905835a, 0xa1820375, 0xa4be5cab, 0x96a6c058, 0x2c2ccd70, 0xba40fce3, 0xd794c46b, 0x8fbae83e, 0xc3aa7899, 0x3d3ff8ed, 0xa0d42b5b, 0x571c0c97, 0xd2811516, 0xf7e7b96c, 0x4fd2fcbd, 0xe2fdec94, 0x282cc436, 0x78e8e95c, 0x80a3b613, 0xcfbee20c, 0xd4a32d1c, 0x2a12ff13, 0x6af82936, 0xe5630258, 0x8efa6a98, 0x294fb2d1, 0xdeb57086, 0x5f0fddb3, 0xeceda7ce, 0x4c87305f, 0x3a6d3307, 0xe22d2942, 0x9d060217, 0x1e42ed02, 0xb6f63b52, 0x4367f39f, 0x055cf262, 0x03a461b2, 0x5ef9e382, 0x386bc03a, 0x2a1e79c7, 0xf1a0058b, 0xd4d2dea9, 0x56baf37d, 0x5daff6cc, 0xf03a951d, 0xaef7de45, 0xa8f4581e, 0x3960b555, 0xffbfff6d, 0xbe702a23, 0x8f5b6d6f, 0x061739fb, 0x98696f47, 0x3fd596d4, 0x151eac6b, 0xa9fcc4f5, 0x69181a12, 0x3ac5a107, 0xb5198fe7, 0x96bcb1da, 0x1b5ddf8e, 0xc757d650, 0x65865c3a, 0x8fc0a41a, 0x87435536, 0x99eda6f2, 0x41874794, 0x29cff4e8, 0xb70efd9a, 0x3103f6e7, 0x84d2453b, 0x15a450bd, 0x74f49af1, 0x60f664b1, 0xa1c86935, 0xfdafbce1, 0xe36353e3, 0x5d9ba739, 0xbc0559ba, 0x708b0054, 0xd41d808c, 0xb2f31723, 0x9027c41f, 0xf136d165, 0xb5374b12, 0x9420a6ac, 0x273958b6, 0xe6c2fad0, 0xebdc1f21, 0xfb33af8b, 0xc71c25cd, 0xe9a2d8e5, 0xbeb38a50, 0xbceb7cc2, 0x4e4e73f0, 0xcd6c251d, 0xde4c032c, 0x4b04ac30, 0x725b8b21, 0x4eb8c33b, 0x20d07b75, 0x0567aa63, 0xb56b2bb7, 0xc1f5fd3a, 0xcafd35ca, 0x470dd4da, 0xfe4f94cd, 0xfb8de424, 0xe8dbcf40, 0xfe50a37a, 0x62db5b5d, 0xf32f4ab6, 0x2c4a8a51, 0x18473dc0, 0xfe0cbb6e, 0xfe399efd, 0xdf34ecc9, 0x6ccd5055, 0x46097073, 0x139135c2, 0x721c76f6, 0x1c6a94b4, 0x6eee014d, 0x8a508e02, 0x3da538f5, 0x280d394f, 0x5248a0c4, 0x3ce94c6c, 0x9a71ad3a, 0x8493dd05, 0xe43f0ab6, 0x18e4ed42, 0x6c5c0e09, 0x42b06ec9, 0x8d330343, 0xa45b6f59, 0x2a573c0c, 0xd7fd3de6, 0xeedeab68, 0x5c84dafc, 0xbbd1b1a8, 0xa3ce1ad1, 0x85b70bed, 0xb6add07f, 0xa531309c, 0x8f8ab852, 0x564de332, 0xeac9ed0c, 0x73da402c, 0x3ec52761, 0x43af2f4d, 0xd6ff45c8, 0x4c367462, 0xd553bd6a, 0x44724855, 0x3b2aa728, 0x56e5eb65, 0xeaf16173, 0x33fa42ff, 0xd714bb5d, 0xfbd0a3b9, 0xaf517134, 0x9416c8cd, 0x534cf94f, 0x548947c2, 0x34193569, 0x32f4389a, 0xfe7028bc, 0xed73b1ed, 0x9db95770, 0x468e3922, 0x0440c3cd, 0x60059a62, 0x33504562, 0x2b229fbd, 0x5174dca5, 0xf7028752, 0xd63c6aa8, 0x31276f38, 0x0646721c, 0xb0191da8, 0xe00e6de0, 0x9eac1a6e, 0x9f7628a5, 0xed6c06ea, 0x0bb8af15, 0xf119fb12, 0x38693c1c, 0x732bc0fe, 0x84953275, 0xb82ec888, 0x33a4f1b3, 0x3099835e, 0x028a8782, 0x5fdd51d7, 0xc6c717b3, 0xb06caf71, 0x17c8c111, 0x61bad754, 0x9fd03061, 0xe09df1af, 0x3bc9eb73, 0x85878413, 0x9889aaf2, 0x3f5a9e46, 0x42c9f01f, 0x9984a4f4, 0xd5de43cc, 0xd294daed, 0xbecba2d2, 0xf1f6e72c, 0x5551128a, 0x83af87e2, 0x6f0342ba, }; static const struct got_error *addblk(struct got_delta_table *, FILE *, uint8_t *, off_t, off_t, off_t, uint32_t); static uint32_t hashblk(const unsigned char *p, off_t n, uint32_t seed) { return murmurhash2(p, n, seed); } static const struct got_error * lookup(int *n, struct got_delta_table *dt, FILE *f, off_t file_offset0, off_t len, off_t offset, uint32_t h) { struct got_delta_block *block; uint8_t buf[GOT_DELTIFY_MAXCHUNK]; uint8_t buf2[GOT_DELTIFY_MAXCHUNK]; size_t r = 0; int i; for (i = h % dt->size; dt->offs[i] != 0; i = (i + 1) % dt->size) { block = &dt->blocks[dt->offs[i] - 1]; if (block->len != len || block->hash != h) continue; if (r == 0) { if (fseeko(f, file_offset0 + offset, SEEK_SET) == -1) return got_error_from_errno("fseeko"); r = fread(buf, 1, len, f); if (r != len) { if (!ferror(f)) break; /* why? */ return got_ferror(f, GOT_ERR_IO); } } if (fseeko(f, file_offset0 + block->offset, SEEK_SET) == -1) return got_error_from_errno("fseeko"); if (fread(buf2, 1, len, f) != len) return got_ferror(f, GOT_ERR_IO); if (memcmp(buf, buf2, len) == 0) break; } *n = i; return NULL; } static const struct got_error * lookup_mem(int *n, struct got_delta_table *dt, uint8_t *basedata, off_t basefile_offset0, uint8_t *p, off_t len, uint32_t h) { struct got_delta_block *block; uint8_t *d; int i; for (i = h % dt->size; dt->offs[i] != 0; i = (i + 1) % dt->size) { block = &dt->blocks[dt->offs[i] - 1]; if (len == block->len && h == block->hash) { d = basedata + basefile_offset0 + block->offset; if (memcmp(d, p, len) == 0) break; } } *n = i; return NULL; } static const struct got_error * resizeht(struct got_delta_table *dt, FILE *f, off_t offset0, uint8_t *data, off_t len) { const struct got_error *err; struct got_delta_block *b; size_t newsize, oldsize; int i, n; if (dt->nblocks == dt->nalloc) { newsize = dt->nalloc + 256; b = reallocarray(dt->blocks, newsize, sizeof(*dt->blocks)); if (b == NULL) return got_error_from_errno("reallocarray"); dt->blocks = b; dt->nalloc = newsize; } if (dt->blocks == NULL || dt->len * 100 / dt->size > 70) { oldsize = dt->size; dt->size *= 2; free(dt->offs); dt->offs = calloc(dt->size, sizeof(*dt->offs)); if (dt->offs == NULL) { dt->size = oldsize; return got_error_from_errno("calloc"); } for (i = 0; i < dt->nblocks; ++i) { b = &dt->blocks[i]; if (f) err = lookup(&n, dt, f, offset0, b->len, b->offset, b->hash); else err = lookup_mem(&n, dt, data, offset0, data + b->offset, b->len, b->hash); if (err) { free(dt->offs); dt->offs = NULL; dt->size = oldsize; return err; } assert(dt->offs[n] == 0); dt->offs[n] = i + 1; } } return NULL; } static const struct got_error * addblk(struct got_delta_table *dt, FILE *f, uint8_t *data, off_t file_offset0, off_t len, off_t offset, uint32_t h) { const struct got_error *err; struct got_delta_block *block; int i; if (len == 0) return NULL; err = resizeht(dt, f, file_offset0, data, len); if (err) return err; if (f) err = lookup(&i, dt, f, file_offset0, len, offset, h); else err = lookup_mem(&i, dt, data, file_offset0, data + offset, len, h); if (err) return err; if (dt->offs[i] != 0) return NULL; /* found */ dt->offs[i] = dt->nblocks + 1; block = &dt->blocks[dt->nblocks]; block->len = len; block->offset = offset; block->hash = h; dt->nblocks++; dt->len++; return NULL; } static const struct got_error * lookupblk(struct got_delta_block **block, struct got_delta_table *dt, unsigned char *p, off_t len, uint32_t seed, FILE *basefile, off_t basefile_offset0) { int i; uint32_t h; uint8_t buf[GOT_DELTIFY_MAXCHUNK]; struct got_delta_block *b; size_t r; *block = NULL; h = hashblk(p, len, seed); for (i = h % dt->size; dt->offs[i] != 0; i = (i + 1) % dt->size) { b = &dt->blocks[dt->offs[i] - 1]; if (b->hash != h || b->len != len) continue; if (fseeko(basefile, basefile_offset0 + b->offset, SEEK_SET) == -1) return got_error_from_errno("fseeko"); r = fread(buf, 1, len, basefile); if (r != len) return got_ferror(basefile, GOT_ERR_IO); if (memcmp(p, buf, len) == 0) { *block = b; break; } } return NULL; } static const struct got_error * lookupblk_mem(struct got_delta_block **block, struct got_delta_table *dt, unsigned char *p, off_t len, uint32_t seed, uint8_t *basedata, off_t basefile_offset0) { const struct got_error *err; int n; uint32_t h; *block = NULL; h = hashblk(p, len, seed); err = lookup_mem(&n, dt, basedata, basefile_offset0, p, len, h); if (err) return err; if (dt->offs[n] != 0) *block = &dt->blocks[dt->offs[n] - 1]; return NULL; } static const struct got_error * nextblk(uint8_t *buf, off_t *blocklen, FILE *f) { uint32_t gh; const unsigned char *p; size_t r; off_t pos = ftello(f); *blocklen = 0; r = fread(buf, 1, GOT_DELTIFY_MAXCHUNK, f); if (r == 0 && ferror(f)) return got_ferror(f, GOT_ERR_IO); if (r < GOT_DELTIFY_MINCHUNK) return NULL; /* no more delta-worthy blocks left */ /* Got a deltifiable block. Find the split-point where it ends. */ p = buf + GOT_DELTIFY_MINCHUNK; gh = 0; while (p != buf + r) { gh = (gh << 1) + geartab[*p++]; if ((gh & GOT_DELTIFY_SPLITMASK) == 0) break; } *blocklen = (p - buf); if (fseeko(f, pos + *blocklen, SEEK_SET) == -1) return got_error_from_errno("fseeko"); return NULL; } static const struct got_error * nextblk_mem(off_t *blocklen, uint8_t *data, off_t fileoffset, off_t filesize) { uint32_t gh; const unsigned char *p; *blocklen = 0; if (fileoffset >= filesize || filesize - fileoffset < GOT_DELTIFY_MINCHUNK) return NULL; /* no more delta-worthy blocks left */ /* Got a deltifiable block. Find the split-point where it ends. */ p = data + fileoffset + GOT_DELTIFY_MINCHUNK; gh = 0; while (p != data + MIN(fileoffset + GOT_DELTIFY_MAXCHUNK, filesize)) { gh = (gh << 1) + geartab[*p++]; if ((gh & GOT_DELTIFY_SPLITMASK) == 0) break; } *blocklen = (p - (data + fileoffset)); return NULL; } const struct got_error * got_deltify_init(struct got_delta_table **dt, FILE *f, off_t fileoffset, off_t filesize, uint32_t seed) { const struct got_error *err = NULL; uint32_t h; const off_t offset0 = fileoffset; *dt = calloc(1, sizeof(**dt)); if (*dt == NULL) return got_error_from_errno("calloc"); (*dt)->nblocks = 0; (*dt)->nalloc = 128; (*dt)->blocks = calloc((*dt)->nalloc, sizeof(struct got_delta_block)); if ((*dt)->blocks == NULL) { err = got_error_from_errno("calloc"); goto done; } (*dt)->size = 128; (*dt)->offs = calloc((*dt)->size, sizeof(*(*dt)->offs)); if ((*dt)->offs == NULL) { err = got_error_from_errno("calloc"); goto done; } if (fseeko(f, fileoffset, SEEK_SET) == -1) return got_error_from_errno("fseeko"); while (fileoffset < filesize) { uint8_t buf[GOT_DELTIFY_MAXCHUNK]; off_t blocklen; err = nextblk(buf, &blocklen, f); if (err) goto done; if (blocklen == 0) break; h = hashblk(buf, blocklen, seed); err = addblk(*dt, f, NULL, offset0, blocklen, fileoffset - offset0, h); if (err) goto done; fileoffset += blocklen; if (fseeko(f, fileoffset, SEEK_SET) == -1) return got_error_from_errno("fseeko"); } done: if (err) { free((*dt)->blocks); free(*dt); *dt = NULL; } return err; } const struct got_error * got_deltify_init_mem(struct got_delta_table **dt, uint8_t *data, off_t fileoffset, off_t filesize, uint32_t seed) { const struct got_error *err = NULL; uint32_t h; const off_t offset0 = fileoffset; *dt = calloc(1, sizeof(**dt)); if (*dt == NULL) return got_error_from_errno("calloc"); (*dt)->nblocks = 0; (*dt)->nalloc = 128; (*dt)->blocks = calloc((*dt)->nalloc, sizeof(struct got_delta_block)); if ((*dt)->blocks == NULL) { err = got_error_from_errno("calloc"); goto done; } (*dt)->size = 128; (*dt)->offs = calloc((*dt)->size, sizeof(*(*dt)->offs)); if ((*dt)->offs == NULL) { err = got_error_from_errno("calloc"); goto done; } while (fileoffset < filesize) { off_t blocklen; err = nextblk_mem(&blocklen, data, fileoffset, filesize); if (err) goto done; if (blocklen == 0) break; h = hashblk(data + fileoffset, blocklen, seed); err = addblk(*dt, NULL, data, offset0, blocklen, fileoffset - offset0, h); if (err) goto done; fileoffset += blocklen; } done: if (err) { free((*dt)->blocks); free(*dt); *dt = NULL; } return err; } void got_deltify_free(struct got_delta_table *dt) { if (dt == NULL) return; free(dt->blocks); free(dt->offs); free(dt); } static const struct got_error * emitdelta(struct got_delta_instruction **deltas, size_t *nalloc, int *ndeltas, const size_t alloc_chunk_size, int copy, off_t offset, off_t len) { struct got_delta_instruction *d, *p; if (*nalloc < *ndeltas + alloc_chunk_size) { p = reallocarray(*deltas, *nalloc + alloc_chunk_size, sizeof(struct got_delta_instruction)); if (p == NULL) return got_error_from_errno("reallocarray"); *deltas = p; *nalloc += alloc_chunk_size; } *ndeltas += 1; d = &(*deltas)[*ndeltas - 1]; d->copy = copy; d->offset = offset; d->len = len; return NULL; } static const struct got_error * stretchblk(FILE *basefile, off_t base_offset0, struct got_delta_block *block, FILE *f, off_t filesize, off_t *blocklen) { uint8_t basebuf[GOT_DELTIFY_MAXCHUNK], buf[GOT_DELTIFY_MAXCHUNK]; size_t base_r, r, i; int buf_equal = 1; if (fseeko(basefile, base_offset0 + block->offset + *blocklen, SEEK_SET) == -1) return got_error_from_errno("fseeko"); while (buf_equal && *blocklen < (1 << 24) - 1) { base_r = fread(basebuf, 1, sizeof(basebuf), basefile); if (base_r == 0) { if (ferror(basefile)) return got_ferror(basefile, GOT_ERR_IO); break; } r = fread(buf, 1, sizeof(buf), f); if (r == 0) { if (ferror(f)) return got_ferror(f, GOT_ERR_IO); break; } for (i = 0; i < MIN(base_r, r); i++) { if (buf[i] != basebuf[i]) { buf_equal = 0; break; } (*blocklen)++; } } return NULL; } static const struct got_error * stretchblk_file_mem(uint8_t *basedata, off_t base_offset0, off_t basefile_size, struct got_delta_block *block, FILE *f, off_t filesize, off_t *blocklen) { uint8_t buf[GOT_DELTIFY_MAXCHUNK]; size_t r, i; int buf_equal = 1; off_t base_offset = base_offset0 + block->offset + *blocklen; if (base_offset > basefile_size) { return got_error_fmt(GOT_ERR_RANGE, "read beyond the size of delta base at offset %lld", (long long)base_offset); } while (buf_equal && *blocklen < (1 << 24) - 1) { if (base_offset + *blocklen >= basefile_size) break; r = fread(buf, 1, sizeof(buf), f); if (r == 0) { if (ferror(f)) return got_ferror(f, GOT_ERR_IO); break; } for (i = 0; i < MIN(basefile_size - base_offset, r); i++) { if (buf[i] != *(basedata + base_offset + i)) { buf_equal = 0; break; } (*blocklen)++; } } return NULL; } static const struct got_error * stretchblk_mem_file(FILE *basefile, off_t base_offset0, struct got_delta_block *block, uint8_t *data, off_t fileoffset, off_t filesize, off_t *blocklen) { uint8_t basebuf[GOT_DELTIFY_MAXCHUNK]; size_t base_r, i; int buf_equal = 1; if (fileoffset > filesize) { return got_error_fmt(GOT_ERR_RANGE, "read beyond the size of deltify file at offset %lld", (long long)fileoffset); } if (fseeko(basefile, base_offset0 + block->offset + *blocklen, SEEK_SET) == -1) return got_error_from_errno("fseeko"); while (buf_equal && *blocklen < (1 << 24) - 1) { if (fileoffset + *blocklen >= filesize) break; base_r = fread(basebuf, 1, sizeof(basebuf), basefile); if (base_r == 0) { if (ferror(basefile)) return got_ferror(basefile, GOT_ERR_IO); break; } for (i = 0; i < MIN(base_r, filesize - fileoffset); i++) { if (*(data + fileoffset + i) != basebuf[i]) { buf_equal = 0; break; } (*blocklen)++; } } return NULL; } static const struct got_error * stretchblk_mem_mem(uint8_t *basedata, off_t base_offset0, off_t basefile_size, struct got_delta_block *block, uint8_t *data, off_t fileoffset, off_t filesize, off_t *blocklen) { off_t i, maxlen; off_t base_offset = base_offset0 + block->offset + *blocklen; uint8_t *p, *q; if (base_offset > basefile_size) { return got_error_fmt(GOT_ERR_RANGE, "read beyond the size of delta base at offset %lld", (long long)base_offset); } if (fileoffset > filesize) { return got_error_fmt(GOT_ERR_RANGE, "read beyond the size of deltify file at offset %lld", (long long)fileoffset); } p = data + fileoffset; q = basedata + base_offset; maxlen = MIN(basefile_size - base_offset, filesize - fileoffset); for (i = 0; i < maxlen && *blocklen < (1 << 24) - 1; i++) { if (p[i] != q[i]) break; (*blocklen)++; } return NULL; } const struct got_error * got_deltify(struct got_delta_instruction **deltas, int *ndeltas, FILE *f, off_t fileoffset, off_t filesize, uint32_t seed, struct got_delta_table *dt, FILE *basefile, off_t basefile_offset0, off_t basefile_size) { const struct got_error *err = NULL; const off_t offset0 = fileoffset; size_t nalloc = 0; const size_t alloc_chunk_size = 64; *deltas = NULL; *ndeltas = 0; /* * offset0 indicates where data to be deltified begins. * For example, we want to avoid deltifying a Git object header at * the beginning of the file. */ if (fseeko(f, offset0, SEEK_SET) == -1) return got_error_from_errno("fseeko"); *deltas = reallocarray(NULL, alloc_chunk_size, sizeof(struct got_delta_instruction)); if (*deltas == NULL) return got_error_from_errno("reallocarray"); nalloc = alloc_chunk_size; while (fileoffset < filesize) { uint8_t buf[GOT_DELTIFY_MAXCHUNK]; off_t blocklen; struct got_delta_block *block; err = nextblk(buf, &blocklen, f); if (err) break; if (blocklen == 0) { /* Source remainder from the file itself. */ if (fileoffset < filesize) { err = emitdelta(deltas, &nalloc, ndeltas, alloc_chunk_size, 0, fileoffset - offset0, filesize - fileoffset); } break; } err = lookupblk(&block, dt, buf, blocklen, seed, basefile, basefile_offset0); if (err) break; if (block != NULL) { /* * We have found a matching block in the delta base. * Attempt to stretch the block as far as possible and * generate a copy instruction. */ err = stretchblk(basefile, basefile_offset0, block, f, filesize, &blocklen); if (err) break; err = emitdelta(deltas, &nalloc, ndeltas, alloc_chunk_size, 1, block->offset, blocklen); if (err) break; } else { /* * No match. * This block needs to be sourced from the file itself. */ err = emitdelta(deltas, &nalloc, ndeltas, alloc_chunk_size, 0, fileoffset - offset0, blocklen); if (err) break; } fileoffset += blocklen; if (fseeko(f, fileoffset, SEEK_SET) == -1) { err = got_error_from_errno("fseeko"); break; } } if (err) { free(*deltas); *deltas = NULL; *ndeltas = 0; } return err; } const struct got_error * got_deltify_file_mem(struct got_delta_instruction **deltas, int *ndeltas, FILE *f, off_t fileoffset, off_t filesize, uint32_t seed, struct got_delta_table *dt, uint8_t *basedata, off_t basefile_offset0, off_t basefile_size) { const struct got_error *err = NULL; const off_t offset0 = fileoffset; size_t nalloc = 0; const size_t alloc_chunk_size = 64; *deltas = NULL; *ndeltas = 0; /* * offset0 indicates where data to be deltified begins. * For example, we want to avoid deltifying a Git object header at * the beginning of the file. */ if (fseeko(f, offset0, SEEK_SET) == -1) return got_error_from_errno("fseeko"); *deltas = reallocarray(NULL, alloc_chunk_size, sizeof(struct got_delta_instruction)); if (*deltas == NULL) return got_error_from_errno("reallocarray"); nalloc = alloc_chunk_size; while (fileoffset < filesize) { uint8_t buf[GOT_DELTIFY_MAXCHUNK]; off_t blocklen; struct got_delta_block *block; err = nextblk(buf, &blocklen, f); if (err) break; if (blocklen == 0) { /* Source remainder from the file itself. */ if (fileoffset < filesize) { err = emitdelta(deltas, &nalloc, ndeltas, alloc_chunk_size, 0, fileoffset - offset0, filesize - fileoffset); } break; } err = lookupblk_mem(&block, dt, buf, blocklen, seed, basedata, basefile_offset0); if (err) break; if (block != NULL) { /* * We have found a matching block in the delta base. * Attempt to stretch the block as far as possible and * generate a copy instruction. */ err = stretchblk_file_mem(basedata, basefile_offset0, basefile_size, block, f, filesize, &blocklen); if (err) break; err = emitdelta(deltas, &nalloc, ndeltas, alloc_chunk_size, 1, block->offset, blocklen); if (err) break; } else { /* * No match. * This block needs to be sourced from the file itself. */ err = emitdelta(deltas, &nalloc, ndeltas, alloc_chunk_size, 0, fileoffset - offset0, blocklen); if (err) break; } fileoffset += blocklen; if (fseeko(f, fileoffset, SEEK_SET) == -1) { err = got_error_from_errno("fseeko"); break; } } if (err) { free(*deltas); *deltas = NULL; *ndeltas = 0; } return err; } const struct got_error * got_deltify_mem_file(struct got_delta_instruction **deltas, int *ndeltas, uint8_t *data, off_t fileoffset, off_t filesize, uint32_t seed, struct got_delta_table *dt, FILE *basefile, off_t basefile_offset0, off_t basefile_size) { const struct got_error *err = NULL; const off_t offset0 = fileoffset; size_t nalloc = 0; const size_t alloc_chunk_size = 64; *deltas = NULL; *ndeltas = 0; *deltas = reallocarray(NULL, alloc_chunk_size, sizeof(struct got_delta_instruction)); if (*deltas == NULL) return got_error_from_errno("reallocarray"); nalloc = alloc_chunk_size; while (fileoffset < filesize) { off_t blocklen; struct got_delta_block *block; err = nextblk_mem(&blocklen, data, fileoffset, filesize); if (err) break; if (blocklen == 0) { /* Source remainder from the file itself. */ if (fileoffset < filesize) { err = emitdelta(deltas, &nalloc, ndeltas, alloc_chunk_size, 0, fileoffset - offset0, filesize - fileoffset); } break; } err = lookupblk(&block, dt, data + fileoffset, blocklen, seed, basefile, basefile_offset0); if (err) break; if (block != NULL) { /* * We have found a matching block in the delta base. * Attempt to stretch the block as far as possible and * generate a copy instruction. */ err = stretchblk_mem_file(basefile, basefile_offset0, block, data, fileoffset + blocklen, filesize, &blocklen); if (err) break; err = emitdelta(deltas, &nalloc, ndeltas, alloc_chunk_size, 1, block->offset, blocklen); if (err) break; } else { /* * No match. * This block needs to be sourced from the file itself. */ err = emitdelta(deltas, &nalloc, ndeltas, alloc_chunk_size, 0, fileoffset - offset0, blocklen); if (err) break; } fileoffset += blocklen; } if (err) { free(*deltas); *deltas = NULL; *ndeltas = 0; } return err; } const struct got_error * got_deltify_mem_mem(struct got_delta_instruction **deltas, int *ndeltas, uint8_t *data, off_t fileoffset, off_t filesize, uint32_t seed, struct got_delta_table *dt, uint8_t *basedata, off_t basefile_offset0, off_t basefile_size) { const struct got_error *err = NULL; const off_t offset0 = fileoffset; size_t nalloc = 0; const size_t alloc_chunk_size = 64; *deltas = NULL; *ndeltas = 0; *deltas = reallocarray(NULL, alloc_chunk_size, sizeof(struct got_delta_instruction)); if (*deltas == NULL) return got_error_from_errno("reallocarray"); nalloc = alloc_chunk_size; while (fileoffset < filesize) { off_t blocklen; struct got_delta_block *block; err = nextblk_mem(&blocklen, data, fileoffset, filesize); if (err) break; if (blocklen == 0) { /* Source remainder from the file itself. */ if (fileoffset < filesize) { err = emitdelta(deltas, &nalloc, ndeltas, alloc_chunk_size, 0, fileoffset - offset0, filesize - fileoffset); } break; } err = lookupblk_mem(&block, dt, data + fileoffset, blocklen, seed, basedata, basefile_offset0); if (err) break; if (block != NULL) { /* * We have found a matching block in the delta base. * Attempt to stretch the block as far as possible and * generate a copy instruction. */ err = stretchblk_mem_mem(basedata, basefile_offset0, basefile_size, block, data, fileoffset + blocklen, filesize, &blocklen); if (err) break; err = emitdelta(deltas, &nalloc, ndeltas, alloc_chunk_size, 1, block->offset, blocklen); if (err) break; } else { /* * No match. * This block needs to be sourced from the file itself. */ err = emitdelta(deltas, &nalloc, ndeltas, alloc_chunk_size, 0, fileoffset - offset0, blocklen); if (err) break; } fileoffset += blocklen; } if (err) { free(*deltas); *deltas = NULL; *ndeltas = 0; } return err; } got-portable-0.101/lib/murmurhash2.c0000644000175100017510000000234314644143163012774 //----------------------------------------------------------------------------- // MurmurHash2 was written by Austin Appleby, and is placed in the public // domain. The author hereby disclaims copyright to this source code. /* Obtained from https://github.com/aappleby/smhasher */ #include #include #include "murmurhash2.h" uint32_t murmurhash2(const unsigned char * key, int len, uint32_t seed) { // 'm' and 'r' are mixing constants generated offline. // They're not really 'magic', they just happen to work well. const uint32_t m = 0x5bd1e995; const int r = 24; // Initialize the hash to a 'random' value uint32_t h = seed ^ len; // Mix 4 bytes at a time into the hash const unsigned char *data = key; while(len >= 4) { uint32_t k; memcpy(&k, data, sizeof(k)); k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; data += 4; len -= 4; } // Handle the last few bytes of the input array switch(len) { case 3: h ^= data[2] << 16; case 2: h ^= data[1] << 8; case 1: h ^= data[0]; h *= m; }; // Do a few final mixes of the hash to ensure the last few // bytes are well-incorporated. h ^= h >> 13; h *= m; h ^= h >> 15; return h; } got-portable-0.101/lib/got_lib_object_cache.h0000644000175100017510000000337014644143163014615 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ enum got_object_cache_type { GOT_OBJECT_CACHE_TYPE_OBJ, GOT_OBJECT_CACHE_TYPE_TREE, GOT_OBJECT_CACHE_TYPE_COMMIT, GOT_OBJECT_CACHE_TYPE_TAG, GOT_OBJECT_CACHE_TYPE_RAW, }; struct got_object_cache_entry { struct got_object_id id; union { struct got_object *obj; struct got_tree_object *tree; struct got_commit_object *commit; struct got_tag_object *tag; struct got_raw_object *raw; } data; }; struct got_object_cache { enum got_object_cache_type type; struct got_object_idset *idset; size_t size; int cache_searches; int cache_hit; int cache_miss; int cache_evict; int cache_toolarge; size_t max_cached_size; }; const struct got_error *got_object_cache_init(struct got_object_cache *, enum got_object_cache_type); const struct got_error *got_object_cache_add(struct got_object_cache *, struct got_object_id *, void *); void *got_object_cache_get(struct got_object_cache *, struct got_object_id *); void got_object_cache_close(struct got_object_cache *); got-portable-0.101/lib/patch.c0000664000175100017510000006456414644144735011643 /* * Copyright (c) 2022 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Apply patches. * * Things that we may want to support: * + support indented patches? * + support other kinds of patches? */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_reference.h" #include "got_cancel.h" #include "got_worktree.h" #include "got_repository.h" #include "got_opentemp.h" #include "got_patch.h" #include "got_diff.h" #include "got_lib_delta.h" #include "got_lib_diff.h" #include "got_lib_object.h" #include "got_lib_privsep.h" #include "got_lib_hash.h" #ifndef MIN #define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif struct got_patch_line { char mode; char *line; size_t len; }; struct got_patch_hunk { STAILQ_ENTRY(got_patch_hunk) entries; const struct got_error *err; int ws_mangled; int offset; int old_nonl; int new_nonl; int old_from; int old_lines; int new_from; int new_lines; size_t len; size_t cap; struct got_patch_line *lines; }; STAILQ_HEAD(got_patch_hunk_head, got_patch_hunk); struct got_patch { int xbit; char *old; char *new; char cid[41]; char blob[41]; struct got_patch_hunk_head head; }; struct patch_args { got_patch_progress_cb progress_cb; void *progress_arg; struct got_patch_hunk_head *head; }; static mode_t apply_umask(mode_t mode) { mode_t um; um = umask(000); umask(um); return mode & ~um; } static const struct got_error * send_patch(struct imsgbuf *ibuf, int fd) { const struct got_error *err = NULL; if (imsg_compose(ibuf, GOT_IMSG_PATCH_FILE, 0, 0, fd, NULL, 0) == -1) { err = got_error_from_errno( "imsg_compose GOT_IMSG_PATCH_FILE"); close(fd); return err; } return got_privsep_flush_imsg(ibuf); } static void patch_free(struct got_patch *p) { struct got_patch_hunk *h; size_t i; while (!STAILQ_EMPTY(&p->head)) { h = STAILQ_FIRST(&p->head); STAILQ_REMOVE_HEAD(&p->head, entries); for (i = 0; i < h->len; ++i) free(h->lines[i].line); free(h->lines); free(h); } free(p->new); free(p->old); memset(p, 0, sizeof(*p)); STAILQ_INIT(&p->head); } static const struct got_error * pushline(struct got_patch_hunk *h, const char *line, size_t len) { void *t; size_t newcap; if (h->len == h->cap) { if ((newcap = h->cap * 1.5) == 0) newcap = 16; t = recallocarray(h->lines, h->cap, newcap, sizeof(h->lines[0])); if (t == NULL) return got_error_from_errno("recallocarray"); h->lines = t; h->cap = newcap; } if ((t = malloc(len - 1)) == NULL) return got_error_from_errno("malloc"); memcpy(t, line + 1, len - 1); /* skip the line type */ h->lines[h->len].mode = *line; h->lines[h->len].line = t; h->lines[h->len].len = len - 2; /* line type and trailing NUL */ h->len++; return NULL; } static const struct got_error * recv_patch(struct imsgbuf *ibuf, int *done, struct got_patch *p, int strip) { const struct got_error *err = NULL; struct imsg imsg; struct got_imsg_patch_hunk hdr; struct got_imsg_patch patch; struct got_patch_hunk *h = NULL; size_t datalen; int lastmode = -1; memset(p, 0, sizeof(*p)); STAILQ_INIT(&p->head); err = got_privsep_recv_imsg(&imsg, ibuf, 0); if (err) return err; if (imsg.hdr.type == GOT_IMSG_PATCH_EOF) { *done = 1; goto done; } if (imsg.hdr.type != GOT_IMSG_PATCH) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(patch)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&patch, imsg.data, sizeof(patch)); if (patch.old[sizeof(patch.old)-1] != '\0' || patch.new[sizeof(patch.new)-1] != '\0' || patch.cid[sizeof(patch.cid)-1] != '\0' || patch.blob[sizeof(patch.blob)-1] != '\0') { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } if (*patch.cid != '\0') strlcpy(p->cid, patch.cid, sizeof(p->cid)); if (*patch.blob != '\0') strlcpy(p->blob, patch.blob, sizeof(p->blob)); p->xbit = patch.xbit; /* automatically set strip=1 for git-style diffs */ if (strip == -1 && patch.git && (*patch.old == '\0' || !strncmp(patch.old, "a/", 2)) && (*patch.new == '\0' || !strncmp(patch.new, "b/", 2))) strip = 1; /* prefer the new name if not /dev/null for not git-style diffs */ if (!patch.git && *patch.new != '\0' && *patch.old != '\0') { err = got_path_strip(&p->old, patch.new, strip); if (err) goto done; } else if (*patch.old != '\0') { err = got_path_strip(&p->old, patch.old, strip); if (err) goto done; } if (*patch.new != '\0') { err = got_path_strip(&p->new, patch.new, strip); if (err) goto done; } if (p->old == NULL && p->new == NULL) { err = got_error(GOT_ERR_PATCH_MALFORMED); goto done; } imsg_free(&imsg); for (;;) { char *t; err = got_privsep_recv_imsg(&imsg, ibuf, 0); if (err) { patch_free(p); return err; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; switch (imsg.hdr.type) { case GOT_IMSG_PATCH_DONE: if (h != NULL && h->len == 0) err = got_error(GOT_ERR_PATCH_MALFORMED); goto done; case GOT_IMSG_PATCH_HUNK: if (h != NULL && (h->len == 0 || h->old_nonl || h->new_nonl)) { err = got_error(GOT_ERR_PATCH_MALFORMED); goto done; } lastmode = -1; if (datalen != sizeof(hdr)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&hdr, imsg.data, sizeof(hdr)); if (hdr.oldfrom < 0 || hdr.newfrom < 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } if ((h = calloc(1, sizeof(*h))) == NULL) { err = got_error_from_errno("calloc"); goto done; } h->old_from = hdr.oldfrom; h->old_lines = hdr.oldlines; h->new_from = hdr.newfrom; h->new_lines = hdr.newlines; STAILQ_INSERT_TAIL(&p->head, h, entries); break; case GOT_IMSG_PATCH_LINE: if (h == NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } t = imsg.data; /* at least one char */ if (datalen < 2 || t[datalen-1] != '\0') { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } if (*t != ' ' && *t != '-' && *t != '+' && *t != '\\') { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } if (*t != '\\') err = pushline(h, t, datalen); else if (lastmode == '-') h->old_nonl = 1; else if (lastmode == '+') h->new_nonl = 1; else err = got_error(GOT_ERR_PATCH_MALFORMED); if (err) goto done; lastmode = *t; break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } imsg_free(&imsg); } done: if (err) patch_free(p); imsg_free(&imsg); return err; } static void reverse_patch(struct got_patch *p) { struct got_patch_hunk *h; size_t i; int tmp; STAILQ_FOREACH(h, &p->head, entries) { tmp = h->old_from; h->old_from = h->new_from; h->new_from = tmp; tmp = h->old_lines; h->old_lines = h->new_lines; h->new_lines = tmp; tmp = h->old_nonl; h->old_nonl = h->new_nonl; h->new_nonl = tmp; for (i = 0; i < h->len; ++i) { if (h->lines[i].mode == '+') h->lines[i].mode = '-'; else if (h->lines[i].mode == '-') h->lines[i].mode = '+'; } } } /* * Copy data from orig starting at copypos until pos into tmp. * If pos is -1, copy until EOF. */ static const struct got_error * copy(FILE *tmp, FILE *orig, off_t copypos, off_t pos) { char buf[BUFSIZ]; size_t len, r, w; if (fseeko(orig, copypos, SEEK_SET) == -1) return got_error_from_errno("fseeko"); while (pos == -1 || copypos < pos) { len = sizeof(buf); if (pos > 0) len = MIN(len, (size_t)pos - copypos); r = fread(buf, 1, len, orig); if (r != len && ferror(orig)) return got_error_from_errno("fread"); w = fwrite(buf, 1, r, tmp); if (w != r) return got_error_from_errno("fwrite"); copypos += len; if (r != len && feof(orig)) { if (pos == -1) return NULL; return got_error(GOT_ERR_HUNK_FAILED); } } return NULL; } static int lines_eq(struct got_patch_line *, const char *, size_t, int *); static const struct got_error * locate_hunk(FILE *orig, struct got_patch_hunk *h, off_t *pos, int *lineno) { const struct got_error *err = NULL; struct got_patch_line *l = &h->lines[0]; char *line = NULL; char mode = l->mode; size_t linesize = 0; ssize_t linelen; off_t match = -1; int mangled = 0, match_lineno = -1; for (;;) { (*lineno)++; linelen = getline(&line, &linesize, orig); if (linelen == -1) { if (ferror(orig)) err = got_error_from_errno("getline"); /* An EOF is fine iff the target file is empty. */ if (feof(orig) && match == -1 && h->old_lines != 0) err = got_error(GOT_ERR_HUNK_FAILED); match = 0; match_lineno = (*lineno)-1; break; } if ((mode == ' ' && lines_eq(l, line, linelen, &mangled)) || (mode == '-' && lines_eq(l, line, linelen, &mangled)) || (mode == '+' && *lineno == h->old_from)) { match = ftello(orig); if (match == -1) { err = got_error_from_errno("ftello"); break; } match -= linelen; match_lineno = (*lineno)-1; } if (*lineno >= h->old_from && match != -1) { if (mangled) h->ws_mangled = 1; break; } } if (err == NULL) { *pos = match; *lineno = match_lineno; if (fseeko(orig, match, SEEK_SET) == -1) err = got_error_from_errno("fseeko"); } free(line); return err; } static int lines_eq(struct got_patch_line *l, const char *b, size_t len, int *mangled) { char *a = l->line; size_t i, j; if (len > 00 && b[len - 1] == '\n') len--; *mangled = 0; if (l->len == len && !memcmp(a, b, len)) return 1; *mangled = 1; i = j = 0; for (;;) { while (i < l->len && (a[i] == '\t' || a[i] == ' ' || a[i] == '\f')) i++; while (j < len && (b[j] == '\t' || b[j] == ' ' || b[j] == '\f')) j++; if (i == l->len || j == len || a[i] != b[j]) break; i++, j++; } return (i == l->len && j == len); } static const struct got_error * test_hunk(FILE *orig, struct got_patch_hunk *h) { const struct got_error *err = NULL; char *line = NULL; size_t linesize = 0, i = 0; ssize_t linelen; int mangled; for (i = 0; i < h->len; ++i) { switch (h->lines[i].mode) { case '+': continue; case ' ': case '-': linelen = getline(&line, &linesize, orig); if (linelen == -1) { if (ferror(orig)) err = got_error_from_errno("getline"); else err = got_error( GOT_ERR_HUNK_FAILED); goto done; } if (!lines_eq(&h->lines[i], line, linelen, &mangled)) { err = got_error(GOT_ERR_HUNK_FAILED); goto done; } if (mangled) h->ws_mangled = 1; break; } } done: free(line); return err; } static const struct got_error * apply_hunk(FILE *orig, FILE *tmp, struct got_patch_hunk *h, int *lineno, off_t from) { const struct got_error *err = NULL; const char *t; size_t linesize = 0, i, new = 0; char *line = NULL; char mode; size_t l; ssize_t linelen; if (orig != NULL && fseeko(orig, from, SEEK_SET) == -1) return got_error_from_errno("fseeko"); for (i = 0; i < h->len; ++i) { switch (mode = h->lines[i].mode) { case '-': case ' ': (*lineno)++; if (orig != NULL) { linelen = getline(&line, &linesize, orig); if (linelen == -1) { err = got_error_from_errno("getline"); goto done; } if (line[linelen - 1] == '\n') line[linelen - 1] = '\0'; t = line; l = linelen - 1; } else { t = h->lines[i].line; l = h->lines[i].len; } if (mode == '-') continue; if (fwrite(t, 1, l, tmp) != l || fputc('\n', tmp) == EOF) { err = got_error_from_errno("fprintf"); goto done; } break; case '+': new++; t = h->lines[i].line; l = h->lines[i].len; if (fwrite(t, 1, l, tmp) != l) { err = got_error_from_errno("fprintf"); goto done; } if (new != h->new_lines || !h->new_nonl) { if (fprintf(tmp, "\n") < 0) { err = got_error_from_errno("fprintf"); goto done; } } break; } } done: free(line); return err; } static const struct got_error * patch_file(struct got_patch *p, FILE *orig, FILE *tmp) { const struct got_error *err = NULL; struct got_patch_hunk *h; struct stat sb; int lineno = 0; off_t copypos, pos; char *line = NULL; size_t linesize = 0; ssize_t linelen; if (p->old == NULL) { /* create */ h = STAILQ_FIRST(&p->head); if (h == NULL || STAILQ_NEXT(h, entries) != NULL) return got_error(GOT_ERR_PATCH_MALFORMED); return apply_hunk(orig, tmp, h, &lineno, 0); } /* When deleting binary files there are no hunks to apply. */ if (p->new == NULL && STAILQ_EMPTY(&p->head)) return NULL; if (fstat(fileno(orig), &sb) == -1) return got_error_from_errno("fstat"); copypos = 0; STAILQ_FOREACH(h, &p->head, entries) { tryagain: err = locate_hunk(orig, h, &pos, &lineno); if (err != NULL && err->code == GOT_ERR_HUNK_FAILED) h->err = err; if (err != NULL) return err; err = copy(tmp, orig, copypos, pos); if (err != NULL) return err; copypos = pos; err = test_hunk(orig, h); if (err != NULL && err->code == GOT_ERR_HUNK_FAILED) { /* * try to apply the hunk again starting the search * after the previous partial match. */ if (fseeko(orig, pos, SEEK_SET) == -1) return got_error_from_errno("fseeko"); linelen = getline(&line, &linesize, orig); if (linelen == -1) return got_error_from_errno("getline"); lineno++; goto tryagain; } if (err != NULL) return err; if (lineno + 1 != h->old_from) h->offset = lineno + 1 - h->old_from; err = apply_hunk(orig, tmp, h, &lineno, pos); if (err != NULL) return err; copypos = ftello(orig); if (copypos == -1) return got_error_from_errno("ftello"); } if (p->new == NULL && sb.st_size != copypos) { h = STAILQ_FIRST(&p->head); h->err = got_error(GOT_ERR_HUNK_FAILED); err = h->err; } else if (!feof(orig)) err = copy(tmp, orig, copypos, -1); return err; } static const struct got_error * report_progress(struct patch_args *pa, const char *old, const char *new, unsigned char status, const struct got_error *orig_error) { const struct got_error *err; struct got_patch_hunk *h; err = pa->progress_cb(pa->progress_arg, old, new, status, orig_error, 0, 0, 0, 0, 0, 0, NULL); if (err) return err; STAILQ_FOREACH(h, pa->head, entries) { if (h->offset == 0 && !h->ws_mangled && h->err == NULL) continue; err = pa->progress_cb(pa->progress_arg, old, new, 0, NULL, h->old_from, h->old_lines, h->new_from, h->new_lines, h->offset, h->ws_mangled, h->err); if (err) return err; } return NULL; } static const struct got_error * patch_delete(void *arg, unsigned char status, unsigned char staged_status, const char *path) { return report_progress(arg, path, NULL, status, NULL); } static const struct got_error * patch_add(void *arg, unsigned char status, const char *path) { return report_progress(arg, NULL, path, status, NULL); } static const struct got_error * open_blob(char **path, FILE **fp, const char *blobid, struct got_repository *repo) { const struct got_error *err = NULL; struct got_blob_object *blob = NULL; struct got_object_id id, *idptr, *matched_id = NULL; int fd = -1; *fp = NULL; *path = NULL; if (strlen(blobid) != SHA1_DIGEST_STRING_LENGTH - 1) { err = got_repo_match_object_id(&matched_id, NULL, blobid, GOT_OBJ_TYPE_BLOB, NULL /* do not resolve tags */, repo); if (err) return err; idptr = matched_id; } else { if (!got_parse_object_id(&id, blobid, GOT_HASH_SHA1)) return got_error(GOT_ERR_BAD_OBJ_ID_STR); idptr = &id; } fd = got_opentempfd(); if (fd == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } err = got_object_open_as_blob(&blob, repo, idptr, 8192, fd); if (err) goto done; err = got_opentemp_named(path, fp, GOT_TMPDIR_STR "/got-patch-blob", ""); if (err) goto done; err = got_object_blob_dump_to_file(NULL, NULL, NULL, *fp, blob); if (err) goto done; done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob) got_object_blob_close(blob); if (matched_id != NULL) free(matched_id); if (err) { if (*fp != NULL) fclose(*fp); if (*path != NULL) unlink(*path); free(*path); *fp = NULL; *path = NULL; } return err; } static const struct got_error * prepare_merge(int *do_merge, char **apath, FILE **afile, struct got_worktree *worktree, struct got_repository *repo, struct got_patch *p, struct got_object_id *commit_id, struct got_tree_object *tree, const char *path) { const struct got_error *err = NULL; *do_merge = 0; *apath = NULL; *afile = NULL; /* don't run the diff3 merge on creations/deletions */ if (p->old == NULL || p->new == NULL) return NULL; if (commit_id) { struct got_object_id *id; err = got_object_tree_find_path(&id, NULL, repo, tree, path); if (err) return err; got_object_id_hex(id, p->blob, sizeof(p->blob)); got_object_id_hex(commit_id, p->cid, sizeof(p->cid)); free(id); err = open_blob(apath, afile, p->blob, repo); *do_merge = err == NULL; } else if (*p->blob != '\0') { err = open_blob(apath, afile, p->blob, repo); /* * ignore failures to open this blob, we might have * parsed gibberish. */ if (err && !(err->code == GOT_ERR_ERRNO && errno == ENOENT) && err->code != GOT_ERR_NO_OBJ) return err; *do_merge = err == NULL; err = NULL; } return err; } static const struct got_error * apply_patch(int *overlapcnt, struct got_worktree *worktree, struct got_repository *repo, struct got_fileindex *fileindex, const char *old, const char *new, struct got_patch *p, int nop, int reverse, struct got_object_id *commit_id, struct got_tree_object *tree, struct patch_args *pa, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; struct stat sb; int do_merge = 0, file_renamed = 0; char *oldlabel = NULL, *newlabel = NULL, *anclabel = NULL; char *oldpath = NULL, *newpath = NULL; char *tmppath = NULL, *template = NULL; char *apath = NULL, *mergepath = NULL; FILE *oldfile = NULL, *tmpfile = NULL, *afile = NULL, *mergefile = NULL; int outfd; mode_t mode = GOT_DEFAULT_FILE_MODE; *overlapcnt = 0; err = prepare_merge(&do_merge, &apath, &afile, worktree, repo, p, commit_id, tree, old); if (err) return err; if (reverse && !do_merge) reverse_patch(p); if (asprintf(&oldpath, "%s/%s", got_worktree_get_root_path(worktree), old) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (asprintf(&newpath, "%s/%s", got_worktree_get_root_path(worktree), new) == -1) { err = got_error_from_errno("asprintf"); goto done; } file_renamed = strcmp(oldpath, newpath); if (asprintf(&template, "%s/got-patch", got_worktree_get_root_path(worktree)) == -1) { err = got_error_from_errno(template); goto done; } if (p->old != NULL) { if ((oldfile = fopen(oldpath, "r")) == NULL) { err = got_error_from_errno2("open", oldpath); goto done; } if (fstat(fileno(oldfile), &sb) == -1) { err = got_error_from_errno2("fstat", oldpath); goto done; } mode = sb.st_mode; } else if (p->xbit) mode |= (S_IXUSR | S_IXGRP | S_IXOTH); err = got_opentemp_named(&tmppath, &tmpfile, template, ""); if (err) goto done; outfd = fileno(tmpfile); err = patch_file(p, afile != NULL ? afile : oldfile, tmpfile); if (err) goto done; if (do_merge) { const char *type, *id; if (fseeko(afile, 0, SEEK_SET) == -1 || fseeko(oldfile, 0, SEEK_SET) == -1 || fseeko(tmpfile, 0, SEEK_SET) == -1) { err = got_error_from_errno("fseeko"); goto done; } if (asprintf(&oldlabel, "--- %s", p->old) == -1) { err = got_error_from_errno("asprintf"); oldlabel = NULL; goto done; } if (asprintf(&newlabel, "+++ %s", p->new) == -1) { err = got_error_from_errno("asprintf"); newlabel = NULL; goto done; } if (*p->cid != '\0') { type = "commit"; id = p->cid; } else { type = "blob"; id = p->blob; } if (asprintf(&anclabel, "%s %s", type, id) == -1) { err = got_error_from_errno("asprintf"); anclabel = NULL; goto done; } if (reverse) { char *s; FILE *t; s = anclabel; anclabel = newlabel; newlabel = s; t = afile; afile = tmpfile; tmpfile = t; } err = got_opentemp_named(&mergepath, &mergefile, template, ""); if (err) goto done; outfd = fileno(mergefile); err = got_merge_diff3(overlapcnt, outfd, tmpfile, afile, oldfile, oldlabel, anclabel, newlabel, GOT_DIFF_ALGORITHM_PATIENCE); if (err) goto done; } if (nop) goto done; if (p->old != NULL && p->new == NULL) { err = got_worktree_patch_schedule_rm(old, repo, worktree, fileindex, patch_delete, pa); goto done; } if (fchmod(outfd, apply_umask(mode)) == -1) { err = got_error_from_errno2("chmod", tmppath); goto done; } if (mergepath) { err = got_path_move_file(mergepath, newpath); if (err) goto done; free(mergepath); mergepath = NULL; } else { err = got_path_move_file(tmppath, newpath); if (err) goto done; free(tmppath); tmppath = NULL; } if (file_renamed) { err = got_worktree_patch_schedule_rm(old, repo, worktree, fileindex, patch_delete, pa); if (err == NULL) err = got_worktree_patch_schedule_add(new, repo, worktree, fileindex, patch_add, pa); if (err) unlink(newpath); } else if (p->old == NULL) { err = got_worktree_patch_schedule_add(new, repo, worktree, fileindex, patch_add, pa); if (err) unlink(newpath); } else if (*overlapcnt != 0) err = report_progress(pa, old, new, GOT_STATUS_CONFLICT, NULL); else if (do_merge) err = report_progress(pa, old, new, GOT_STATUS_MERGE, NULL); else err = report_progress(pa, old, new, GOT_STATUS_MODIFY, NULL); done: free(template); if (tmppath != NULL && unlink(tmppath) == -1 && err == NULL) err = got_error_from_errno("unlink"); if (tmpfile != NULL && fclose(tmpfile) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(tmppath); free(oldpath); if (oldfile != NULL && fclose(oldfile) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (apath != NULL && unlink(apath) == -1 && err == NULL) err = got_error_from_errno("unlink"); if (afile != NULL && fclose(afile) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(apath); if (mergepath != NULL && unlink(mergepath) == -1 && err == NULL) err = got_error_from_errno("unlink"); if (mergefile != NULL && fclose(mergefile) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(mergepath); free(newpath); free(oldlabel); free(newlabel); free(anclabel); return err; } const struct got_error * got_patch(int fd, struct got_worktree *worktree, struct got_repository *repo, int nop, int strip, int reverse, struct got_object_id *commit_id, got_patch_progress_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL, *complete_err = NULL; struct got_fileindex *fileindex = NULL; struct got_commit_object *commit = NULL; struct got_tree_object *tree = NULL; char *fileindex_path = NULL; char *oldpath, *newpath; struct imsgbuf *ibuf; int imsg_fds[2] = {-1, -1}; int overlapcnt, done = 0, failed = 0; pid_t pid; ibuf = calloc(1, sizeof(*ibuf)); if (ibuf == NULL) { err = got_error_from_errno("calloc"); goto done; } if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) { err = got_error_from_errno("socketpair"); goto done; } pid = fork(); if (pid == -1) { err = got_error_from_errno("fork"); goto done; } else if (pid == 0) { got_privsep_exec_child(imsg_fds, GOT_PATH_PROG_READ_PATCH, NULL); /* not reached */ } if (close(imsg_fds[1]) == -1) { err = got_error_from_errno("close"); goto done; } imsg_fds[1] = -1; imsg_init(ibuf, imsg_fds[0]); err = send_patch(ibuf, fd); fd = -1; if (err) goto done; err = got_worktree_patch_prepare(&fileindex, &fileindex_path, worktree); if (err) goto done; if (commit_id) { err = got_object_open_as_commit(&commit, repo, commit_id); if (err) goto done; err = got_object_open_as_tree(&tree, repo, commit->tree_id); if (err) goto done; } while (!done && err == NULL) { struct got_patch p; struct patch_args pa; pa.progress_cb = progress_cb; pa.progress_arg = progress_arg; pa.head = &p.head; err = recv_patch(ibuf, &done, &p, strip); if (err || done) break; err = got_worktree_patch_check_path(p.old, p.new, &oldpath, &newpath, worktree, repo, fileindex); if (err == NULL) err = apply_patch(&overlapcnt, worktree, repo, fileindex, oldpath, newpath, &p, nop, reverse, commit_id, tree, &pa, cancel_cb, cancel_arg); if (err != NULL) { failed = 1; /* recoverable errors */ if (err->code == GOT_ERR_FILE_STATUS || (err->code == GOT_ERR_ERRNO && errno == ENOENT)) err = report_progress(&pa, p.old, p.new, GOT_STATUS_CANNOT_UPDATE, err); else if (err->code == GOT_ERR_HUNK_FAILED) err = report_progress(&pa, p.old, p.new, GOT_STATUS_CANNOT_UPDATE, NULL); } if (overlapcnt != 0) failed = 1; free(oldpath); free(newpath); patch_free(&p); if (err) break; } done: if (fileindex != NULL) complete_err = got_worktree_patch_complete(fileindex, fileindex_path); if (complete_err && err == NULL) err = complete_err; free(fileindex_path); if (tree) got_object_tree_close(tree); if (commit) got_object_commit_close(commit); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (ibuf != NULL) imsg_clear(ibuf); if (imsg_fds[0] != -1 && close(imsg_fds[0]) == -1 && err == NULL) err = got_error_from_errno("close"); if (imsg_fds[1] != -1 && close(imsg_fds[1]) == -1 && err == NULL) err = got_error_from_errno("close"); if (err == NULL && failed) err = got_error(GOT_ERR_PATCH_FAILED); return err; } got-portable-0.101/lib/object_cache.c0000664000175100017510000002475514644144735013133 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_lib_delta.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_idset.h" #include "got_lib_object_cache.h" /* * XXX This should be reworked to track cache size and usage in bytes, * rather than tracking N elements capped to a maximum element size. */ #define GOT_OBJECT_CACHE_SIZE_OBJ 256 #define GOT_OBJECT_CACHE_SIZE_TREE 256 #define GOT_OBJECT_CACHE_SIZE_COMMIT 64 #define GOT_OBJECT_CACHE_SIZE_TAG 256 #define GOT_OBJECT_CACHE_SIZE_RAW 16 #define GOT_OBJECT_CACHE_MAX_ELEM_SIZE 1048576 /* 1 MB */ const struct got_error * got_object_cache_init(struct got_object_cache *cache, enum got_object_cache_type type) { struct rlimit rl; memset(cache, 0, sizeof(*cache)); cache->idset = got_object_idset_alloc(); if (cache->idset == NULL) return got_error_from_errno("got_object_idset_alloc"); cache->type = type; switch (type) { case GOT_OBJECT_CACHE_TYPE_OBJ: cache->size = GOT_OBJECT_CACHE_SIZE_OBJ; break; case GOT_OBJECT_CACHE_TYPE_TREE: cache->size = GOT_OBJECT_CACHE_SIZE_TREE; break; case GOT_OBJECT_CACHE_TYPE_COMMIT: cache->size = GOT_OBJECT_CACHE_SIZE_COMMIT; break; case GOT_OBJECT_CACHE_TYPE_TAG: cache->size = GOT_OBJECT_CACHE_SIZE_TAG; break; case GOT_OBJECT_CACHE_TYPE_RAW: if (getrlimit(RLIMIT_NOFILE, &rl) == -1) return got_error_from_errno("getrlimit"); cache->size = GOT_OBJECT_CACHE_SIZE_RAW; if (cache->size > rl.rlim_cur / 16) cache->size = rl.rlim_cur / 16; break; } return NULL; } static size_t get_size_obj(struct got_object *obj) { size_t size = sizeof(*obj); struct got_delta *delta; if ((obj->flags & GOT_OBJ_FLAG_DELTIFIED) == 0) return size; STAILQ_FOREACH(delta, &obj->deltas.entries, entry) { if (SIZE_MAX - sizeof(*delta) < size) return SIZE_MAX; size += sizeof(*delta); } return size; } static size_t get_size_tree(struct got_tree_object *tree) { size_t size = sizeof(*tree); size += sizeof(struct got_tree_entry) * tree->nentries; return size; } static size_t get_size_commit(struct got_commit_object *commit) { size_t size = sizeof(*commit); struct got_object_qid *qid; size += sizeof(*commit->tree_id); size += strlen(commit->author); size += strlen(commit->committer); size += strlen(commit->logmsg); STAILQ_FOREACH(qid, &commit->parent_ids, entry) size += sizeof(*qid) + sizeof(qid->id); return size; } static size_t get_size_tag(struct got_tag_object *tag) { size_t size = sizeof(*tag); size += strlen(tag->tag); size += strlen(tag->tagger); size += strlen(tag->tagmsg); return size; } static size_t get_size_raw(struct got_raw_object *raw) { return sizeof(*raw); } const struct got_error * got_object_cache_add(struct got_object_cache *cache, struct got_object_id *id, void *item) { const struct got_error *err = NULL; struct got_object_cache_entry *ce; int nelem; size_t size; switch (cache->type) { case GOT_OBJECT_CACHE_TYPE_OBJ: size = get_size_obj((struct got_object *)item); break; case GOT_OBJECT_CACHE_TYPE_TREE: size = get_size_tree((struct got_tree_object *)item); break; case GOT_OBJECT_CACHE_TYPE_COMMIT: size = get_size_commit((struct got_commit_object *)item); break; case GOT_OBJECT_CACHE_TYPE_TAG: size = get_size_tag((struct got_tag_object *)item); break; case GOT_OBJECT_CACHE_TYPE_RAW: size = get_size_raw((struct got_raw_object *)item); break; default: return got_error(GOT_ERR_OBJ_TYPE); } if (size > GOT_OBJECT_CACHE_MAX_ELEM_SIZE) { #ifdef GOT_OBJ_CACHE_DEBUG char *id_str; if (got_object_id_str(&id_str, id) != NULL) return got_error_from_errno("got_object_id_str"); fprintf(stderr, "%s: not caching ", getprogname()); switch (cache->type) { case GOT_OBJECT_CACHE_TYPE_OBJ: fprintf(stderr, "object"); break; case GOT_OBJECT_CACHE_TYPE_TREE: fprintf(stderr, "tree"); break; case GOT_OBJECT_CACHE_TYPE_COMMIT: fprintf(stderr, "commit"); break; case GOT_OBJECT_CACHE_TYPE_TAG: fprintf(stderr, "tag"); break; case GOT_OBJECT_CACHE_TYPE_RAW: fprintf(stderr, "raw"); break; } fprintf(stderr, " %s (%zd bytes; %zd MB)\n", id_str, size, size/1024/1024); free(id_str); #endif cache->cache_toolarge++; return got_error(GOT_ERR_OBJ_TOO_LARGE); } nelem = got_object_idset_num_elements(cache->idset); if (nelem >= cache->size) { err = got_object_idset_remove((void **)&ce, cache->idset, NULL); if (err) return err; switch (cache->type) { case GOT_OBJECT_CACHE_TYPE_OBJ: got_object_close(ce->data.obj); break; case GOT_OBJECT_CACHE_TYPE_TREE: got_object_tree_close(ce->data.tree); break; case GOT_OBJECT_CACHE_TYPE_COMMIT: got_object_commit_close(ce->data.commit); break; case GOT_OBJECT_CACHE_TYPE_TAG: got_object_tag_close(ce->data.tag); break; case GOT_OBJECT_CACHE_TYPE_RAW: got_object_raw_close(ce->data.raw); break; } memset(ce, 0, sizeof(*ce)); cache->cache_evict++; } else { ce = malloc(sizeof(*ce)); if (ce == NULL) return got_error_from_errno("malloc"); } memcpy(&ce->id, id, sizeof(ce->id)); switch (cache->type) { case GOT_OBJECT_CACHE_TYPE_OBJ: ce->data.obj = (struct got_object *)item; break; case GOT_OBJECT_CACHE_TYPE_TREE: ce->data.tree = (struct got_tree_object *)item; break; case GOT_OBJECT_CACHE_TYPE_COMMIT: ce->data.commit = (struct got_commit_object *)item; break; case GOT_OBJECT_CACHE_TYPE_TAG: ce->data.tag = (struct got_tag_object *)item; break; case GOT_OBJECT_CACHE_TYPE_RAW: ce->data.raw = (struct got_raw_object *)item; break; } err = got_object_idset_add(cache->idset, id, ce); if (err) free(ce); else if (size > cache->max_cached_size) cache->max_cached_size = size; return err; } void * got_object_cache_get(struct got_object_cache *cache, struct got_object_id *id) { struct got_object_cache_entry *ce; cache->cache_searches++; ce = got_object_idset_get(cache->idset, id); if (ce) { cache->cache_hit++; switch (cache->type) { case GOT_OBJECT_CACHE_TYPE_OBJ: return ce->data.obj; case GOT_OBJECT_CACHE_TYPE_TREE: return ce->data.tree; case GOT_OBJECT_CACHE_TYPE_COMMIT: return ce->data.commit; case GOT_OBJECT_CACHE_TYPE_TAG: return ce->data.tag; case GOT_OBJECT_CACHE_TYPE_RAW: return ce->data.raw; } } cache->cache_miss++; return NULL; } #ifdef GOT_OBJ_CACHE_DEBUG static void print_cache_stats(struct got_object_cache *cache, const char *name) { fprintf(stderr, "%s: %s cache: %d elements, %d searches, %d hits, " "%d missed, %d evicted, %d too large, max cached %zd bytes\n", getprogname(), name, cache->idset ? got_object_idset_num_elements(cache->idset) : -1, cache->cache_searches, cache->cache_hit, cache->cache_miss, cache->cache_evict, cache->cache_toolarge, cache->max_cached_size); } static const struct got_error * check_refcount(struct got_object_id *id, void *data, void *arg) { struct got_object_cache *cache = arg; struct got_object_cache_entry *ce = data; struct got_object *obj; struct got_tree_object *tree; struct got_commit_object *commit; struct got_tag_object *tag; struct got_raw_object *raw; char *id_str; if (got_object_id_str(&id_str, id) != NULL) return NULL; switch (cache->type) { case GOT_OBJECT_CACHE_TYPE_OBJ: obj = ce->data.obj; if (obj->refcnt == 1) break; fprintf(stderr, "object %s has %d unclaimed references\n", id_str, obj->refcnt - 1); break; case GOT_OBJECT_CACHE_TYPE_TREE: tree = ce->data.tree; if (tree->refcnt == 1) break; fprintf(stderr, "tree %s has %d unclaimed references\n", id_str, tree->refcnt - 1); break; case GOT_OBJECT_CACHE_TYPE_COMMIT: commit = ce->data.commit; if (commit->refcnt == 1) break; fprintf(stderr, "commit %s has %d unclaimed references\n", id_str, commit->refcnt - 1); break; case GOT_OBJECT_CACHE_TYPE_TAG: tag = ce->data.tag; if (tag->refcnt == 1) break; fprintf(stderr, "tag %s has %d unclaimed references\n", id_str, tag->refcnt - 1); break; case GOT_OBJECT_CACHE_TYPE_RAW: raw = ce->data.raw; if (raw->refcnt == 1) break; fprintf(stderr, "raw %s has %d unclaimed references\n", id_str, raw->refcnt - 1); break; } free(id_str); return NULL; } #endif static const struct got_error * free_entry(struct got_object_id *id, void *data, void *arg) { struct got_object_cache *cache = arg; struct got_object_cache_entry *ce = data; switch (cache->type) { case GOT_OBJECT_CACHE_TYPE_OBJ: got_object_close(ce->data.obj); break; case GOT_OBJECT_CACHE_TYPE_TREE: got_object_tree_close(ce->data.tree); break; case GOT_OBJECT_CACHE_TYPE_COMMIT: got_object_commit_close(ce->data.commit); break; case GOT_OBJECT_CACHE_TYPE_TAG: got_object_tag_close(ce->data.tag); break; case GOT_OBJECT_CACHE_TYPE_RAW: got_object_raw_close(ce->data.raw); break; } free(ce); return NULL; } void got_object_cache_close(struct got_object_cache *cache) { #ifdef GOT_OBJ_CACHE_DEBUG switch (cache->type) { case GOT_OBJECT_CACHE_TYPE_OBJ: print_cache_stats(cache, "object"); break; case GOT_OBJECT_CACHE_TYPE_TREE: print_cache_stats(cache, "tree"); break; case GOT_OBJECT_CACHE_TYPE_COMMIT: print_cache_stats(cache, "commit"); break; case GOT_OBJECT_CACHE_TYPE_TAG: print_cache_stats(cache, "tag"); break; case GOT_OBJECT_CACHE_TYPE_RAW: print_cache_stats(cache, "raw"); break; } if (cache->idset) got_object_idset_for_each(cache->idset, check_refcount, cache); #endif if (cache->idset) { got_object_idset_for_each(cache->idset, free_entry, cache); got_object_idset_free(cache->idset); cache->idset = NULL; } cache->size = 0; } got-portable-0.101/lib/lockfile.c0000664000175100017510000000534014644144735012317 /* * Copyright (c) 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_path.h" #include "got_lib_lockfile.h" const struct got_error * got_lockfile_lock(struct got_lockfile **lf, const char *path, int dir_fd) { const struct got_error *err = NULL; int attempts = 5; *lf = calloc(1, sizeof(**lf)); if (*lf == NULL) return got_error_from_errno("calloc"); (*lf)->fd = -1; (*lf)->locked_path = strdup(path); if ((*lf)->locked_path == NULL) { err = got_error_from_errno("strdup"); goto done; } if (asprintf(&(*lf)->path, "%s%s", path, GOT_LOCKFILE_SUFFIX) == -1) { err = got_error_from_errno("asprintf"); goto done; } do { if (dir_fd != -1) { (*lf)->fd = openat(dir_fd, (*lf)->path, O_RDWR | O_CREAT | O_EXCL | O_EXLOCK | O_CLOEXEC, GOT_DEFAULT_FILE_MODE); } else { (*lf)->fd = open((*lf)->path, O_RDWR | O_CREAT | O_EXCL | O_EXLOCK | O_CLOEXEC, GOT_DEFAULT_FILE_MODE); } if ((*lf)->fd != -1) break; if (errno != EEXIST) { err = got_error_from_errno2("open", (*lf)->path); goto done; } sleep(1); } while (--attempts > 0); if ((*lf)->fd == -1) { err = got_error_fmt(GOT_ERR_LOCKFILE_TIMEOUT, "%s", (*lf)->path); } done: if (err) { got_lockfile_unlock(*lf, dir_fd); *lf = NULL; } return err; } const struct got_error * got_lockfile_unlock(struct got_lockfile *lf, int dir_fd) { const struct got_error *err = NULL; if (dir_fd != -1) { if (lf->path && lf->fd != -1 && unlinkat(dir_fd, lf->path, 0) != 0) err = got_error_from_errno("unlinkat"); } else if (lf->path && lf->fd != -1 && unlink(lf->path) != 0) err = got_error_from_errno("unlink"); if (lf->fd != -1 && close(lf->fd) == -1 && err == NULL) err = got_error_from_errno("close"); free(lf->path); free(lf->locked_path); free(lf); return err; } got-portable-0.101/lib/delta.c0000664000175100017510000002273614644144735011630 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_repository.h" #include "got_object.h" #include "got_path.h" #include "got_lib_delta.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #ifndef MIN #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) #endif struct got_delta * got_delta_open(off_t offset, size_t tslen, int type, size_t size, off_t data_offset) { struct got_delta *delta; delta = malloc(sizeof(*delta)); if (delta == NULL) return NULL; delta->type = type; delta->offset = offset; delta->tslen = tslen; delta->size = size; delta->data_offset = data_offset; return delta; } const struct got_error * got_delta_chain_get_base_type(int *type, struct got_delta_chain *deltas) { struct got_delta *delta; /* The first delta in the chain should represent the base object. */ delta = STAILQ_FIRST(&deltas->entries); if (delta->type == GOT_OBJ_TYPE_COMMIT || delta->type == GOT_OBJ_TYPE_TREE || delta->type == GOT_OBJ_TYPE_BLOB || delta->type == GOT_OBJ_TYPE_TAG) { *type = delta->type; return NULL; } return got_error(GOT_ERR_BAD_DELTA_CHAIN); } /* Fetch another (required) byte from the delta stream. */ static const struct got_error * next_delta_byte(const uint8_t **p, size_t *remain) { if (--(*remain) == 0) return got_error_msg(GOT_ERR_BAD_DELTA, "delta data truncated"); (*p)++; return NULL; } static const struct got_error * parse_size(uint64_t *size, const uint8_t **p, size_t *remain) { const struct got_error *err = NULL; int i = 0; *size = 0; do { /* We do not support size values which don't fit in 64 bit. */ if (i > 9) return got_error(GOT_ERR_NO_SPACE); if (i == 0) *size = ((**p) & GOT_DELTA_SIZE_VAL_MASK); else { size_t shift = GOT_DELTA_SIZE_SHIFT * i; *size |= (((**p) & GOT_DELTA_SIZE_VAL_MASK) << shift); } if (((**p) & GOT_DELTA_SIZE_MORE) == 0) break; i++; err = next_delta_byte(p, remain); } while (err == NULL); return err; } static const struct got_error * parse_opcode(off_t *offset, size_t *len, const uint8_t **p, size_t *remain) { const struct got_error *err = NULL; off_t o = 0; size_t l = 0; uint8_t opcode = **p; if (opcode & GOT_DELTA_COPY_OFF1) { err = next_delta_byte(p, remain); if (err) return err; o = (off_t)(**p); } if (opcode & GOT_DELTA_COPY_OFF2) { err = next_delta_byte(p, remain); if (err) return err; o |= ((off_t)(**p)) << 8; } if (opcode & GOT_DELTA_COPY_OFF3) { err = next_delta_byte(p, remain); if (err) return err; o |= ((off_t)(**p)) << 16; } if (opcode & GOT_DELTA_COPY_OFF4) { err = next_delta_byte(p, remain); if (err) return err; o |= ((off_t)(**p)) << 24; } if (opcode & GOT_DELTA_COPY_LEN1) { err = next_delta_byte(p, remain); if (err) return err; l = (off_t)(**p); } if (opcode & GOT_DELTA_COPY_LEN2) { err = next_delta_byte(p, remain); if (err) return err; l |= ((off_t)(**p)) << 8; } if (opcode & GOT_DELTA_COPY_LEN3) { err = next_delta_byte(p, remain); if (err) return err; l |= ((off_t)(**p)) << 16; } if (o == 0) o = GOT_DELTA_COPY_DEFAULT_OFF; if (l == 0) l = GOT_DELTA_COPY_DEFAULT_LEN; *offset = o; *len = l; return NULL; } static const struct got_error * copy_from_base(FILE *base_file, off_t offset, size_t size, FILE *outfile) { if (fseeko(base_file, offset, SEEK_SET) != 0) return got_error_from_errno("fseeko"); while (size > 0) { uint8_t data[2048]; size_t len = MIN(size, sizeof(data)); size_t n; n = fread(data, len, 1, base_file); if (n != 1) return got_ferror(base_file, GOT_ERR_IO); n = fwrite(data, len, 1, outfile); if (n != 1) return got_ferror(outfile, GOT_ERR_IO); size -= len; } return NULL; } static const struct got_error * copy_from_delta(const uint8_t **p, size_t *remain, size_t len, FILE *outfile) { size_t n; if (*remain < len) return got_error_msg(GOT_ERR_BAD_DELTA, "copy from beyond end of delta data"); n = fwrite(*p, len, 1, outfile); if (n != 1) return got_ferror(outfile, GOT_ERR_IO); *p += len; *remain -= len; return NULL; } static const struct got_error * parse_delta_sizes(uint64_t *base_size, uint64_t *result_size, const uint8_t **p, size_t *remain) { const struct got_error *err; /* Read the two size fields at the beginning of the stream. */ err = parse_size(base_size, p, remain); if (err) return err; err = next_delta_byte(p, remain); if (err) return err; err = parse_size(result_size, p, remain); if (err) return err; return NULL; } const struct got_error * got_delta_get_sizes(uint64_t *base_size, uint64_t *result_size, const uint8_t *delta_buf, size_t delta_len) { size_t remain; const uint8_t *p; if (delta_len < GOT_DELTA_STREAM_LENGTH_MIN) return got_error_msg(GOT_ERR_BAD_DELTA, "delta too small"); p = delta_buf; remain = delta_len; return parse_delta_sizes(base_size, result_size, &p, &remain); } const struct got_error * got_delta_apply_in_mem(uint8_t *base_buf, size_t base_bufsz, const uint8_t *delta_buf, size_t delta_len, uint8_t *outbuf, size_t *outsize, size_t maxoutsize) { const struct got_error *err = NULL; uint64_t base_size, result_size; size_t remain; const uint8_t *p; *outsize= 0; if (delta_len < GOT_DELTA_STREAM_LENGTH_MIN) return got_error_msg(GOT_ERR_BAD_DELTA, "delta too small"); p = delta_buf; remain = delta_len; err = parse_delta_sizes(&base_size, &result_size, &p, &remain); if (err) return err; /* Decode and execute copy instructions from the delta stream. */ err = next_delta_byte(&p, &remain); while (err == NULL && remain > 0) { if (*p & GOT_DELTA_BASE_COPY) { off_t offset = 0; size_t len = 0; err = parse_opcode(&offset, &len, &p, &remain); if (err) break; if (SIZE_MAX - offset < len || offset + len < 0 || base_bufsz < offset + len || *outsize + len > maxoutsize) return got_error_msg(GOT_ERR_BAD_DELTA, "bad delta copy length"); memcpy(outbuf + *outsize, base_buf + offset, len); if (err == NULL) { *outsize += len; if (remain > 0) { p++; remain--; } } } else { size_t len = (size_t)*p; if (len == 0) { err = got_error_msg(GOT_ERR_BAD_DELTA, "zero length delta"); break; } err = next_delta_byte(&p, &remain); if (err) break; if (remain < len || SIZE_MAX - *outsize < len || *outsize + len > maxoutsize) return got_error_msg(GOT_ERR_BAD_DELTA, "bad delta copy length"); memcpy(outbuf + *outsize, p, len); p += len; remain -= len; *outsize += len; } } if (*outsize != result_size) err = got_error_msg(GOT_ERR_BAD_DELTA, "delta application result size mismatch"); return err; } const struct got_error * got_delta_apply(FILE *base_file, const uint8_t *delta_buf, size_t delta_len, FILE *outfile, size_t *outsize) { const struct got_error *err = NULL; uint64_t base_size, result_size; size_t remain = 0; const uint8_t *p; FILE *memstream = NULL; char *memstream_buf = NULL; size_t memstream_size = 0; *outsize = 0; if (delta_len < GOT_DELTA_STREAM_LENGTH_MIN) return got_error_msg(GOT_ERR_BAD_DELTA, "delta too small"); p = delta_buf; remain = delta_len; err = parse_delta_sizes(&base_size, &result_size, &p, &remain); if (err) return err; if (result_size < GOT_DELTA_RESULT_SIZE_CACHED_MAX) memstream = open_memstream(&memstream_buf, &memstream_size); /* Decode and execute copy instructions from the delta stream. */ err = next_delta_byte(&p, &remain); while (err == NULL && remain > 0) { if (*p & GOT_DELTA_BASE_COPY) { off_t offset = 0; size_t len = 0; err = parse_opcode(&offset, &len, &p, &remain); if (err) break; err = copy_from_base(base_file, offset, len, memstream ? memstream : outfile); if (err == NULL) { *outsize += len; if (remain > 0) { p++; remain--; } } } else { size_t len = (size_t)*p; if (len == 0) { err = got_error_msg(GOT_ERR_BAD_DELTA, "zero length delta"); break; } err = next_delta_byte(&p, &remain); if (err) break; err = copy_from_delta(&p, &remain, len, memstream ? memstream : outfile); if (err == NULL) *outsize += len; } } if (*outsize != result_size) err = got_error_msg(GOT_ERR_BAD_DELTA, "delta application result size mismatch"); if (memstream != NULL) { if (fclose(memstream) == EOF) err = got_error_from_errno("fclose"); if (err == NULL) { size_t n; n = fwrite(memstream_buf, 1, memstream_size, outfile); if (n != memstream_size) err = got_ferror(outfile, GOT_ERR_IO); } free(memstream_buf); } if (err == NULL) rewind(outfile); return err; } got-portable-0.101/lib/object_parse.c0000664000175100017510000006236514644144735013201 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_repository.h" #include "got_opentemp.h" #include "got_path.h" #include "got_lib_hash.h" #include "got_lib_delta.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_object_qid.h" #include "got_lib_object_cache.h" #include "got_lib_pack.h" #include "got_lib_repository.h" #ifndef nitems #define nitems(_a) (sizeof(_a) / sizeof((_a)[0])) #endif const struct got_error * got_object_type_label(const char **label, int obj_type) { const struct got_error *err = NULL; switch (obj_type) { case GOT_OBJ_TYPE_BLOB: *label = GOT_OBJ_LABEL_BLOB; break; case GOT_OBJ_TYPE_TREE: *label = GOT_OBJ_LABEL_TREE; break; case GOT_OBJ_TYPE_COMMIT: *label = GOT_OBJ_LABEL_COMMIT; break; case GOT_OBJ_TYPE_TAG: *label = GOT_OBJ_LABEL_TAG; break; default: *label = NULL; err = got_error(GOT_ERR_OBJ_TYPE); break; } return err; } void got_object_close(struct got_object *obj) { if (obj->refcnt > 0) { obj->refcnt--; if (obj->refcnt > 0) return; } if (obj->flags & GOT_OBJ_FLAG_DELTIFIED) { struct got_delta *delta; while (!STAILQ_EMPTY(&obj->deltas.entries)) { delta = STAILQ_FIRST(&obj->deltas.entries); STAILQ_REMOVE_HEAD(&obj->deltas.entries, entry); free(delta); } } free(obj); } const struct got_error * got_object_raw_close(struct got_raw_object *obj) { const struct got_error *err = NULL; if (obj->refcnt > 0) { obj->refcnt--; if (obj->refcnt > 0) return NULL; } if (obj->close_cb) obj->close_cb(obj); if (obj->f == NULL) { if (obj->fd != -1) { if (munmap(obj->data, obj->hdrlen + obj->size) == -1) err = got_error_from_errno("munmap"); if (close(obj->fd) == -1 && err == NULL) err = got_error_from_errno("close"); } else free(obj->data); } else { if (fclose(obj->f) == EOF && err == NULL) err = got_error_from_errno("fclose"); } free(obj); return err; } const struct got_error * got_object_parse_header(struct got_object **obj, char *buf, size_t len) { const char *obj_labels[] = { GOT_OBJ_LABEL_COMMIT, GOT_OBJ_LABEL_TREE, GOT_OBJ_LABEL_BLOB, GOT_OBJ_LABEL_TAG, }; const int obj_types[] = { GOT_OBJ_TYPE_COMMIT, GOT_OBJ_TYPE_TREE, GOT_OBJ_TYPE_BLOB, GOT_OBJ_TYPE_TAG, }; int type = 0; size_t size = 0; size_t i; char *end; *obj = NULL; end = memchr(buf, '\0', len); if (end == NULL) return got_error(GOT_ERR_BAD_OBJ_HDR); for (i = 0; i < nitems(obj_labels); i++) { const char *label = obj_labels[i]; size_t label_len = strlen(label); const char *errstr; if (len <= label_len || buf + label_len >= end || strncmp(buf, label, label_len) != 0) continue; type = obj_types[i]; size = strtonum(buf + label_len, 0, LONG_MAX, &errstr); if (errstr != NULL) return got_error(GOT_ERR_BAD_OBJ_HDR); break; } if (type == 0) return got_error(GOT_ERR_BAD_OBJ_HDR); *obj = calloc(1, sizeof(**obj)); if (*obj == NULL) return got_error_from_errno("calloc"); (*obj)->type = type; (*obj)->hdrlen = end - buf + 1; (*obj)->size = size; return NULL; } const struct got_error * got_object_read_header(struct got_object **obj, int fd) { const struct got_error *err; struct got_inflate_buf zb; uint8_t *buf; const size_t zbsize = 64; size_t outlen, totlen; int nbuf = 1; *obj = NULL; buf = malloc(zbsize); if (buf == NULL) return got_error_from_errno("malloc"); buf[0] = '\0'; err = got_inflate_init(&zb, buf, zbsize, NULL); if (err) return err; totlen = 0; do { err = got_inflate_read_fd(&zb, fd, &outlen, NULL); if (err) goto done; if (outlen == 0) break; totlen += outlen; if (memchr(zb.outbuf, '\0', outlen) == NULL) { uint8_t *newbuf; nbuf++; newbuf = recallocarray(buf, nbuf - 1, nbuf, zbsize); if (newbuf == NULL) { err = got_error_from_errno("recallocarray"); goto done; } buf = newbuf; zb.outbuf = newbuf + totlen; zb.outlen = (nbuf * zbsize) - totlen; } } while (memchr(zb.outbuf, '\0', outlen) == NULL); err = got_object_parse_header(obj, buf, totlen); done: free(buf); got_inflate_end(&zb); return err; } const struct got_error * got_object_read_raw(uint8_t **outbuf, off_t *size, size_t *hdrlen, size_t max_in_mem_size, int outfd, struct got_object_id *expected_id, int infd) { const struct got_error *err = NULL; struct got_object *obj; struct got_inflate_checksum csum; struct got_object_id id; struct got_hash ctx; size_t len, consumed; FILE *f = NULL; *outbuf = NULL; *size = 0; *hdrlen = 0; got_hash_init(&ctx, GOT_HASH_SHA1); memset(&csum, 0, sizeof(csum)); csum.output_ctx = &ctx; if (lseek(infd, SEEK_SET, 0) == -1) return got_error_from_errno("lseek"); err = got_object_read_header(&obj, infd); if (err) return err; if (lseek(infd, SEEK_SET, 0) == -1) return got_error_from_errno("lseek"); if (obj->size + obj->hdrlen <= max_in_mem_size) { err = got_inflate_to_mem_fd(outbuf, &len, &consumed, &csum, obj->size + obj->hdrlen, infd); } else { int fd; /* * XXX This uses an extra file descriptor for no good reason. * We should have got_inflate_fd_to_fd(). */ fd = dup(infd); if (fd == -1) return got_error_from_errno("dup"); f = fdopen(fd, "r"); if (f == NULL) { err = got_error_from_errno("fdopen"); close(fd); goto done; } err = got_inflate_to_fd(&len, f, &csum, outfd); } if (err) goto done; if (len < obj->hdrlen || len != obj->hdrlen + obj->size) { err = got_error(GOT_ERR_BAD_OBJ_HDR); goto done; } got_hash_final_object_id(&ctx, &id); if (got_object_id_cmp(expected_id, &id) != 0) { err = got_error_checksum(expected_id); goto done; } *size = obj->size; *hdrlen = obj->hdrlen; done: got_object_close(obj); if (f && fclose(f) == EOF && err == NULL) err = got_error_from_errno("fclose"); return err; } struct got_commit_object * got_object_commit_alloc_partial(void) { struct got_commit_object *commit; commit = calloc(1, sizeof(*commit)); if (commit == NULL) return NULL; commit->tree_id = malloc(sizeof(*commit->tree_id)); if (commit->tree_id == NULL) { free(commit); return NULL; } STAILQ_INIT(&commit->parent_ids); return commit; } const struct got_error * got_object_commit_add_parent(struct got_commit_object *commit, const char *id_str) { const struct got_error *err = NULL; struct got_object_qid *qid; err = got_object_qid_alloc_partial(&qid); if (err) return err; if (!got_parse_object_id(&qid->id, id_str, GOT_HASH_SHA1)) { err = got_error(GOT_ERR_BAD_OBJ_DATA); got_object_qid_free(qid); return err; } STAILQ_INSERT_TAIL(&commit->parent_ids, qid, entry); commit->nparents++; return NULL; } static const struct got_error * parse_gmtoff(time_t *gmtoff, const char *tzstr) { int sign = 1; const char *p = tzstr; time_t h, m; *gmtoff = 0; if (*p == '-') sign = -1; else if (*p != '+') return got_error(GOT_ERR_BAD_OBJ_DATA); p++; if (!isdigit((unsigned char)*p) && !isdigit((unsigned char)*(p + 1))) return got_error(GOT_ERR_BAD_OBJ_DATA); h = (((*p - '0') * 10) + (*(p + 1) - '0')); p += 2; if (!isdigit((unsigned char)*p) && !isdigit((unsigned char)*(p + 1))) return got_error(GOT_ERR_BAD_OBJ_DATA); m = ((*p - '0') * 10) + (*(p + 1) - '0'); *gmtoff = (h * 60 * 60 + m * 60) * sign; return NULL; } static const struct got_error * parse_commit_time(time_t *time, time_t *gmtoff, char *committer) { const struct got_error *err = NULL; const char *errstr; char *space, *tzstr; /* Parse and strip off trailing timezone indicator string. */ space = strrchr(committer, ' '); if (space == NULL) return got_error(GOT_ERR_BAD_OBJ_DATA); tzstr = strdup(space + 1); if (tzstr == NULL) return got_error_from_errno("strdup"); err = parse_gmtoff(gmtoff, tzstr); free(tzstr); if (err) { if (err->code != GOT_ERR_BAD_OBJ_DATA) return err; /* Old versions of Git omitted the timestamp. */ *time = 0; *gmtoff = 0; return NULL; } *space = '\0'; /* Timestamp is separated from committer name + email by space. */ space = strrchr(committer, ' '); if (space == NULL) return got_error(GOT_ERR_BAD_OBJ_DATA); /* Timestamp parsed here is expressed as UNIX timestamp (UTC). */ *time = strtonum(space + 1, 0, INT64_MAX, &errstr); if (errstr) return got_error(GOT_ERR_BAD_OBJ_DATA); /* Strip off parsed time information, leaving just author and email. */ *space = '\0'; return NULL; } void got_object_commit_close(struct got_commit_object *commit) { if (commit->refcnt > 0) { commit->refcnt--; if (commit->refcnt > 0) return; } got_object_id_queue_free(&commit->parent_ids); free(commit->tree_id); free(commit->author); free(commit->committer); free(commit->logmsg); free(commit); } struct got_object_id * got_object_commit_get_tree_id(struct got_commit_object *commit) { return commit->tree_id; } int got_object_commit_get_nparents(struct got_commit_object *commit) { return commit->nparents; } const struct got_object_id_queue * got_object_commit_get_parent_ids(struct got_commit_object *commit) { return &commit->parent_ids; } const char * got_object_commit_get_author(struct got_commit_object *commit) { return commit->author; } time_t got_object_commit_get_author_time(struct got_commit_object *commit) { return commit->author_time; } time_t got_object_commit_get_author_gmtoff(struct got_commit_object *commit) { return commit->author_gmtoff; } const char * got_object_commit_get_committer(struct got_commit_object *commit) { return commit->committer; } time_t got_object_commit_get_committer_time(struct got_commit_object *commit) { return commit->committer_time; } time_t got_object_commit_get_committer_gmtoff(struct got_commit_object *commit) { return commit->committer_gmtoff; } const struct got_error * got_object_commit_get_logmsg(char **logmsg, struct got_commit_object *commit) { const struct got_error *err = NULL; const char *src; char *dst; size_t len; len = strlen(commit->logmsg); *logmsg = malloc(len + 2); /* leave room for a trailing \n and \0 */ if (*logmsg == NULL) return got_error_from_errno("malloc"); /* * Strip out unusual headers. Headers are separated from the commit * message body by a single empty line. */ src = commit->logmsg; dst = *logmsg; while (*src != '\0' && *src != '\n') { int copy_header = 1, eol = 0; if (strncmp(src, GOT_COMMIT_LABEL_TREE, strlen(GOT_COMMIT_LABEL_TREE)) != 0 && strncmp(src, GOT_COMMIT_LABEL_AUTHOR, strlen(GOT_COMMIT_LABEL_AUTHOR)) != 0 && strncmp(src, GOT_COMMIT_LABEL_PARENT, strlen(GOT_COMMIT_LABEL_PARENT)) != 0 && strncmp(src, GOT_COMMIT_LABEL_COMMITTER, strlen(GOT_COMMIT_LABEL_COMMITTER)) != 0) copy_header = 0; while (*src != '\0' && !eol) { if (copy_header) { *dst = *src; dst++; } if (*src == '\n') eol = 1; src++; } } *dst = '\0'; if (strlcat(*logmsg, src, len + 1) >= len + 1) { err = got_error(GOT_ERR_NO_SPACE); goto done; } /* Trim redundant trailing whitespace. */ len = strlen(*logmsg); while (len > 1 && isspace((unsigned char)(*logmsg)[len - 2]) && isspace((unsigned char)(*logmsg)[len - 1])) { (*logmsg)[len - 1] = '\0'; len--; } /* Append a trailing newline if missing. */ if (len > 0 && (*logmsg)[len - 1] != '\n') { (*logmsg)[len] = '\n'; (*logmsg)[len + 1] = '\0'; } done: if (err) { free(*logmsg); *logmsg = NULL; } return err; } const char * got_object_commit_get_logmsg_raw(struct got_commit_object *commit) { return commit->logmsg; } const struct got_error * got_object_parse_commit(struct got_commit_object **commit, char *buf, size_t len) { const struct got_error *err = NULL; enum got_hash_algorithm algo = GOT_HASH_SHA1; char *s = buf; size_t label_len; ssize_t remain = (ssize_t)len; if (remain == 0) return got_error(GOT_ERR_BAD_OBJ_DATA); *commit = got_object_commit_alloc_partial(); if (*commit == NULL) return got_error_from_errno("got_object_commit_alloc_partial"); label_len = strlen(GOT_COMMIT_LABEL_TREE); if (strncmp(s, GOT_COMMIT_LABEL_TREE, label_len) == 0) { remain -= label_len; if (remain < SHA1_DIGEST_STRING_LENGTH) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } s += label_len; if (!got_parse_object_id((*commit)->tree_id, s, algo)) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } remain -= SHA1_DIGEST_STRING_LENGTH; s += SHA1_DIGEST_STRING_LENGTH; } else { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } label_len = strlen(GOT_COMMIT_LABEL_PARENT); while (strncmp(s, GOT_COMMIT_LABEL_PARENT, label_len) == 0) { remain -= label_len; if (remain < SHA1_DIGEST_STRING_LENGTH) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } s += label_len; err = got_object_commit_add_parent(*commit, s); if (err) goto done; remain -= SHA1_DIGEST_STRING_LENGTH; s += SHA1_DIGEST_STRING_LENGTH; } label_len = strlen(GOT_COMMIT_LABEL_AUTHOR); if (strncmp(s, GOT_COMMIT_LABEL_AUTHOR, label_len) == 0) { char *p; size_t slen; remain -= label_len; if (remain <= 0) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } s += label_len; p = memchr(s, '\n', remain); if (p == NULL) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } *p = '\0'; slen = strlen(s); err = parse_commit_time(&(*commit)->author_time, &(*commit)->author_gmtoff, s); if (err) goto done; (*commit)->author = strdup(s); if ((*commit)->author == NULL) { err = got_error_from_errno("strdup"); goto done; } s += slen + 1; remain -= slen + 1; } label_len = strlen(GOT_COMMIT_LABEL_COMMITTER); if (strncmp(s, GOT_COMMIT_LABEL_COMMITTER, label_len) == 0) { char *p; size_t slen; remain -= label_len; if (remain <= 0) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } s += label_len; p = memchr(s, '\n', remain); if (p == NULL) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } *p = '\0'; slen = strlen(s); err = parse_commit_time(&(*commit)->committer_time, &(*commit)->committer_gmtoff, s); if (err) goto done; (*commit)->committer = strdup(s); if ((*commit)->committer == NULL) { err = got_error_from_errno("strdup"); goto done; } s += slen + 1; remain -= slen + 1; } (*commit)->logmsg = strndup(s, remain); if ((*commit)->logmsg == NULL) { err = got_error_from_errno("strndup"); goto done; } done: if (err) { got_object_commit_close(*commit); *commit = NULL; } return err; } const struct got_error * got_object_read_commit(struct got_commit_object **commit, int fd, struct got_object_id *expected_id, size_t expected_size) { struct got_object *obj = NULL; const struct got_error *err = NULL; size_t len; uint8_t *p; struct got_inflate_checksum csum; struct got_hash ctx; struct got_object_id id; got_hash_init(&ctx, GOT_HASH_SHA1); memset(&csum, 0, sizeof(csum)); csum.output_ctx = &ctx; err = got_inflate_to_mem_fd(&p, &len, NULL, &csum, expected_size, fd); if (err) return err; got_hash_final_object_id(&ctx, &id); if (got_object_id_cmp(expected_id, &id) != 0) { err = got_error_checksum(expected_id); goto done; } err = got_object_parse_header(&obj, p, len); if (err) goto done; if (len < obj->hdrlen + obj->size) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } if (obj->type != GOT_OBJ_TYPE_COMMIT) { err = got_error(GOT_ERR_OBJ_TYPE); goto done; } /* Skip object header. */ len -= obj->hdrlen; err = got_object_parse_commit(commit, p + obj->hdrlen, len); done: free(p); if (obj) got_object_close(obj); return err; } void got_object_tree_close(struct got_tree_object *tree) { if (tree->refcnt > 0) { tree->refcnt--; if (tree->refcnt > 0) return; } free(tree->entries); free(tree); } const struct got_error * got_object_parse_tree_entry(struct got_parsed_tree_entry *pte, size_t *elen, char *buf, size_t maxlen) { char *p, *space; *elen = 0; *elen = strnlen(buf, maxlen) + 1; if (*elen > maxlen) return got_error(GOT_ERR_BAD_OBJ_DATA); space = memchr(buf, ' ', *elen); if (space == NULL || space <= buf) return got_error(GOT_ERR_BAD_OBJ_DATA); pte->mode = 0; p = buf; while (p < space) { if (*p < '0' || *p > '7') return got_error(GOT_ERR_BAD_OBJ_DATA); pte->mode <<= 3; pte->mode |= *p - '0'; p++; } if (*elen > maxlen || maxlen - *elen < SHA1_DIGEST_LENGTH) return got_error(GOT_ERR_BAD_OBJ_DATA); pte->name = space + 1; pte->namelen = strlen(pte->name); buf += *elen; pte->id = buf; *elen += SHA1_DIGEST_LENGTH; return NULL; } static int pte_cmp(const void *pa, const void *pb) { const struct got_parsed_tree_entry *a = pa, *b = pb; return got_path_cmp(a->name, b->name, a->namelen, b->namelen); } const struct got_error * got_object_parse_tree(struct got_parsed_tree_entry **entries, size_t *nentries, size_t *nentries_alloc, uint8_t *buf, size_t len) { const struct got_error *err = NULL; size_t remain = len; const size_t nalloc = 16; struct got_parsed_tree_entry *pte; int i; *nentries = 0; if (remain == 0) return NULL; /* tree is empty */ while (remain > 0) { size_t elen; if (*nentries >= *nentries_alloc) { pte = recallocarray(*entries, *nentries_alloc, *nentries_alloc + nalloc, sizeof(**entries)); if (pte == NULL) { err = got_error_from_errno("recallocarray"); goto done; } *entries = pte; *nentries_alloc += nalloc; } pte = &(*entries)[*nentries]; err = got_object_parse_tree_entry(pte, &elen, buf, remain); if (err) goto done; buf += elen; remain -= elen; (*nentries)++; } if (remain != 0) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } if (*nentries > 1) { mergesort(*entries, *nentries, sizeof(**entries), pte_cmp); for (i = 0; i < *nentries - 1; i++) { struct got_parsed_tree_entry *prev = &(*entries)[i]; pte = &(*entries)[i + 1]; if (got_path_cmp(prev->name, pte->name, prev->namelen, pte->namelen) == 0) { err = got_error(GOT_ERR_TREE_DUP_ENTRY); break; } } } done: if (err) *nentries = 0; return err; } const struct got_error * got_object_read_tree(struct got_parsed_tree_entry **entries, size_t *nentries, size_t *nentries_alloc, uint8_t **p, int fd, struct got_object_id *expected_id) { const struct got_error *err = NULL; struct got_object *obj = NULL; size_t len; struct got_inflate_checksum csum; struct got_hash ctx; struct got_object_id id; got_hash_init(&ctx, GOT_HASH_SHA1); memset(&csum, 0, sizeof(csum)); csum.output_ctx = &ctx; err = got_inflate_to_mem_fd(p, &len, NULL, &csum, 0, fd); if (err) return err; got_hash_final_object_id(&ctx, &id); if (got_object_id_cmp(expected_id, &id) != 0) { err = got_error_checksum(expected_id); goto done; } err = got_object_parse_header(&obj, *p, len); if (err) goto done; if (len < obj->hdrlen + obj->size) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } /* Skip object header. */ len -= obj->hdrlen; err = got_object_parse_tree(entries, nentries, nentries_alloc, *p + obj->hdrlen, len); done: if (obj) got_object_close(obj); return err; } void got_object_tag_close(struct got_tag_object *tag) { if (tag->refcnt > 0) { tag->refcnt--; if (tag->refcnt > 0) return; } free(tag->tag); free(tag->tagger); free(tag->tagmsg); free(tag); } const struct got_error * got_object_parse_tag(struct got_tag_object **tag, uint8_t *buf, size_t len) { const struct got_error *err = NULL; enum got_hash_algorithm algo = GOT_HASH_SHA1; size_t remain = len; char *s = buf; size_t label_len; if (remain == 0) return got_error(GOT_ERR_BAD_OBJ_DATA); *tag = calloc(1, sizeof(**tag)); if (*tag == NULL) return got_error_from_errno("calloc"); label_len = strlen(GOT_TAG_LABEL_OBJECT); if (strncmp(s, GOT_TAG_LABEL_OBJECT, label_len) == 0) { remain -= label_len; if (remain < SHA1_DIGEST_STRING_LENGTH) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } s += label_len; if (!got_parse_object_id(&(*tag)->id, s, algo)) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } remain -= SHA1_DIGEST_STRING_LENGTH; s += SHA1_DIGEST_STRING_LENGTH; } else { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } if (remain <= 0) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } label_len = strlen(GOT_TAG_LABEL_TYPE); if (strncmp(s, GOT_TAG_LABEL_TYPE, label_len) == 0) { remain -= label_len; if (remain <= 0) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } s += label_len; if (strncmp(s, GOT_OBJ_LABEL_COMMIT, strlen(GOT_OBJ_LABEL_COMMIT)) == 0) { (*tag)->obj_type = GOT_OBJ_TYPE_COMMIT; label_len = strlen(GOT_OBJ_LABEL_COMMIT); s += label_len; remain -= label_len; } else if (strncmp(s, GOT_OBJ_LABEL_TREE, strlen(GOT_OBJ_LABEL_TREE)) == 0) { (*tag)->obj_type = GOT_OBJ_TYPE_TREE; label_len = strlen(GOT_OBJ_LABEL_TREE); s += label_len; remain -= label_len; } else if (strncmp(s, GOT_OBJ_LABEL_BLOB, strlen(GOT_OBJ_LABEL_BLOB)) == 0) { (*tag)->obj_type = GOT_OBJ_TYPE_BLOB; label_len = strlen(GOT_OBJ_LABEL_BLOB); s += label_len; remain -= label_len; } else if (strncmp(s, GOT_OBJ_LABEL_TAG, strlen(GOT_OBJ_LABEL_TAG)) == 0) { (*tag)->obj_type = GOT_OBJ_TYPE_TAG; label_len = strlen(GOT_OBJ_LABEL_TAG); s += label_len; remain -= label_len; } else { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } if (remain <= 0 || *s != '\n') { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } s++; remain--; if (remain <= 0) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } } else { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } label_len = strlen(GOT_TAG_LABEL_TAG); if (strncmp(s, GOT_TAG_LABEL_TAG, label_len) == 0) { char *p; size_t slen; remain -= label_len; if (remain <= 0) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } s += label_len; p = memchr(s, '\n', remain); if (p == NULL) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } *p = '\0'; slen = strlen(s); (*tag)->tag = strndup(s, slen); if ((*tag)->tag == NULL) { err = got_error_from_errno("strndup"); goto done; } s += slen + 1; remain -= slen + 1; if (remain <= 0) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } } else { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } label_len = strlen(GOT_TAG_LABEL_TAGGER); if (strncmp(s, GOT_TAG_LABEL_TAGGER, label_len) == 0) { char *p; size_t slen; remain -= label_len; if (remain <= 0) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } s += label_len; p = memchr(s, '\n', remain); if (p == NULL) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } *p = '\0'; slen = strlen(s); err = parse_commit_time(&(*tag)->tagger_time, &(*tag)->tagger_gmtoff, s); if (err) goto done; (*tag)->tagger = strdup(s); if ((*tag)->tagger == NULL) { err = got_error_from_errno("strdup"); goto done; } s += slen + 1; remain -= slen + 1; if (remain < 0) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } } else { /* Some old tags in the Linux git repo have no tagger. */ (*tag)->tagger = strdup(""); if ((*tag)->tagger == NULL) { err = got_error_from_errno("strdup"); goto done; } } (*tag)->tagmsg = strndup(s, remain); if ((*tag)->tagmsg == NULL) { err = got_error_from_errno("strndup"); goto done; } done: if (err) { got_object_tag_close(*tag); *tag = NULL; } return err; } const struct got_error * got_object_read_tag(struct got_tag_object **tag, int fd, struct got_object_id *expected_id, size_t expected_size) { const struct got_error *err = NULL; struct got_object *obj = NULL; size_t len; uint8_t *p; struct got_inflate_checksum csum; struct got_hash ctx; struct got_object_id id; got_hash_init(&ctx, GOT_HASH_SHA1); memset(&csum, 0, sizeof(csum)); csum.output_ctx = &ctx; err = got_inflate_to_mem_fd(&p, &len, NULL, &csum, expected_size, fd); if (err) return err; got_hash_final_object_id(&ctx, &id); if (got_object_id_cmp(expected_id, &id) != 0) { err = got_error_checksum(expected_id); goto done; } err = got_object_parse_header(&obj, p, len); if (err) goto done; if (len < obj->hdrlen + obj->size) { err = got_error(GOT_ERR_BAD_OBJ_DATA); goto done; } /* Skip object header. */ len -= obj->hdrlen; err = got_object_parse_tag(tag, p + obj->hdrlen, len); done: free(p); if (obj) got_object_close(obj); return err; } got-portable-0.101/lib/worktree_open.c0000664000175100017510000002121214644144735013406 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include "got_cancel.h" #include "got_error.h" #include "got_reference.h" #include "got_path.h" #include "got_worktree.h" #include "got_repository.h" #include "got_gotconfig.h" #include "got_object.h" #include "got_lib_worktree.h" #include "got_lib_gotconfig.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif static const struct got_error * read_meta_file(char **content, const char *path_got, const char *name) { const struct got_error *err = NULL; char *path; int fd = -1; ssize_t n; struct stat sb; *content = NULL; if (asprintf(&path, "%s/%s", path_got, name) == -1) { err = got_error_from_errno("asprintf"); path = NULL; goto done; } fd = open(path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { if (errno == ENOENT) err = got_error_path(path, GOT_ERR_WORKTREE_META); else err = got_error_from_errno2("open", path); goto done; } if (flock(fd, LOCK_SH | LOCK_NB) == -1) { err = (errno == EWOULDBLOCK ? got_error(GOT_ERR_WORKTREE_BUSY) : got_error_from_errno2("flock", path)); goto done; } if (fstat(fd, &sb) != 0) { err = got_error_from_errno2("fstat", path); goto done; } if (sb.st_size == 0) { err = got_error_path(path, GOT_ERR_WORKTREE_META); goto done; } *content = calloc(1, sb.st_size); if (*content == NULL) { err = got_error_from_errno("calloc"); goto done; } n = read(fd, *content, sb.st_size); if (n != sb.st_size) { err = (n == -1 ? got_error_from_errno2("read", path) : got_error_path(path, GOT_ERR_WORKTREE_META)); goto done; } if ((*content)[sb.st_size - 1] != '\n') { err = got_error_path(path, GOT_ERR_WORKTREE_META); goto done; } (*content)[sb.st_size - 1] = '\0'; done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno2("close", path_got); free(path); if (err) { free(*content); *content = NULL; } return err; } static const struct got_error * open_worktree(struct got_worktree **worktree, const char *path, const char *meta_dir) { const struct got_error *err = NULL; char *path_meta; char *formatstr = NULL; char *uuidstr = NULL; char *path_lock = NULL; char *base_commit_id_str = NULL; int version, fd = -1; const char *errstr; struct got_repository *repo = NULL; int *pack_fds = NULL; uint32_t uuid_status; *worktree = NULL; if (asprintf(&path_meta, "%s/%s", path, meta_dir) == -1) { err = got_error_from_errno("asprintf"); path_meta = NULL; goto done; } if (asprintf(&path_lock, "%s/%s", path_meta, GOT_WORKTREE_LOCK) == -1) { err = got_error_from_errno("asprintf"); path_lock = NULL; goto done; } fd = open(path_lock, O_RDWR | O_EXLOCK | O_NONBLOCK | O_CLOEXEC); if (fd == -1) { err = (errno == EWOULDBLOCK ? got_error(GOT_ERR_WORKTREE_BUSY) : got_error_from_errno2("open", path_lock)); goto done; } err = read_meta_file(&formatstr, path_meta, GOT_WORKTREE_FORMAT); if (err) goto done; version = strtonum(formatstr, 1, INT_MAX, &errstr); if (errstr) { err = got_error_msg(GOT_ERR_WORKTREE_META, "could not parse work tree format version number"); goto done; } if (version != GOT_WORKTREE_FORMAT_VERSION) { err = got_error(GOT_ERR_WORKTREE_VERS); goto done; } *worktree = calloc(1, sizeof(**worktree)); if (*worktree == NULL) { err = got_error_from_errno("calloc"); goto done; } (*worktree)->lockfd = -1; (*worktree)->root_path = realpath(path, NULL); if ((*worktree)->root_path == NULL) { err = got_error_from_errno2("realpath", path); goto done; } (*worktree)->meta_dir = meta_dir; err = read_meta_file(&(*worktree)->repo_path, path_meta, GOT_WORKTREE_REPOSITORY); if (err) goto done; err = read_meta_file(&(*worktree)->path_prefix, path_meta, GOT_WORKTREE_PATH_PREFIX); if (err) goto done; err = read_meta_file(&base_commit_id_str, path_meta, GOT_WORKTREE_BASE_COMMIT); if (err) goto done; err = read_meta_file(&uuidstr, path_meta, GOT_WORKTREE_UUID); if (err) goto done; uuid_from_string(uuidstr, &(*worktree)->uuid, &uuid_status); if (uuid_status != uuid_s_ok) { err = got_error_uuid(uuid_status, "uuid_from_string"); goto done; } err = got_repo_pack_fds_open(&pack_fds); if (err) goto done; err = got_repo_open(&repo, (*worktree)->repo_path, NULL, pack_fds); if (err) goto done; err = got_object_resolve_id_str(&(*worktree)->base_commit_id, repo, base_commit_id_str); if (err) goto done; err = read_meta_file(&(*worktree)->head_ref_name, path_meta, GOT_WORKTREE_HEAD_REF); if (err) goto done; if (asprintf(&(*worktree)->gotconfig_path, "%s/%s/%s", (*worktree)->root_path, (*worktree)->meta_dir, GOT_GOTCONFIG_FILENAME) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_gotconfig_read(&(*worktree)->gotconfig, (*worktree)->gotconfig_path); if (err) goto done; (*worktree)->root_fd = open((*worktree)->root_path, O_DIRECTORY | O_CLOEXEC); if ((*worktree)->root_fd == -1) { err = got_error_from_errno2("open", (*worktree)->root_path); goto done; } done: if (repo) { const struct got_error *close_err = got_repo_close(repo); if (err == NULL) err = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (err == NULL) err = pack_err; } free(path_meta); free(path_lock); free(base_commit_id_str); free(uuidstr); free(formatstr); if (err) { if (fd != -1) close(fd); if (*worktree != NULL) got_worktree_close(*worktree); *worktree = NULL; } else (*worktree)->lockfd = fd; return err; } const struct got_error * got_worktree_open(struct got_worktree **worktree, const char *path, const char *meta_dir) { const struct got_error *err = NULL; char *worktree_path; const char *meta_dirs[] = { GOT_WORKTREE_GOT_DIR, GOT_WORKTREE_CVG_DIR }; int i; worktree_path = strdup(path); if (worktree_path == NULL) return got_error_from_errno("strdup"); for (;;) { char *parent_path; if (meta_dir == NULL) { for (i = 0; i < nitems(meta_dirs); i++) { err = open_worktree(worktree, worktree_path, meta_dirs[i]); if (err == NULL || err->code == GOT_ERR_WORKTREE_BUSY) break; } } else err = open_worktree(worktree, worktree_path, meta_dir); if (err && !(err->code == GOT_ERR_ERRNO && errno == ENOENT)) { free(worktree_path); return err; } if (*worktree) { free(worktree_path); return NULL; } if (worktree_path[0] == '/' && worktree_path[1] == '\0') break; err = got_path_dirname(&parent_path, worktree_path); if (err) { if (err->code != GOT_ERR_BAD_PATH) { free(worktree_path); return err; } break; } free(worktree_path); worktree_path = parent_path; } free(worktree_path); return got_error(GOT_ERR_NOT_WORKTREE); } const struct got_error * got_worktree_close(struct got_worktree *worktree) { const struct got_error *err = NULL; if (worktree->lockfd != -1) { if (close(worktree->lockfd) == -1) err = got_error_from_errno2("close", got_worktree_get_root_path(worktree)); } if (close(worktree->root_fd) == -1 && err == NULL) err = got_error_from_errno2("close", got_worktree_get_root_path(worktree)); free(worktree->repo_path); free(worktree->path_prefix); free(worktree->base_commit_id); free(worktree->head_ref_name); free(worktree->root_path); free(worktree->gotconfig_path); got_gotconfig_free(worktree->gotconfig); free(worktree); return err; } const char * got_worktree_get_root_path(struct got_worktree *worktree) { return worktree->root_path; } const char * got_worktree_get_repo_path(struct got_worktree *worktree) { return worktree->repo_path; } const char * got_worktree_get_path_prefix(struct got_worktree *worktree) { return worktree->path_prefix; } got-portable-0.101/lib/arraylist.h0000664000175100017510000000753214644144735012553 /* Auto-reallocating array for arbitrary member types. */ /* * Copyright (c) 2020 Neels Hofmeyr * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Usage: * * ARRAYLIST(any_type_t) list; * // OR * typedef ARRAYLIST(any_type_t) any_type_list_t; * any_type_list_t list; * * // pass the number of (at first unused) members to add on each realloc: * ARRAYLIST_INIT(list, 128); * any_type_t *x; * while (bar) { * // This enlarges the allocated array as needed; * // list.head may change due to realloc: * ARRAYLIST_ADD(x, list); * if (!x) * return ENOMEM; * *x = random_foo_value; * } * for (i = 0; i < list.len; i++) * printf("%s", foo_to_str(list.head[i])); * ARRAYLIST_FREE(list); */ #include "got_compat.h" #define ARRAYLIST(MEMBER_TYPE) \ struct { \ MEMBER_TYPE *head; \ MEMBER_TYPE *p; \ unsigned int len; \ unsigned int allocated; \ unsigned int alloc_blocksize; \ } #define ARRAYLIST_INIT(ARRAY_LIST, ALLOC_BLOCKSIZE) do { \ (ARRAY_LIST).head = NULL; \ (ARRAY_LIST).len = 0; \ (ARRAY_LIST).allocated = 0; \ (ARRAY_LIST).alloc_blocksize = ALLOC_BLOCKSIZE; \ } while(0) #define ARRAYLIST_ADD(NEW_ITEM_P, ARRAY_LIST) do { \ if ((ARRAY_LIST).len && !(ARRAY_LIST).allocated) { \ NEW_ITEM_P = NULL; \ break; \ } \ if ((ARRAY_LIST).head == NULL \ || (ARRAY_LIST).allocated < (ARRAY_LIST).len + 1) { \ (ARRAY_LIST).p = recallocarray((ARRAY_LIST).head, \ (ARRAY_LIST).len, \ (ARRAY_LIST).allocated + \ ((ARRAY_LIST).allocated ? \ (ARRAY_LIST).allocated / 2 : \ (ARRAY_LIST).alloc_blocksize ? \ (ARRAY_LIST).alloc_blocksize : 8), \ sizeof(*(ARRAY_LIST).head)); \ if ((ARRAY_LIST).p == NULL) { \ NEW_ITEM_P = NULL; \ break; \ } \ (ARRAY_LIST).allocated += \ (ARRAY_LIST).allocated ? \ (ARRAY_LIST).allocated / 2 : \ (ARRAY_LIST).alloc_blocksize ? \ (ARRAY_LIST).alloc_blocksize : 8, \ (ARRAY_LIST).head = (ARRAY_LIST).p; \ (ARRAY_LIST).p = NULL; \ }; \ if ((ARRAY_LIST).head == NULL \ || (ARRAY_LIST).allocated < (ARRAY_LIST).len + 1) { \ NEW_ITEM_P = NULL; \ break; \ } \ (NEW_ITEM_P) = &(ARRAY_LIST).head[(ARRAY_LIST).len]; \ (ARRAY_LIST).len++; \ } while (0) #define ARRAYLIST_INSERT(NEW_ITEM_P, ARRAY_LIST, AT_IDX) do { \ int _at_idx = (AT_IDX); \ ARRAYLIST_ADD(NEW_ITEM_P, ARRAY_LIST); \ if ((NEW_ITEM_P) \ && _at_idx >= 0 \ && _at_idx < (ARRAY_LIST).len) { \ memmove(&(ARRAY_LIST).head[_at_idx + 1], \ &(ARRAY_LIST).head[_at_idx], \ ((ARRAY_LIST).len - 1 - _at_idx) \ * sizeof(*(ARRAY_LIST).head)); \ (NEW_ITEM_P) = &(ARRAY_LIST).head[_at_idx]; \ }; \ } while (0) #define ARRAYLIST_CLEAR(ARRAY_LIST) \ (ARRAY_LIST).len = 0 #define ARRAYLIST_FREE(ARRAY_LIST) \ do { \ if ((ARRAY_LIST).head && (ARRAY_LIST).allocated) \ free((ARRAY_LIST).head); \ ARRAYLIST_INIT(ARRAY_LIST, (ARRAY_LIST).alloc_blocksize); \ } while(0) #define ARRAYLIST_FOREACH(ITEM_P, ARRAY_LIST) \ for ((ITEM_P) = (ARRAY_LIST).head; \ (ITEM_P) - (ARRAY_LIST).head < (ARRAY_LIST).len; \ (ITEM_P)++) #define ARRAYLIST_IDX(ITEM_P, ARRAY_LIST) ((ITEM_P) - (ARRAY_LIST).head) got-portable-0.101/lib/commit_graph.c0000664000175100017510000006235514644144735013211 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_cancel.h" #include "got_commit_graph.h" #include "got_path.h" #include "got_lib_delta.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_idset.h" #include "got_lib_object_qid.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif struct got_commit_graph_node { struct got_object_id id; /* Used for topological sorting. */ struct got_commit_graph_node *parents[2]; struct got_commit_graph_node **more_parents; int nparents; int indegree; /* Used only during iteration. */ time_t timestamp; TAILQ_ENTRY(got_commit_graph_node) entry; }; TAILQ_HEAD(got_commit_graph_iter_list, got_commit_graph_node); struct got_commit_graph_branch_tip { struct got_object_id *commit_id; struct got_commit_object *commit; struct got_commit_graph_node *new_node; }; struct got_commit_graph { /* The set of all commits we have traversed. */ struct got_object_idset *node_ids; int flags; #define GOT_COMMIT_GRAPH_FIRST_PARENT_TRAVERSAL 0x01 #define GOT_COMMIT_GRAPH_TOPOSORT 0x02 /* * A set of object IDs of known parent commits which we have not yet * traversed. Each commit ID in this set represents a branch in commit * history: Either the first-parent branch of the head node, or another * branch corresponding to a traversed merge commit for which we have * not traversed a branch point commit yet. * * Whenever we add a commit with a matching ID to the graph, we remove * its corresponding element from this set, and add new elements for * each of that commit's parent commits which were not traversed yet. * * When API users ask us to fetch more commits, we fetch commits from * all currently open branches. This allows API users to process * commits in linear order even though the history contains branches. */ struct got_object_idset *open_branches; /* Array of branch tips for fetch_commits_from_open_branches(). */ struct got_commit_graph_branch_tip *tips; int ntips; /* Path of tree entry of interest to the API user. */ char *path; /* * Nodes which will be passed to the API user next, sorted by * commit timestamp. Sorted in topological order only if topological * sorting was requested. */ struct got_commit_graph_iter_list iter_list; }; static const struct got_error * detect_changed_path(int *changed, struct got_commit_object *commit, struct got_object_id *commit_id, const char *path, struct got_repository *repo) { const struct got_error *err = NULL; struct got_commit_object *pcommit = NULL; struct got_tree_object *tree = NULL, *ptree = NULL; struct got_object_qid *pid; if (got_path_is_root_dir(path)) { *changed = 1; return NULL; } *changed = 0; pid = STAILQ_FIRST(&commit->parent_ids); if (pid == NULL) { struct got_object_id *obj_id; err = got_object_id_by_path(&obj_id, repo, commit, path); if (err) { if (err->code == GOT_ERR_NO_TREE_ENTRY) err = NULL; } else *changed = 1; /* The path was created in this commit. */ free(obj_id); return err; } err = got_object_open_as_tree(&tree, repo, commit->tree_id); if (err) return err; err = got_object_open_as_commit(&pcommit, repo, &pid->id); if (err) goto done; err = got_object_open_as_tree(&ptree, repo, pcommit->tree_id); if (err) goto done; err = got_object_tree_path_changed(changed, tree, ptree, path, repo); done: if (tree) got_object_tree_close(tree); if (ptree) got_object_tree_close(ptree); if (pcommit) got_object_commit_close(pcommit); return err; } static void add_node_to_iter_list(struct got_commit_graph *graph, struct got_commit_graph_node *node, time_t committer_time) { struct got_commit_graph_node *n, *next; node->timestamp = committer_time; n = TAILQ_FIRST(&graph->iter_list); while (n) { next = TAILQ_NEXT(n, entry); if (next && node->timestamp >= next->timestamp) { TAILQ_INSERT_BEFORE(next, node, entry); return; } n = next; } TAILQ_INSERT_TAIL(&graph->iter_list, node, entry); } static const struct got_error * add_node(struct got_commit_graph_node **new_node, struct got_commit_graph *graph, struct got_object_id *commit_id, struct got_repository *repo) { const struct got_error *err = NULL; struct got_commit_graph_node *node; *new_node = NULL; node = calloc(1, sizeof(*node)); if (node == NULL) return got_error_from_errno("calloc"); memcpy(&node->id, commit_id, sizeof(node->id)); node->nparents = -1; err = got_object_idset_add(graph->node_ids, &node->id, node); if (err) free(node); else *new_node = node; return err; } /* * Ask got-read-pack to traverse first-parent history until a commit is * encountered which modified graph->path, or until the pack file runs * out of relevant commits. This is faster than sending an individual * request for each commit stored in the pack file. */ static const struct got_error * packed_first_parent_traversal(int *ncommits_traversed, struct got_commit_graph *graph, struct got_object_id *commit_id, struct got_repository *repo) { const struct got_error *err = NULL; struct got_object_id_queue traversed_commits; struct got_object_qid *qid; STAILQ_INIT(&traversed_commits); *ncommits_traversed = 0; err = got_traverse_packed_commits(&traversed_commits, commit_id, graph->path, repo); if (err) return err; /* Add all traversed commits to the graph... */ STAILQ_FOREACH(qid, &traversed_commits, entry) { if (got_object_idset_contains(graph->open_branches, &qid->id)) continue; if (got_object_idset_contains(graph->node_ids, &qid->id)) continue; (*ncommits_traversed)++; /* ... except the last commit is the new branch tip. */ if (STAILQ_NEXT(qid, entry) == NULL) { err = got_object_idset_add(graph->open_branches, &qid->id, NULL); break; } err = got_object_idset_add(graph->node_ids, &qid->id, NULL); if (err) break; } got_object_id_queue_free(&traversed_commits); return err; } static const struct got_error * close_branch(struct got_commit_graph *graph, struct got_object_id *commit_id) { const struct got_error *err; err = got_object_idset_remove(NULL, graph->open_branches, commit_id); if (err && err->code != GOT_ERR_NO_OBJ) return err; return NULL; } static const struct got_error * advance_branch(struct got_commit_graph *graph, struct got_object_id *commit_id, struct got_commit_object *commit, struct got_repository *repo) { const struct got_error *err; struct got_object_qid *qid; struct got_object_id *merged_id = NULL; err = close_branch(graph, commit_id); if (err) return err; if (graph->flags & GOT_COMMIT_GRAPH_FIRST_PARENT_TRAVERSAL) { qid = STAILQ_FIRST(&commit->parent_ids); if (qid == NULL || got_object_idset_contains(graph->open_branches, &qid->id)) return NULL; /* * The root directory always changes by definition, and when * logging the root we want to traverse consecutive commits * even if they point at the same tree. * But if we are looking for a specific path then we can avoid * fetching packed commits which did not modify the path and * only fetch their IDs. This speeds up 'got blame'. */ if (!got_path_is_root_dir(graph->path) && (commit->flags & GOT_COMMIT_FLAG_PACKED)) { int ncommits = 0; err = packed_first_parent_traversal(&ncommits, graph, &qid->id, repo); if (err || ncommits > 0) return err; } return got_object_idset_add(graph->open_branches, &qid->id, NULL); } /* * If we are graphing commits for a specific path, skip branches * which do not contribute any content to this path. */ if (commit->nparents > 1 && !got_path_is_root_dir(graph->path)) { err = got_object_id_by_path(&merged_id, repo, commit, graph->path); if (err && err->code != GOT_ERR_NO_TREE_ENTRY) return err; /* The requested path does not exist in this merge commit. */ } if (commit->nparents > 1 && !got_path_is_root_dir(graph->path) && merged_id != NULL) { struct got_object_id *prev_id = NULL; int branches_differ = 0; STAILQ_FOREACH(qid, &commit->parent_ids, entry) { struct got_object_id *id = NULL; struct got_commit_object *pcommit = NULL; if (got_object_idset_contains(graph->open_branches, &qid->id)) continue; err = got_object_open_as_commit(&pcommit, repo, &qid->id); if (err) { free(merged_id); free(prev_id); return err; } err = got_object_id_by_path(&id, repo, pcommit, graph->path); got_object_commit_close(pcommit); pcommit = NULL; if (err) { if (err->code == GOT_ERR_NO_TREE_ENTRY) { branches_differ = 1; continue; } free(merged_id); free(prev_id); return err; } if (prev_id) { if (!branches_differ && got_object_id_cmp(id, prev_id) != 0) branches_differ = 1; free(prev_id); } prev_id = id; /* * If a branch has created the merged content we can * skip any other branches. */ if (got_object_id_cmp(merged_id, id) == 0) { err = got_object_idset_add(graph->open_branches, &qid->id, NULL); free(merged_id); free(id); return err; } } free(prev_id); prev_id = NULL; free(merged_id); merged_id = NULL; /* * If the path's content is the same on all branches, * follow the first parent only. */ if (!branches_differ) { qid = STAILQ_FIRST(&commit->parent_ids); if (qid == NULL) return NULL; if (got_object_idset_contains(graph->open_branches, &qid->id)) return NULL; if (got_object_idset_contains(graph->node_ids, &qid->id)) return NULL; /* parent already traversed */ return got_object_idset_add(graph->open_branches, &qid->id, NULL); } } STAILQ_FOREACH(qid, &commit->parent_ids, entry) { if (got_object_idset_contains(graph->open_branches, &qid->id)) continue; if (got_object_idset_contains(graph->node_ids, &qid->id)) continue; /* parent already traversed */ err = got_object_idset_add(graph->open_branches, &qid->id, NULL); if (err) return err; } return NULL; } const struct got_error * got_commit_graph_open(struct got_commit_graph **graph, const char *path, int first_parent_traversal) { const struct got_error *err = NULL; *graph = calloc(1, sizeof(**graph)); if (*graph == NULL) return got_error_from_errno("calloc"); TAILQ_INIT(&(*graph)->iter_list); (*graph)->path = strdup(path); if ((*graph)->path == NULL) { err = got_error_from_errno("strdup"); goto done; } (*graph)->node_ids = got_object_idset_alloc(); if ((*graph)->node_ids == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } (*graph)->open_branches = got_object_idset_alloc(); if ((*graph)->open_branches == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } if (first_parent_traversal) (*graph)->flags |= GOT_COMMIT_GRAPH_FIRST_PARENT_TRAVERSAL; done: if (err) { got_commit_graph_close(*graph); *graph = NULL; } return err; } struct add_branch_tip_arg { struct got_commit_graph_branch_tip *tips; int ntips; struct got_repository *repo; struct got_commit_graph *graph; }; static const struct got_error * add_branch_tip(struct got_object_id *commit_id, void *data, void *arg) { const struct got_error *err; struct add_branch_tip_arg *a = arg; struct got_commit_graph_node *new_node; struct got_commit_object *commit; err = got_object_open_as_commit(&commit, a->repo, commit_id); if (err) return err; err = add_node(&new_node, a->graph, commit_id, a->repo); if (err) { got_object_commit_close(commit); return err; } a->tips[a->ntips].commit_id = &new_node->id; a->tips[a->ntips].commit = commit; a->tips[a->ntips].new_node = new_node; a->ntips++; return NULL; } static const struct got_error * fetch_commits_from_open_branches(struct got_commit_graph *graph, struct got_repository *repo, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err; struct add_branch_tip_arg arg; int i, ntips; ntips = got_object_idset_num_elements(graph->open_branches); if (ntips == 0) return NULL; /* (Re-)allocate branch tips array if necessary. */ if (graph->ntips < ntips) { struct got_commit_graph_branch_tip *tips; tips = recallocarray(graph->tips, graph->ntips, ntips, sizeof(*tips)); if (tips == NULL) return got_error_from_errno("recallocarray"); graph->tips = tips; graph->ntips = ntips; } arg.tips = graph->tips; arg.ntips = 0; /* add_branch_tip() will increment */ arg.repo = repo; arg.graph = graph; err = got_object_idset_for_each(graph->open_branches, add_branch_tip, &arg); if (err) goto done; for (i = 0; i < arg.ntips; i++) { struct got_object_id *commit_id; struct got_commit_object *commit; struct got_commit_graph_node *new_node; int changed; if (cancel_cb) { err = (*cancel_cb)(cancel_arg); if (err) break; } commit_id = arg.tips[i].commit_id; commit = arg.tips[i].commit; new_node = arg.tips[i].new_node; err = detect_changed_path(&changed, commit, commit_id, graph->path, repo); if (err) { if (err->code != GOT_ERR_NO_OBJ) break; /* * History of the path stops here on the current * branch. Keep going on other branches. */ err = close_branch(graph, commit_id); if (err) break; continue; } if (changed) { add_node_to_iter_list(graph, new_node, got_object_commit_get_committer_time(commit)); arg.tips[i].new_node = NULL; } err = advance_branch(graph, commit_id, commit, repo); if (err) break; } done: for (i = 0; i < arg.ntips; i++) { got_object_commit_close(arg.tips[i].commit); free(arg.tips[i].new_node); } return err; } void got_commit_graph_close(struct got_commit_graph *graph) { struct got_commit_graph_node *node; while ((node = TAILQ_FIRST(&graph->iter_list))) { TAILQ_REMOVE(&graph->iter_list, node, entry); free(node->more_parents); free(node); } if (graph->open_branches) got_object_idset_free(graph->open_branches); if (graph->node_ids) got_object_idset_free(graph->node_ids); free(graph->tips); free(graph->path); free(graph); } static const struct got_error * remove_branch_tip(struct got_object_id *commit_id, void *data, void *arg) { struct got_object_idset *open_branches = arg; return got_object_idset_remove(NULL, open_branches, commit_id); } const struct got_error * got_commit_graph_bfsort(struct got_commit_graph *graph, struct got_object_id *id, struct got_repository *repo, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; struct got_commit_graph_node *node; graph->flags &= ~GOT_COMMIT_GRAPH_TOPOSORT; /* Clear left-over state from previous iteration attempts. */ while ((node = TAILQ_FIRST(&graph->iter_list))) TAILQ_REMOVE(&graph->iter_list, node, entry); err = got_object_idset_for_each(graph->open_branches, remove_branch_tip, graph->open_branches); if (err) return err; err = got_object_idset_add(graph->open_branches, id, NULL); if (err) return err; /* Locate first commit which changed graph->path. */ while (TAILQ_EMPTY(&graph->iter_list) && got_object_idset_num_elements(graph->open_branches) > 0) { err = fetch_commits_from_open_branches(graph, repo, cancel_cb, cancel_arg); if (err) return err; } if (TAILQ_EMPTY(&graph->iter_list)) { const char *path; if (got_path_is_root_dir(graph->path)) return got_error_no_obj(id); path = graph->path; while (path[0] == '/') path++; return got_error_path(path, GOT_ERR_NO_TREE_ENTRY); } return NULL; } const struct got_error * got_commit_graph_iter_next(struct got_object_id *id, struct got_commit_graph *graph, struct got_repository *repo, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; struct got_commit_graph_node *node, *pnode; int i; node = TAILQ_FIRST(&graph->iter_list); if (node == NULL) { /* We are done iterating, or iteration was not started. */ return got_error(GOT_ERR_ITER_COMPLETED); } if (graph->flags & GOT_COMMIT_GRAPH_TOPOSORT) { /* At least one node with in-degree zero must exist. */ while (node->indegree != 0) node = TAILQ_NEXT(node, entry); } else { while (TAILQ_NEXT(node, entry) == NULL && got_object_idset_num_elements(graph->open_branches) > 0) { err = fetch_commits_from_open_branches(graph, repo, cancel_cb, cancel_arg); if (err) return err; } } memcpy(id, &node->id, sizeof(*id)); TAILQ_REMOVE(&graph->iter_list, node, entry); if (graph->flags & GOT_COMMIT_GRAPH_TOPOSORT) { /* When visiting a commit decrement in-degree of all parents. */ for (i = 0; i < node->nparents; i++) { if (i < nitems(node->parents)) pnode = node->parents[i]; else pnode = node->more_parents[i]; pnode->indegree--; } } free(node); return NULL; } static const struct got_error * find_yca_add_id(struct got_object_id **yca_id, struct got_commit_graph *graph, struct got_object_idset *commit_ids, struct got_repository *repo, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; struct got_object_id id; err = got_commit_graph_iter_next(&id, graph, repo, cancel_cb, cancel_arg); if (err) return err; if (got_object_idset_contains(commit_ids, &id)) { *yca_id = got_object_id_dup(&id); if (*yca_id == NULL) err = got_error_from_errno("got_object_id_dup"); return err; } return got_object_idset_add(commit_ids, &id, NULL); } /* * Sets *yca_id to the youngest common ancestor of commit_id and * commit_id2. Returns got_error(GOT_ERR_ANCESTRY) if they have no * common ancestors. * * If first_parent_traversal is nonzero, only linear history is considered. * If toposort is set then sort commits in topological order before * traversing them. */ const struct got_error * got_commit_graph_find_youngest_common_ancestor(struct got_object_id **yca_id, struct got_object_id *commit_id, struct got_object_id *commit_id2, int first_parent_traversal, int toposort, struct got_repository *repo, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; struct got_commit_graph *graph = NULL, *graph2 = NULL; int completed = 0, completed2 = 0; struct got_object_idset *commit_ids; *yca_id = NULL; commit_ids = got_object_idset_alloc(); if (commit_ids == NULL) return got_error_from_errno("got_object_idset_alloc"); err = got_commit_graph_open(&graph, "/", first_parent_traversal); if (err) goto done; err = got_commit_graph_open(&graph2, "/", first_parent_traversal); if (err) goto done; if (toposort) { err = got_commit_graph_toposort(graph, commit_id, repo, cancel_cb, cancel_arg); if (err) goto done; err = got_commit_graph_toposort(graph2, commit_id2, repo, cancel_cb, cancel_arg); if (err) goto done; } else { err = got_commit_graph_bfsort(graph, commit_id, repo, cancel_cb, cancel_arg); if (err) goto done; err = got_commit_graph_bfsort(graph2, commit_id2, repo, cancel_cb, cancel_arg); if (err) goto done; } for (;;) { if (cancel_cb) { err = (*cancel_cb)(cancel_arg); if (err) break; } if (!completed) { err = find_yca_add_id(yca_id, graph, commit_ids, repo, cancel_cb, cancel_arg); if (err) { if (err->code != GOT_ERR_ITER_COMPLETED) break; err = NULL; completed = 1; } if (*yca_id) break; } if (!completed2) { err = find_yca_add_id(yca_id, graph2, commit_ids, repo, cancel_cb, cancel_arg); if (err) { if (err->code != GOT_ERR_ITER_COMPLETED) break; err = NULL; completed2 = 1; } if (*yca_id) break; } if (completed && completed2) { err = got_error(GOT_ERR_ANCESTRY); break; } } done: got_object_idset_free(commit_ids); if (graph) got_commit_graph_close(graph); if (graph2) got_commit_graph_close(graph2); return err; } /* * Sort the graph for traversal in topological order. * * This implementation is based on the description of topological sorting * of git commits by Derrick Stolee at * https://github.blog/2022-08-30-gits-database-internals-ii-commit-history-queries/#topological-sorting * which reads as follows: * * The basic algorithm for topological sorting is Kahn’s algorithm which * follows two big steps: * 1. Walk all reachable commits, counting the number of times a commit appears * as a parent of another commit. Call these numbers the in-degree of the * commit, referencing the number of incoming edges. * 2. Walk the reachable commits, but only visit a commit if its in-degree * value is zero. When visiting a commit, decrement the in-degree value of * each parent. * * This algorithm works because at least one of our starting points will * have in-degree zero, and then decrementing the in-degree value is similar * to deleting the commit from the graph, always having at least one commit * with in-degree zero. */ const struct got_error * got_commit_graph_toposort(struct got_commit_graph *graph, struct got_object_id *id, struct got_repository *repo, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; struct got_commit_graph_node *node = NULL, *pnode = NULL; struct got_commit_object *commit = NULL; struct got_object_id_queue commits; const struct got_object_id_queue *parent_ids; struct got_object_qid *qid = NULL, *pid; int i; STAILQ_INIT(&commits); if (graph->flags & GOT_COMMIT_GRAPH_FIRST_PARENT_TRAVERSAL) return got_commit_graph_bfsort(graph, id, repo, cancel_cb, cancel_arg); /* Clear left-over state from previous iteration attempts. */ while ((node = TAILQ_FIRST(&graph->iter_list))) TAILQ_REMOVE(&graph->iter_list, node, entry); err = got_object_idset_for_each(graph->open_branches, remove_branch_tip, graph->open_branches); if (err) return err; graph->flags |= GOT_COMMIT_GRAPH_TOPOSORT; /* * Sorting the commit graph in topological order requires visiting * every reachable commit. This is very expensive but there are * ways to speed this up significantly in the future: * 1) Run this loop in got-read-pack if possible. * 2) Use Git's commit-graph file to compute the result incrementally. * See the blog post linked above for details. */ err = got_object_qid_alloc_partial(&qid); if (err) return err; memcpy(&qid->id, id, sizeof(qid->id)); STAILQ_INSERT_TAIL(&commits, qid, entry); while (!STAILQ_EMPTY(&commits)) { if (cancel_cb) { err = (*cancel_cb)(cancel_arg); if (err) break; } qid = STAILQ_FIRST(&commits); STAILQ_REMOVE_HEAD(&commits, entry); err = got_object_open_as_commit(&commit, repo, &qid->id); if (err) break; node = got_object_idset_get(graph->node_ids, &qid->id); if (node == NULL) { err = add_node(&node, graph, id, repo); if (err) break; TAILQ_INSERT_TAIL(&graph->iter_list, node, entry); } got_object_qid_free(qid); qid = NULL; if (node->timestamp != 0) /* already traversed once */ continue; if (node->nparents == -1) { node->nparents = got_object_commit_get_nparents(commit); if (node->nparents > nitems(node->parents)) { node->more_parents = calloc(node->nparents, sizeof(*node->more_parents)); if (node->more_parents == NULL) { err = got_error_from_errno("calloc"); break; } } } node->timestamp = got_object_commit_get_committer_time(commit); parent_ids = got_object_commit_get_parent_ids(commit); i = 0; STAILQ_FOREACH(pid, parent_ids, entry) { if (cancel_cb) { err = (*cancel_cb)(cancel_arg); if (err) goto done; } /* * Increment the in-degree counter every time a given * commit appears as the parent of another commit. */ pnode = got_object_idset_get(graph->node_ids, &pid->id); if (pnode == NULL) { err = add_node(&pnode, graph, &pid->id, repo); if (err) goto done; TAILQ_INSERT_TAIL(&graph->iter_list, pnode, entry); } pnode->indegree++; /* * Cache parent pointers on the node to make future * in-degree updates easier. */ if (node->nparents <= nitems(node->parents)) { node->parents[i] = pnode; } else { node->more_parents[i] = pnode; if (i < nitems(node->parents)) node->parents[i] = pnode; } i++; /* Keep traversing through all parent commits. */ err = got_object_qid_alloc_partial(&qid); if (err) goto done; memcpy(&qid->id, &pid->id, sizeof(qid->id)); STAILQ_INSERT_TAIL(&commits, qid, entry); qid = NULL; } got_object_commit_close(commit); commit = NULL; } done: if (commit) got_object_commit_close(commit); got_object_qid_free(qid); got_object_id_queue_free(&commits); return err; } got-portable-0.101/lib/bufio.c0000664000175100017510000001706614644144735011643 /* * bufio.c was written by Omar Polo * * This is free and unencumbered software released into the public domain. * * Anyone is free to copy, modify, publish, use, compile, sell, or * distribute this software, either in source code form or as a compiled * binary, for any purpose, commercial or non-commercial, and by any * means. * * In jurisdictions that recognize copyright laws, the author or authors * of this software dedicate any and all copyright interest in the * software to the public domain. We make this dedication for the benefit * of the public at large and to the detriment of our heirs and * successors. We intend this dedication to be an overt act of * relinquishment in perpetuity of all present and future rights to this * software under copyright law. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include "bufio.h" int buf_init(struct buf *buf) { const size_t cap = BIO_CHUNK; memset(buf, 0, sizeof(*buf)); if ((buf->buf = malloc(cap)) == NULL) return (-1); buf->cap = cap; return (0); } static int buf_grow(struct buf *buf) { size_t newcap; void *t; newcap = buf->cap + BIO_CHUNK; t = realloc(buf->buf, newcap); if (t == NULL) return (-1); buf->buf = t; buf->cap = newcap; return (0); } int buf_has_line(struct buf *buf, const char *nl) { return (memmem(buf->buf, buf->len, nl, strlen(nl)) != NULL); } char * buf_getdelim(struct buf *buf, const char *nl, size_t *len) { uint8_t *endl; size_t nlen; *len = 0; nlen = strlen(nl); if ((endl = memmem(buf->buf, buf->len, nl, nlen)) == NULL) return (NULL); *len = endl + nlen - buf->buf; *endl = '\0'; return (buf->buf); } void buf_drain(struct buf *buf, size_t l) { buf->cur = 0; if (l >= buf->len) { buf->len = 0; return; } memmove(buf->buf, buf->buf + l, buf->len - l); buf->len -= l; } void buf_drain_line(struct buf *buf, const char *nl) { uint8_t *endln; size_t nlen; nlen = strlen(nl); if ((endln = memmem(buf->buf, buf->len, nl, nlen)) == NULL) return; buf_drain(buf, endln + nlen - buf->buf); } void buf_free(struct buf *buf) { free(buf->buf); memset(buf, 0, sizeof(*buf)); } int bufio_init(struct bufio *bio) { memset(bio, 0, sizeof(*bio)); bio->fd = -1; if (buf_init(&bio->wbuf) == -1) return (-1); if (buf_init(&bio->rbuf) == -1) { buf_free(&bio->wbuf); return (-1); } return (0); } void bufio_free(struct bufio *bio) { if (bio->ctx) tls_free(bio->ctx); bio->ctx = NULL; if (bio->fd != -1) close(bio->fd); bio->fd = -1; buf_free(&bio->rbuf); buf_free(&bio->wbuf); } int bufio_close(struct bufio *bio) { if (bio->ctx == NULL) return (0); switch (tls_close(bio->ctx)) { case 0: return 0; case TLS_WANT_POLLIN: errno = EAGAIN; bio->wantev = BUFIO_WANT_READ; return (-1); case TLS_WANT_POLLOUT: errno = EAGAIN; bio->wantev = BUFIO_WANT_WRITE; return (-1); default: return (-1); } } int bufio_reset(struct bufio *bio) { bufio_free(bio); return (bufio_init(bio)); } void bufio_set_fd(struct bufio *bio, int fd) { bio->fd = fd; } int bufio_starttls(struct bufio *bio, const char *host, int insecure, const uint8_t *cert, size_t certlen, const uint8_t *key, size_t keylen) { struct tls_config *conf; if ((conf = tls_config_new()) == NULL) return (-1); if (insecure) { tls_config_insecure_noverifycert(conf); tls_config_insecure_noverifyname(conf); tls_config_insecure_noverifytime(conf); } if (cert && tls_config_set_keypair_mem(conf, cert, certlen, key, keylen) == -1) { tls_config_free(conf); return (-1); } if ((bio->ctx = tls_client()) == NULL) { tls_config_free(conf); return (-1); } if (tls_configure(bio->ctx, conf) == -1) { tls_config_free(conf); return (-1); } tls_config_free(conf); if (tls_connect_socket(bio->ctx, bio->fd, host) == -1) return (-1); return (0); } int bufio_ev(struct bufio *bio) { short ev; if (bio->wantev) return (bio->wantev); ev = BUFIO_WANT_READ; if (bio->wbuf.len != 0) ev |= BUFIO_WANT_WRITE; return (ev); } int bufio_handshake(struct bufio *bio) { if (bio->ctx == NULL) { errno = EINVAL; return (-1); } switch (tls_handshake(bio->ctx)) { case 0: return (0); case TLS_WANT_POLLIN: errno = EAGAIN; bio->wantev = BUFIO_WANT_READ; return (-1); case TLS_WANT_POLLOUT: errno = EAGAIN; bio->wantev = BUFIO_WANT_WRITE; return (-1); default: return (-1); } } ssize_t bufio_read(struct bufio *bio) { struct buf *rbuf = &bio->rbuf; ssize_t r; assert(rbuf->cap >= rbuf->len); if (rbuf->cap - rbuf->len < BIO_CHUNK) { if (buf_grow(rbuf) == -1) return (-1); } if (bio->ctx) { r = tls_read(bio->ctx, rbuf->buf + rbuf->len, rbuf->cap - rbuf->len); switch (r) { case TLS_WANT_POLLIN: errno = EAGAIN; bio->wantev = BUFIO_WANT_READ; return (-1); case TLS_WANT_POLLOUT: errno = EAGAIN; bio->wantev = BUFIO_WANT_WRITE; return (-1); case -1: bio->wantev = 0; errno = 0; return (-1); default: bio->wantev = 0; rbuf->len += r; return (r); } } r = read(bio->fd, rbuf->buf + rbuf->len, rbuf->cap - rbuf->len); if (r == -1) return (-1); rbuf->len += r; return (r); } size_t bufio_drain(struct bufio *bio, void *d, size_t len) { struct buf *rbuf = &bio->rbuf; if (len > rbuf->len) len = rbuf->len; memcpy(d, rbuf->buf, len); buf_drain(rbuf, len); return (len); } ssize_t bufio_write(struct bufio *bio) { struct buf *wbuf = &bio->wbuf; ssize_t w; if (bio->ctx) { switch (w = tls_write(bio->ctx, wbuf->buf, wbuf->len)) { case TLS_WANT_POLLIN: errno = EAGAIN; bio->wantev = BUFIO_WANT_READ; return (-1); case TLS_WANT_POLLOUT: errno = EAGAIN; bio->wantev = BUFIO_WANT_WRITE; return (-1); case -1: return (-1); default: bio->wantev = 0; buf_drain(wbuf, w); return (w); } } w = write(bio->fd, wbuf->buf, wbuf->len); if (w == -1) return (-1); buf_drain(wbuf, w); return (w); } const char * bufio_io_err(struct bufio *bio) { if (bio->ctx) return tls_error(bio->ctx); return strerror(errno); } int bufio_compose(struct bufio *bio, const void *d, size_t len) { struct buf *wbuf = &bio->wbuf; while (wbuf->cap - wbuf->len < len) { if (buf_grow(wbuf) == -1) return (-1); } memcpy(wbuf->buf + wbuf->len, d, len); wbuf->len += len; return (0); } int bufio_compose_str(struct bufio *bio, const char *str) { return (bufio_compose(bio, str, strlen(str))); } int bufio_compose_fmt(struct bufio *bio, const char *fmt, ...) { va_list ap; char *str; int r; va_start(ap, fmt); r = vasprintf(&str, fmt, ap); va_end(ap); if (r == -1) return (-1); r = bufio_compose(bio, str, r); free(str); return (r); } void bufio_rewind_cursor(struct bufio *bio) { bio->rbuf.cur = 0; } int bufio_get_cb(void *d) { struct bufio *bio = d; struct buf *rbuf = &bio->rbuf; if (rbuf->cur >= rbuf->len) return (EOF); return (rbuf->buf[rbuf->cur++]); } int bufio_peek_cb(void *d) { struct bufio *bio = d; struct buf *rbuf = &bio->rbuf; if (rbuf->cur >= rbuf->len) return (EOF); return (rbuf->buf[rbuf->cur]); } got-portable-0.101/lib/got_lib_delta.h0000644000175100017510000000776714644143163013333 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct got_delta { STAILQ_ENTRY(got_delta) entry; off_t offset; size_t tslen; int type; size_t size; off_t data_offset; }; struct got_delta_chain { int nentries; STAILQ_HEAD(, got_delta) entries; }; #define GOT_DELTA_CHAIN_RECURSION_MAX 500 struct got_delta *got_delta_open(off_t, size_t, int, size_t, off_t); const struct got_error *got_delta_chain_get_base_type(int *, struct got_delta_chain *); const struct got_error *got_delta_get_sizes(uint64_t *, uint64_t *, const uint8_t *, size_t); const struct got_error *got_delta_apply_in_mem(uint8_t *, size_t, const uint8_t *, size_t, uint8_t *, size_t *, size_t); const struct got_error *got_delta_apply(FILE *, const uint8_t *, size_t, FILE *, size_t *); /* * The amount of result data we may keep in RAM while applying deltas. * Data larger than this is written to disk during delta application (slow). */ #define GOT_DELTA_RESULT_SIZE_CACHED_MAX (8 * 1024 * 1024) /* bytes */ /* * Definitions for delta data streams. */ #define GOT_DELTA_STREAM_LENGTH_MIN 4 /* bytes */ /* * A delta stream begins with two size fields. The first specifies the * size of the delta base, and the second describes the expected size of * the data which results from applying the delta to the delta base. * * Each size field uses a variable length encoding: * size0...sizeN form a 7+7+7+...+7 bit integer, where size0 is the * least significant part and sizeN is the most significant part. * If the MSB of a size byte is set, an additional size byte follows. */ #define GOT_DELTA_SIZE_VAL_MASK 0x7f #define GOT_DELTA_SIZE_SHIFT 7 #define GOT_DELTA_SIZE_MORE 0x80 /* * The rest of the delta stream contains copy instructions. * * A base copy instruction copies N bytes starting at offset X from the delta * base to the output. Base copy instructions begin with a byte which has its * MSB set. The remaining bits of this byte describe how many offset and * length value bytes follow. * The offset X is encoded in 1 to 4 bytes, and the length N is encoded in * 1 to 3 bytes. For both values, the first byte contributes the least * significant part and the last byte which is present contributes the * most significant part. * If the offset value is omitted, an offset of zero is implied. * If the length value is omitted, a default length of 65536 bytes is implied. * * An inline copy instruction copies data from the delta stream to the output. * Such instructions begin with one byte which does not have the MSB set * and which specifies the length of the inline data which follows (i.e. * at most 127 bytes). A length value of zero is invalid. */ #define GOT_DELTA_BASE_COPY 0x80 #define GOT_DELTA_COPY_OFF1 0x01 /* byte 1 of offset is present */ #define GOT_DELTA_COPY_OFF2 0x02 /* byte 2 of offset is present */ #define GOT_DELTA_COPY_OFF3 0x04 /* byte 3 of offset is present */ #define GOT_DELTA_COPY_OFF4 0x08 /* byte 4 of offset is present */ #define GOT_DELTA_COPY_LEN1 0x10 /* byte 1 of length is present */ #define GOT_DELTA_COPY_LEN2 0x20 /* byte 2 of length is present */ #define GOT_DELTA_COPY_LEN3 0x40 /* byte 3 of length is present */ #define GOT_DELTA_COPY_DEFAULT_OFF 0x0 /* default offset if omitted */ #define GOT_DELTA_COPY_DEFAULT_LEN 0x10000 /* default length if omitted */ got-portable-0.101/lib/rcsutil.c0000664000175100017510000000651414644144735012220 /* $OpenBSD: rcsutil.c,v 1.46 2017/08/29 16:47:33 otto Exp $ */ /* * Copyright (c) 2005, 2006 Joris Vink * Copyright (c) 2006 Xavier Santolaria * Copyright (c) 2006 Niall O'Higgins * Copyright (c) 2006 Ray Lai * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include "got_compat.h" #include "buf.h" #include "rcsutil.h" /* * Split the contents of a file into a list of lines. */ struct rcs_lines * rcs_splitlines(u_char *data, size_t len) { u_char *c, *p; struct rcs_lines *lines; struct rcs_line *lp; size_t i, tlen; lines = calloc(1, sizeof(*lines)); if (lines == NULL) return NULL; TAILQ_INIT(&(lines->l_lines)); lp = calloc(1, sizeof(*lp)); if (lp == NULL) { free(lines); return NULL; } TAILQ_INSERT_TAIL(&(lines->l_lines), lp, l_list); p = c = data; for (i = 0; i < len; i++) { if (*p == '\n' || (i == len - 1)) { tlen = p - c + 1; lp = malloc(sizeof(*lp)); if (lp == NULL) { rcs_freelines(lines); return NULL; } lp->l_line = c; lp->l_len = tlen; lp->l_lineno = ++(lines->l_nblines); TAILQ_INSERT_TAIL(&(lines->l_lines), lp, l_list); c = p + 1; } p++; } return (lines); } void rcs_freelines(struct rcs_lines *lines) { struct rcs_line *lp; while ((lp = TAILQ_FIRST(&(lines->l_lines))) != NULL) { TAILQ_REMOVE(&(lines->l_lines), lp, l_list); free(lp); } free(lines); } BUF * rcs_patchfile(u_char *data, size_t dlen, u_char *patch, size_t plen, int (*p)(struct rcs_lines *, struct rcs_lines *)) { const struct got_error *err = NULL; struct rcs_lines *dlines, *plines; struct rcs_line *lp; BUF *res; size_t newlen; dlines = rcs_splitlines(data, dlen); plines = rcs_splitlines(patch, plen); if (p(dlines, plines) < 0) { rcs_freelines(dlines); rcs_freelines(plines); return (NULL); } err = buf_alloc(&res, 1024); if (err) return NULL; TAILQ_FOREACH(lp, &dlines->l_lines, l_list) { if (lp->l_line == NULL) continue; buf_append(&newlen, res, lp->l_line, lp->l_len); } rcs_freelines(dlines); rcs_freelines(plines); return (res); } got-portable-0.101/lib/pack_index.c0000664000175100017510000006117214644144735012641 /* * Copyright (c) 2019 Ori Bernstein * Copyright (c) 2020, 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_lib_hash.h" #include "got_lib_delta.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_object_idset.h" #include "got_lib_privsep.h" #include "got_lib_pack.h" #include "got_lib_ratelimit.h" #include "got_lib_pack_index.h" #include "got_lib_delta_cache.h" struct got_indexed_object { struct got_object_id id; /* * Has this object been fully resolved? * If so, we know its ID, otherwise we don't and 'id' is invalid. */ int valid; /* Offset of type+size field for this object in pack file. */ off_t off; /* Type+size values parsed from pack file. */ uint8_t type; uint64_t size; /* Length of on-disk type+size data. */ size_t tslen; /* Length of object data following type+size. */ size_t len; uint32_t crc; union { struct { /* For ref deltas. */ struct got_object_id ref_id; } ref; struct { /* For offset deltas. */ off_t base_offset; size_t base_offsetlen; } ofs; } delta; }; static void putbe32(char *b, uint32_t n) { b[0] = n >> 24; b[1] = n >> 16; b[2] = n >> 8; b[3] = n >> 0; } static const struct got_error * read_checksum(uint32_t *crc, struct got_hash *ctx, int fd, size_t len) { uint8_t buf[8192]; size_t n; ssize_t r; for (n = len; n > 0; n -= r){ r = read(fd, buf, n > sizeof(buf) ? sizeof(buf) : n); if (r == -1) return got_error_from_errno("read"); if (r == 0) break; if (crc) *crc = crc32(*crc, buf, r); if (ctx) got_hash_update(ctx, buf, r); } return NULL; } static const struct got_error * read_file_digest(struct got_hash *ctx, FILE *f, size_t len) { uint8_t buf[8192]; size_t n, r; for (n = len; n > 0; n -= r) { r = fread(buf, 1, n > sizeof(buf) ? sizeof(buf) : n, f); if (r == 0) { if (feof(f)) return NULL; return got_ferror(f, GOT_ERR_IO); } got_hash_update(ctx, buf, r); } return NULL; } static const struct got_error * read_packed_object(struct got_pack *pack, struct got_indexed_object *obj, FILE *tmpfile, struct got_hash *pack_hash_ctx) { const struct got_error *err = NULL; struct got_hash ctx; uint8_t *data = NULL; size_t datalen = 0; ssize_t n; char *header; size_t headerlen; const char *obj_label; size_t mapoff = obj->off; struct got_inflate_checksum csum; memset(&csum, 0, sizeof(csum)); csum.input_ctx = pack_hash_ctx; csum.input_crc = &obj->crc; err = got_pack_parse_object_type_and_size(&obj->type, &obj->size, &obj->tslen, pack, obj->off); if (err) return err; if (pack->map) { obj->crc = crc32(obj->crc, pack->map + mapoff, obj->tslen); got_hash_update(pack_hash_ctx, pack->map + mapoff, obj->tslen); mapoff += obj->tslen; } else { /* XXX Seek back and get the CRC of on-disk type+size bytes. */ if (lseek(pack->fd, obj->off, SEEK_SET) == -1) return got_error_from_errno("lseek"); err = read_checksum(&obj->crc, pack_hash_ctx, pack->fd, obj->tslen); if (err) return err; } switch (obj->type) { case GOT_OBJ_TYPE_BLOB: case GOT_OBJ_TYPE_COMMIT: case GOT_OBJ_TYPE_TREE: case GOT_OBJ_TYPE_TAG: if (obj->size > GOT_DELTA_RESULT_SIZE_CACHED_MAX) { if (fseek(tmpfile, 0L, SEEK_SET) == -1) { err = got_error_from_errno("fseek"); break; } if (pack->map) { err = got_inflate_to_file_mmap(&datalen, &obj->len, &csum, pack->map, mapoff, pack->filesize - mapoff, tmpfile); } else { err = got_inflate_to_file_fd(&datalen, &obj->len, &csum, pack->fd, tmpfile); } } else { if (pack->map) { err = got_inflate_to_mem_mmap(&data, &datalen, &obj->len, &csum, pack->map, mapoff, pack->filesize - mapoff); } else { err = got_inflate_to_mem_fd(&data, &datalen, &obj->len, &csum, obj->size, pack->fd); } } if (err) break; got_hash_init(&ctx, GOT_HASH_SHA1); err = got_object_type_label(&obj_label, obj->type); if (err) { free(data); break; } if (asprintf(&header, "%s %lld", obj_label, (long long)obj->size) == -1) { err = got_error_from_errno("asprintf"); free(data); break; } headerlen = strlen(header) + 1; got_hash_update(&ctx, header, headerlen); if (obj->size > GOT_DELTA_RESULT_SIZE_CACHED_MAX) { err = read_file_digest(&ctx, tmpfile, datalen); if (err) { free(header); free(data); break; } } else got_hash_update(&ctx, data, datalen); got_hash_final_object_id(&ctx, &obj->id); free(header); free(data); break; case GOT_OBJ_TYPE_REF_DELTA: memset(obj->id.sha1, 0xff, SHA1_DIGEST_LENGTH); if (pack->map) { if (mapoff + SHA1_DIGEST_LENGTH >= pack->filesize) { err = got_error(GOT_ERR_BAD_PACKFILE); break; } memcpy(obj->delta.ref.ref_id.sha1, pack->map + mapoff, SHA1_DIGEST_LENGTH); obj->crc = crc32(obj->crc, pack->map + mapoff, SHA1_DIGEST_LENGTH); got_hash_update(pack_hash_ctx, pack->map + mapoff, SHA1_DIGEST_LENGTH); mapoff += SHA1_DIGEST_LENGTH; err = got_inflate_to_mem_mmap(NULL, &datalen, &obj->len, &csum, pack->map, mapoff, pack->filesize - mapoff); if (err) break; } else { n = read(pack->fd, obj->delta.ref.ref_id.sha1, SHA1_DIGEST_LENGTH); if (n == -1) { err = got_error_from_errno("read"); break; } if (n < sizeof(obj->id)) { err = got_error(GOT_ERR_BAD_PACKFILE); break; } obj->crc = crc32(obj->crc, obj->delta.ref.ref_id.sha1, SHA1_DIGEST_LENGTH); got_hash_update(pack_hash_ctx, obj->delta.ref.ref_id.sha1, SHA1_DIGEST_LENGTH); err = got_inflate_to_mem_fd(NULL, &datalen, &obj->len, &csum, obj->size, pack->fd); if (err) break; } obj->len += SHA1_DIGEST_LENGTH; break; case GOT_OBJ_TYPE_OFFSET_DELTA: memset(obj->id.sha1, 0xff, SHA1_DIGEST_LENGTH); err = got_pack_parse_offset_delta(&obj->delta.ofs.base_offset, &obj->delta.ofs.base_offsetlen, pack, obj->off, obj->tslen); if (err) break; if (pack->map) { if (mapoff + obj->delta.ofs.base_offsetlen >= pack->filesize) { err = got_error(GOT_ERR_BAD_PACKFILE); break; } if (mapoff + obj->delta.ofs.base_offsetlen > SIZE_MAX) { err = got_error_fmt(GOT_ERR_RANGE, "mapoff %lld would overflow size_t", (long long)mapoff + obj->delta.ofs.base_offsetlen); break; } obj->crc = crc32(obj->crc, pack->map + mapoff, obj->delta.ofs.base_offsetlen); got_hash_update(pack_hash_ctx, pack->map + mapoff, obj->delta.ofs.base_offsetlen); mapoff += obj->delta.ofs.base_offsetlen; err = got_inflate_to_mem_mmap(NULL, &datalen, &obj->len, &csum, pack->map, mapoff, pack->filesize - mapoff); if (err) break; } else { /* * XXX Seek back and get CRC and SHA1 of on-disk * offset bytes. */ if (lseek(pack->fd, obj->off + obj->tslen, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); break; } err = read_checksum(&obj->crc, pack_hash_ctx, pack->fd, obj->delta.ofs.base_offsetlen); if (err) break; err = got_inflate_to_mem_fd(NULL, &datalen, &obj->len, &csum, obj->size, pack->fd); if (err) break; } obj->len += obj->delta.ofs.base_offsetlen; break; default: err = got_error(GOT_ERR_OBJ_TYPE); break; } return err; } const struct got_error * got_pack_hwrite(int fd, void *buf, int len, struct got_hash *ctx) { ssize_t w; got_hash_update(ctx, buf, len); w = write(fd, buf, len); if (w == -1) return got_error_from_errno("write"); if (w != len) return got_error(GOT_ERR_IO); return NULL; } static const struct got_error * resolve_deltified_object(struct got_pack *pack, struct got_packidx *packidx, struct got_indexed_object *obj, FILE *tmpfile, FILE *delta_base_file, FILE *delta_accum_file) { const struct got_error *err = NULL; struct got_delta_chain deltas; struct got_delta *delta; uint8_t *buf = NULL; size_t len = 0; struct got_hash ctx; char *header = NULL; size_t headerlen; uint64_t max_size; int base_obj_type; const char *obj_label; deltas.nentries = 0; STAILQ_INIT(&deltas.entries); err = got_pack_resolve_delta_chain(&deltas, packidx, pack, obj->off, obj->tslen, obj->type, obj->size, GOT_DELTA_CHAIN_RECURSION_MAX); if (err) goto done; err = got_pack_get_delta_chain_max_size(&max_size, &deltas, pack); if (err) goto done; if (max_size > GOT_DELTA_RESULT_SIZE_CACHED_MAX) { rewind(tmpfile); rewind(delta_base_file); rewind(delta_accum_file); err = got_pack_dump_delta_chain_to_file(&len, &deltas, pack, tmpfile, delta_base_file, delta_accum_file); if (err) goto done; } else { err = got_pack_dump_delta_chain_to_mem(&buf, &len, &deltas, pack); } if (err) goto done; err = got_delta_chain_get_base_type(&base_obj_type, &deltas); if (err) goto done; err = got_object_type_label(&obj_label, base_obj_type); if (err) goto done; if (asprintf(&header, "%s %zd", obj_label, len) == -1) { err = got_error_from_errno("asprintf"); goto done; } headerlen = strlen(header) + 1; got_hash_init(&ctx, GOT_HASH_SHA1); got_hash_update(&ctx, header, headerlen); if (max_size > GOT_DELTA_RESULT_SIZE_CACHED_MAX) { err = read_file_digest(&ctx, tmpfile, len); if (err) goto done; } else got_hash_update(&ctx, buf, len); got_hash_final_object_id(&ctx, &obj->id); done: free(buf); free(header); while (!STAILQ_EMPTY(&deltas.entries)) { delta = STAILQ_FIRST(&deltas.entries); STAILQ_REMOVE_HEAD(&deltas.entries, entry); free(delta); } return err; } /* Determine the slot in the pack index a given object ID should use. */ static int find_object_idx(struct got_packidx *packidx, uint8_t *sha1) { u_int8_t id0 = sha1[0]; uint32_t nindexed = be32toh(packidx->hdr.fanout_table[0xff]); int left = 0, right = nindexed - 1; int cmp = 0, i = 0; if (id0 > 0) left = be32toh(packidx->hdr.fanout_table[id0 - 1]); while (left <= right) { struct got_packidx_object_id *oid; i = ((left + right) / 2); oid = &packidx->hdr.sorted_ids[i]; cmp = memcmp(sha1, oid->sha1, SHA1_DIGEST_LENGTH); if (cmp == 0) return -1; /* object already indexed */ else if (cmp > 0) left = i + 1; else if (cmp < 0) right = i - 1; } return left; } #if 0 static void print_packidx(struct got_packidx *packidx) { uint32_t nindexed = be32toh(packidx->hdr.fanout_table[0xff]); int i; fprintf(stderr, "object IDs:\n"); for (i = 0; i < nindexed; i++) { char hex[SHA1_DIGEST_STRING_LENGTH]; got_sha1_digest_to_str(packidx->hdr.sorted_ids[i].sha1, hex, sizeof(hex)); fprintf(stderr, "%s\n", hex); } fprintf(stderr, "\n"); fprintf(stderr, "object offsets:\n"); for (i = 0; i < nindexed; i++) { uint32_t offset = be32toh(packidx->hdr.offsets[i]); if (offset & GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX) { int j = offset & GOT_PACKIDX_OFFSET_VAL_MASK; fprintf(stderr, "%u -> %llu\n", offset, be64toh(packidx->hdr.large_offsets[j])); } else fprintf(stderr, "%u\n", offset); } fprintf(stderr, "\n"); fprintf(stderr, "fanout table:"); for (i = 0; i <= 0xff; i++) fprintf(stderr, " %u", be32toh(packidx->hdr.fanout_table[i])); fprintf(stderr, "\n"); } #endif static void add_indexed_object(struct got_packidx *packidx, uint32_t idx, struct got_indexed_object *obj) { int i; memcpy(packidx->hdr.sorted_ids[idx].sha1, obj->id.sha1, SHA1_DIGEST_LENGTH); packidx->hdr.crc32[idx] = htobe32(obj->crc); if (obj->off < GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX) packidx->hdr.offsets[idx] = htobe32(obj->off); else { packidx->hdr.offsets[idx] = htobe32(packidx->nlargeobj | GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX); packidx->hdr.large_offsets[packidx->nlargeobj] = htobe64(obj->off); packidx->nlargeobj++; } for (i = obj->id.sha1[0]; i <= 0xff; i++) { uint32_t n = be32toh(packidx->hdr.fanout_table[i]); packidx->hdr.fanout_table[i] = htobe32(n + 1); } } static int indexed_obj_cmp(const void *pa, const void *pb) { struct got_indexed_object *a, *b; a = (struct got_indexed_object *)pa; b = (struct got_indexed_object *)pb; return got_object_id_cmp(&a->id, &b->id); } static void make_packidx(struct got_packidx *packidx, uint32_t nobj, struct got_indexed_object *objects) { struct got_indexed_object *obj; int i; uint32_t idx = 0; qsort(objects, nobj, sizeof(struct got_indexed_object), indexed_obj_cmp); memset(packidx->hdr.fanout_table, 0, GOT_PACKIDX_V2_FANOUT_TABLE_ITEMS * sizeof(uint32_t)); packidx->nlargeobj = 0; for (i = 0; i < nobj; i++) { obj = &objects[i]; if (obj->valid) add_indexed_object(packidx, idx++, obj); } } static void update_packidx(struct got_packidx *packidx, uint32_t nobj, struct got_indexed_object *obj) { int idx; uint32_t nindexed = be32toh(packidx->hdr.fanout_table[0xff]); idx = find_object_idx(packidx, obj->id.sha1); if (idx == -1) return; /* object already indexed */ memmove(&packidx->hdr.sorted_ids[idx + 1], &packidx->hdr.sorted_ids[idx], sizeof(struct got_packidx_object_id) * (nindexed - idx)); memmove(&packidx->hdr.offsets[idx + 1], &packidx->hdr.offsets[idx], sizeof(uint32_t) * (nindexed - idx)); add_indexed_object(packidx, idx, obj); } static const struct got_error * report_progress(uint32_t nobj_total, uint32_t nobj_indexed, uint32_t nobj_loose, uint32_t nobj_resolved, struct got_ratelimit *rl, got_pack_index_progress_cb progress_cb, void *progress_arg) { const struct got_error *err; int elapsed = 0; if (rl) { err = got_ratelimit_check(&elapsed, rl); if (err || !elapsed) return err; } return progress_cb(progress_arg, nobj_total, nobj_indexed, nobj_loose, nobj_resolved); } const struct got_error * got_pack_index(struct got_pack *pack, int idxfd, FILE *tmpfile, FILE *delta_base_file, FILE *delta_accum_file, uint8_t *pack_sha1_expected, got_pack_index_progress_cb progress_cb, void *progress_arg, struct got_ratelimit *rl) { const struct got_error *err; struct got_packfile_hdr hdr; struct got_packidx packidx; char buf[8]; char pack_sha1[SHA1_DIGEST_LENGTH]; uint32_t nobj, nvalid, nloose, nresolved = 0, i; struct got_indexed_object *objects = NULL, *obj; struct got_hash ctx; uint8_t packidx_hash[SHA1_DIGEST_LENGTH]; ssize_t r, w; int pass, have_ref_deltas = 0, first_delta_idx = -1; size_t mapoff = 0; int p_indexed = 0, last_p_indexed = -1; int p_resolved = 0, last_p_resolved = -1; /* Require that pack file header and SHA1 trailer are present. */ if (pack->filesize < sizeof(hdr) + SHA1_DIGEST_LENGTH) return got_error_msg(GOT_ERR_BAD_PACKFILE, "short pack file"); if (pack->map) { memcpy(&hdr, pack->map, sizeof(hdr)); mapoff += sizeof(hdr); } else { r = read(pack->fd, &hdr, sizeof(hdr)); if (r == -1) return got_error_from_errno("read"); if (r < sizeof(hdr)) return got_error_msg(GOT_ERR_BAD_PACKFILE, "short pack file"); } if (hdr.signature != htobe32(GOT_PACKFILE_SIGNATURE)) return got_error_msg(GOT_ERR_BAD_PACKFILE, "bad packfile signature"); if (hdr.version != htobe32(GOT_PACKFILE_VERSION)) return got_error_msg(GOT_ERR_BAD_PACKFILE, "bad packfile version"); nobj = be32toh(hdr.nobjects); if (nobj == 0) return got_error_msg(GOT_ERR_BAD_PACKFILE, "bad packfile with zero objects"); /* We compute the SHA1 of pack file contents and verify later on. */ got_hash_init(&ctx, GOT_HASH_SHA1); got_hash_update(&ctx, &hdr, sizeof(hdr)); /* * Create an in-memory pack index which will grow as objects * IDs in the pack file are discovered. Only fields used to * read deltified objects will be needed by the pack.c library * code, so setting up just a pack index header is sufficient. */ memset(&packidx, 0, sizeof(packidx)); packidx.hdr.magic = malloc(sizeof(uint32_t)); if (packidx.hdr.magic == NULL) return got_error_from_errno("malloc"); *packidx.hdr.magic = htobe32(GOT_PACKIDX_V2_MAGIC); packidx.hdr.version = malloc(sizeof(uint32_t)); if (packidx.hdr.version == NULL) { err = got_error_from_errno("malloc"); goto done; } *packidx.hdr.version = htobe32(GOT_PACKIDX_VERSION); packidx.hdr.fanout_table = calloc(GOT_PACKIDX_V2_FANOUT_TABLE_ITEMS, sizeof(uint32_t)); if (packidx.hdr.fanout_table == NULL) { err = got_error_from_errno("calloc"); goto done; } packidx.hdr.sorted_ids = calloc(nobj, sizeof(struct got_packidx_object_id)); if (packidx.hdr.sorted_ids == NULL) { err = got_error_from_errno("calloc"); goto done; } packidx.hdr.crc32 = calloc(nobj, sizeof(uint32_t)); if (packidx.hdr.crc32 == NULL) { err = got_error_from_errno("calloc"); goto done; } packidx.hdr.offsets = calloc(nobj, sizeof(uint32_t)); if (packidx.hdr.offsets == NULL) { err = got_error_from_errno("calloc"); goto done; } /* Large offsets table is empty for pack files < 2 GB. */ if (pack->filesize >= GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX) { packidx.hdr.large_offsets = calloc(nobj, sizeof(uint64_t)); if (packidx.hdr.large_offsets == NULL) { err = got_error_from_errno("calloc"); goto done; } } nvalid = 0; nloose = 0; objects = calloc(nobj, sizeof(struct got_indexed_object)); if (objects == NULL) return got_error_from_errno("calloc"); /* * First pass: locate all objects and identify un-deltified objects. * * When this pass has completed we will know offset, type, size, and * CRC information for all objects in this pack file. We won't know * any of the actual object IDs of deltified objects yet since we * will not yet attempt to combine deltas. */ pass = 1; for (i = 0; i < nobj; i++) { /* Don't send too many progress privsep messages. */ p_indexed = ((i + 1) * 100) / nobj; if (p_indexed != last_p_indexed) { err = report_progress(nobj, i + 1, nloose, 0, rl, progress_cb, progress_arg); if (err) goto done; last_p_indexed = p_indexed; } obj = &objects[i]; obj->crc = crc32(0L, NULL, 0); /* Store offset to type+size information for this object. */ if (pack->map) { obj->off = mapoff; } else { obj->off = lseek(pack->fd, 0, SEEK_CUR); if (obj->off == -1) { err = got_error_from_errno("lseek"); goto done; } } err = read_packed_object(pack, obj, tmpfile, &ctx); if (err) goto done; if (pack->map) { mapoff += obj->tslen + obj->len; } else { if (lseek(pack->fd, obj->off + obj->tslen + obj->len, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } } if (obj->type == GOT_OBJ_TYPE_BLOB || obj->type == GOT_OBJ_TYPE_TREE || obj->type == GOT_OBJ_TYPE_COMMIT || obj->type == GOT_OBJ_TYPE_TAG) { obj->valid = 1; nloose++; } else { if (first_delta_idx == -1) first_delta_idx = i; if (obj->type == GOT_OBJ_TYPE_REF_DELTA) have_ref_deltas = 1; } } nvalid = nloose; /* * Having done a full pass over the pack file and can now * verify its checksum. */ got_hash_final(&ctx, pack_sha1); if (memcmp(pack_sha1_expected, pack_sha1, SHA1_DIGEST_LENGTH) != 0) { err = got_error(GOT_ERR_PACKFILE_CSUM); goto done; } /* Verify the SHA1 checksum stored at the end of the pack file. */ if (pack->map) { if (pack->filesize > SIZE_MAX) { err = got_error_fmt(GOT_ERR_RANGE, "filesize %lld overflows size_t", (long long)pack->filesize); goto done; } memcpy(pack_sha1_expected, pack->map + pack->filesize - SHA1_DIGEST_LENGTH, SHA1_DIGEST_LENGTH); } else { ssize_t n; if (lseek(pack->fd, -SHA1_DIGEST_LENGTH, SEEK_END) == -1) { err = got_error_from_errno("lseek"); goto done; } n = read(pack->fd, pack_sha1_expected, SHA1_DIGEST_LENGTH); if (n == -1) { err = got_error_from_errno("read"); goto done; } if (n != SHA1_DIGEST_LENGTH) { err = got_error(GOT_ERR_IO); goto done; } } if (memcmp(pack_sha1, pack_sha1_expected, SHA1_DIGEST_LENGTH) != 0) { err = got_error_msg(GOT_ERR_BAD_PACKFILE, "bad checksum in pack file trailer"); goto done; } if (first_delta_idx == -1) first_delta_idx = 0; /* In order to resolve ref deltas we need an in-progress pack index. */ if (have_ref_deltas) make_packidx(&packidx, nobj, objects); /* * Second pass: We can now resolve deltas to compute the IDs of * objects which appear in deltified form. Because deltas can be * chained this pass may require a couple of iterations until all * IDs of deltified objects have been discovered. */ pass++; while (nvalid != nobj) { int n = 0; /* * This loop will only run once unless the pack file * contains ref deltas which refer to objects located * later in the pack file, which is unusual. * Offset deltas can always be resolved in one pass * unless the packfile is corrupt. */ for (i = first_delta_idx; i < nobj; i++) { obj = &objects[i]; if (obj->type != GOT_OBJ_TYPE_REF_DELTA && obj->type != GOT_OBJ_TYPE_OFFSET_DELTA) continue; if (obj->valid) continue; if (pack->map == NULL && lseek(pack->fd, obj->off + obj->tslen, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } err = resolve_deltified_object(pack, &packidx, obj, tmpfile, delta_base_file, delta_accum_file); if (err) { if (err->code != GOT_ERR_NO_OBJ) goto done; /* * We cannot resolve this object yet because * a delta base is unknown. Try again later. */ continue; } obj->valid = 1; n++; if (have_ref_deltas) update_packidx(&packidx, nobj, obj); /* Don't send too many progress privsep messages. */ p_resolved = ((nresolved + n) * 100) / nobj; if (p_resolved != last_p_resolved) { err = report_progress(nobj, nobj, nloose, nresolved + n, rl, progress_cb, progress_arg); if (err) goto done; last_p_resolved = p_resolved; } } if (pass++ > 3 && n == 0) { err = got_error_msg(GOT_ERR_BAD_PACKFILE, "could not resolve any of deltas; packfile could " "be corrupt"); goto done; } nresolved += n; nvalid += n; } if (nloose + nresolved != nobj) { static char msg[64]; snprintf(msg, sizeof(msg), "discovered only %d of %d objects", nloose + nresolved, nobj); err = got_error_msg(GOT_ERR_BAD_PACKFILE, msg); goto done; } err = report_progress(nobj, nobj, nloose, nresolved, NULL, progress_cb, progress_arg); if (err) goto done; make_packidx(&packidx, nobj, objects); free(objects); objects = NULL; got_hash_init(&ctx, GOT_HASH_SHA1); putbe32(buf, GOT_PACKIDX_V2_MAGIC); putbe32(buf + 4, GOT_PACKIDX_VERSION); err = got_pack_hwrite(idxfd, buf, 8, &ctx); if (err) goto done; err = got_pack_hwrite(idxfd, packidx.hdr.fanout_table, GOT_PACKIDX_V2_FANOUT_TABLE_ITEMS * sizeof(uint32_t), &ctx); if (err) goto done; err = got_pack_hwrite(idxfd, packidx.hdr.sorted_ids, nobj * SHA1_DIGEST_LENGTH, &ctx); if (err) goto done; err = got_pack_hwrite(idxfd, packidx.hdr.crc32, nobj * sizeof(uint32_t), &ctx); if (err) goto done; err = got_pack_hwrite(idxfd, packidx.hdr.offsets, nobj * sizeof(uint32_t), &ctx); if (err) goto done; if (packidx.nlargeobj > 0) { err = got_pack_hwrite(idxfd, packidx.hdr.large_offsets, packidx.nlargeobj * sizeof(uint64_t), &ctx); if (err) goto done; } err = got_pack_hwrite(idxfd, pack_sha1, SHA1_DIGEST_LENGTH, &ctx); if (err) goto done; got_hash_final(&ctx, packidx_hash); w = write(idxfd, packidx_hash, sizeof(packidx_hash)); if (w == -1) { err = got_error_from_errno("write"); goto done; } if (w != sizeof(packidx_hash)) { err = got_error(GOT_ERR_IO); goto done; } done: free(objects); free(packidx.hdr.magic); free(packidx.hdr.version); free(packidx.hdr.fanout_table); free(packidx.hdr.sorted_ids); free(packidx.hdr.offsets); free(packidx.hdr.large_offsets); return err; } got-portable-0.101/lib/gitproto.c0000664000175100017510000002326414644144735012403 /* * Copyright (c) 2019 Ori Bernstein * Copyright (c) 2021 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include "got_error.h" #include "got_path.h" #include "got_lib_gitproto.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif static void free_tokens(char **tokens, size_t ntokens) { int i; for (i = 0; i < ntokens; i++) { free(tokens[i]); tokens[i] = NULL; } } static const struct got_error * tokenize_line(char **tokens, char *line, int len, int mintokens, int maxtokens) { const struct got_error *err = NULL; char *p; size_t i, n = 0; for (i = 0; i < maxtokens; i++) tokens[i] = NULL; for (i = 0; n < len && i < maxtokens; i++) { while (n < len && isspace((unsigned char)*line)) { line++; n++; } p = line; while (*line != '\0' && n < len && (!isspace((unsigned char)*line) || i == maxtokens - 1)) { line++; n++; } tokens[i] = strndup(p, line - p); if (tokens[i] == NULL) { err = got_error_from_errno("strndup"); goto done; } /* Skip \0 field-delimiter at end of token. */ while (line[0] == '\0' && n < len) { line++; n++; } } if (i < mintokens) err = got_error_msg(GOT_ERR_BAD_PACKET, "pkt-line contains too few tokens"); done: if (err) free_tokens(tokens, i); return err; } const struct got_error * got_gitproto_parse_refline(char **id_str, char **refname, char **server_capabilities, char *line, int len) { const struct got_error *err = NULL; char *tokens[3]; *id_str = NULL; *refname = NULL; /* don't reset *server_capabilities */ err = tokenize_line(tokens, line, len, 2, nitems(tokens)); if (err) return err; if (tokens[0]) *id_str = tokens[0]; if (tokens[1]) *refname = tokens[1]; if (tokens[2]) { if (*server_capabilities == NULL) { char *p; *server_capabilities = tokens[2]; p = strrchr(*server_capabilities, '\n'); if (p) *p = '\0'; } else free(tokens[2]); } return NULL; } const struct got_error * got_gitproto_parse_want_line(char **id_str, char **capabilities, char *line, int len) { const struct got_error *err = NULL; char *tokens[3]; *id_str = NULL; /* don't reset *capabilities */ err = tokenize_line(tokens, line, len, 2, nitems(tokens)); if (err) return err; if (tokens[0] == NULL) { free_tokens(tokens, nitems(tokens)); return got_error_msg(GOT_ERR_BAD_PACKET, "empty want-line"); } if (strcmp(tokens[0], "want") != 0) { free_tokens(tokens, nitems(tokens)); return got_error_msg(GOT_ERR_BAD_PACKET, "bad want-line"); } free(tokens[0]); if (tokens[1]) *id_str = tokens[1]; if (tokens[2]) { if (*capabilities == NULL) { char *p; *capabilities = tokens[2]; p = strrchr(*capabilities, '\n'); if (p) *p = '\0'; } else free(tokens[2]); } return NULL; } const struct got_error * got_gitproto_parse_have_line(char **id_str, char *line, int len) { const struct got_error *err = NULL; char *tokens[2]; *id_str = NULL; err = tokenize_line(tokens, line, len, 2, nitems(tokens)); if (err) return err; if (tokens[0] == NULL) { free_tokens(tokens, nitems(tokens)); return got_error_msg(GOT_ERR_BAD_PACKET, "empty have-line"); } if (strcmp(tokens[0], "have") != 0) { free_tokens(tokens, nitems(tokens)); return got_error_msg(GOT_ERR_BAD_PACKET, "bad have-line"); } free(tokens[0]); if (tokens[1]) *id_str = tokens[1]; return NULL; } const struct got_error * got_gitproto_parse_ref_update_line(char **old_id_str, char **new_id_str, char **refname, char **capabilities, char *line, size_t len) { const struct got_error *err = NULL; char *tokens[4]; *old_id_str = NULL; *new_id_str = NULL; *refname = NULL; /* don't reset *capabilities */ err = tokenize_line(tokens, line, len, 3, nitems(tokens)); if (err) return err; if (tokens[0] == NULL || tokens[1] == NULL || tokens[2] == NULL) { free_tokens(tokens, nitems(tokens)); return got_error_msg(GOT_ERR_BAD_PACKET, "empty ref-update"); } *old_id_str = tokens[0]; *new_id_str = tokens[1]; *refname = tokens[2]; if (tokens[3]) { if (*capabilities == NULL) { char *p; *capabilities = tokens[3]; p = strrchr(*capabilities, '\n'); if (p) *p = '\0'; } else free(tokens[3]); } return NULL; } static const struct got_error * match_capability(char **my_capabilities, const char *capa, const struct got_capability *mycapa) { char *equalsign; char *s; equalsign = strchr(capa, '='); if (equalsign) { if (strncmp(capa, mycapa->key, equalsign - capa) != 0) return NULL; } else { if (strcmp(capa, mycapa->key) != 0) return NULL; } if (asprintf(&s, "%s %s%s%s", *my_capabilities != NULL ? *my_capabilities : "", mycapa->key, mycapa->value != NULL ? "=" : "", mycapa->value != NULL ? mycapa->value : "") == -1) return got_error_from_errno("asprintf"); free(*my_capabilities); *my_capabilities = s; return NULL; } static const struct got_error * add_symref(struct got_pathlist_head *symrefs, char *capa) { const struct got_error *err = NULL; char *colon, *name = NULL, *target = NULL; /* Need at least "A:B" */ if (strlen(capa) < 3) return NULL; colon = strchr(capa, ':'); if (colon == NULL) return NULL; *colon = '\0'; name = strdup(capa); if (name == NULL) return got_error_from_errno("strdup"); target = strdup(colon + 1); if (target == NULL) { err = got_error_from_errno("strdup"); goto done; } /* We can't validate the ref itself here. The main process will. */ err = got_pathlist_append(symrefs, name, target); done: if (err) { free(name); free(target); } return err; } const struct got_error * got_gitproto_match_capabilities(char **common_capabilities, struct got_pathlist_head *symrefs, char *capabilities, const struct got_capability my_capabilities[], size_t ncapa) { const struct got_error *err = NULL; char *capa, *equalsign; size_t i; *common_capabilities = NULL; do { capa = strsep(&capabilities, " "); if (capa == NULL) return NULL; equalsign = strchr(capa, '='); if (equalsign != NULL && symrefs != NULL && strncmp(capa, "symref", equalsign - capa) == 0) { err = add_symref(symrefs, equalsign + 1); if (err) break; continue; } for (i = 0; i < ncapa; i++) { err = match_capability(common_capabilities, capa, &my_capabilities[i]); if (err) break; } } while (capa); if (*common_capabilities == NULL) { *common_capabilities = strdup(""); if (*common_capabilities == NULL) err = got_error_from_errno("strdup"); } return err; } const struct got_error * got_gitproto_append_capabilities(size_t *capalen, char *buf, size_t offset, size_t bufsize, const struct got_capability my_capabilities[], size_t ncapa) { char *p = buf + offset; size_t i, len, remain = bufsize - offset; *capalen = 0; if (offset >= bufsize || remain < 1) return got_error(GOT_ERR_NO_SPACE); /* Capabilities are hidden behind a NUL byte. */ *p = '\0'; p++; remain--; *capalen += 1; for (i = 0; i < ncapa; i++) { len = strlcat(p, " ", remain); if (len >= remain) return got_error(GOT_ERR_NO_SPACE); remain -= len; *capalen += 1; len = strlcat(p, my_capabilities[i].key, remain); if (len >= remain) return got_error(GOT_ERR_NO_SPACE); remain -= len; *capalen += strlen(my_capabilities[i].key); if (my_capabilities[i].value == NULL) continue; len = strlcat(p, "=", remain); if (len >= remain) return got_error(GOT_ERR_NO_SPACE); remain -= len; *capalen += 1; len = strlcat(p, my_capabilities[i].value, remain); if (len >= remain) return got_error(GOT_ERR_NO_SPACE); remain -= len; *capalen += strlen(my_capabilities[i].value); } return NULL; } const struct got_error * got_gitproto_split_capabilities_str(struct got_capability **capabilities, size_t *ncapabilities, char *capabilities_str) { char *capastr, *capa; size_t i; *capabilities = NULL; *ncapabilities = 0; /* Compute number of capabilities on a copy of the input string. */ capastr = strdup(capabilities_str); if (capastr == NULL) return got_error_from_errno("strdup"); do { capa = strsep(&capastr, " "); if (capa && *capa != '\0') (*ncapabilities)++; } while (capa); free(capastr); *capabilities = calloc(*ncapabilities, sizeof(**capabilities)); if (*capabilities == NULL) return got_error_from_errno("calloc"); /* Modify input string in place, splitting it into key/value tuples. */ i = 0; for (;;) { char *key = NULL, *value = NULL, *equalsign; capa = strsep(&capabilities_str, " "); if (capa == NULL) break; if (*capa == '\0') continue; if (i >= *ncapabilities) { /* should not happen */ free(*capabilities); *capabilities = NULL; *ncapabilities = 0; return got_error(GOT_ERR_NO_SPACE); } key = capa; equalsign = strchr(capa, '='); if (equalsign != NULL) { *equalsign = '\0'; value = equalsign + 1; } (*capabilities)[i].key = key; (*capabilities)[i].value = value; i++; } return NULL; } got-portable-0.101/lib/diff_output.c0000644000175100017510000002142314644143163013047 /* Common parts for printing diff output */ /* * Copyright (c) 2020 Neels Hofmeyr * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include "diff_internal.h" static int get_atom_byte(int *ch, struct diff_atom *atom, off_t off) { off_t cur; if (atom->at != NULL) { *ch = atom->at[off]; return 0; } cur = ftello(atom->root->f); if (cur == -1) return errno; if (cur != atom->pos + off && fseeko(atom->root->f, atom->pos + off, SEEK_SET) == -1) return errno; *ch = fgetc(atom->root->f); if (*ch == EOF && ferror(atom->root->f)) return errno; return 0; } #define DIFF_OUTPUT_BUF_SIZE 512 int diff_output_lines(struct diff_output_info *outinfo, FILE *dest, const char *prefix, struct diff_atom *start_atom, unsigned int count) { struct diff_atom *atom; off_t outoff = 0, *offp; uint8_t *typep; int rc; if (outinfo && outinfo->line_offsets.len > 0) { unsigned int idx = outinfo->line_offsets.len - 1; outoff = outinfo->line_offsets.head[idx]; } foreach_diff_atom(atom, start_atom, count) { off_t outlen = 0; int i, ch, nbuf = 0; unsigned int len = atom->len; unsigned char buf[DIFF_OUTPUT_BUF_SIZE + 1 /* '\n' */]; size_t n; n = strlcpy(buf, prefix, sizeof(buf)); if (n >= DIFF_OUTPUT_BUF_SIZE) /* leave room for '\n' */ return ENOBUFS; nbuf += n; if (len) { rc = get_atom_byte(&ch, atom, len - 1); if (rc) return rc; if (ch == '\n') len--; } for (i = 0; i < len; i++) { rc = get_atom_byte(&ch, atom, i); if (rc) return rc; if (nbuf >= DIFF_OUTPUT_BUF_SIZE) { rc = fwrite(buf, 1, nbuf, dest); if (rc != nbuf) return errno; outlen += rc; nbuf = 0; } buf[nbuf++] = ch; } buf[nbuf++] = '\n'; rc = fwrite(buf, 1, nbuf, dest); if (rc != nbuf) return errno; outlen += rc; if (outinfo) { ARRAYLIST_ADD(offp, outinfo->line_offsets); if (offp == NULL) return ENOMEM; outoff += outlen; *offp = outoff; ARRAYLIST_ADD(typep, outinfo->line_types); if (typep == NULL) return ENOMEM; *typep = *prefix == ' ' ? DIFF_LINE_CONTEXT : *prefix == '-' ? DIFF_LINE_MINUS : *prefix == '+' ? DIFF_LINE_PLUS : DIFF_LINE_NONE; } } return DIFF_RC_OK; } int diff_output_chunk_left_version(struct diff_output_info **output_info, FILE *dest, const struct diff_input_info *info, const struct diff_result *result, const struct diff_chunk_context *cc) { int rc, c_idx; struct diff_output_info *outinfo = NULL; if (diff_range_empty(&cc->left)) return DIFF_RC_OK; if (output_info) { *output_info = diff_output_info_alloc(); if (*output_info == NULL) return ENOMEM; outinfo = *output_info; } /* Write out all chunks on the left side. */ for (c_idx = cc->chunk.start; c_idx < cc->chunk.end; c_idx++) { const struct diff_chunk *c = &result->chunks.head[c_idx]; if (c->left_count) { rc = diff_output_lines(outinfo, dest, "", c->left_start, c->left_count); if (rc) return rc; } } return DIFF_RC_OK; } int diff_output_chunk_right_version(struct diff_output_info **output_info, FILE *dest, const struct diff_input_info *info, const struct diff_result *result, const struct diff_chunk_context *cc) { int rc, c_idx; struct diff_output_info *outinfo = NULL; if (diff_range_empty(&cc->right)) return DIFF_RC_OK; if (output_info) { *output_info = diff_output_info_alloc(); if (*output_info == NULL) return ENOMEM; outinfo = *output_info; } /* Write out all chunks on the right side. */ for (c_idx = cc->chunk.start; c_idx < cc->chunk.end; c_idx++) { const struct diff_chunk *c = &result->chunks.head[c_idx]; if (c->right_count) { rc = diff_output_lines(outinfo, dest, "", c->right_start, c->right_count); if (rc) return rc; } } return DIFF_RC_OK; } int diff_output_trailing_newline_msg(struct diff_output_info *outinfo, FILE *dest, const struct diff_chunk *c) { enum diff_chunk_type chunk_type = diff_chunk_type(c); struct diff_atom *atom, *start_atom; unsigned int atom_count; int rc, ch; off_t outoff = 0, *offp; uint8_t *typep; if (chunk_type == CHUNK_MINUS || chunk_type == CHUNK_SAME) { start_atom = c->left_start; atom_count = c->left_count; } else if (chunk_type == CHUNK_PLUS) { start_atom = c->right_start; atom_count = c->right_count; } else return EINVAL; /* Locate the last atom. */ if (atom_count == 0) return EINVAL; atom = &start_atom[atom_count - 1]; rc = get_atom_byte(&ch, atom, atom->len - 1); if (rc != DIFF_RC_OK) return rc; if (ch != '\n') { if (outinfo && outinfo->line_offsets.len > 0) { unsigned int idx = outinfo->line_offsets.len - 1; outoff = outinfo->line_offsets.head[idx]; } rc = fprintf(dest, "\\ No newline at end of file\n"); if (rc < 0) return errno; if (outinfo) { ARRAYLIST_ADD(offp, outinfo->line_offsets); if (offp == NULL) return ENOMEM; outoff += rc; *offp = outoff; ARRAYLIST_ADD(typep, outinfo->line_types); if (typep == NULL) return ENOMEM; *typep = DIFF_LINE_NONE; } } return DIFF_RC_OK; } static bool is_function_prototype(unsigned char ch) { return (isalpha((unsigned char)ch) || ch == '_' || ch == '$'); } #define begins_with(s, pre) (strncmp(s, pre, sizeof(pre)-1) == 0) int diff_output_match_function_prototype(char *prototype, size_t prototype_size, int *last_prototype_idx, const struct diff_result *result, const struct diff_chunk_context *cc) { struct diff_atom *start_atom, *atom; const struct diff_data *data; unsigned char buf[DIFF_FUNCTION_CONTEXT_SIZE]; const char *state = NULL; int rc, i, ch; if (result->left->atoms.len > 0 && cc->left.start > 0) { data = result->left; start_atom = &data->atoms.head[cc->left.start - 1]; } else return DIFF_RC_OK; diff_data_foreach_atom_backwards_from(start_atom, atom, data) { int atom_idx = diff_atom_root_idx(data, atom); if (atom_idx < *last_prototype_idx) break; rc = get_atom_byte(&ch, atom, 0); if (rc) return rc; buf[0] = (unsigned char)ch; if (!is_function_prototype(buf[0])) continue; for (i = 1; i < atom->len && i < sizeof(buf) - 1; i++) { rc = get_atom_byte(&ch, atom, i); if (rc) return rc; if (ch == '\n') break; buf[i] = (unsigned char)ch; } buf[i] = '\0'; if (begins_with(buf, "private:")) { if (!state) state = " (private)"; } else if (begins_with(buf, "protected:")) { if (!state) state = " (protected)"; } else if (begins_with(buf, "public:")) { if (!state) state = " (public)"; } else { if (state) /* don't care about truncation */ strlcat(buf, state, sizeof(buf)); strlcpy(prototype, buf, prototype_size); break; } } *last_prototype_idx = diff_atom_root_idx(data, start_atom); return DIFF_RC_OK; } struct diff_output_info * diff_output_info_alloc(void) { struct diff_output_info *output_info; off_t *offp; uint8_t *typep; output_info = malloc(sizeof(*output_info)); if (output_info != NULL) { ARRAYLIST_INIT(output_info->line_offsets, 128); ARRAYLIST_ADD(offp, output_info->line_offsets); if (offp == NULL) { diff_output_info_free(output_info); return NULL; } *offp = 0; ARRAYLIST_INIT(output_info->line_types, 128); ARRAYLIST_ADD(typep, output_info->line_types); if (typep == NULL) { diff_output_info_free(output_info); return NULL; } *typep = DIFF_LINE_NONE; } return output_info; } void diff_output_info_free(struct diff_output_info *output_info) { ARRAYLIST_FREE(output_info->line_offsets); ARRAYLIST_FREE(output_info->line_types); free(output_info); } const char * diff_output_get_label_left(const struct diff_input_info *info) { if (info->flags & DIFF_INPUT_LEFT_NONEXISTENT) return "/dev/null"; return info->left_path ? info->left_path : "a"; } const char * diff_output_get_label_right(const struct diff_input_info *info) { if (info->flags & DIFF_INPUT_RIGHT_NONEXISTENT) return "/dev/null"; return info->right_path ? info->right_path : "b"; } got-portable-0.101/lib/diff_output_plain.c0000644000175100017510000001547514644143163014244 /* Output all lines of a diff_result. */ /* * Copyright (c) 2020 Neels Hofmeyr * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include "diff_internal.h" static int output_plain_chunk(struct diff_output_info *outinfo, FILE *dest, const struct diff_input_info *info, const struct diff_result *result, struct diff_chunk_context *cc, off_t *outoff, bool headers_only) { off_t *offp; int left_start, left_len, right_start, right_len; int rc; bool change = false; left_len = cc->left.end - cc->left.start; if (left_len < 0) return EINVAL; else if (result->left->atoms.len == 0) left_start = 0; else if (left_len == 0 && cc->left.start > 0) left_start = cc->left.start; else if (cc->left.end > 0) left_start = cc->left.start + 1; else left_start = cc->left.start; right_len = cc->right.end - cc->right.start; if (right_len < 0) return EINVAL; else if (result->right->atoms.len == 0) right_start = 0; else if (right_len == 0 && cc->right.start > 0) right_start = cc->right.start; else if (cc->right.end > 0) right_start = cc->right.start + 1; else right_start = cc->right.start; if (left_len == 0) { /* addition */ if (right_len == 1) { rc = fprintf(dest, "%da%d\n", left_start, right_start); } else { rc = fprintf(dest, "%da%d,%d\n", left_start, right_start, cc->right.end); } } else if (right_len == 0) { /* deletion */ if (left_len == 1) { rc = fprintf(dest, "%dd%d\n", left_start, right_start); } else { rc = fprintf(dest, "%d,%dd%d\n", left_start, cc->left.end, right_start); } } else { /* change */ change = true; if (left_len == 1 && right_len == 1) { rc = fprintf(dest, "%dc%d\n", left_start, right_start); } else if (left_len == 1) { rc = fprintf(dest, "%dc%d,%d\n", left_start, right_start, cc->right.end); } else if (right_len == 1) { rc = fprintf(dest, "%d,%dc%d\n", left_start, cc->left.end, right_start); } else { rc = fprintf(dest, "%d,%dc%d,%d\n", left_start, cc->left.end, right_start, cc->right.end); } } if (rc < 0) return errno; if (outinfo) { ARRAYLIST_ADD(offp, outinfo->line_offsets); if (offp == NULL) return ENOMEM; *outoff += rc; *offp = *outoff; } /* * Now write out all the joined chunks. * * If the hunk denotes a change, it will come in the form of a deletion * chunk followed by a addition chunk. Print a marker to break up the * additions and deletions when this happens. */ int c_idx; for (c_idx = cc->chunk.start; !headers_only && c_idx < cc->chunk.end; c_idx++) { const struct diff_chunk *c = &result->chunks.head[c_idx]; if (c->left_count && !c->right_count) rc = diff_output_lines(outinfo, dest, c->solved ? "< " : "?", c->left_start, c->left_count); else if (c->right_count && !c->left_count) { if (change) { rc = fprintf(dest, "---\n"); if (rc < 0) return errno; if (outinfo) { ARRAYLIST_ADD(offp, outinfo->line_offsets); if (offp == NULL) return ENOMEM; *outoff += rc; *offp = *outoff; } } rc = diff_output_lines(outinfo, dest, c->solved ? "> " : "?", c->right_start, c->right_count); } if (rc) return rc; if (cc->chunk.end == result->chunks.len) { rc = diff_output_trailing_newline_msg(outinfo, dest, c); if (rc != DIFF_RC_OK) return rc; } } return DIFF_RC_OK; } int diff_output_plain(struct diff_output_info **output_info, FILE *dest, const struct diff_input_info *info, const struct diff_result *result, int hunk_headers_only) { struct diff_output_info *outinfo = NULL; struct diff_chunk_context cc = {}; int atomizer_flags = (result->left->atomizer_flags| result->right->atomizer_flags); int flags = (result->left->root->diff_flags | result->right->root->diff_flags); bool force_text = (flags & DIFF_FLAG_FORCE_TEXT_DATA); bool have_binary = (atomizer_flags & DIFF_ATOMIZER_FOUND_BINARY_DATA); int i, rc; off_t outoff = 0, *offp; if (!result) return EINVAL; if (result->rc != DIFF_RC_OK) return result->rc; if (output_info) { *output_info = diff_output_info_alloc(); if (*output_info == NULL) return ENOMEM; outinfo = *output_info; } if (have_binary && !force_text) { for (i = 0; i < result->chunks.len; i++) { struct diff_chunk *c = &result->chunks.head[i]; enum diff_chunk_type t = diff_chunk_type(c); if (t != CHUNK_MINUS && t != CHUNK_PLUS) continue; rc = fprintf(dest, "Binary files %s and %s differ\n", diff_output_get_label_left(info), diff_output_get_label_right(info)); if (rc < 0) return errno; if (outinfo) { ARRAYLIST_ADD(offp, outinfo->line_offsets); if (offp == NULL) return ENOMEM; outoff += rc; *offp = outoff; } break; } return DIFF_RC_OK; } for (i = 0; i < result->chunks.len; i++) { struct diff_chunk *chunk = &result->chunks.head[i]; enum diff_chunk_type t = diff_chunk_type(chunk); struct diff_chunk_context next; if (t != CHUNK_MINUS && t != CHUNK_PLUS) continue; if (diff_chunk_context_empty(&cc)) { /* Note down the start point, any number of subsequent * chunks may be joined up to this chunk by being * directly adjacent. */ diff_chunk_context_get(&cc, result, i, 0); continue; } /* There already is a previous chunk noted down for being * printed. Does it join up with this one? */ diff_chunk_context_get(&next, result, i, 0); if (diff_chunk_contexts_touch(&cc, &next)) { /* This next context touches or overlaps the previous * one, join. */ diff_chunk_contexts_merge(&cc, &next); /* When we merge the last chunk we can end up with one * hanging chunk and have to come back for it after the * loop */ continue; } rc = output_plain_chunk(outinfo, dest, info, result, &cc, &outoff, hunk_headers_only); if (rc != DIFF_RC_OK) return rc; cc = next; } if (!diff_chunk_context_empty(&cc)) return output_plain_chunk(outinfo, dest, info, result, &cc, &outoff, hunk_headers_only); return DIFF_RC_OK; } got-portable-0.101/lib/read_gitconfig.c0000664000175100017510000001646114644144735013501 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_repository.h" #include "got_path.h" #include "got_lib_gitconfig.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_object_cache.h" #include "got_lib_privsep.h" #include "got_lib_pack.h" #include "got_lib_repository.h" static int get_boolean_val(char *val) { return (strcasecmp(val, "true") == 0 || strcasecmp(val, "on") == 0 || strcasecmp(val, "yes") == 0 || strcmp(val, "1") == 0); } static int skip_node(struct got_gitconfig *gitconfig, struct got_gitconfig_list_node *node) { /* * Skip config nodes which do not describe remotes, and remotes * which do not have a fetch URL defined (as used by git-annex). */ return (strncasecmp("remote \"", node->field, 8) != 0 || got_gitconfig_get_str(gitconfig, node->field, "url") == NULL); } const struct got_error * got_repo_read_gitconfig(int *gitconfig_repository_format_version, char **gitconfig_author_name, char **gitconfig_author_email, struct got_remote_repo **remotes, int *nremotes, char **gitconfig_owner, char ***extnames, char ***extvals, int *nextensions, const char *gitconfig_path) { const struct got_error *err = NULL; struct got_gitconfig *gitconfig = NULL; struct got_gitconfig_list *tags; struct got_gitconfig_list_node *node; int fd, i; const char *author, *email, *owner; *gitconfig_repository_format_version = 0; if (extnames) *extnames = NULL; if (extvals) *extvals = NULL; if (nextensions) *nextensions = 0; *gitconfig_author_name = NULL; *gitconfig_author_email = NULL; if (remotes) *remotes = NULL; if (nremotes) *nremotes = 0; if (gitconfig_owner) *gitconfig_owner = NULL; fd = open(gitconfig_path, O_RDONLY | O_CLOEXEC); if (fd == -1) { if (errno == ENOENT) return NULL; return got_error_from_errno2("open", gitconfig_path); } err = got_gitconfig_open(&gitconfig, fd); if (err) goto done; *gitconfig_repository_format_version = got_gitconfig_get_num(gitconfig, "core", "repositoryformatversion", 0); tags = got_gitconfig_get_tag_list(gitconfig, "extensions"); if (extnames && extvals && nextensions && tags) { size_t numext = 0; TAILQ_FOREACH(node, &tags->fields, link) { char *ext = node->field; char *val = got_gitconfig_get_str(gitconfig, "extensions", ext); if (get_boolean_val(val)) numext++; } *extnames = calloc(numext, sizeof(char *)); if (*extnames == NULL) { err = got_error_from_errno("calloc"); goto done; } *extvals = calloc(numext, sizeof(char *)); if (*extvals == NULL) { err = got_error_from_errno("calloc"); goto done; } TAILQ_FOREACH(node, &tags->fields, link) { char *ext = node->field; char *val = got_gitconfig_get_str(gitconfig, "extensions", ext); if (get_boolean_val(val)) { char *extstr = NULL, *valstr = NULL; extstr = strdup(ext); if (extstr == NULL) { err = got_error_from_errno("strdup"); goto done; } valstr = strdup(val); if (valstr == NULL) { err = got_error_from_errno("strdup"); goto done; } (*extnames)[(*nextensions)] = extstr; (*extvals)[(*nextensions)] = valstr; (*nextensions)++; } } } author = got_gitconfig_get_str(gitconfig, "user", "name"); if (author) { *gitconfig_author_name = strdup(author); if (*gitconfig_author_name == NULL) { err = got_error_from_errno("strdup"); goto done; } } email = got_gitconfig_get_str(gitconfig, "user", "email"); if (email) { *gitconfig_author_email = strdup(email); if (*gitconfig_author_email == NULL) { err = got_error_from_errno("strdup"); goto done; } } if (gitconfig_owner) { owner = got_gitconfig_get_str(gitconfig, "gotweb", "owner"); if (owner == NULL) owner = got_gitconfig_get_str(gitconfig, "gitweb", "owner"); if (owner) { *gitconfig_owner = strdup(owner); if (*gitconfig_owner == NULL) { err = got_error_from_errno("strdup"); goto done; } } } if (remotes && nremotes) { struct got_gitconfig_list *sections; size_t nalloc = 0; err = got_gitconfig_get_section_list(§ions, gitconfig); if (err) return err; TAILQ_FOREACH(node, §ions->fields, link) { if (skip_node(gitconfig, node)) continue; nalloc++; } *remotes = recallocarray(NULL, 0, nalloc, sizeof(**remotes)); if (*remotes == NULL) { err = got_error_from_errno("recallocarray"); goto done; } i = 0; TAILQ_FOREACH(node, §ions->fields, link) { struct got_remote_repo *remote; char *name, *end, *mirror; const char *fetch_url, *send_url; if (skip_node(gitconfig, node) != 0) continue; remote = &(*remotes)[i]; name = strdup(node->field + 8); if (name == NULL) { err = got_error_from_errno("strdup"); goto done; } end = strrchr(name, '"'); if (end) *end = '\0'; remote->name = name; fetch_url = got_gitconfig_get_str(gitconfig, node->field, "url"); remote->fetch_url = strdup(fetch_url); if (remote->fetch_url == NULL) { err = got_error_from_errno("strdup"); free(remote->name); remote->name = NULL; goto done; } send_url = got_gitconfig_get_str(gitconfig, node->field, "pushurl"); if (send_url == NULL) send_url = got_gitconfig_get_str(gitconfig, node->field, "url"); remote->send_url = strdup(send_url); if (remote->send_url == NULL) { err = got_error_from_errno("strdup"); free(remote->name); remote->name = NULL; free(remote->fetch_url); remote->fetch_url = NULL; goto done; } remote->mirror_references = 0; mirror = got_gitconfig_get_str(gitconfig, node->field, "mirror"); if (mirror != NULL && get_boolean_val(mirror)) remote->mirror_references = 1; i++; (*nremotes)++; } } done: if (fd != -1) close(fd); if (gitconfig) got_gitconfig_close(gitconfig); if (err) { if (extnames && extvals && nextensions) { for (i = 0; i < (*nextensions); i++) { free((*extnames)[i]); free((*extvals)[i]); } free(*extnames); *extnames = NULL; free(*extvals); *extvals = NULL; *nextensions = 0; } if (remotes && nremotes) { for (i = 0; i < (*nremotes); i++) { struct got_remote_repo *remote; remote = &(*remotes)[i]; free(remote->name); free(remote->fetch_url); free(remote->send_url); } free(*remotes); *remotes = NULL; *nremotes = 0; } } return err; } got-portable-0.101/lib/buf.c0000664000175100017510000001766514644144735011320 /* $OpenBSD: buf.c,v 1.27 2016/10/16 13:35:51 okan Exp $ */ /* * Copyright (c) 2003 Jean-Francois Brousseau * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include "buf.h" #include "got_error.h" #define BUF_INCR 128 #define SIZE_LEFT(b) ((b)->cb_size - (b)->cb_len) static const struct got_error *buf_grow(BUF *, size_t); /* * Create a new buffer structure and return a pointer to it. This structure * uses dynamically-allocated memory and must be freed with buf_free(), once * the buffer is no longer needed. */ const struct got_error * buf_alloc(BUF **b, size_t len) { const struct got_error *err = NULL; *b = malloc(sizeof(**b)); if (*b == NULL) return got_error_from_errno("malloc"); /* Postpone creation of zero-sized buffers */ if (len > 0) { (*b)->cb_buf = calloc(1, len); if ((*b)->cb_buf == NULL) { err = got_error_from_errno("calloc"); free(*b); *b = NULL; return err; } } else (*b)->cb_buf = NULL; (*b)->cb_size = len; (*b)->cb_len = 0; return NULL; } /* * Open the file specified by and load all of its contents into a * buffer. * Returns the loaded buffer on success or NULL on failure. * Sets errno on error. */ const struct got_error * buf_load(BUF **buf, FILE *f) { const struct got_error *err = NULL; size_t ret; size_t len; u_char *bp; struct stat st; *buf = NULL; if (fstat(fileno(f), &st) == -1) { err = got_error_from_errno("fstat"); goto out; } if ((uintmax_t)st.st_size > SIZE_MAX) { err = got_error_set_errno(EFBIG, "cannot fit file into memory buffer"); goto out; } err = buf_alloc(buf, st.st_size); if (err) goto out; for (bp = (*buf)->cb_buf; ; bp += ret) { len = SIZE_LEFT(*buf); ret = fread(bp, 1, len, f); if (ret == 0 && ferror(f)) { err = got_ferror(f, GOT_ERR_IO); goto out; } else if (ret == 0) break; (*buf)->cb_len += (size_t)ret; } out: if (err) { buf_free(*buf); *buf = NULL; } return err; } const struct got_error * buf_load_fd(BUF **buf, int fd) { const struct got_error *err = NULL; unsigned char out[8192]; ssize_t r; size_t len; err = buf_alloc(buf, 8192); if (err) return err; do { r = read(fd, out, sizeof(out)); if (r == -1) return got_error_from_errno("read"); if (r > 0) { err = buf_append(&len, *buf, out, r); if (err) return err; } } while (r > 0); return NULL; } void buf_free(BUF *b) { if (b == NULL) return; free(b->cb_buf); free(b); } /* * Free the buffer 's structural information but do not free the contents * of the buffer. Instead, they are returned and should be freed later using * free(). */ void * buf_release(BUF *b) { void *tmp; tmp = b->cb_buf; free(b); return (tmp); } u_char * buf_get(BUF *b) { return (b->cb_buf); } /* * Empty the contents of the buffer and reset pointers. */ void buf_empty(BUF *b) { memset(b->cb_buf, 0, b->cb_size); b->cb_len = 0; } /* Discard the leading bytes from the buffer. */ const struct got_error * buf_discard(BUF *b, size_t n) { if (n > b->cb_len) return got_error(GOT_ERR_RANGE); if (n == b->cb_len) buf_empty(b); else { memmove(b->cb_buf, b->cb_buf + n, b->cb_len - n); b->cb_len -= n; } return NULL; } /* * Append a single character to the end of the buffer . */ const struct got_error * buf_putc(BUF *b, int c) { const struct got_error *err = NULL; u_char *bp; if (SIZE_LEFT(b) == 0) { err = buf_grow(b, BUF_INCR); if (err) return err; } bp = b->cb_buf + b->cb_len; *bp = (u_char)c; b->cb_len++; return NULL; } /* * Append a string to the end of buffer . */ const struct got_error * buf_puts(size_t *newlen, BUF *b, const char *str) { return buf_append(newlen, b, str, strlen(str)); } /* * Return u_char at buffer position . */ u_char buf_getc(BUF *b, size_t pos) { return (b->cb_buf[pos]); } /* * Append bytes of data pointed to by to the buffer . If the * buffer is too small to accept all data, it will get resized to an * appropriate size to accept all data. * Returns the number of bytes successfully appended to the buffer. */ const struct got_error * buf_append(size_t *newlen, BUF *b, const void *data, size_t len) { const struct got_error *err = NULL; size_t left, rlen; u_char *bp; left = SIZE_LEFT(b); rlen = len; if (left < len) { err = buf_grow(b, len - left); if (err) return err; } bp = b->cb_buf + b->cb_len; memcpy(bp, data, rlen); b->cb_len += rlen; *newlen = rlen; return NULL; } /* * Returns the size of the buffer that is being used. */ size_t buf_len(BUF *b) { return (b->cb_len); } /* * Write the contents of the buffer to the specified */ int buf_write_fd(BUF *b, int fd) { u_char *bp; size_t len; ssize_t ret; len = b->cb_len; bp = b->cb_buf; do { ret = write(fd, bp, len); if (ret == -1) { if (errno == EINTR || errno == EAGAIN) continue; return (-1); } len -= (size_t)ret; bp += (size_t)ret; } while (len > 0); return (0); } /* * Write the contents of the buffer to the file whose path is given in * . If the file does not exist, it is created with mode . */ const struct got_error * buf_write(BUF *b, const char *path, mode_t mode) { const struct got_error *err = NULL; int fd; open: if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, mode)) == -1) { err = got_error_from_errno2("open", path); if (errno == EACCES && unlink(path) != -1) goto open; else return err; } if (buf_write_fd(b, fd) == -1) { err = got_error_from_errno("buf_write_fd"); (void)unlink(path); return err; } if (fchmod(fd, mode) < 0) err = got_error_from_errno2("fchmod", path); if (close(fd) == -1 && err == NULL) err = got_error_from_errno2("close", path); return err; } /* * Write the contents of the buffer to a temporary file whose path is * specified using