usage.con commit Merge branch 'en/rename-directory-detection' (f72432d)
   1/*
   2 * GIT - The information manager from hell
   3 *
   4 * Copyright (C) Linus Torvalds, 2005
   5 */
   6#include "git-compat-util.h"
   7#include "cache.h"
   8
   9void vreportf(const char *prefix, const char *err, va_list params)
  10{
  11        char msg[4096];
  12        char *p;
  13
  14        vsnprintf(msg, sizeof(msg), err, params);
  15        for (p = msg; *p; p++) {
  16                if (iscntrl(*p) && *p != '\t' && *p != '\n')
  17                        *p = '?';
  18        }
  19        fprintf(stderr, "%s%s\n", prefix, msg);
  20}
  21
  22static NORETURN void usage_builtin(const char *err, va_list params)
  23{
  24        vreportf("usage: ", err, params);
  25        exit(129);
  26}
  27
  28static NORETURN void die_builtin(const char *err, va_list params)
  29{
  30        vreportf("fatal: ", err, params);
  31        exit(128);
  32}
  33
  34static void error_builtin(const char *err, va_list params)
  35{
  36        vreportf("error: ", err, params);
  37}
  38
  39static void warn_builtin(const char *warn, va_list params)
  40{
  41        vreportf("warning: ", warn, params);
  42}
  43
  44static int die_is_recursing_builtin(void)
  45{
  46        static int dying;
  47        /*
  48         * Just an arbitrary number X where "a < x < b" where "a" is
  49         * "maximum number of pthreads we'll ever plausibly spawn" and
  50         * "b" is "something less than Inf", since the point is to
  51         * prevent infinite recursion.
  52         */
  53        static const int recursion_limit = 1024;
  54
  55        dying++;
  56        if (dying > recursion_limit) {
  57                return 1;
  58        } else if (dying == 2) {
  59                warning("die() called many times. Recursion error or racy threaded death!");
  60                return 0;
  61        } else {
  62                return 0;
  63        }
  64}
  65
  66/* If we are in a dlopen()ed .so write to a global variable would segfault
  67 * (ugh), so keep things static. */
  68static NORETURN_PTR void (*usage_routine)(const char *err, va_list params) = usage_builtin;
  69static NORETURN_PTR void (*die_routine)(const char *err, va_list params) = die_builtin;
  70static void (*error_routine)(const char *err, va_list params) = error_builtin;
  71static void (*warn_routine)(const char *err, va_list params) = warn_builtin;
  72static int (*die_is_recursing)(void) = die_is_recursing_builtin;
  73
  74void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params))
  75{
  76        die_routine = routine;
  77}
  78
  79void set_error_routine(void (*routine)(const char *err, va_list params))
  80{
  81        error_routine = routine;
  82}
  83
  84void (*get_error_routine(void))(const char *err, va_list params)
  85{
  86        return error_routine;
  87}
  88
  89void set_warn_routine(void (*routine)(const char *warn, va_list params))
  90{
  91        warn_routine = routine;
  92}
  93
  94void (*get_warn_routine(void))(const char *warn, va_list params)
  95{
  96        return warn_routine;
  97}
  98
  99void set_die_is_recursing_routine(int (*routine)(void))
 100{
 101        die_is_recursing = routine;
 102}
 103
 104void NORETURN usagef(const char *err, ...)
 105{
 106        va_list params;
 107
 108        va_start(params, err);
 109        usage_routine(err, params);
 110        va_end(params);
 111}
 112
 113void NORETURN usage(const char *err)
 114{
 115        usagef("%s", err);
 116}
 117
 118void NORETURN die(const char *err, ...)
 119{
 120        va_list params;
 121
 122        if (die_is_recursing()) {
 123                fputs("fatal: recursion detected in die handler\n", stderr);
 124                exit(128);
 125        }
 126
 127        va_start(params, err);
 128        die_routine(err, params);
 129        va_end(params);
 130}
 131
 132static const char *fmt_with_err(char *buf, int n, const char *fmt)
 133{
 134        char str_error[256], *err;
 135        int i, j;
 136
 137        err = strerror(errno);
 138        for (i = j = 0; err[i] && j < sizeof(str_error) - 1; ) {
 139                if ((str_error[j++] = err[i++]) != '%')
 140                        continue;
 141                if (j < sizeof(str_error) - 1) {
 142                        str_error[j++] = '%';
 143                } else {
 144                        /* No room to double the '%', so we overwrite it with
 145                         * '\0' below */
 146                        j--;
 147                        break;
 148                }
 149        }
 150        str_error[j] = 0;
 151        /* Truncation is acceptable here */
 152        snprintf(buf, n, "%s: %s", fmt, str_error);
 153        return buf;
 154}
 155
 156void NORETURN die_errno(const char *fmt, ...)
 157{
 158        char buf[1024];
 159        va_list params;
 160
 161        if (die_is_recursing()) {
 162                fputs("fatal: recursion detected in die_errno handler\n",
 163                        stderr);
 164                exit(128);
 165        }
 166
 167        va_start(params, fmt);
 168        die_routine(fmt_with_err(buf, sizeof(buf), fmt), params);
 169        va_end(params);
 170}
 171
 172#undef error_errno
 173int error_errno(const char *fmt, ...)
 174{
 175        char buf[1024];
 176        va_list params;
 177
 178        va_start(params, fmt);
 179        error_routine(fmt_with_err(buf, sizeof(buf), fmt), params);
 180        va_end(params);
 181        return -1;
 182}
 183
 184#undef error
 185int error(const char *err, ...)
 186{
 187        va_list params;
 188
 189        va_start(params, err);
 190        error_routine(err, params);
 191        va_end(params);
 192        return -1;
 193}
 194
 195void warning_errno(const char *warn, ...)
 196{
 197        char buf[1024];
 198        va_list params;
 199
 200        va_start(params, warn);
 201        warn_routine(fmt_with_err(buf, sizeof(buf), warn), params);
 202        va_end(params);
 203}
 204
 205void warning(const char *warn, ...)
 206{
 207        va_list params;
 208
 209        va_start(params, warn);
 210        warn_routine(warn, params);
 211        va_end(params);
 212}
 213
 214/* Only set this, ever, from t/helper/, when verifying that bugs are caught. */
 215int BUG_exit_code;
 216
 217static NORETURN void BUG_vfl(const char *file, int line, const char *fmt, va_list params)
 218{
 219        char prefix[256];
 220
 221        /* truncation via snprintf is OK here */
 222        if (file)
 223                snprintf(prefix, sizeof(prefix), "BUG: %s:%d: ", file, line);
 224        else
 225                snprintf(prefix, sizeof(prefix), "BUG: ");
 226
 227        vreportf(prefix, fmt, params);
 228        if (BUG_exit_code)
 229                exit(BUG_exit_code);
 230        abort();
 231}
 232
 233#ifdef HAVE_VARIADIC_MACROS
 234NORETURN void BUG_fl(const char *file, int line, const char *fmt, ...)
 235{
 236        va_list ap;
 237        va_start(ap, fmt);
 238        BUG_vfl(file, line, fmt, ap);
 239        va_end(ap);
 240}
 241#else
 242NORETURN void BUG(const char *fmt, ...)
 243{
 244        va_list ap;
 245        va_start(ap, fmt);
 246        BUG_vfl(NULL, 0, fmt, ap);
 247        va_end(ap);
 248}
 249#endif
 250
 251#ifdef SUPPRESS_ANNOTATED_LEAKS
 252void unleak_memory(const void *ptr, size_t len)
 253{
 254        static struct suppressed_leak_root {
 255                struct suppressed_leak_root *next;
 256                char data[FLEX_ARRAY];
 257        } *suppressed_leaks;
 258        struct suppressed_leak_root *root;
 259
 260        FLEX_ALLOC_MEM(root, data, ptr, len);
 261        root->next = suppressed_leaks;
 262        suppressed_leaks = root;
 263}
 264#endif