#include "cache.h"
#include "quote.h"
+/*
+ * "Normalize" a key argument by converting NULL to our trace_default,
+ * and otherwise passing through the value. All caller-facing functions
+ * should normalize their inputs in this way, though most get it
+ * for free by calling get_trace_fd() (directly or indirectly).
+ */
+static void normalize_trace_key(struct trace_key **key)
+{
+ static struct trace_key trace_default = { "GIT_TRACE" };
+ if (!*key)
+ *key = &trace_default;
+}
+
/* Get a trace file descriptor from "key" env variable. */
static int get_trace_fd(struct trace_key *key)
{
- static struct trace_key trace_default = { "GIT_TRACE" };
const char *trace;
- /* use default "GIT_TRACE" if NULL */
- if (!key)
- key = &trace_default;
+ normalize_trace_key(&key);
/* don't open twice */
if (key->initialized)
else if (is_absolute_path(trace)) {
int fd = open(trace, O_WRONLY | O_APPEND | O_CREAT, 0666);
if (fd == -1) {
- fprintf(stderr,
- "Could not open '%s' for tracing: %s\n"
- "Defaulting to tracing on stderr...\n",
+ warning("could not open '%s' for tracing: %s",
trace, strerror(errno));
- key->fd = STDERR_FILENO;
+ trace_disable(key);
} else {
key->fd = fd;
key->need_close = 1;
}
} else {
- fprintf(stderr, "What does '%s' for %s mean?\n"
- "If you want to trace into a file, then please set "
- "%s to an absolute pathname (starting with /).\n"
- "Defaulting to tracing on stderr...\n",
- trace, key->key, key->key);
- key->fd = STDERR_FILENO;
+ warning("unknown trace value for '%s': %s\n"
+ " If you want to trace into a file, then please set %s\n"
+ " to an absolute pathname (starting with /)",
+ key->key, trace, key->key);
+ trace_disable(key);
}
key->initialized = 1;
void trace_disable(struct trace_key *key)
{
+ normalize_trace_key(&key);
+
if (key->need_close)
close(key->fd);
key->fd = 0;
key->need_close = 0;
}
-static const char err_msg[] = "Could not trace into fd given by "
- "GIT_TRACE environment variable";
-
static int prepare_trace_line(const char *file, int line,
struct trace_key *key, struct strbuf *buf)
{
return 1;
}
-static void print_trace_line(struct trace_key *key, struct strbuf *buf)
+static void trace_write(struct trace_key *key, const void *buf, unsigned len)
{
- /* append newline if missing */
- if (buf->len && buf->buf[buf->len - 1] != '\n')
- strbuf_addch(buf, '\n');
+ if (write_in_full(get_trace_fd(key), buf, len) < 0) {
+ normalize_trace_key(&key);
+ warning("unable to write trace for %s: %s",
+ key->key, strerror(errno));
+ trace_disable(key);
+ }
+}
- write_or_whine_pipe(get_trace_fd(key), buf->buf, buf->len, err_msg);
+void trace_verbatim(struct trace_key *key, const void *buf, unsigned len)
+{
+ if (!trace_want(key))
+ return;
+ trace_write(key, buf, len);
+}
+
+static void print_trace_line(struct trace_key *key, struct strbuf *buf)
+{
+ strbuf_complete_line(buf);
+ trace_write(key, buf->buf, buf->len);
strbuf_release(buf);
}
va_end(ap);
}
-void trace_strbuf(const char *key, const struct strbuf *data)
+void trace_strbuf(struct trace_key *key, const struct strbuf *data)
{
trace_strbuf_fl(NULL, 0, key, data);
}
static const char *quote_crnl(const char *path)
{
- static char new_path[PATH_MAX];
- const char *p2 = path;
- char *p1 = new_path;
+ static struct strbuf new_path = STRBUF_INIT;
if (!path)
return NULL;
- while (*p2) {
- switch (*p2) {
- case '\\': *p1++ = '\\'; *p1++ = '\\'; break;
- case '\n': *p1++ = '\\'; *p1++ = 'n'; break;
- case '\r': *p1++ = '\\'; *p1++ = 'r'; break;
+ strbuf_reset(&new_path);
+
+ while (*path) {
+ switch (*path) {
+ case '\\': strbuf_addstr(&new_path, "\\\\"); break;
+ case '\n': strbuf_addstr(&new_path, "\\n"); break;
+ case '\r': strbuf_addstr(&new_path, "\\r"); break;
default:
- *p1++ = *p2;
+ strbuf_addch(&new_path, *path);
}
- p2++;
+ path++;
}
- *p1 = '\0';
- return new_path;
+ return new_path.buf;
}
/* FIXME: move prefix to startup_info struct and get rid of this arg */
{
static struct trace_key key = TRACE_KEY_INIT(SETUP);
const char *git_work_tree;
- char cwd[PATH_MAX];
+ char *cwd;
if (!trace_want(&key))
return;
- if (!getcwd(cwd, PATH_MAX))
- die("Unable to get current working directory");
+ cwd = xgetcwd();
if (!(git_work_tree = get_git_work_tree()))
git_work_tree = "(null)";
prefix = "(null)";
trace_printf_key(&key, "setup: git_dir: %s\n", quote_crnl(get_git_dir()));
+ trace_printf_key(&key, "setup: git_common_dir: %s\n", quote_crnl(get_git_common_dir()));
trace_printf_key(&key, "setup: worktree: %s\n", quote_crnl(git_work_tree));
trace_printf_key(&key, "setup: cwd: %s\n", quote_crnl(cwd));
trace_printf_key(&key, "setup: prefix: %s\n", quote_crnl(prefix));
+
+ free(cwd);
}
int trace_want(struct trace_key *key)
return !!get_trace_fd(key);
}
-#ifdef HAVE_CLOCK_GETTIME
+#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC)
static inline uint64_t highres_nanos(void)
{
* Returns nanoseconds since the epoch (01/01/1970), for performance tracing
* (i.e. favoring high precision over wall clock time accuracy).
*/
-inline uint64_t getnanotime(void)
+uint64_t getnanotime(void)
{
static uint64_t offset;
if (offset > 1) {