]>
git.cameronkatri.com Git - cgit.git/blob - cgit.c
1 /* cgit.c: cgi for the git scm
3 * Copyright (C) 2006 Lars Hjemli
5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text)
11 #include "ui-shared.h"
13 static int cgit_prepare_cache(struct cacheitem
*item
)
15 if (!ctx
.repo
&& ctx
.qry
.repo
) {
16 ctx
.page
.title
= fmt("%s - %s", ctx
.cfg
.root_title
,
18 cgit_print_http_headers(&ctx
);
19 cgit_print_docstart(&ctx
);
20 cgit_print_pageheader(&ctx
);
21 cgit_print_error(fmt("Unknown repo: %s", ctx
.qry
.repo
));
27 item
->name
= xstrdup(fmt("%s/index.html", ctx
.cfg
.cache_root
));
28 item
->ttl
= ctx
.cfg
.cache_root_ttl
;
33 item
->name
= xstrdup(fmt("%s/%s/index.%s.html", ctx
.cfg
.cache_root
,
34 cache_safe_filename(ctx
.repo
->url
),
35 cache_safe_filename(ctx
.qry
.raw
)));
36 item
->ttl
= ctx
.cfg
.cache_repo_ttl
;
38 item
->name
= xstrdup(fmt("%s/%s/%s/%s.html", ctx
.cfg
.cache_root
,
39 cache_safe_filename(ctx
.repo
->url
),
41 cache_safe_filename(ctx
.qry
.raw
)));
42 if (ctx
.qry
.has_symref
)
43 item
->ttl
= ctx
.cfg
.cache_dynamic_ttl
;
44 else if (ctx
.qry
.has_sha1
)
45 item
->ttl
= ctx
.cfg
.cache_static_ttl
;
47 item
->ttl
= ctx
.cfg
.cache_repo_ttl
;
58 int find_current_ref(const char *refname
, const unsigned char *sha1
,
59 int flags
, void *cb_data
)
61 struct refmatch
*info
;
63 info
= (struct refmatch
*)cb_data
;
64 if (!strcmp(refname
, info
->req_ref
))
67 info
->first_ref
= xstrdup(refname
);
71 char *find_default_branch(struct cgit_repo
*repo
)
75 info
.req_ref
= repo
->defbranch
;
76 info
.first_ref
= NULL
;
78 for_each_branch_ref(find_current_ref
, &info
);
82 return info
.first_ref
;
85 static int prepare_repo_cmd(struct cgit_context
*ctx
)
88 unsigned char sha1
[20];
91 setenv("GIT_DIR", ctx
->repo
->path
, 1);
92 setup_git_directory_gently(&nongit
);
94 ctx
->page
.title
= fmt("%s - %s", ctx
->cfg
.root_title
,
96 tmp
= fmt("Not a git repository: '%s'", ctx
->repo
->path
);
98 cgit_print_http_headers(ctx
);
99 cgit_print_docstart(ctx
);
100 cgit_print_pageheader(ctx
);
101 cgit_print_error(tmp
);
105 ctx
->page
.title
= fmt("%s - %s", ctx
->repo
->name
, ctx
->repo
->desc
);
107 if (!ctx
->qry
.head
) {
108 ctx
->qry
.head
= xstrdup(find_default_branch(ctx
->repo
));
109 ctx
->repo
->defbranch
= ctx
->qry
.head
;
112 if (!ctx
->qry
.head
) {
113 cgit_print_http_headers(ctx
);
114 cgit_print_docstart(ctx
);
115 cgit_print_pageheader(ctx
);
116 cgit_print_error("Repository seems to be empty");
121 if (get_sha1(ctx
->qry
.head
, sha1
)) {
122 tmp
= xstrdup(ctx
->qry
.head
);
123 ctx
->qry
.head
= ctx
->repo
->defbranch
;
124 cgit_print_http_headers(ctx
);
125 cgit_print_docstart(ctx
);
126 cgit_print_pageheader(ctx
);
127 cgit_print_error(fmt("Invalid branch: %s", tmp
));
134 static void process_request(struct cgit_context
*ctx
)
136 struct cgit_cmd
*cmd
;
138 cmd
= cgit_get_cmd(ctx
);
140 ctx
->page
.title
= "cgit error";
142 cgit_print_http_headers(ctx
);
143 cgit_print_docstart(ctx
);
144 cgit_print_pageheader(ctx
);
145 cgit_print_error("Invalid request");
150 if (cmd
->want_repo
&& prepare_repo_cmd(ctx
))
153 if (cmd
->want_layout
) {
154 cgit_print_http_headers(ctx
);
155 cgit_print_docstart(ctx
);
156 cgit_print_pageheader(ctx
);
161 if (cmd
->want_layout
)
165 static long ttl_seconds(long ttl
)
168 return 60 * 60 * 24 * 365;
173 static void cgit_fill_cache(struct cacheitem
*item
, int use_cache
)
178 stdout2
= chk_positive(dup(STDOUT_FILENO
),
179 "Preserving STDOUT");
180 chk_zero(close(STDOUT_FILENO
), "Closing STDOUT");
181 chk_positive(dup2(item
->fd
, STDOUT_FILENO
), "Dup2(cachefile)");
184 ctx
.page
.modified
= time(NULL
);
185 ctx
.page
.expires
= ctx
.page
.modified
+ ttl_seconds(item
->ttl
);
186 process_request(&ctx
);
189 chk_zero(close(STDOUT_FILENO
), "Close redirected STDOUT");
190 chk_positive(dup2(stdout2
, STDOUT_FILENO
),
191 "Restoring original STDOUT");
192 chk_zero(close(stdout2
), "Closing temporary STDOUT");
196 static void cgit_check_cache(struct cacheitem
*item
)
201 if (++i
> ctx
.cfg
.max_lock_attempts
) {
202 die("cgit_refresh_cache: unable to lock %s: %s",
203 item
->name
, strerror(errno
));
205 if (!cache_exist(item
)) {
206 if (!cache_lock(item
)) {
210 if (!cache_exist(item
)) {
211 cgit_fill_cache(item
, 1);
214 cache_cancel_lock(item
);
216 } else if (cache_expired(item
) && cache_lock(item
)) {
217 if (cache_expired(item
)) {
218 cgit_fill_cache(item
, 1);
221 cache_cancel_lock(item
);
226 static void cgit_print_cache(struct cacheitem
*item
)
228 static char buf
[4096];
231 int fd
= open(item
->name
, O_RDONLY
);
233 die("Unable to open cached file %s", item
->name
);
235 while((i
=read(fd
, buf
, sizeof(buf
))) > 0)
236 write(STDOUT_FILENO
, buf
, i
);
241 static void cgit_parse_args(int argc
, const char **argv
)
245 for (i
= 1; i
< argc
; i
++) {
246 if (!strncmp(argv
[i
], "--cache=", 8)) {
247 ctx
.cfg
.cache_root
= xstrdup(argv
[i
]+8);
249 if (!strcmp(argv
[i
], "--nocache")) {
252 if (!strncmp(argv
[i
], "--query=", 8)) {
253 ctx
.qry
.raw
= xstrdup(argv
[i
]+8);
255 if (!strncmp(argv
[i
], "--repo=", 7)) {
256 ctx
.qry
.repo
= xstrdup(argv
[i
]+7);
258 if (!strncmp(argv
[i
], "--page=", 7)) {
259 ctx
.qry
.page
= xstrdup(argv
[i
]+7);
261 if (!strncmp(argv
[i
], "--head=", 7)) {
262 ctx
.qry
.head
= xstrdup(argv
[i
]+7);
263 ctx
.qry
.has_symref
= 1;
265 if (!strncmp(argv
[i
], "--sha1=", 7)) {
266 ctx
.qry
.sha1
= xstrdup(argv
[i
]+7);
267 ctx
.qry
.has_sha1
= 1;
269 if (!strncmp(argv
[i
], "--ofs=", 6)) {
270 ctx
.qry
.ofs
= atoi(argv
[i
]+6);
275 int main(int argc
, const char **argv
)
277 struct cacheitem item
;
278 const char *cgit_config_env
= getenv("CGIT_CONFIG");
280 cgit_prepare_context(&ctx
);
281 item
.st
.st_mtime
= time(NULL
);
282 cgit_repolist
.length
= 0;
283 cgit_repolist
.count
= 0;
284 cgit_repolist
.repos
= NULL
;
286 cgit_read_config(cgit_config_env
? cgit_config_env
: CGIT_CONFIG
,
287 cgit_global_config_cb
);
288 if (getenv("SCRIPT_NAME"))
289 ctx
.cfg
.script_name
= xstrdup(getenv("SCRIPT_NAME"));
290 if (getenv("QUERY_STRING"))
291 ctx
.qry
.raw
= xstrdup(getenv("QUERY_STRING"));
292 cgit_parse_args(argc
, argv
);
293 cgit_parse_query(ctx
.qry
.raw
, cgit_querystring_cb
);
294 if (!cgit_prepare_cache(&item
))
296 if (ctx
.cfg
.nocache
) {
297 cgit_fill_cache(&item
, 0);
299 cgit_check_cache(&item
);
300 cgit_print_cache(&item
);