Private Island Networks Inc.

Build, Test, and Debug cGit - the hyperfast web frontend for Git, on Ubuntu Linux 18.04

A brief summary of getting started with cgit on Ubuntu Linux along with debugging a segfault we encountered

Overview

We use cgit to host our open source Git repositories on https://privateisland.tech and also for our internal projects on local web servers. If you're not already familiar with cgit, it is a popular Common Gateway Interface (CGI) web interface written in the C language. We interact with it externally on a daily basis with sites like The Yocto Project. cgit is highly customizable, provides an intuitive web interface, and allows developers to continue working with their Git repos directly using a shell (as opposed to Github) regardless of whether the repo is bare or has a working directory.

One of the great things about the cgit CGI application is that it can be tested and debugged on a command line independent of how it is deployed (e.g., Apache), and we show this below while also building cgit from its own repo. The cgit README includes easy build instructions, but we include them below for the sake of completeness.

Clone and build cgit:

$ cd /build
$ git clone https://git.zx2c4.com/cgit/ cgit
Cloning into 'cgit'...

$ cd cgit

$ git submodule init 
Submodule 'git' (https://git.kernel.org/pub/scm/git/git.git) registered for path 'git'

$ git submodule update
Cloning into '/build/cgit/git'...

Before building the code, we create a cgit.conf file to customize the installation (i.e., install into /opt/cgit):

CGIT_SCRIPT_PATH = /opt/cgit/bin
CGIT_CONFIG = /opt/cgit/etc/cgitrc
CACHE_ROOT = /opt/cgit/cache/cgit
prefix = /opt/cgit/local

And the installed package requirements to make both cgit and git on Ubuntu are minimal:

$ sudo apt install build-essential libssl-dev zlib1g-dev

Let's build it:

$ make
$ make install

$ tree /opt/cgit
/opt/cgit
.
├── bin
│   ├── cgit.cgi
│   ├── cgit.css
│   ├── cgit.js
│   ├── cgit.png
│   ├── favicon.ico
│   └── robots.txt
└── local
    └── lib
        └── cgit
            └── filters
                ├── about-formatting.sh
                ├── commit-links.sh
                ├── email-gravatar.lua
                ├── email-gravatar.py
                ├── email-libravatar.lua
                ├── file-authentication.lua
                ├── gentoo-ldap-authentication.lua
                ├── html-converters
                │   ├── man2html
                │   ├── md2html
                │   ├── rst2html
                │   └── txt2html
                ├── owner-example.lua
                ├── simple-authentication.lua
                ├── syntax-highlighting.py
                └── syntax-highlighting.sh

Now create a simple test repo for the purpose of verifying cgit operation and add the repo to the etc/cgitrc file:

$ mkdir /opt/tst-git; cd /opt/tst-git
$ touch a
$ git init
Initialized empty Git repository in /opt/tst-git/.git/

$ git add .
$ git commit -m 'initial commit'
[master (root-commit) 7891040] initial commit
...

$ mkdir -p /opt/cgit/etc
$ touch /opt/cgit/etc/cgitrc

Add the following lines to etc/cgitrc:

repo.url=tst-git
repo.path=/opt/tst-git/.git

Now try running cgit.cgi from the command line:

$ ./cgit.cgi 
Content-Type: text/html; charset=UTF-8
Last-Modified: Sun, 15 Sep 2024 03:33:37 GMT
Expires: Sun, 15 Sep 2024 03:38:37 GMT

<!DOCTYPE html>
<html lang='en'>
<head>
<title>Git repository browser</title>
<meta name='generator' content='cgit v1.2.3-70-g09d2'/>
<meta name='robots' content='index, nofollow'/>
<link rel='stylesheet' type='text/css' href='/cgit.css'/>
<script type='text/javascript' src='/cgit.js'></script>
<link rel='shortcut icon' href='/favicon.ico'/>
</head>
<body>
<div id='cgit'><table id='header'>
<tr>
<td class='logo' rowspan='2'><a href='cgit.cgi/'><img src='/cgit.png' alt='cgit logo'/></a></td>
<td class='main'>Git repository browser</td></tr>
<tr><td class='sub'>a fast webinterface for the git dscm</td></tr></table>
<table class='tabs'><tr><td>
<a class='active' href='cgit.cgi/'>index</a></td><td class='form'><form method='get' action='cgit.cgi/'>
<input type='search' name='q' size='10' value=''/>
<input type='submit' value='search'/>
</form></td></tr></table>
<div class='content'><table summary='repository list' class='list nowrap'><tr class='nohover'><th class='left'><a href='cgit.cgi/?s=name'>Name</a></th><th class='left'><a href='cgit.cgi/?s=desc'>Description</a></th><th class='left'><a href='cgit.cgi/?s=owner'>Owner</a></th><th class='left'><a href='cgit.cgi/?s=idle'>Idle</a></th></tr>
<tr><td class='toplevel-repo'><a href='cgit.cgi/tst-git/'>tst-git</a></td><td><a href='cgit.cgi/tst-git/'>[no description]</a></td><td><a href='cgit.cgi/?q='></a></td><td><span class='age-mins' data-ut='1726371138' title='2024-09-15 03:32:18 +0000'>1 min.</span></td></tr>
</table></div> <!-- class=content -->
<div class='footer'>generated by <a href='https://git.zx2c4.com/cgit/about/'>cgit v1.2.3-70-g09d2</a> (<a href='https://git-scm.com/'>git 2.46.0</a>) at 2024-09-15 03:33:37 +0000</div>
</div> <!-- id=cgit -->
</body>
</html>

Next, you can test that cgit returns the repo's contents when passing the tst-git url to it:

$ QUERY_STRING="url=tst-git" ./cgit.cgi 
...

Below is how this looks when served up from our local Apache web server:

cgit web interface
Figure 1. Serve cgit with Apache

Debugging cgit

When we first started testing cgit, we were getting a segfault due to a typo in our cgitrc file. Instead of "repo.path", we had "reo.path". Here's how we debugged / discovered it:

$ QUERY_STRING="url=tst-git" ./cgit.cgi 
Segmentation fault (core dumped)

Next, we run it again, but this time with gdb and generate a backtrace:

$ QUERY_STRING="url=tst-git" gdb ./cgit.cgi 
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
...
(gdb) run
Starting program: /opt/cgit/bin/cgit.cgi 
Program received signal SIGSEGV, Segmentation fault.
__strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:120
120	../sysdeps/x86_64/multiarch/../strlen.S: No such file or directory.
(gdb) backtrace
#0  __strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:120
#1  0x00007ffff73e2aa9 in __add_to_environ (name=name@entry=0x55555569acef "GIT_DIR", value=0x0, combined=combined@entry=0x0, 
    replace=replace@entry=1) at setenv.c:131
#2  0x00007ffff73e2c8a in __setenv (name=name@entry=0x55555569acef "GIT_DIR", value=<optimized
		out>, replace=replace@entry=1) at setenv.c:259
#3  0x0000555555561dc5 in prepare_repo_env (nongit=0x7fffffffcfdc) at ../cgit.c:564
#4  process_request () at ../cgit.c:718
#5  0x00005555555636bc in cache_process (size=<optimized out>, path=<optimized
		out>, key=<optimized out>, ttl=<optimized out>, 
    fn=fn@entry=0x555555561d70 <process_request>) at ../cache.c:370
#6  0x0000555555562ad7 in cmd_main (argc=<optimized out>, argv=<optimized
		out>) at ../cgit.c:1096
#7  0x000055555555f6af in main (argc=1, argv=0x7fffffffe438) at common-main.c:45

From here, we started stepping through the code in prepare_repo_env and soon realized that repo.path was set to null and causing the segfault.

Instead of stepping through the code in gdb on the command line, we created a quick C project for it in Eclipse inside our /build/cgit directory, set the CGIT_CONFIG and QUERY_STRING environment variables, and found the problem by stepping through the /build/cgit application in the Eclipse IDE.

Testing with Apache

Below we follow Apache's Tutorial on Dynamic Content with CGI to set up a test cgit server using the Apache Web Server on Ubuntu 18.04 Linux.

Make sure we have cgid module support enabled:

$ ls -l /etc/apache2/mods-enabled/*cgi*
ls: cannot access '/etc/apache2/mods-enabled/*cgi*': No such file or directory

$ sudo a2enmod cgid
Enabling module cgid.

$ sudo apachectl -k restart

$ ls -l /etc/apache2/mods-enabled/*cgi*
lrwxrwxrwx 1 root root 27 Apr 29 17:43 /etc/apache2/mods-enabled/cgid.conf -> ../mods-available/cgid.conf
lrwxrwxrwx 1 root root 27 Apr 29 17:43 /etc/apache2/mods-enabled/cgid.load -> ../mods-available/cgid.load

Specify the location of our static files in our "cgitrc" file:

css=/static/cgit.css
logo=/static/cgit.png
repo.url=tst-git
repo.path=/opt/tst-git/.git

Modify our apache2.conf file

ScriptAlias "/repos/"  "/opt/cgit/bin/"

<Directory /opt/cgit/bin/>
	Require all granted
</Directory>

Restart your Apache server and visit cgit.cgi (e.g., http://<host>/repos/cgit.cgi). You should see something similar to Figure 1.

Super Simple Python CGI Script

The Apache Tutorial covers a lot of great material and provides some simple example CGI scripts in Perl. However, if you're looking for something in Python, try this one (prints the environment):

#!/usr/bin/python3
import cgi
print("Content-Type:text/html\n\n")
cgi.print_environ()

Making Repo Changes via HTTP

As we understand it, cgit is for viewing repositories and not making changes (i.e., pushing a new commit). Fortunately Git itself provides CGI backend scripts that can be used to set up a Smart HTTP server. We document the basic steps for this in Build an Apache HTTP Server from Source and Configure it to Work as a GIT HTTP Server

We'll continue updating this article as we progress with cgit...

Additional References

Didn't find an answer to your question? Post your issue below or in our new FORUM, and we'll try our best to help you find a solution.

And please note that we update our site daily with new content related to our open source approach to network security and system design. If you would like to be notified about these changes, then please join our mailing list.

Related articles on this site:

share
subscribe to mailing list:

Date: Nov. 17, 2019

Author: Peter

Comment:

Thank you for this tutorial. I managed to get everything working just by following along, up until I viewed the tst-git repository on localhost, and the .css file was not found. I finally got this working by editing cgit/etc/cgitrc as: css=/cgit.css logo=/cgit.png and copying those two files from cgit/bin to /var/www/html/ Is this step required, or is there a setup option I'm missing?

Date: Nov. 17, 2019

Author: Mind Chasers

Comment:

Hi Peter. Yes, you did the right thing. BTW, you can refer to "cgitrc.5.txt" in your cloned repo for extensive documentation on cgitrc.

Add a new comment here or reply to one above:

your email address will be kept private
authenticate with a 3rd party for enhanced features, such as image upload
previous month
next month
Su
Mo
Tu
Wd
Th
Fr
Sa
loading