X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=usage.c;h=1868a24f7a5148b1714dc4a9730f343339e61dce;hb=a78305ffbca58e49a7cdad901df0ae779bbed8fb;hp=17f52c1b5ce631eed1cdf3447d80e7223a2e6f01;hpb=46e398b69c0f68ade36b2a3e224a9ce3908eb26e;p=platform%2Fupstream%2Fgit.git diff --git a/usage.c b/usage.c index 17f52c1..1868a24 100644 --- a/usage.c +++ b/usage.c @@ -6,81 +6,141 @@ #include "git-compat-util.h" #include "cache.h" -static FILE *error_handle; -static int tweaked_error_buffering; - void vreportf(const char *prefix, const char *err, va_list params) { - FILE *fh = error_handle ? error_handle : stderr; + char msg[4096]; + char *p, *pend = msg + sizeof(msg); + size_t prefix_len = strlen(prefix); - fflush(fh); - if (!tweaked_error_buffering) { - setvbuf(fh, NULL, _IOLBF, 0); - tweaked_error_buffering = 1; + if (sizeof(msg) <= prefix_len) { + fprintf(stderr, "BUG!!! too long a prefix '%s'\n", prefix); + abort(); + } + memcpy(msg, prefix, prefix_len); + p = msg + prefix_len; + if (vsnprintf(p, pend - p, err, params) < 0) + *p = '\0'; /* vsnprintf() failed, clip at prefix */ + + for (; p != pend - 1 && *p; p++) { + if (iscntrl(*p) && *p != '\t' && *p != '\n') + *p = '?'; } - fputs(prefix, fh); - vfprintf(fh, err, params); - fputc('\n', fh); + *(p++) = '\n'; /* we no longer need a NUL */ + fflush(stderr); + write_in_full(2, msg, p - msg); } static NORETURN void usage_builtin(const char *err, va_list params) { vreportf("usage: ", err, params); + + /* + * When we detect a usage error *before* the command dispatch in + * cmd_main(), we don't know what verb to report. Force it to this + * to facilitate post-processing. + */ + trace2_cmd_name("_usage_"); + + /* + * Currently, the (err, params) are usually just the static usage + * string which isn't very useful here. Usually, the call site + * manually calls fprintf(stderr,...) with the actual detailed + * syntax error before calling usage(). + * + * TODO It would be nice to update the call sites to pass both + * the static usage string and the detailed error message. + */ + exit(129); } static NORETURN void die_builtin(const char *err, va_list params) { + /* + * We call this trace2 function first and expect it to va_copy 'params' + * before using it (because an 'ap' can only be walked once). + */ + trace2_cmd_error_va(err, params); + vreportf("fatal: ", err, params); + exit(128); } static void error_builtin(const char *err, va_list params) { + /* + * We call this trace2 function first and expect it to va_copy 'params' + * before using it (because an 'ap' can only be walked once). + */ + trace2_cmd_error_va(err, params); + vreportf("error: ", err, params); } static void warn_builtin(const char *warn, va_list params) { + /* + * We call this trace2 function first and expect it to va_copy 'params' + * before using it (because an 'ap' can only be walked once). + */ + trace2_cmd_error_va(warn, params); + vreportf("warning: ", warn, params); } static int die_is_recursing_builtin(void) { static int dying; - return dying++; + /* + * Just an arbitrary number X where "a < x < b" where "a" is + * "maximum number of pthreads we'll ever plausibly spawn" and + * "b" is "something less than Inf", since the point is to + * prevent infinite recursion. + */ + static const int recursion_limit = 1024; + + dying++; + if (dying > recursion_limit) { + return 1; + } else if (dying == 2) { + warning("die() called many times. Recursion error or racy threaded death!"); + return 0; + } else { + return 0; + } } /* If we are in a dlopen()ed .so write to a global variable would segfault * (ugh), so keep things static. */ -static NORETURN_PTR void (*usage_routine)(const char *err, va_list params) = usage_builtin; -static NORETURN_PTR void (*die_routine)(const char *err, va_list params) = die_builtin; -static void (*error_routine)(const char *err, va_list params) = error_builtin; -static void (*warn_routine)(const char *err, va_list params) = warn_builtin; +static NORETURN_PTR report_fn usage_routine = usage_builtin; +static NORETURN_PTR report_fn die_routine = die_builtin; +static report_fn error_routine = error_builtin; +static report_fn warn_routine = warn_builtin; static int (*die_is_recursing)(void) = die_is_recursing_builtin; -void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params)) +void set_die_routine(NORETURN_PTR report_fn routine) { die_routine = routine; } -void set_error_routine(void (*routine)(const char *err, va_list params)) +void set_error_routine(report_fn routine) { error_routine = routine; } -void (*get_error_routine(void))(const char *err, va_list params) +report_fn get_error_routine(void) { return error_routine; } -void set_warn_routine(void (*routine)(const char *warn, va_list params)) +void set_warn_routine(report_fn routine) { warn_routine = routine; } -void (*get_warn_routine(void))(const char *warn, va_list params) +report_fn get_warn_routine(void) { return warn_routine; } @@ -90,12 +150,6 @@ void set_die_is_recursing_routine(int (*routine)(void)) die_is_recursing = routine; } -void set_error_handle(FILE *fh) -{ - error_handle = fh; - tweaked_error_buffering = 0; -} - void NORETURN usagef(const char *err, ...) { va_list params; @@ -143,6 +197,7 @@ static const char *fmt_with_err(char *buf, int n, const char *fmt) } } str_error[j] = 0; + /* Truncation is acceptable here */ snprintf(buf, n, "%s: %s", fmt, str_error); return buf; } @@ -204,3 +259,55 @@ void warning(const char *warn, ...) warn_routine(warn, params); va_end(params); } + +/* Only set this, ever, from t/helper/, when verifying that bugs are caught. */ +int BUG_exit_code; + +static NORETURN void BUG_vfl(const char *file, int line, const char *fmt, va_list params) +{ + char prefix[256]; + + /* truncation via snprintf is OK here */ + if (file) + snprintf(prefix, sizeof(prefix), "BUG: %s:%d: ", file, line); + else + snprintf(prefix, sizeof(prefix), "BUG: "); + + vreportf(prefix, fmt, params); + if (BUG_exit_code) + exit(BUG_exit_code); + abort(); +} + +#ifdef HAVE_VARIADIC_MACROS +NORETURN void BUG_fl(const char *file, int line, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + BUG_vfl(file, line, fmt, ap); + va_end(ap); +} +#else +NORETURN void BUG(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + BUG_vfl(NULL, 0, fmt, ap); + va_end(ap); +} +#endif + +#ifdef SUPPRESS_ANNOTATED_LEAKS +void unleak_memory(const void *ptr, size_t len) +{ + static struct suppressed_leak_root { + struct suppressed_leak_root *next; + char data[FLEX_ARRAY]; + } *suppressed_leaks; + struct suppressed_leak_root *root; + + FLEX_ALLOC_MEM(root, data, ptr, len); + root->next = suppressed_leaks; + suppressed_leaks = root; +} +#endif