all repos — cgit @ d14c5f6d3ac827e7b46831c4151638ab4b638ae1

a hyperfast web frontend for git written in c

cgit.c (view raw)

  1/* cgit.c: cgi for the git scm
  2 *
  3 * Copyright (C) 2006 Lars Hjemli
  4 *
  5 * Licensed under GNU General Public License v2
  6 *   (see COPYING for full license text)
  7 */
  8
  9#include "cgit.h"
 10
 11const char cgit_version[] = CGIT_VERSION;
 12
 13int htmlfd = 0;
 14
 15char *cgit_root         = "/usr/src/git";
 16char *cgit_root_title   = "Git repository browser";
 17char *cgit_css          = "/cgit.css";
 18char *cgit_logo         = "/git-logo.png";
 19char *cgit_logo_link    = "http://www.kernel.org/pub/software/scm/git/docs/";
 20char *cgit_virtual_root = NULL;
 21
 22char *cgit_cache_root   = "/var/cache/cgit";
 23
 24int cgit_max_lock_attempts     =  5;
 25int cgit_cache_root_ttl        =  5;
 26int cgit_cache_repo_ttl        =  5;
 27int cgit_cache_dynamic_ttl     =  5;
 28int cgit_cache_static_ttl      = -1;
 29int cgit_cache_max_create_time =  5;
 30
 31char *cgit_repo_name    = NULL;
 32char *cgit_repo_desc    = NULL;
 33char *cgit_repo_owner   = NULL;
 34
 35int cgit_query_has_symref = 0;
 36int cgit_query_has_sha1   = 0;
 37
 38char *cgit_querystring  = NULL;
 39char *cgit_query_repo   = NULL;
 40char *cgit_query_page   = NULL;
 41char *cgit_query_head   = NULL;
 42char *cgit_query_sha1   = NULL;
 43
 44struct cacheitem cacheitem;
 45
 46void cgit_global_config_cb(const char *name, const char *value)
 47{
 48	if (!strcmp(name, "root"))
 49		cgit_root = xstrdup(value);
 50	else if (!strcmp(name, "root-title"))
 51		cgit_root_title = xstrdup(value);
 52	else if (!strcmp(name, "css"))
 53		cgit_css = xstrdup(value);
 54	else if (!strcmp(name, "logo"))
 55		cgit_logo = xstrdup(value);
 56	else if (!strcmp(name, "logo-link"))
 57		cgit_logo_link = xstrdup(value);
 58	else if (!strcmp(name, "virtual-root"))
 59		cgit_virtual_root = xstrdup(value);
 60}
 61
 62void cgit_repo_config_cb(const char *name, const char *value)
 63{
 64	if (!strcmp(name, "name"))
 65		cgit_repo_name = xstrdup(value);
 66	else if (!strcmp(name, "desc"))
 67		cgit_repo_desc = xstrdup(value);
 68	else if (!strcmp(name, "owner"))
 69		cgit_repo_owner = xstrdup(value);
 70}
 71
 72void cgit_querystring_cb(const char *name, const char *value)
 73{
 74	if (!strcmp(name,"r"))
 75		cgit_query_repo = xstrdup(value);
 76	else if (!strcmp(name, "p"))
 77		cgit_query_page = xstrdup(value);
 78	else if (!strcmp(name, "h")) {
 79		cgit_query_head = xstrdup(value);
 80		cgit_query_has_symref = 1;
 81	} else if (!strcmp(name, "id")) {
 82		cgit_query_sha1 = xstrdup(value);
 83		cgit_query_has_sha1 = 1;
 84	}
 85}
 86
 87static void cgit_print_object(char *hex)
 88{
 89	unsigned char sha1[20];
 90	//struct object *object;
 91	char type[20];
 92	unsigned char *buf;
 93	unsigned long size;
 94
 95	if (get_sha1_hex(hex, sha1)){
 96		cgit_print_error(fmt("Bad hex value: %s", hex));
 97	        return;
 98	}
 99
100	if (sha1_object_info(sha1, type, NULL)){
101		cgit_print_error("Bad object name");
102		return;
103	}
104
105	buf = read_sha1_file(sha1, type, &size);
106	if (!buf) {
107		cgit_print_error("Error reading object");
108		return;
109	}
110
111	buf[size] = '\0';
112	html("<h2>Object view</h2>");
113	htmlf("sha1=%s<br/>type=%s<br/>size=%i<br/>", hex, type, size);
114	html("<pre>");
115	html_txt(buf);
116	html("</pre>");
117}
118
119static void cgit_print_repo_page(struct cacheitem *item)
120{
121	if (chdir(fmt("%s/%s", cgit_root, cgit_query_repo)) || 
122	    cgit_read_config("info/cgit", cgit_repo_config_cb)) {
123		char *title = fmt("%s - %s", cgit_root_title, "Bad request");
124		cgit_print_docstart(title, item);
125		cgit_print_pageheader(title);
126		cgit_print_error(fmt("Unable to scan repository: %s",
127				     strerror(errno)));
128		cgit_print_docend();
129		return;
130	}
131	setenv("GIT_DIR", fmt("%s/%s", cgit_root, cgit_query_repo), 1);
132	char *title = fmt("%s - %s", cgit_repo_name, cgit_repo_desc);
133	cgit_print_docstart(title, item);
134	cgit_print_pageheader(title);
135	if (!cgit_query_page)
136		cgit_print_summary();
137	else if (!strcmp(cgit_query_page, "log")) {
138		cgit_print_log(cgit_query_head, 0, 100);
139	} else if (!strcmp(cgit_query_page, "view")) {
140		cgit_print_object(cgit_query_sha1);
141	}
142	cgit_print_docend();
143}
144
145static void cgit_fill_cache(struct cacheitem *item)
146{
147	htmlfd = item->fd;
148	item->st.st_mtime = time(NULL);
149	if (cgit_query_repo)
150		cgit_print_repo_page(item);
151	else
152		cgit_print_repolist(item);
153}
154
155static void cgit_refresh_cache(struct cacheitem *item)
156{
157	int i = 0;
158
159	cache_prepare(item);
160 top:
161	if (++i > cgit_max_lock_attempts) {
162		die("cgit_refresh_cache: unable to lock %s: %s",
163		    item->name, strerror(errno));
164	}
165	if (!cache_exist(item)) {
166		if (!cache_lock(item)) {
167			sleep(1);
168			goto top;
169		}
170		if (!cache_exist(item))
171			cgit_fill_cache(item);
172		cache_unlock(item);
173	} else if (cache_expired(item) && cache_lock(item)) {
174		if (cache_expired(item))
175			cgit_fill_cache(item);
176		cache_unlock(item);
177	}
178}
179
180static void cgit_print_cache(struct cacheitem *item)
181{
182	static char buf[4096];
183	ssize_t i;
184
185	int fd = open(item->name, O_RDONLY);
186	if (fd<0)
187		die("Unable to open cached file %s", item->name);
188
189	while((i=read(fd, buf, sizeof(buf))) > 0)
190		write(STDOUT_FILENO, buf, i);
191
192	close(fd);
193}
194
195int main(int argc, const char **argv)
196{
197	cgit_read_config("/etc/cgitrc", cgit_global_config_cb);
198	cgit_querystring = xstrdup(getenv("QUERY_STRING"));
199	cgit_parse_query(cgit_querystring, cgit_querystring_cb);
200	cgit_refresh_cache(&cacheitem);
201	cgit_print_cache(&cacheitem);
202	return 0;
203}