git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [BUG?] git-daemon 2.49.0 in F40 no longer exports user directories

From
Jeff King <peff@peff.net>
Date
Jul 26, 2025, 07:51 UTC
Message-ID
<20250726075136.GA3032762@coredump.intra.peff.net>
In-Reply-To
<aIOslkzu-x8K9o_C@shell.armlinux.org.uk>
On Fri, Jul 25, 2025 at 05:11:02PM +0100, Russell King (Oracle) wrote:
Show 5 quoted lines
> While I've been away on holiday over the last three weeks, my co-admin
> updated ZenIV to Fedora 40, and now I find that git-daemon no longer
> exports my "public_git" directory. My attempts at debugging this have
> failed - I tried adding strace to the git@.service but I get nothing.
> This is a regression.

I'm not aware of anything changing here recently, and ~user expansion does seem to work for me. E.g. using v2.49.0 and running:

  git daemon --base-path=/tmp/foo --export-all --user-path=public_git \
	--verbose --log-destination=stderr
and then running:
  mkdir ~peff/public_git
  git init --bare ~peff/public_git/repo.git
  git -C ~peff/public_git/repo.git --work-tree=. commit --allow-empty -m foo
  git ls-remote git://localhost/~peff/repo.git
works. I get a similar log message to you here:
> Jul 25 16:56:55 ZenIV git-daemon[4046439]: [4046439] userpath <public_git>, request <~rmk/linux-arm.git/>, namlen 4, restlen 15, slash </linux-arm.git/>

That is, even though we print ~peff (or ~rmk), I think we still look for repos in /home/peff. E.g., if I strace and substitute "none.git" (to make the trace smaller, since we won't find a repo), I see it looking at:

  
  newfstatat(AT_FDCWD, "/home/peff/public_git/none.git/.git", 0x7ffc1cf9c8d0, 0) = -1 ENOENT (No such file or directory)
  newfstatat(AT_FDCWD, "/home/peff/public_git/none.git", 0x7ffc1cf9c8d0, 0) = -1 ENOENT (No such file or directory)
  newfstatat(AT_FDCWD, "/home/peff/public_git/none.git.git/.git", 0x7ffc1cf9c8d0, 0) = -1 ENOENT (No such file or directory)
  newfstatat(AT_FDCWD, "/home/peff/public_git/none.git.git", 0x7ffc1cf9c8d0, 0) = -1 ENOENT (No such file or directory)
If you strace, do you see similar stat calls?
But of course I don't get this log line:
> Jul 25 16:56:55 ZenIV git-daemon[4046439]: [4046439] '~rmk/public_git/linux-arm.git': not in directory list

which isn't too surprising since things succeed for me. But the "not in directory list" part is interesting. If we could not find the repo on disk, we get something more like:

  '~peff/public_git/none.git' does not appear to be a git repository

Looking through daemon.c:path_ok(), if we see the user-path expansion but not "does not appear to be a git repository", then we're getting hung up on this code:

          if ( ok_paths && *ok_paths ) {
                  const char **pp;
                  int pathlen = strlen(path);
  
                  /* The validation is done on the paths after enter_repo
                   * appends optional {.git,.git/.git} and friends, but
                   * it does not use getcwd().  So if your /pub is
                   * a symlink to /mnt/pub, you can include /pub and
                   * do not have to say /mnt/pub.
                   * Do not say /pub/.
                   */
                  for ( pp = ok_paths ; *pp ; pp++ ) {
                          int len = strlen(*pp);
                          if (len <= pathlen &&
                              !memcmp(*pp, path, len) &&
                              (path[len] == '\0' ||
                               (!strict_paths && path[len] == '/')))
                                  return path;
                  }
          }
          else {
                  /* be backwards compatible */
                  if (!strict_paths)
                          return path;
          }

My command line does not set --strict-paths, and neither does yours. So presumably you are stuck on the ok_paths. But those come from non-option paths on the git-daemon command line. My invocation does not pass any, and from what you wrote here:

Show 12 quoted lines
> and /lib/systemd/system/git@.service contains:
> 
> [Unit]
> Description=Git Repositories Server Daemon
> Documentation=man:git-daemon(1)
> 
> [Service]
> User=nobody
> ExecStart=-/usr/libexec/git-core/git-daemon --base-path=/var/lib/git --export-all \
>           --user-path=public_git --inetd --log-destination=stderr --verbose
> StandardInput=socket
> StandardError=journal

neither do you. Is it possible that when invoking git-daemon, systemd is adding more arguments? Can you check with systemd logs or via strace (or maybe even ps, though I guess the process is short-lived in inetd mode)?

I'm not very familiar with systemd, but IIRC @-services are just templates that expect an argument. And in this case the argument is filled in when the git.socket service runs the git@ unit for a single connection. But I think that argument is only expanded by a %-placeholder, not shoved onto the ExecStart line.

So I dunno. I am just guessing at the systemd connection. But it seems like somehow an extra argument is ending up in your git-daemon invocation.

-Peff
PS My invocation above is obviously not running in --inetd mode like
   yours is, but I don't think that's the culprit. If I put this into
   /tmp/proxy:
     #!/bin/sh
     exec git daemon --base-path=/tmp/foo --export-all --inetd \
	--user-path=public_git --log-destination=stderr --verbose
  and then invoke it directly:
    git -c core.gitproxy=/tmp/proxy ls-remote git://localhost/~peff/repo.git
  it works the same.
  I also tried taking the FC40 git@.service and git.socket files and
  sticking them in my systemd setup, and it also seems to work. So I am
  all out of guesses.
Previous: Russell King (Oracle)Next: Todd Zullinger
Message 2 of 5 in “[BUG?] git-daemon 2.49.0 in F40 no longer exports user directories”
  1. Russell King (Oracle)Jul 25, 2025
  2. Jeff KingJul 26, 2025
  3. Todd ZullingerJul 26, 2025
  4. Jeff KingJul 27, 2025
  5. Russell King (Oracle)Jul 27, 2025

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.