werror.c 6.48 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1 2
/* werror.c
 *
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 *
 * $Id$ */

/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 1998 Niels Mller
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Niels Möller's avatar
Niels Möller committed
24 25 26 27
 */

#include "werror.h"

Niels Möller's avatar
Niels Möller committed
28
#include "charset.h"
29 30
#include "gc.h"
#include "io.h"
31
#include "parse.h"
Niels Möller's avatar
Niels Möller committed
32

Niels Möller's avatar
Niels Möller committed
33 34
#include <stdio.h>
#include <stdarg.h>
Niels Möller's avatar
Niels Möller committed
35
#include <ctype.h>
36
#include <unistd.h>
Niels Möller's avatar
Niels Möller committed
37

38 39
int debug_flag = 0;
int quiet_flag = 0;
40
int verbose_flag = 0;
41

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
int error_fd = STDERR_FILENO;

#define BUF_SIZE 500
static UINT8 error_buffer[BUF_SIZE];
static UINT32 error_pos = 0;

static int (*error_write)(int fd, UINT32 length, UINT8 *data) = write_raw;

#define WERROR(l, d) (error_write(error_fd, (l), (d)))

static void werror_flush(void)
{
  if (error_pos)
    {
      WERROR(error_pos, error_buffer);
      error_pos = 0;
    }
}

static void werror_putc(UINT8 c)
{
  if (error_pos == BUF_SIZE)
    werror_flush();

  error_buffer[error_pos++] = c;
}

void set_error_stream(int fd, int with_poll)
{
  error_fd = fd;

  error_write = with_poll ? write_raw_with_poll : write_raw;
}

76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
void wwrite(char *msg)
{
  if (!quiet_flag)
    {
      UINT32 size = strlen(msg);

      if (error_pos + size <= BUF_SIZE)
	{
	  memcpy(error_buffer + error_pos, msg, size);
	  error_pos += size;
      
	  if (size && (msg[size-1] == '\n'))
	    werror_flush();	
	}
      else
	{
	  werror_flush();
	  WERROR(size, msg);
	}
    }
}

#ifdef HAVE_VSNPRINTF
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
/* FIXME: Too bad we can't create a custom FILE * using werror_putc to
 * output each character. */
static void w_vnprintf(unsigned size, const char *format, va_list args)
{
  int written;
  
  if (error_pos + size <= BUF_SIZE)
    {
      written = vsnprintf(error_buffer + error_pos, size, format, args);

      error_pos += (written >= 0) ? written : size;
    }
  else
    {
      UINT8 *s = alloca(size);

      werror_flush();
      written = vsnprintf(s, size, format, args);

      if (written >= 0)
	size = written;
      
      WERROR(size, s);
    }
}
124
#else /* !HAVE_VSNPRINTF */
125

126
#warning No vsnprintf. Some output to stderr will be lost.
127

128 129 130 131
static void w_vnprintf(unsigned size, const char *format, va_list args)
{
  /* NOTE: This loses the interesting parts of the messages. */
  wwrite(format);
132
}
133 134
#endif /* !HAVE_VSNPRINTF */

135 136 137 138 139 140 141 142 143
static void w_nprintf(UINT32 size, const char *format, ...)
{
  va_list args;
  va_start(args, format);
  w_vnprintf(size, format, args);
  va_end(args);
}

#define WERROR_MAX 150
144
void werror(const char *format, ...) 
Niels Möller's avatar
Niels Möller committed
145 146 147
{
  va_list args;

148 149 150
  if (!quiet_flag)
    {
      va_start(args, format);
151
      w_vnprintf(WERROR_MAX, format, args);
152
      va_end(args);
153
      werror_flush();
154 155 156
    }
}

157
void debug(const char *format, ...) 
158 159 160 161 162 163
{
  va_list args;

  if (debug_flag)
    {
      va_start(args, format);
164
      w_vnprintf(WERROR_MAX, format, args);
165
      va_end(args);
166
      werror_flush();
167 168 169
    }
}

170
void verbose(const char *format, ...) 
171 172 173 174 175 176
{
  va_list args;

  if (verbose_flag)
    {
      va_start(args, format);
177
      w_vnprintf(WERROR_MAX, format, args);
178
      va_end(args);
179
      werror_flush();
180 181 182
    }
}

Niels Möller's avatar
Niels Möller committed
183
static void wash_char(UINT8 c)
184
{
Niels Möller's avatar
Niels Möller committed
185 186
  static const char hex[16] = "0123456789abcdef";
  
187
  switch(c)
188
    {
189
    case '\\':
190 191
      werror_putc('\\');
      werror_putc('\\');
192 193 194 195 196 197
      break;
    case '\r':
      /* Ignore */
      break;
    default:
      if (!isprint(c))
198
	{
199
	  werror_putc('\\');
Niels Möller's avatar
Niels Möller committed
200 201
	  werror_putc(hex[c / 16]);
	  werror_putc(hex[c % 16]);
202 203
	  break;
	}
204 205
      /* Fall through */
    case '\n':
206
      werror_putc(c);
207
      break;
208 209 210
    }
}

211
/* Escape non-printable characters. */
212
static void write_washed(UINT32 length, UINT8 *msg)
213
{
214
  UINT32 i;
215 216 217

  for(i = 0; i<length; i++)
    wash_char(msg[i]);
218 219

  werror_flush();
220 221
}

Niels Möller's avatar
Niels Möller committed
222
/* For outputting data received from the other end */
223 224 225
void werror_safe(UINT32 length, UINT8 *msg)
{
  if (!quiet_flag)
226
    write_washed(length, msg);
227 228 229 230 231
}

void debug_safe(UINT32 length, UINT8 *msg)
{
  if (debug_flag)
232
    write_washed(length, msg);
Niels Möller's avatar
Niels Möller committed
233 234
}

235 236 237
void verbose_safe(UINT32 length, UINT8 *msg)
{
  if (verbose_flag)
238
    write_washed(length, msg);
239 240
}

241
static void write_utf8(UINT32 length, UINT8 *msg)
242
{
Niels Möller's avatar
Niels Möller committed
243
  struct simple_buffer buffer;
244 245
  
  simple_buffer_init(&buffer, length, msg);
Niels Möller's avatar
Niels Möller committed
246 247
  
  while(1)
248
    {
Niels Möller's avatar
Niels Möller committed
249 250 251 252 253 254 255
      UINT32 ucs4;
      
      switch (parse_utf8(&buffer, &ucs4))
	{
	case -1:
	  return;
	case 0:
256 257
	  werror_putc('\\');
	  werror_putc('!');
Niels Möller's avatar
Niels Möller committed
258 259 260 261 262
	  return;
	case 1:
	  {
	    int local = ucs4_to_local(ucs4);
	    if (local < 0)
263 264 265 266
	      {
		werror_putc('\\');
		werror_putc('?');
	      }
Niels Möller's avatar
Niels Möller committed
267 268
	    else
	      wash_char(local);
Niels Möller's avatar
Niels Möller committed
269
	    break;
Niels Möller's avatar
Niels Möller committed
270 271 272 273
	  }
	default:
	  fatal("Internal error");
	}
274
    }
275
  werror_flush();
Niels Möller's avatar
Niels Möller committed
276
}
277 278

void werror_utf8(UINT32 length, UINT8 *msg)
Niels Möller's avatar
Niels Möller committed
279
{
280 281 282
  if (!quiet_flag)
    write_utf8(length, msg);
}
Niels Möller's avatar
Niels Möller committed
283

284 285 286 287 288
void verbose_utf8(UINT32 length, UINT8 *msg)
{
  if (verbose_flag)
    write_utf8(length, msg);
}
Niels Möller's avatar
Niels Möller committed
289

290 291 292 293
void debug_utf8(UINT32 length, UINT8 *msg)
{
  if (debug_flag)
    write_utf8(length, msg);
Niels Möller's avatar
Niels Möller committed
294
}
Niels Möller's avatar
Niels Möller committed
295

296
/* Bignums */
297 298 299 300 301 302 303 304
static void write_mpz(mpz_t n)
{
  UINT8 *s = alloca(mpz_sizeinbase(n, 16) + 2);
  mpz_get_str(s, 16, n);

  WERROR(strlen(s), s);
}

Niels Möller's avatar
Niels Möller committed
305 306
void werror_mpz(mpz_t n)
{
Niels Möller's avatar
Niels Möller committed
307
  if (!quiet_flag)
308
    write_mpz(n);
Niels Möller's avatar
Niels Möller committed
309 310 311 312 313
}

void debug_mpz(mpz_t n)
{
  if (debug_flag)
314
    write_mpz(n);
Niels Möller's avatar
Niels Möller committed
315 316 317 318 319 320
}

void verbose_mpz(mpz_t n)
{
  if (verbose_flag)
    mpz_out_str(stderr, 16, n);
Niels Möller's avatar
Niels Möller committed
321
}
322 323 324 325

/* hex dumps */
static void write_hex(UINT32 length, UINT8 *data)
{
326
  UINT32 i;
327
  
328
  w_nprintf(40, "(size %d = 0x%x)", length, length);
329 330 331 332

  for(i=0; i<length; i++)
  {
    if (! (i%16))
333
      w_nprintf(20, "\n%08x: ", i);
334
    
335
    w_nprintf(4, "%02x ", data[i]);
336
  }
Niels Möller's avatar
Niels Möller committed
337
  w_nprintf(2, "\n");
338
  werror_flush();
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
}

void werror_hex(UINT32 length, UINT8 *data)
{
  if (!quiet_flag)
    write_hex(length, data);
}

void debug_hex(UINT32 length, UINT8 *data)
{
  if (debug_flag)
    write_hex(length, data);
}

void verbose_hex(UINT32 length, UINT8 *data)
{
  if (verbose_flag)
    write_hex(length, data);
}

359
void fatal(const char *format, ...) 
360 361 362 363
{
  va_list args;

  va_start(args, format);
364
  w_vnprintf(WERROR_MAX, format, args);
365
  va_end(args);
366
  werror_flush();
367 368 369

  abort();
}