summaryrefslogtreecommitdiff
path: root/dev-util/kup
diff options
context:
space:
mode:
authorroot <root@alpha.trunkmasters.com>2026-06-04 16:47:34 -0500
committerroot <root@alpha.trunkmasters.com>2026-06-04 16:47:34 -0500
commitdda948891d3731927b821ce31f9d9a2d03ba20c5 (patch)
tree99cd40be4cbb0606260da212cd81b8ab2db9da9b /dev-util/kup
parenta3ceca1b4c0d9bdb550dc23f06ffbb5a8e033bc7 (diff)
downloadbaldeagleos-repo-dda948891d3731927b821ce31f9d9a2d03ba20c5.tar.gz
baldeagleos-repo-dda948891d3731927b821ce31f9d9a2d03ba20c5.tar.xz
baldeagleos-repo-dda948891d3731927b821ce31f9d9a2d03ba20c5.zip
Adding metadata
Diffstat (limited to 'dev-util/kup')
-rw-r--r--dev-util/kup/Manifest1
-rw-r--r--dev-util/kup/files/kup-0.3.6-path-lookup-compressor.patch62
-rw-r--r--dev-util/kup/files/kup-server-gitolite-subcmd-r2.patch242
-rw-r--r--dev-util/kup/files/kup-server-putraw.patch302
-rw-r--r--dev-util/kup/files/kup.tmpfilesd7
-rw-r--r--dev-util/kup/kup-0.3.6-r6.ebuild69
-rw-r--r--dev-util/kup/kup-0.3.6-r8.ebuild71
-rw-r--r--dev-util/kup/metadata.xml8
8 files changed, 762 insertions, 0 deletions
diff --git a/dev-util/kup/Manifest b/dev-util/kup/Manifest
new file mode 100644
index 000000000000..7ebc092355c6
--- /dev/null
+++ b/dev-util/kup/Manifest
@@ -0,0 +1 @@
+DIST kup-0.3.6.tar.xz 41404 BLAKE2B 7c4187032b3d29ea06ddeaea813370e5a68fa94c9b85dbd92930651ad52ea103a98be26bae32b9120d136d3558b27c29323191aab36a895e4b040eb8fd83d12f SHA512 136cd179abb6b658050cd51f00a4cee2b9022b40ce17c9e50290fcdd2303de2ca21a64569b4af6a46db88959812200b3654fce06a0b3c081af0c89b5db2ded20
diff --git a/dev-util/kup/files/kup-0.3.6-path-lookup-compressor.patch b/dev-util/kup/files/kup-0.3.6-path-lookup-compressor.patch
new file mode 100644
index 000000000000..453160f3c68e
--- /dev/null
+++ b/dev-util/kup/files/kup-0.3.6-path-lookup-compressor.patch
@@ -0,0 +1,62 @@
+Rely on PATH to find (de)compressors rather than assuming a location
+which will break w/ unmerged-usr.
+--- a/kup-server
++++ b/kup-server
+@@ -160,16 +160,16 @@ if (defined($cfg->param('compressors.use'))) {
+ } else {
+ %zformats = (
+ '.gz' => {
+- 'compress' => '/bin/gzip -9',
+- 'decompress' => '/bin/gzip -cd',
++ 'compress' => 'gzip -9',
++ 'decompress' => 'gzip -cd',
+ },
+ '.bz2' => {
+- 'compress' => '/usr/bin/bzip2 -9',
+- 'decompress' => '/usr/bin/bzip2 -cd',
++ 'compress' => 'bzip2 -9',
++ 'decompress' => 'bzip2 -cd',
+ },
+ '.xz' => {
+- 'compress' => '/usr/bin/xz -9',
+- 'decompress' => '/usr/bin/xz -cd',
++ 'compress' => 'xz -9',
++ 'decompress' => 'xz -cd',
+ },
+ );
+ }
+--- a/kup-server.1
++++ b/kup-server.1
+@@ -107,12 +107,12 @@ sure to configure the decompress command to output to stdout. E.g.:
+ .RS
+ .nf
+ [gz]
+-compress_command = /bin/pigz -9
+-decompress_command = /bin/gzip -cd
++compress_command = pigz -9
++decompress_command = gzip -cd
+
+ [xz]
+-compress_command = /bin/xz -9 -T0
+-decompress_command = /bin/xz -cd
++compress_command = xz -9 -T0
++decompress_command = xz -cd
+ .fi
+ .RE
+ .SH AUTHOR
+--- a/kup-server.cfg
++++ b/kup-server.cfg
+@@ -60,9 +60,9 @@ use = gz, xz
+ ; Specify which commands should be used for compression and decompression of
+ ; each archival format. Make sure the decompression command outputs to stdout.
+ [gz]
+-compress_command = /bin/pigz -9
+-decompress_command = /bin/gzip -cd
++compress_command = pigz -9
++decompress_command = gzip -cd
+
+ [xz]
+-compress_command = /bin/xz -9 -T0
+-decompress_command = /bin/xz -cd
++compress_command = xz -9 -T0
++decompress_command = xz -cd
diff --git a/dev-util/kup/files/kup-server-gitolite-subcmd-r2.patch b/dev-util/kup/files/kup-server-gitolite-subcmd-r2.patch
new file mode 100644
index 000000000000..0caf51e25223
--- /dev/null
+++ b/dev-util/kup/files/kup-server-gitolite-subcmd-r2.patch
@@ -0,0 +1,242 @@
+Upstream kup provided this patch, that was apparently written by the Gitolite
+author.
+
+--- standard/kup-server 2017-03-28 13:01:24.000000000 -0400
++++ gitolite/kup-server 2018-03-26 15:01:20.000000000 -0400
+@@ -1,4 +1,4 @@
+-#!/usr/bin/perl -T
++#!/usr/bin/perl
+ ## -----------------------------------------------------------------------
+ ##
+ ## Copyright 2011 Intel Corporation; author: H. Peter Anvin
+@@ -68,12 +68,20 @@
+
+ use Digest::SHA;
+
+-my $VERSION = '0.3.6';
+-
+-# Scrub the environment completely
+-%ENV = ('PATH' => '/bin:/usr/bin',
+- 'LANG' => 'C',
+- 'SHELL' => '/bin/false'); # Nothing in this program should shell out
++use lib $ENV{GL_LIBDIR};
++use Gitolite::Easy;
++use Gitolite::Conf::Load;
++
++my $VERSION = '0.3.6 (gitolite integrated)';
++
++# Scrub the environment completely, except gitolite variables and HOME
++{
++ my %env = %ENV;
++ %ENV = ('PATH' => '/bin:/usr/bin',
++ 'LANG' => 'C',
++ 'SHELL' => '/bin/false'); # Nothing in this program should shell out
++ $ENV{$_} = $env{$_} for ('HOME', grep(/^GL_/, keys %env));
++}
+
+ # The standard function to call on bail
+ sub fatal($) {
+@@ -88,16 +96,7 @@
+ }
+
+ sub my_username() {
+- my $whoami = getuid();
+- my ($name,$passwd,$uid,$gid,$quota,$comment,$gcos,$dir,$shell,$expire) = getpwuid($whoami);
+-
+- if (!defined($name) || $whoami != $uid) {
+- # We haven't called openlog() yet so we need to do it here
+- openlog("kup-server($whoami)", 'ndelay,pid', LOG_LOCAL5);
+- fatal("You don't exist, go away!");
+- }
+-
+- return (defined($name) && $whoami == $uid) ? $name : $whoami;
++ return $ENV{GL_USER};
+ }
+
+ my $user_name = my_username();
+@@ -106,7 +105,7 @@
+
+
+ # Get config values from kup-server.cfg
+-my $cfg_file = '/etc/kup/kup-server.cfg';
++my $cfg_file = '/etc/kup/kup-server.cfg';
+
+ my $cfg = new Config::Simple($cfg_file);
+
+@@ -371,6 +370,51 @@
+ return 1;
+ }
+
++# kup-server may "read" files from the kup data_path, or repos. If a repo is
++# supplied, we assume it's a gitolite repo and check access accordingly (while
++# remembering that kup seems to add a leading slash). If a repo is *not*
++# supplied, we assume we're talking about the kup data_path, which means we
++# make gitolite access rules from the "fake" repo called "@kup-server"
++sub read_allowed
++{
++ Gitolite::Common::trace( 1, 'read_allowed', @_ );
++ my $repo = shift || '@kup-server';
++
++ # gitolite expects a "normalised" repo name; no leading slash, no trailing ".git"
++ $repo =~ s(^/)(); $repo =~ s/\.git$//;
++
++ return can_read($repo);
++}
++
++# kup-server does not write to normal repos, it only writes to files in the
++# kup data_path. So we don't have to worry about any repo other than
++# "@kup-server", which is therefore hardcoded in here.
++sub write_allowed
++{
++ Gitolite::Common::trace( 1, 'write_allowed', @_ );
++ my($path, $perm) = @_;
++
++ # other values for perm are + (rm) and C (mkdir), analogous to gitolite's
++ # "+ means delete or rewind branch, C means create branch"
++ $perm ||= 'W';
++
++ my $repo = '@kup-server';
++
++ # the paths that gitolite expects start with "refs/heads/", since we are
++ # simply re-using the existing ACL for this. (But remember $path, in
++ # kup-land, already starts with a "/".)
++ $path = "refs/heads" . $path;
++
++ return can_write($repo, $perm, $path) ||
++ can_write($repo, $perm, "$path/");
++ # the second check is because, when specifying a permission on a directory
++ # in gitolite, you end with a "/", say "RW+C foo/ = user". To exercise
++ # that right, the user runs "kup mkdir foo" or "kup rm foo". This fails,
++ # because the regex "foo/" won't match. (In a *git* repo it doesn't
++ # matter, because git doesn't allow empty directories, so it never
++ # happens).
++}
++
+ # Return a percentage, valid even if the denominator is zero
+ sub percentage($$)
+ {
+@@ -526,6 +570,10 @@
+ fatal("Invalid pathname in TAR command");
+ }
+
++ if (!read_allowed($tree)) {
++ fatal("Read access denied");
++ }
++
+ if (!is_clean_string($prefix)) {
+ fatal("Invalid prefix string");
+ }
+@@ -569,6 +617,10 @@
+ fatal("Invalid pathname in DIFF command");
+ }
+
++ if (!read_allowed($tree)) {
++ fatal("Read access denied");
++ }
++
+ if ($tree !~ /\.git$/ || ! -d $git_path.$tree ||
+ ! -d $git_path.$tree.'/objects') {
+ fatal("No such git tree");
+@@ -788,8 +840,13 @@
+ or fatal("dup error");
+ close($devnull);
+
++ my $gpgvbin = '/opt/gnupg22/bin/gpgv';
++ if ( ! -x $gpgvbin) {
++ $gpgvbin = '/usr/bin/gpgv';
++ }
++
+ my $status =
+- system('/usr/bin/gpgv',
++ system($gpgvbin,
+ '--quiet',
+ '--homedir', $tmpdir,
+ '--keyring', $pgp_path."/${user_name}.gpg",
+@@ -839,6 +896,10 @@
+ fatal("Invalid filename in PUT command");
+ }
+
++ if (!write_allowed($file)) {
++ fatal("Write access denied");
++ }
++
+ my @install_ext;
+ my @conflic_ext;
+ my $stem;
+@@ -917,6 +978,10 @@
+ fatal("Invalid filename in MKDIR command");
+ }
+
++ if (!write_allowed($file, 'C')) {
++ fatal("MKDIR access denied");
++ }
++
+ my @badext = ('.sign', keys(%zformats));
+
+ foreach my $e (@badext) {
+@@ -991,6 +1056,16 @@
+ fatal("Invalid filename in $cmd command");
+ }
+
++ if ($cmd eq 'MOVE') {
++ if (!write_allowed($from, '+')) {
++ fatal("Delete (as part of MOVE) access denied");
++ }
++ }
++
++ if (!write_allowed($to)) {
++ fatal("Write access denied");
++ }
++
+ if ($from =~ /\.gz$/) {
+ if ($to !~ /\.gz$/) {
+ fatal("$cmd of .gz file must itself end in .gz");
+@@ -1093,6 +1168,10 @@
+ fatal("Invalid pathname in DELETE command");
+ }
+
++ if (!write_allowed($file, "+")) {
++ fatal("Delete access denied");
++ }
++
+ if ($file !~ /\.gz$/ &&
+ has_extension($file, '.sign', keys(%zformats))) {
+ fatal("DELETE of auxiliary files not supported");
+@@ -1222,6 +1301,10 @@
+
+ my($dir) = @args;
+
++ if (!read_allowed()) {
++ fatal("Read access denied");
++ }
++
+ # DIR / is permitted unlike any other command
+ $dir =~ s:/$::g;
+ if ($dir ne '' && !is_valid_filename($dir)) {
+@@ -1261,7 +1344,25 @@
+
+ sub do_info()
+ {
+- print "kup-server $VERSION\n";
++ print "kup-server $VERSION\n\n";
++
++ my %xlat = (
++ R => 'ls',
++ RW => 'put',
++ 'RW+' => 'put/rm/mv',
++ 'RWC' => 'put/mkdir',
++ 'RW+C' => 'put/rm/mv/mkdir',
++ '-' => '(denied)',
++ );
++ Gitolite::Conf::Load::load('@kup-server');
++ my @rules = Gitolite::Conf::Load::rules('@kup-server', $ENV{GL_USER});
++ for my $r (@rules) {
++ my ($dummy, $perm, $ref) = @$r;
++ $ref =~ s(^refs/heads/)();
++ $ref =~ s(/USER/)(/$ENV{GL_USER}/);
++ $ref = ($ref eq 'refs/.*') ? '/*' : '/' . $ref . '*';
++ printf "%-24s %s\n", ($xlat{$perm} || $perm), $ref;
++ }
+ }
+
+ sub get_command()
diff --git a/dev-util/kup/files/kup-server-putraw.patch b/dev-util/kup/files/kup-server-putraw.patch
new file mode 100644
index 000000000000..d88b80216829
--- /dev/null
+++ b/dev-util/kup/files/kup-server-putraw.patch
@@ -0,0 +1,302 @@
+https://github.com/robbat2/kup/pull/1
+
+From ee7223a8eea366ae8c39450f25272f3006732abb Mon Sep 17 00:00:00 2001
+From: "Robin H. Johnson" <rjohnson@coreweave.com>
+Date: Wed, 11 Mar 2026 21:39:06 -0700
+Subject: [PATCH] feat: putraw command
+
+Signed-off-by: Robin H. Johnson <rjohnson@coreweave.com>
+---
+ kup | 46 ++++++++++++++++++++++++++++++++++++
+ kup-server | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ kup-server.1 | 9 ++++++-
+ kup.1 | 46 +++++++++++++++++++++++++++++-------
+ 4 files changed, 158 insertions(+), 10 deletions(-)
+
+diff --git a/kup b/kup
+index f3a5d0f..bdb37c5 100755
+--- a/kup
++++ b/kup
+@@ -93,6 +93,7 @@ sub usage($) {
+ print STDERR " put local_file signature remote_path\n";
+ print STDERR " put --tar [--prefix=] remote_tree ref signature remote_path\n";
+ print STDERR " put --diff remote_tree ref1 ref2 signature remote_path\n";
++ print STDERR " putraw local_file signature remote_path\n";
+ print STDERR " mkdir remote_path\n";
+ print STDERR " mv|move old_path new_path\n";
+ print STDERR " ln|link old_path new_path\n";
+@@ -474,6 +475,49 @@ sub cmd_put()
+ command('PUT', url_encode($remote));
+ }
+
++# PUTRAW command - upload a file exactly as-is without recompression
++sub cmd_putraw()
++{
++ my $file = shift @args;
++
++ if ($file =~ /^-/) {
++ die "$0: unknown option to putraw command: $file\n";
++ }
++
++ # Upload the file as-is; force plain ('%') format so the server stores
++ # exactly the bytes we have locally without decompressing.
++ cat_file('DATA', $file, '%');
++
++ # Get the local filename without directory
++ my($vol, $dir, $file_tail);
++ ($vol, $dir, $file_tail) = File::Spec->splitpath($file);
++
++ my $sign = shift @args;
++ my $remote = shift @args;
++
++ if (!defined($remote)) {
++ usage(1);
++ }
++
++ # Allow trailing slash to use local filename
++ if ($remote =~ m:/$: && defined($file_tail)) {
++ $remote .= $file_tail;
++ }
++
++ my $xrt = $remote;
++ $remote = canonicalize_path($remote);
++ if (!is_valid_filename($remote)) {
++ die "$0: invalid pathname: $xrt\n";
++ }
++
++ if ($remote =~ /\.sign$/) {
++ die "$0: target filename cannot end in .sign\n";
++ }
++
++ cat_file('SIGN', $sign, undef);
++ command('PUTRAW', url_encode($remote));
++}
++
+ # MKDIR command
+ sub cmd_mkdir()
+ {
+@@ -601,6 +645,8 @@ sub process_commands()
+
+ if ($cmd eq 'put') {
+ cmd_put();
++ } elsif ($cmd eq 'putraw') {
++ cmd_putraw();
+ } elsif ($cmd eq 'mkdir') {
+ cmd_mkdir();
+ } elsif ($cmd eq 'move' || $cmd eq 'mv') {
+diff --git a/kup-server b/kup-server
+index 8bdab50..ba326fa 100755
+--- a/kup-server
++++ b/kup-server
+@@ -30,6 +30,8 @@
+ # - updates the current signature blob (follows immediately)
+ # PUT pathname
+ # - installs the current data blob as <pathname>
++# PUTRAW pathname
++# - installs the current data blob as <pathname> without recompression
+ # MKDIR pathname
+ # - creates a new directory
+ # MOVE old-path new-path
+@@ -903,6 +905,69 @@ sub put_file(@)
+ cleanup();
+ }
+
++sub putraw_file(@)
++{
++ my @args = @_;
++
++ if (scalar(@args) != 1) {
++ fatal("Bad PUTRAW command");
++ }
++
++ my($file) = @args;
++
++ if (!$have_data) {
++ fatal("PUTRAW without DATA");
++ }
++ if (!$have_sign) {
++ fatal("PUTRAW without SIGN");
++ }
++
++ if (!signature_valid()) {
++ fatal("Signature invalid");
++ }
++
++ if (!is_valid_filename($file)) {
++ fatal("Invalid filename in PUTRAW command");
++ }
++
++ if ($file =~ /\.sign$/) {
++ fatal("$file: Target filename cannot end in .sign");
++ }
++
++ make_timestamps_match();
++
++ # Log SHA256 of the raw (as-uploaded) file
++ my $sha = Digest::SHA->new('sha256');
++ print STDERR "\rCalculating sha256 for ".$file." ";
++ $sha->addfile($tmpdir.'/data');
++ syslog(LOG_NOTICE, "sha256: %s: %s", $file, $sha->hexdigest);
++ print STDERR "... logged.\n";
++
++ lock_tree();
++
++ foreach my $e ('', '.sign') {
++ if (-e $data_path.$file.$e && ! -f _) {
++ fatal("$file: Trying to overwrite a non-file");
++ }
++ }
++
++ my @install_ext = ('.sign', '');
++ my @undoes = ();
++ foreach my $e (@install_ext) {
++ my $target = $data_path.$file.$e;
++ if (!rename($tmpdir.'/data'.$e, $target)) {
++ my $err = $!;
++ unlink(@undoes);
++ $! = $err;
++ fatal("$file: Failed to install files: $!");
++ }
++ push(@undoes, $target);
++ }
++
++ unlock_tree();
++ cleanup();
++}
++
+ sub do_mkdir(@)
+ {
+ my @args = @_;
+@@ -1305,6 +1370,8 @@ while (defined($line = get_command())) {
+ get_sign_data(@args);
+ } elsif ($cmd eq 'PUT') {
+ put_file(@args);
++ } elsif ($cmd eq 'PUTRAW') {
++ putraw_file(@args);
+ } elsif ($cmd eq 'MKDIR') {
+ do_mkdir(@args);
+ } elsif ($cmd eq 'MOVE' || $cmd eq 'LINK') {
+diff --git a/kup-server.1 b/kup-server.1
+index 2143090..6dd8ec7 100644
+--- a/kup-server.1
++++ b/kup-server.1
+@@ -28,6 +28,12 @@ for specific tree access control. On the client side, a corresponding
+ client-side utility
+ .BR kup
+ is used to initiate the connection and perform the uploads.
++.PP
++Uploaded files must be accompanied by a PGP detached signature. For
++the \fBPUT\fP command the signature covers the uncompressed content and
++the server generates all configured compression formats. For the
++\fBPUTRAW\fP command the signature covers the file exactly as uploaded,
++and the server stores it verbatim without recompression.
+ .SH GLOBAL CONFIG
+ .PP
+ The configuration file for
+@@ -127,4 +133,5 @@ or (at your option) any later version; incorporated herein by
+ reference. There is NO warranty; not even for MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE.
+ .SH "SEE ALSO"
+-.BR kup (1)
++.BR kup (1),
++.BR kup-proto (5)
+diff --git a/kup.1 b/kup.1
+index 811afb3..6ad8210 100644
+--- a/kup.1
++++ b/kup.1
+@@ -18,9 +18,13 @@ kup \- kernel.org upload utility
+ .PP
+ This utility is used to upload files to \fIkernel.org\fP and other
+ systems using the same upload system (\fBkup-server\fP). Each upload
+-is required to have a PGP signature, and the server will generate
+-multiple compressed formats if the content uploaded is intended to be
+-compressed.
++is required to have a PGP signature. For the
++.B put
++command, the server will generate multiple compressed formats if the
++content uploaded is intended to be compressed. For the
++.B putraw
++command, the file is stored exactly as uploaded without any
++recompression.
+ .PP
+ Additionally, if the user has content from a
+ .BR git (1)
+@@ -68,15 +72,19 @@ or if not set, no subcommand will be used (default kup-server behavior).
+ A series of commands can be specified on a single command line,
+ separated by a double dash argument (\fB\-\-\fP).
+ .PP
+-In all cases, PGP signatures are detached signature files
++For the \fBput\fP command, PGP signatures are detached signature files
+ corresponding to the \fIuncompressed\fP content. If a
+-\fIremote_path\fP ends in \fP\.gz\fP then
++\fIremote_path\fP ends in \fB\.gz\fP then
+ .BR gzip ,
+ .B bzip2
+ and
+ .B xz
+ compressed files are generated on the server; otherwise the content is
+ stored uncompressed.
++.PP
++For the \fBputraw\fP command, the PGP signature must correspond to the
++exact bytes of \fIlocal_file\fP as uploaded. The file is stored
++verbatim at \fIremote_path\fP with no recompression.
+ .TP
+ \fBput\fP \fIlocal_file\fP \fPsignature_file\fP \fIremote_path\fP
+ Upload the file \fIlocal_file\fP signed with
+@@ -111,6 +119,14 @@ version of
+ .B git
+ locally as on the server in order to produce a valid signature.
+ .TP
++\fBputraw\fP \fIlocal_file\fP \fIsignature_file\fP \fIremote_path\fP
++Upload the file \fIlocal_file\fP signed with \fIsignature_file\fP and
++store it at \fIremote_path\fP exactly as-is, without any
++decompression or recompression. The signature must cover the exact
++bytes of \fIlocal_file\fP. Unlike \fBput\fP, the remote filename
++extension is not remapped and no additional compression formats are
++generated.
++.TP
+ \fBmkdir\fP \fIremote_path\fP
+ Create a new directory on the server.
+ .TP
+@@ -139,10 +155,10 @@ relative to the \fIold_path\fP minus the final component. Similarly,
+ if \fInew_path\fP ends in a slash then the final component of
+ \fIold_path\fP will be appended.
+ .PP
+-For the \fPput\fP command, except when \fB\-\-tar\fP or \fB\-\-diff\fP
+-is specified, if the \fIremote_path\fP ends in a slash then the
+-final (filename) component of \fIlocal_file\fP will be appended to the
+-final pathname.
++For the \fBput\fP command, except when \fB\-\-tar\fP or \fB\-\-diff\fP
++is specified, and for the \fBputraw\fP command, if the \fIremote_path\fP
++ends in a slash then the final (filename) component of \fIlocal_file\fP
++will be appended to the final pathname.
+ .SH CONFIG FILE
+ Kup checks the presence of $HOME/.kuprc and can load the
+ .B host
+@@ -174,6 +190,16 @@ kup put foolib-1.0.tar.bz2 foolib-1.0.tar.asc /pub/foolib/foolib-1.0.tar.bz2
+ .fi
+ .RE
+ .PP
++Upload a pre-built tarball exactly as-is (e.g. a release artifact that
++must not be altered), signing the compressed file directly:
++.PP
++.RS
++.nf
++gpg --detach-sign --armor foolib-1.0.tar.gz
++kup putraw foolib-1.0.tar.gz foolib-1.0.tar.gz.asc /pub/foolib/foolib-1.0.tar.gz
++.fi
++.RE
++.PP
+ Generate a tarball locally, sign it, then tell kup-server to generate an
+ identical tarball on the server, verify the signature, and put the compressed
+ results in /pub/foolib:
+@@ -197,6 +223,8 @@ or (at your option) any later version; incorporated herein by
+ reference. There is NO warranty; not even for MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE.
+ .SH "SEE ALSO"
++.BR kup-proto (5),
++.BR kup-server (1),
+ .BR git (1),
+ .BR ssh (1),
+ .BR gzip (1),
+
diff --git a/dev-util/kup/files/kup.tmpfilesd b/dev-util/kup/files/kup.tmpfilesd
new file mode 100644
index 000000000000..d8f2211b9aa7
--- /dev/null
+++ b/dev-util/kup/files/kup.tmpfilesd
@@ -0,0 +1,7 @@
+# see kup-server.cfg & man kup-server
+d /run/kup 0755 root root -
+f /run/kup/lock 0644 root root -
+
+# Upload tempdir; needs to be on the same filesystem as /var/lib/kup for atomic
+# move.
+d /var/lib/kup/tmp 1777 root root -
diff --git a/dev-util/kup/kup-0.3.6-r6.ebuild b/dev-util/kup/kup-0.3.6-r6.ebuild
new file mode 100644
index 000000000000..7945bf51d92c
--- /dev/null
+++ b/dev-util/kup/kup-0.3.6-r6.ebuild
@@ -0,0 +1,69 @@
+# Copyright 1999-2026 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=8
+
+inherit tmpfiles
+
+DESCRIPTION="kernel.org uploader tool"
+HOMEPAGE="https://www.kernel.org/pub/software/network/kup"
+SRC_URI="https://www.kernel.org/pub/software/network/kup/${P}.tar.xz"
+
+# Debian has sometimes carried useful patches
+#DEB_PR=6
+#DEB_P=${PN}_${PV}-${DEB_PR}
+#SRC_URI+=" mirror://debian/pool/main/${PN::1}/${PN}/${DEB_P}.debian.tar.xz"
+
+LICENSE="GPL-2"
+SLOT="0"
+KEYWORDS="amd64 ~x86"
+IUSE="gitolite"
+
+RDEPEND="
+ app-arch/pigz
+ app-arch/xz-utils
+ dev-lang/perl
+ virtual/perl-Encode
+ virtual/perl-File-Spec
+ dev-perl/BSD-Resource
+ dev-perl/Config-Simple"
+
+DOCS=( README )
+
+PATCHES=(
+ "${FILESDIR}"/${PN}-0.3.6-path-lookup-compressor.patch
+)
+
+src_prepare() {
+ if use gitolite; then
+ cp -f "${S}/${PN}-server" "${S}/${PN}-server-gitolite" || die
+ patch "${S}/${PN}-server-gitolite" <"${FILESDIR}"/${PN}-server-gitolite-subcmd-r2.patch || die
+
+ fi
+ default
+}
+
+src_install() {
+ dobin "${PN}" "${PN}-server" gpg-sign-all genrings
+ doman "${PN}.1" "${PN}-server.1"
+ insinto /etc/kup
+ doins kup-server.cfg
+ einstalldocs
+ # Gitolite expects "kup-server" inside the commands directory.
+ if use gitolite; then
+ exeinto /usr/libexec/gitolite/commands/
+ newexe kup-server-gitolite kup-server
+ # Gentoo's gitolite fork has a slightly different path:
+ exeinto /usr/libexec/gitolite-gentoo/commands/
+ dosym -r /usr/libexec/gitolite/commands/kup-server /usr/libexec/gitolite-gentoo/commands/kup-server
+ fi
+ # Important data kept here
+ keepdir /var/lib/kup/pub
+ keepdir /var/lib/kup/pgp
+ # Will create other directories
+ newtmpfiles "${FILESDIR}"/kup.tmpfilesd kup.conf
+}
+
+pkg_postinst() {
+ tmpfiles_process ${PN}.conf
+}
diff --git a/dev-util/kup/kup-0.3.6-r8.ebuild b/dev-util/kup/kup-0.3.6-r8.ebuild
new file mode 100644
index 000000000000..7bdf7331d102
--- /dev/null
+++ b/dev-util/kup/kup-0.3.6-r8.ebuild
@@ -0,0 +1,71 @@
+# Copyright 1999-2026 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=8
+
+inherit tmpfiles
+
+DESCRIPTION="kernel.org uploader tool"
+HOMEPAGE="https://www.kernel.org/pub/software/network/kup"
+SRC_URI="https://www.kernel.org/pub/software/network/kup/${P}.tar.xz"
+
+# Debian has sometimes carried useful patches
+#DEB_PR=6
+#DEB_P=${PN}_${PV}-${DEB_PR}
+#SRC_URI+=" mirror://debian/pool/main/${PN::1}/${PN}/${DEB_P}.debian.tar.xz"
+
+LICENSE="GPL-2"
+SLOT="0"
+KEYWORDS="amd64 x86"
+IUSE="gitolite"
+
+RDEPEND="
+ app-arch/pigz
+ app-arch/xz-utils
+ dev-lang/perl
+ virtual/perl-Encode
+ virtual/perl-File-Spec
+ dev-perl/BSD-Resource
+ dev-perl/Config-Simple"
+
+DOCS=( README )
+
+PATCHES=(
+ "${FILESDIR}"/${PN}-0.3.6-path-lookup-compressor.patch
+ "${FILESDIR}"/${PN}-server-putraw.patch
+)
+
+src_prepare() {
+ default
+
+ if use gitolite; then
+ cp -f "${S}/${PN}-server" "${S}/${PN}-server-gitolite" || die
+ patch "${S}/${PN}-server-gitolite" <"${FILESDIR}"/${PN}-server-gitolite-subcmd-r2.patch || die
+
+ fi
+}
+
+src_install() {
+ dobin "${PN}" "${PN}-server" gpg-sign-all genrings
+ doman "${PN}.1" "${PN}-server.1"
+ insinto /etc/kup
+ doins kup-server.cfg
+ einstalldocs
+ # Gitolite expects "kup-server" inside the commands directory.
+ if use gitolite; then
+ exeinto /usr/libexec/gitolite/commands/
+ newexe kup-server-gitolite kup-server
+ # Gentoo's gitolite fork has a slightly different path:
+ exeinto /usr/libexec/gitolite-gentoo/commands/
+ dosym -r /usr/libexec/gitolite/commands/kup-server /usr/libexec/gitolite-gentoo/commands/kup-server
+ fi
+ # Important data kept here
+ keepdir /var/lib/kup/pub
+ keepdir /var/lib/kup/pgp
+ # Will create other directories
+ newtmpfiles "${FILESDIR}"/kup.tmpfilesd kup.conf
+}
+
+pkg_postinst() {
+ tmpfiles_process ${PN}.conf
+}
diff --git a/dev-util/kup/metadata.xml b/dev-util/kup/metadata.xml
new file mode 100644
index 000000000000..c46eff616b92
--- /dev/null
+++ b/dev-util/kup/metadata.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE pkgmetadata SYSTEM "https://docs.baldeagleos.com/dtd/metadata.dtd">
+<pkgmetadata>
+ <use>
+ <flag name="gitolite">Enable support for <pkg>dev-vcs/gitolite</pkg> in kup-server</flag>
+ </use>
+ <origin>baldeagleos-repo</origin>
+</pkgmetadata>