usage.con commit vreport: sanitize ASCII control chars (f290089)
   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
   9static FILE *error_handle;
  10
  11void vreportf(const char *prefix, const char *err, va_list params)
  12{
  13        char msg[4096];
  14        FILE *fh = error_handle ? error_handle : stderr;
  15        char *p;
  16
  17        vsnprintf(msg, sizeof(msg), err, params);
  18        for (p = msg; *p; p++) {
  19                if (iscntrl(*p) && *p != '\t' && *p != '\n')
  20                        *p = '?';
  21        }
  22        fprintf(fh, "%s%s\n", prefix, msg);
  23}
  24
  25static NORETURN void usage_builtin(const char *err, va_list params)
  26{
  27        vreportf("usage: ", err, params);
  28        exit(129);
  29}
  30
  31static NORETURN void die_builtin(const char *err, va_list params)
  32{
  33        vreportf("fatal: ", err, params);
  34        exit(128);
  35}
  36
  37static void error_builtin(const char *err, va_list params)
  38{
  39        vreportf("error: ", err, params);
  40}
  41
  42static void warn_builtin(const char *warn, va_list params)
  43{
  44        vreportf("warning: ", warn, params);
  45}
  46
  47static int die_is_recursing_builtin(void)
  48{
  49        static int dying;
  50        return dying++;
  51}
  52
  53/* If we are in a dlopen()ed .so write to a global variable would segfault
  54 * (ugh), so keep things static. */
  55static NORETURN_PTR void (*usage_routine)(const char *err, va_list params) = usage_builtin;
  56static NORETURN_PTR void (*die_routine)(const char *err, va_list params) = die_builtin;
  57static void (*error_routine)(const char *err, va_list params) = error_builtin;
  58static void (*warn_routine)(const char *err, va_list params) = warn_builtin;
  59static int (*die_is_recursing)(void) = die_is_recursing_builtin;
  60
  61void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params))
  62{
  63        die_routine = routine;
  64}
  65
  66void set_error_routine(void (*routine)(const char *err, va_list params))
  67{
  68        error_routine = routine;
  69}
  70
  71void set_die_is_recursing_routine(int (*routine)(void))
  72{
  73        die_is_recursing = routine;
  74}
  75
  76void set_error_handle(FILE *fh)
  77{
  78        error_handle = fh;
  79}
  80
  81void NORETURN usagef(const char *err, ...)
  82{
  83        va_list params;
  84
  85        va_start(params, err);
  86        usage_routine(err, params);
  87        va_end(params);
  88}
  89
  90void NORETURN usage(const char *err)
  91{
  92        usagef("%s", err);
  93}
  94
  95void NORETURN die(const char *err, ...)
  96{
  97        va_list params;
  98
  99        if (die_is_recursing()) {
 100                fputs("fatal: recursion detected in die handler\n", stderr);
 101                exit(128);
 102        }
 103
 104        va_start(params, err);
 105        die_routine(err, params);
 106        va_end(params);
 107}
 108
 109void NORETURN die_errno(const char *fmt, ...)
 110{
 111        va_list params;
 112        char fmt_with_err[1024];
 113        char str_error[256], *err;
 114        int i, j;
 115
 116        if (die_is_recursing()) {
 117                fputs("fatal: recursion detected in die_errno handler\n",
 118                        stderr);
 119                exit(128);
 120        }
 121
 122        err = strerror(errno);
 123        for (i = j = 0; err[i] && j < sizeof(str_error) - 1; ) {
 124                if ((str_error[j++] = err[i++]) != '%')
 125                        continue;
 126                if (j < sizeof(str_error) - 1) {
 127                        str_error[j++] = '%';
 128                } else {
 129                        /* No room to double the '%', so we overwrite it with
 130                         * '\0' below */
 131                        j--;
 132                        break;
 133                }
 134        }
 135        str_error[j] = 0;
 136        snprintf(fmt_with_err, sizeof(fmt_with_err), "%s: %s", fmt, str_error);
 137
 138        va_start(params, fmt);
 139        die_routine(fmt_with_err, params);
 140        va_end(params);
 141}
 142
 143#undef error
 144int error(const char *err, ...)
 145{
 146        va_list params;
 147
 148        va_start(params, err);
 149        error_routine(err, params);
 150        va_end(params);
 151        return -1;
 152}
 153
 154void warning(const char *warn, ...)
 155{
 156        va_list params;
 157
 158        va_start(params, warn);
 159        warn_routine(warn, params);
 160        va_end(params);
 161}