Mind Chasers Inc.
Mind Chasers 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://mindchasers.com 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 again 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
$ make
$ make install

$ tree /opt/cgit
/opt/cgit
├── bin
│   ├── cgit.cgi
│   ├── cgit.css
│   ├── 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:

$ cd /opt/cgit/bin
$ ./cgit.cgi

Content-Type: text/html; charset=UTF-8
Last-Modified: Sun, 03 Mar 2019 20:21:24 GMT
Expires: Sun, 03 Mar 2019 20:26:24 GMT

<!DOCTYPE html>
<html lang='en'>
<head>
<title>Git repository browser</title>
<meta name='generator' content='cgit v1.2.1-18-gbd029'/>
<meta name='robots' content='index, nofollow'/>
<link rel='stylesheet' type='text/css' href='/cgit.css'/>
<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 title='tst-git' 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' title='2019-03-03 20:18:57 +0000'>2 min.</span></td></tr>
</table></div> <!-- class=content -->
<div class='footer'>generated by <a href='https://git.zx2c4.com/cgit/about/'>cgit v1.2.1-18-gbd029</a> (<a href='https://git-scm.com/'>git 2.20.0</a>) at 2019-03-03 20:21:24 +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=, 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=, path=, key=, ttl=, 
    fn=fn@entry=0x555555561d70 ) at ../cache.c:370
#6  0x0000555555562ad7 in cmd_main (argc=, argv=) 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()

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 follow us on Twitter and join our mailing list.

Related articles on this site:

share
subscribe to mailing list:

Please help us improve this article by adding your comment or question:

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