Code

git-svn: correctly display fatal() error messages
[git.git] / receive-pack.c
1 #include "cache.h"
2 #include "pack.h"
3 #include "refs.h"
4 #include "pkt-line.h"
5 #include "run-command.h"
6 #include "exec_cmd.h"
7 #include "commit.h"
8 #include "object.h"
9 #include <sys/wait.h>
11 static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
13 static int deny_non_fast_forwards = 0;
14 static int unpack_limit = 5000;
15 static int report_status;
17 static char capabilities[] = "report-status";
18 static int capabilities_sent;
20 static int receive_pack_config(const char *var, const char *value)
21 {
22         git_default_config(var, value);
24         if (strcmp(var, "receive.denynonfastforwards") == 0)
25         {
26                 deny_non_fast_forwards = git_config_bool(var, value);
27                 return 0;
28         }
30         if (strcmp(var, "receive.unpacklimit") == 0)
31         {
32                 unpack_limit = git_config_int(var, value);
33                 return 0;
34         }
36         return 0;
37 }
39 static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
40 {
41         if (capabilities_sent)
42                 packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
43         else
44                 packet_write(1, "%s %s%c%s\n",
45                              sha1_to_hex(sha1), path, 0, capabilities);
46         capabilities_sent = 1;
47         return 0;
48 }
50 static void write_head_info(void)
51 {
52         for_each_ref(show_ref, NULL);
53         if (!capabilities_sent)
54                 show_ref("capabilities^{}", null_sha1, 0, NULL);
56 }
58 struct command {
59         struct command *next;
60         const char *error_string;
61         unsigned char old_sha1[20];
62         unsigned char new_sha1[20];
63         char ref_name[FLEX_ARRAY]; /* more */
64 };
66 static struct command *commands;
68 static char update_hook[] = "hooks/update";
70 static int run_update_hook(const char *refname,
71                            char *old_hex, char *new_hex)
72 {
73         int code;
75         if (access(update_hook, X_OK) < 0)
76                 return 0;
77         code = run_command(update_hook, refname, old_hex, new_hex, NULL);
78         switch (code) {
79         case 0:
80                 return 0;
81         case -ERR_RUN_COMMAND_FORK:
82                 return error("hook fork failed");
83         case -ERR_RUN_COMMAND_EXEC:
84                 return error("hook execute failed");
85         case -ERR_RUN_COMMAND_WAITPID:
86                 return error("waitpid failed");
87         case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
88                 return error("waitpid is confused");
89         case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
90                 return error("%s died of signal", update_hook);
91         case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
92                 return error("%s died strangely", update_hook);
93         default:
94                 error("%s exited with error code %d", update_hook, -code);
95                 return -code;
96         }
97 }
99 static int update(struct command *cmd)
101         const char *name = cmd->ref_name;
102         unsigned char *old_sha1 = cmd->old_sha1;
103         unsigned char *new_sha1 = cmd->new_sha1;
104         char new_hex[41], old_hex[41];
105         struct ref_lock *lock;
107         cmd->error_string = NULL;
108         if (!strncmp(name, "refs/", 5) && check_ref_format(name + 5)) {
109                 cmd->error_string = "funny refname";
110                 return error("refusing to create funny ref '%s' locally",
111                              name);
112         }
114         strcpy(new_hex, sha1_to_hex(new_sha1));
115         strcpy(old_hex, sha1_to_hex(old_sha1));
116         if (!has_sha1_file(new_sha1)) {
117                 cmd->error_string = "bad pack";
118                 return error("unpack should have generated %s, "
119                              "but I can't find it!", new_hex);
120         }
121         if (deny_non_fast_forwards && !is_null_sha1(old_sha1) &&
122             !strncmp(name, "refs/heads/", 11)) {
123                 struct commit *old_commit, *new_commit;
124                 struct commit_list *bases, *ent;
126                 old_commit = (struct commit *)parse_object(old_sha1);
127                 new_commit = (struct commit *)parse_object(new_sha1);
128                 bases = get_merge_bases(old_commit, new_commit, 1);
129                 for (ent = bases; ent; ent = ent->next)
130                         if (!hashcmp(old_sha1, ent->item->object.sha1))
131                                 break;
132                 free_commit_list(bases);
133                 if (!ent)
134                         return error("denying non-fast forward;"
135                                      " you should pull first");
136         }
137         if (run_update_hook(name, old_hex, new_hex)) {
138                 cmd->error_string = "hook declined";
139                 return error("hook declined to update %s", name);
140         }
142         lock = lock_any_ref_for_update(name, old_sha1);
143         if (!lock) {
144                 cmd->error_string = "failed to lock";
145                 return error("failed to lock %s", name);
146         }
147         write_ref_sha1(lock, new_sha1, "push");
149         fprintf(stderr, "%s: %s -> %s\n", name, old_hex, new_hex);
150         return 0;
153 static char update_post_hook[] = "hooks/post-update";
155 static void run_update_post_hook(struct command *cmd)
157         struct command *cmd_p;
158         int argc;
159         const char **argv;
161         if (access(update_post_hook, X_OK) < 0)
162                 return;
163         for (argc = 1, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
164                 if (cmd_p->error_string)
165                         continue;
166                 argc++;
167         }
168         argv = xmalloc(sizeof(*argv) * (1 + argc));
169         argv[0] = update_post_hook;
171         for (argc = 1, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
172                 char *p;
173                 if (cmd_p->error_string)
174                         continue;
175                 p = xmalloc(strlen(cmd_p->ref_name) + 1);
176                 strcpy(p, cmd_p->ref_name);
177                 argv[argc] = p;
178                 argc++;
179         }
180         argv[argc] = NULL;
181         run_command_v_opt(argc, argv, RUN_COMMAND_NO_STDIO);
184 /*
185  * This gets called after(if) we've successfully
186  * unpacked the data payload.
187  */
188 static void execute_commands(void)
190         struct command *cmd = commands;
192         while (cmd) {
193                 update(cmd);
194                 cmd = cmd->next;
195         }
196         run_update_post_hook(commands);
199 static void read_head_info(void)
201         struct command **p = &commands;
202         for (;;) {
203                 static char line[1000];
204                 unsigned char old_sha1[20], new_sha1[20];
205                 struct command *cmd;
206                 char *refname;
207                 int len, reflen;
209                 len = packet_read_line(0, line, sizeof(line));
210                 if (!len)
211                         break;
212                 if (line[len-1] == '\n')
213                         line[--len] = 0;
214                 if (len < 83 ||
215                     line[40] != ' ' ||
216                     line[81] != ' ' ||
217                     get_sha1_hex(line, old_sha1) ||
218                     get_sha1_hex(line + 41, new_sha1))
219                         die("protocol error: expected old/new/ref, got '%s'",
220                             line);
222                 refname = line + 82;
223                 reflen = strlen(refname);
224                 if (reflen + 82 < len) {
225                         if (strstr(refname + reflen + 1, "report-status"))
226                                 report_status = 1;
227                 }
228                 cmd = xmalloc(sizeof(struct command) + len - 80);
229                 hashcpy(cmd->old_sha1, old_sha1);
230                 hashcpy(cmd->new_sha1, new_sha1);
231                 memcpy(cmd->ref_name, line + 82, len - 81);
232                 cmd->error_string = "n/a (unpacker error)";
233                 cmd->next = NULL;
234                 *p = cmd;
235                 p = &cmd->next;
236         }
239 static const char *parse_pack_header(struct pack_header *hdr)
241         char *c = (char*)hdr;
242         ssize_t remaining = sizeof(struct pack_header);
243         do {
244                 ssize_t r = xread(0, c, remaining);
245                 if (r <= 0)
246                         return "eof before pack header was fully read";
247                 remaining -= r;
248                 c += r;
249         } while (remaining > 0);
250         if (hdr->hdr_signature != htonl(PACK_SIGNATURE))
251                 return "protocol error (pack signature mismatch detected)";
252         if (!pack_version_ok(hdr->hdr_version))
253                 return "protocol error (pack version unsupported)";
254         return NULL;
257 static const char *pack_lockfile;
259 static const char *unpack(void)
261         struct pack_header hdr;
262         const char *hdr_err;
263         char hdr_arg[38];
265         hdr_err = parse_pack_header(&hdr);
266         if (hdr_err)
267                 return hdr_err;
268         snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%u,%u",
269                         ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries));
271         if (ntohl(hdr.hdr_entries) < unpack_limit) {
272                 int code;
273                 const char *unpacker[3];
274                 unpacker[0] = "unpack-objects";
275                 unpacker[1] = hdr_arg;
276                 unpacker[2] = NULL;
277                 code = run_command_v_opt(1, unpacker, RUN_GIT_CMD);
278                 switch (code) {
279                 case 0:
280                         return NULL;
281                 case -ERR_RUN_COMMAND_FORK:
282                         return "unpack fork failed";
283                 case -ERR_RUN_COMMAND_EXEC:
284                         return "unpack execute failed";
285                 case -ERR_RUN_COMMAND_WAITPID:
286                         return "waitpid failed";
287                 case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
288                         return "waitpid is confused";
289                 case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
290                         return "unpacker died of signal";
291                 case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
292                         return "unpacker died strangely";
293                 default:
294                         return "unpacker exited with error code";
295                 }
296         } else {
297                 const char *keeper[6];
298                 int fd[2], s, len, status;
299                 pid_t pid;
300                 char keep_arg[256];
301                 char packname[46];
303                 s = sprintf(keep_arg, "--keep=receive-pack %i on ", getpid());
304                 if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
305                         strcpy(keep_arg + s, "localhost");
307                 keeper[0] = "index-pack";
308                 keeper[1] = "--stdin";
309                 keeper[2] = "--fix-thin";
310                 keeper[3] = hdr_arg;
311                 keeper[4] = keep_arg;
312                 keeper[5] = NULL;
314                 if (pipe(fd) < 0)
315                         return "index-pack pipe failed";
316                 pid = fork();
317                 if (pid < 0)
318                         return "index-pack fork failed";
319                 if (!pid) {
320                         dup2(fd[1], 1);
321                         close(fd[1]);
322                         close(fd[0]);
323                         execv_git_cmd(keeper);
324                         die("execv of index-pack failed");
325                 }
326                 close(fd[1]);
328                 /*
329                  * The first thing we expects from index-pack's output
330                  * is "pack\t%40s\n" or "keep\t%40s\n" (46 bytes) where
331                  * %40s is the newly created pack SHA1 name.  In the "keep"
332                  * case, we need it to remove the corresponding .keep file
333                  * later on.  If we don't get that then tough luck with it.
334                  */
335                 for (len = 0;
336                      len < 46 && (s = xread(fd[0], packname+len, 46-len)) > 0;
337                      len += s);
338                 close(fd[0]);
339                 if (len == 46 && packname[45] == '\n' &&
340                     memcmp(packname, "keep\t", 5) == 0) {
341                         char path[PATH_MAX];
342                         packname[45] = 0;
343                         snprintf(path, sizeof(path), "%s/pack/pack-%s.keep",
344                                  get_object_directory(), packname + 5);
345                         pack_lockfile = xstrdup(path);
346                 }
348                 /* Then wrap our index-pack process. */
349                 while (waitpid(pid, &status, 0) < 0)
350                         if (errno != EINTR)
351                                 return "waitpid failed";
352                 if (WIFEXITED(status)) {
353                         int code = WEXITSTATUS(status);
354                         if (code)
355                                 return "index-pack exited with error code";
356                         reprepare_packed_git();
357                         return NULL;
358                 }
359                 return "index-pack abnormal exit";
360         }
363 static void report(const char *unpack_status)
365         struct command *cmd;
366         packet_write(1, "unpack %s\n",
367                      unpack_status ? unpack_status : "ok");
368         for (cmd = commands; cmd; cmd = cmd->next) {
369                 if (!cmd->error_string)
370                         packet_write(1, "ok %s\n",
371                                      cmd->ref_name);
372                 else
373                         packet_write(1, "ng %s %s\n",
374                                      cmd->ref_name, cmd->error_string);
375         }
376         packet_flush(1);
379 int main(int argc, char **argv)
381         int i;
382         char *dir = NULL;
384         argv++;
385         for (i = 1; i < argc; i++) {
386                 char *arg = *argv++;
388                 if (*arg == '-') {
389                         /* Do flag handling here */
390                         usage(receive_pack_usage);
391                 }
392                 if (dir)
393                         usage(receive_pack_usage);
394                 dir = arg;
395         }
396         if (!dir)
397                 usage(receive_pack_usage);
399         if (!enter_repo(dir, 0))
400                 die("'%s': unable to chdir or not a git archive", dir);
402         setup_ident();
403         git_config(receive_pack_config);
405         write_head_info();
407         /* EOF */
408         packet_flush(1);
410         read_head_info();
411         if (commands) {
412                 const char *unpack_status = unpack();
413                 if (!unpack_status)
414                         execute_commands();
415                 if (pack_lockfile)
416                         unlink(pack_lockfile);
417                 if (report_status)
418                         report(unpack_status);
419         }
420         return 0;