all repos — cgit @ df63119302910587e280d91dce67f6537a671f74

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_repo_page(struct cacheitem *item)
 88{
 89	if (chdir(fmt("%s/%s", cgit_root, cgit_query_repo)) || 
 90	    cgit_read_config("info/cgit", cgit_repo_config_cb)) {
 91		char *title = fmt("%s - %s", cgit_root_title, "Bad request");
 92		cgit_print_docstart(title, item);
 93		cgit_print_pageheader(title);
 94		cgit_print_error(fmt("Unable to scan repository: %s",
 95				     strerror(errno)));
 96		cgit_print_docend();
 97		return;
 98	}
 99	setenv("GIT_DIR", fmt("%s/%s", cgit_root, cgit_query_repo), 1);
100	char *title = fmt("%s - %s", cgit_repo_name, cgit_repo_desc);
101	cgit_print_docstart(title, item);
102	cgit_print_pageheader(title);
103	if (!cgit_query_page)
104		cgit_print_summary();
105	else if (!strcmp(cgit_query_page, "log")) {
106		cgit_print_log(cgit_query_head, 0, 100);
107	} else if (!strcmp(cgit_query_page, "view")) {
108		cgit_print_view(cgit_query_sha1);
109	}
110	cgit_print_docend();
111}
112
113static void cgit_fill_cache(struct cacheitem *item)
114{
115	htmlfd = item->fd;
116	item->st.st_mtime = time(NULL);
117	if (cgit_query_repo)
118		cgit_print_repo_page(item);
119	else
120		cgit_print_repolist(item);
121}
122
123static void cgit_refresh_cache(struct cacheitem *item)
124{
125	int i = 0;
126
127	cache_prepare(item);
128 top:
129	if (++i > cgit_max_lock_attempts) {
130		die("cgit_refresh_cache: unable to lock %s: %s",
131		    item->name, strerror(errno));
132	}
133	if (!cache_exist(item)) {
134		if (!cache_lock(item)) {
135			sleep(1);
136			goto top;
137		}
138		if (!cache_exist(item))
139			cgit_fill_cache(item);
140		cache_unlock(item);
141	} else if (cache_expired(item) && cache_lock(item)) {
142		if (cache_expired(item))
143			cgit_fill_cache(item);
144		cache_unlock(item);
145	}
146}
147
148static void cgit_print_cache(struct cacheitem *item)
149{
150	static char buf[4096];
151	ssize_t i;
152
153	int fd = open(item->name, O_RDONLY);
154	if (fd<0)
155		die("Unable to open cached file %s", item->name);
156
157	while((i=read(fd, buf, sizeof(buf))) > 0)
158		write(STDOUT_FILENO, buf, i);
159
160	close(fd);
161}
162
163int main(int argc, const char **argv)
164{
165	cgit_read_config("/etc/cgitrc", cgit_global_config_cb);
166	cgit_querystring = xstrdup(getenv("QUERY_STRING"));
167	cgit_parse_query(cgit_querystring, cgit_querystring_cb);
168	cgit_refresh_cache(&cacheitem);
169	cgit_print_cache(&cacheitem);
170	return 0;
171}