[PATCH] Consolidate the error handling

Now there is error() for "library" errors and die() for fatal "application"
errors. usage() is now used strictly only for usage errors.

Signed-off-by: Petr Baudis <pasky@ucw.cz>
diff --git a/cache.h b/cache.h
index 07598d4..35b26c7 100644
--- a/cache.h
+++ b/cache.h
@@ -104,7 +104,10 @@
 extern char *sha1_to_hex(const unsigned char *sha1);	/* static buffer result! */
 
 /* General helper functions */
-extern void usage(const char *err, ...);
+extern void usage(const char *err);
+extern void die(const char *err, ...);
+extern int error(const char *err, ...);
+
 extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
 
 #endif /* CACHE_H */
diff --git a/cat-file.c b/cat-file.c
index 3829fb6..3c47d79 100644
--- a/cat-file.c
+++ b/cat-file.c
@@ -13,20 +13,17 @@
 	unsigned long size;
 
 	if (argc != 3 || get_sha1_hex(argv[2], sha1))
-		usage("cat-file: cat-file [-t | tagname] <sha1>");
+		usage("cat-file [-t | tagname] <sha1>");
 	buf = read_sha1_file(sha1, type, &size);
-	if (!buf) {
-		fprintf(stderr, "cat-file %s: bad file\n", argv[2]);
-		exit(1);
-	}
+	if (!buf)
+		die("cat-file %s: bad file", argv[2]);
 	if (!strcmp("-t", argv[1])) {
 		buf = type;
 		size = strlen(type);
 		type[size] = '\n';
 		size++;
 	} else if (strcmp(type, argv[1])) {
-		fprintf(stderr, "cat-file %s: bad tag\n", argv[2]);
-		exit(1);	/* bad tag */
+		die("cat-file %s: bad tag", argv[2]);
 	}
 
 	while (size > 0) {
@@ -37,12 +34,9 @@
 			/* Ignore epipe */
 			if (errno == EPIPE)
 				break;
-			fprintf(stderr, "cat-file: %s\n", strerror(errno));
-			exit(1);
-		}
-		if (!ret) {
-			fprintf(stderr, "cat-file: disk full?");
-			exit(1);
+			die("cat-file: %s", strerror(errno));
+		} else if (!ret) {
+			die("cat-file: disk full?");
 		}
 		size -= ret;
 		buf += ret;
diff --git a/check-files.c b/check-files.c
index c74bf87..7d16691 100644
--- a/check-files.c
+++ b/check-files.c
@@ -18,22 +18,22 @@
 	/* Nonexistent is fine */
 	if (fd < 0) {
 		if (errno != ENOENT)
-			usage("%s: %s", path, strerror(errno));
+			die("%s: %s", path, strerror(errno));
 		return;
 	}
 
 	/* Exists but is not in the cache is not fine */
 	pos = cache_name_pos(path, strlen(path));
 	if (pos < 0)
-		usage("preparing to update existing file '%s' not in cache", path);
+		die("preparing to update existing file '%s' not in cache", path);
 	ce = active_cache[pos];
 
 	if (fstat(fd, &st) < 0)
-		usage("fstat(%s): %s", path, strerror(errno));
+		die("fstat(%s): %s", path, strerror(errno));
 
 	changed = cache_match_stat(ce, &st);
 	if (changed)
-		usage("preparing to update file '%s' not uptodate in cache", path);
+		die("preparing to update file '%s' not uptodate in cache", path);
 }
 
 int main(int argc, char **argv)
diff --git a/checkout-cache.c b/checkout-cache.c
index 6ed8b69..fa78645 100644
--- a/checkout-cache.c
+++ b/checkout-cache.c
@@ -74,24 +74,21 @@
 
 	new = read_sha1_file(ce->sha1, type, &size);
 	if (!new || strcmp(type, "blob")) {
-		fprintf(stderr, "checkout-cache: unable to read sha1 file of %s (%s)\n",
+		return error("checkout-cache: unable to read sha1 file of %s (%s)",
 			ce->name, sha1_to_hex(ce->sha1));
-		return -1;
 	}
 	fd = create_file(ce->name, ce->st_mode);
 	if (fd < 0) {
-		fprintf(stderr, "checkout-cache: unable to create %s (%s)\n",
-			ce->name, strerror(errno));
 		free(new);
-		return -1;
+		return error("checkout-cache: unable to create %s (%s)",
+			ce->name, strerror(errno));
 	}
 	wrote = write(fd, new, size);
 	close(fd);
 	free(new);
-	if (wrote == size)
-		return 0;
-	fprintf(stderr, "checkout-cache: unable to write %s\n", ce->name);
-	return -1;
+	if (wrote != size)
+		return error("checkout-cache: unable to write %s", ce->name);
+	return 0;
 }
 
 static int checkout_entry(struct cache_entry *ce)
@@ -139,8 +136,7 @@
 	int i, force_filename = 0;
 
 	if (read_cache() < 0) {
-		fprintf(stderr, "Invalid cache\n");
-		exit(1);
+		die("invalid cache");
 	}
 
 	for (i = 1; i < argc; i++) {
diff --git a/commit-tree.c b/commit-tree.c
index 352ded1..ef1f068 100644
--- a/commit-tree.c
+++ b/commit-tree.c
@@ -135,7 +135,7 @@
 		fprintf(stderr, "Committing initial tree %s\n", argv[1]);
 	pw = getpwuid(getuid());
 	if (!pw)
-		usage("You don't exist. Go away!");
+		die("You don't exist. Go away!");
 	realgecos = pw->pw_gecos;
 	len = strlen(pw->pw_name);
 	memcpy(realemail, pw->pw_name, len);
diff --git a/diff-tree.c b/diff-tree.c
index 1960c23..04eb933 100644
--- a/diff-tree.c
+++ b/diff-tree.c
@@ -11,7 +11,7 @@
 	int len = strlen(buf) + 1 + 20;
 
 	if (size < len)
-		usage("corrupt tree file");
+		die("corrupt tree file");
 	*bufp = buf + len;
 	*sizep = size - len;
 }
@@ -23,7 +23,7 @@
 	const char *path = strchr(tree, ' ');
 
 	if (!path || size < len + 20 || sscanf(tree, "%o", modep) != 1)
-		usage("corrupt tree file");
+		die("corrupt tree file");
 	*pathp = path+1;
 	return sha1;
 }
@@ -64,7 +64,7 @@
 
 		tree = read_sha1_file(sha1, type, &size);
 		if (!tree || strcmp(type, "tree"))
-			usage("corrupt tree sha %s", sha1_to_hex(sha1));
+			die("corrupt tree sha %s", sha1_to_hex(sha1));
 
 		show_tree(prefix, tree, size, newbase);
 		
@@ -148,7 +148,7 @@
 			update_tree_entry(&tree2, &size2);
 			continue;
 		}
-		usage("diff-tree: internal error");
+		die("diff-tree: internal error");
 	}
 	return 0;
 }
@@ -162,10 +162,10 @@
 
 	tree1 = read_sha1_file(old, type, &size1);
 	if (!tree1 || strcmp(type, "tree"))
-		usage("unable to read source tree");
+		die("unable to read source tree (%s)", sha1_to_hex(old));
 	tree2 = read_sha1_file(new, type, &size2);
 	if (!tree2 || strcmp(type, "tree"))
-		usage("unable to read destination tree");
+		die("unable to read destination tree (%s)", sha1_to_hex(new));
 	retval = diff_tree(tree1, size1, tree2, size2, base);
 	free(tree1);
 	free(tree2);
diff --git a/fsck-cache.c b/fsck-cache.c
index bb5cf19..2bb3a64 100644
--- a/fsck-cache.c
+++ b/fsck-cache.c
@@ -205,8 +205,7 @@
 	struct dirent *de;
 
 	if (!dir) {
-		fprintf(stderr, "missing sha1 directory '%s'", path);
-		return -1;
+		return error("missing sha1 directory '%s'", path);
 	}
 
 	while ((de = readdir(dir)) != NULL) {
diff --git a/ls-tree.c b/ls-tree.c
index 05c743a..102b125 100644
--- a/ls-tree.c
+++ b/ls-tree.c
@@ -13,9 +13,9 @@
 
 	buffer = read_sha1_file(sha1, type, &size);
 	if (!buffer)
-		usage("unable to read sha1 file");
+		die("unable to read sha1 file");
 	if (strcmp(type, "tree"))
-		usage("expected a 'tree' node");
+		die("expected a 'tree' node");
 	while (size) {
 		int len = strlen(buffer)+1;
 		unsigned char *sha1 = buffer + len;
@@ -24,7 +24,7 @@
 		unsigned char *type;
 
 		if (size < len + 20 || sscanf(buffer, "%o", &mode) != 1)
-			usage("corrupt 'tree' file");
+			die("corrupt 'tree' file");
 		buffer = sha1 + 20;
 		size -= len + 20;
 		/* XXX: We do some ugly mode heuristics here.
@@ -48,6 +48,6 @@
 	if (!sha1_file_directory)
 		sha1_file_directory = DEFAULT_DB_ENVIRONMENT;
 	if (list(sha1) < 0)
-		usage("list failed");
+		die("list failed");
 	return 0;
 }
diff --git a/read-cache.c b/read-cache.c
index f1abae1..d8b383f 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -3,24 +3,47 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
+#include <stdarg.h>
 #include "cache.h"
 
 const char *sha1_file_directory = NULL;
 struct cache_entry **active_cache = NULL;
 unsigned int active_nr = 0, active_alloc = 0;
 
-void usage(const char *err, ...)
+void usage(const char *err)
 {
-	va_list args;
-	char string[200];
-
-	va_start(args, err);
-	vsnprintf(string, sizeof(string), err, args);
-	va_end(args);
-	fprintf(stderr, "%s\n", string);
+	fprintf(stderr, "usage: %s\n", err);
 	exit(1);
 }
 
+static void report(const char *prefix, const char *err, va_list params)
+{
+	fputs(prefix, stderr);
+	vfprintf(stderr, err, params);
+	fputs("\n", stderr);
+}
+
+void die(const char *err, ...)
+{
+	va_list params;
+
+	va_start(params, err);
+	report("fatal: ", err, params);
+	va_end(params);
+	exit(1);
+}
+
+int error(const char *err, ...)
+{
+	va_list params;
+
+	va_start(params, err);
+	report("error: ", err, params);
+	va_end(params);
+	return -1;
+}
+
+
 static unsigned hexval(char c)
 {
 	if (c >= '0' && c <= '9')
@@ -218,7 +241,6 @@
 	fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
 	if (fd < 0) {
 		void *map;
-		static int error(const char * string);
 
 		if (errno != EEXIST)
 			return -1;
@@ -240,12 +262,6 @@
 	return 0;
 }
 
-static int error(const char * string)
-{
-	fprintf(stderr, "error: %s\n", string);
-	return -1;
-}
-
 int cache_match_stat(struct cache_entry *ce, struct stat *st)
 {
 	unsigned int changed = 0;
diff --git a/read-tree.c b/read-tree.c
index dc24e91..9aec97f 100644
--- a/read-tree.c
+++ b/read-tree.c
@@ -78,7 +78,7 @@
 
 	newfd = open(".git/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600);
 	if (newfd < 0)
-		usage("unable to create new cachefile");
+		die("unable to create new cachefile");
 	atexit(remove_lock_file);
 	remove_lock = 1;
 
@@ -88,19 +88,19 @@
 		/* "-m" stands for "merge" current directory cache */
 		if (!strcmp(arg, "-m")) {
 			if (active_cache)
-				usage("read-tree: cannot merge old cache on top of new");
+				die("read-tree: cannot merge old cache on top of new");
 			if (read_cache() < 0)
-				usage("read-tree: corrupt directory cache");
+				die("read-tree: corrupt directory cache");
 			continue;
 		}
 		if (get_sha1_hex(arg, sha1) < 0)
 			usage("read-tree [-m] <sha1>");
 		if (read_tree(sha1, "", 0) < 0)
-			usage("failed to unpack tree object %s", arg);
+			die("failed to unpack tree object %s", arg);
 	}
 	if (write_cache(newfd, active_cache, active_nr) ||
 	    rename(".git/index.lock", ".git/index"))
-		usage("unable to write new index file");
+		die("unable to write new index file");
 	remove_lock = 0;
 	return 0;
 }
diff --git a/rev-tree.c b/rev-tree.c
index f2414b2..8c19b31 100644
--- a/rev-tree.c
+++ b/rev-tree.c
@@ -179,7 +179,7 @@
 	char line[500];
 
 	if (!file)
-		usage("bad revtree cache file (%s)", path);
+		die("bad revtree cache file (%s)", path);
 
 	while (fgets(line, sizeof(line), file)) {
 		unsigned long date;
diff --git a/update-cache.c b/update-cache.c
index d08e895..8fcf07a 100644
--- a/update-cache.c
+++ b/update-cache.c
@@ -249,14 +249,14 @@
 
 	newfd = open(".git/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600);
 	if (newfd < 0)
-		usage("unable to create new cachefile");
+		die("unable to create new cachefile");
 
 	atexit(remove_lock_file);
 	remove_lock = 1;
 
 	entries = read_cache();
 	if (entries < 0)
-		usage("cache corrupted");
+		die("cache corrupted");
 
 	for (i = 1 ; i < argc; i++) {
 		char *path = argv[i];
@@ -278,18 +278,18 @@
 				refresh_cache();
 				continue;
 			}
-			usage("unknown option %s", path);
+			die("unknown option %s", path);
 		}
 		if (!verify_path(path)) {
 			fprintf(stderr, "Ignoring path %s\n", argv[i]);
 			continue;
 		}
 		if (add_file_to_cache(path))
-			usage("Unable to add %s to database", path);
+			die("Unable to add %s to database", path);
 	}
 	if (write_cache(newfd, active_cache, active_nr) ||
 	    rename(".git/index.lock", ".git/index"))
-		usage("Unable to write new cachefile");
+		die("Unable to write new cachefile");
 
 	remove_lock = 0;
 	return 0;
diff --git a/write-tree.c b/write-tree.c
index 7eac1df..881c8c2 100644
--- a/write-tree.c
+++ b/write-tree.c
@@ -106,9 +106,9 @@
 	unsigned char sha1[20];
 
 	if (entries <= 0)
-		usage("no cache contents to write");
+		die("write-tree: no cache contents to write");
 	if (write_tree(active_cache, entries, "", 0, sha1) != entries)
-		usage("write-tree: internal error");
+		die("write-tree: internal error");
 	printf("%s\n", sha1_to_hex(sha1));
 	return 0;
 }