|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
|
|
Packit |
c5a612 |
*
|
|
Packit |
c5a612 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
c5a612 |
* it under the terms of the GNU General Public License version 2 as
|
|
Packit |
c5a612 |
* published by the Free Software Foundation.
|
|
Packit |
c5a612 |
*
|
|
Packit |
c5a612 |
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#define _GNU_SOURCE
|
|
Packit |
c5a612 |
#include <config.h>
|
|
Packit |
c5a612 |
#include <stdio.h>
|
|
Packit |
c5a612 |
#include <string.h>
|
|
Packit |
c5a612 |
#include <stdarg.h>
|
|
Packit |
c5a612 |
#include <stdlib.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <netlink.h>
|
|
Packit |
c5a612 |
#include <gmputil.h>
|
|
Packit |
c5a612 |
#include <erec.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct input_descriptor internal_indesc = {
|
|
Packit |
c5a612 |
.type = INDESC_INTERNAL,
|
|
Packit |
c5a612 |
.name = "internal",
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
const struct location internal_location = {
|
|
Packit |
c5a612 |
.indesc = &internal_indesc,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const char * const error_record_names[] = {
|
|
Packit |
c5a612 |
[EREC_INFORMATIONAL] = NULL,
|
|
Packit |
c5a612 |
[EREC_WARNING] = "Warning",
|
|
Packit |
c5a612 |
[EREC_ERROR] = "Error"
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void erec_add_location(struct error_record *erec, const struct location *loc)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
assert(erec->num_locations < EREC_LOCATIONS_MAX);
|
|
Packit |
c5a612 |
erec->locations[erec->num_locations] = *loc;
|
|
Packit |
c5a612 |
erec->locations[erec->num_locations].indesc = loc->indesc;
|
|
Packit |
c5a612 |
erec->num_locations++;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void erec_destroy(struct error_record *erec)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
xfree(erec->msg);
|
|
Packit |
c5a612 |
xfree(erec);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
__attribute__((format(printf, 3, 0)))
|
|
Packit |
c5a612 |
struct error_record *erec_vcreate(enum error_record_types type,
|
|
Packit |
c5a612 |
const struct location *loc,
|
|
Packit |
c5a612 |
const char *fmt, va_list ap)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct error_record *erec;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
erec = xmalloc(sizeof(*erec));
|
|
Packit |
c5a612 |
erec->type = type;
|
|
Packit |
c5a612 |
erec->num_locations = 0;
|
|
Packit |
c5a612 |
erec_add_location(erec, loc);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (vasprintf(&erec->msg, fmt, ap) < 0)
|
|
Packit |
c5a612 |
erec->msg = NULL;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return erec;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
__attribute__((format(printf, 3, 4)))
|
|
Packit |
c5a612 |
struct error_record *erec_create(enum error_record_types type,
|
|
Packit |
c5a612 |
const struct location *loc,
|
|
Packit |
c5a612 |
const char *fmt, ...)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct error_record *erec;
|
|
Packit |
c5a612 |
va_list ap;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
va_start(ap, fmt);
|
|
Packit |
c5a612 |
erec = erec_vcreate(type, loc, fmt, ap);
|
|
Packit |
c5a612 |
va_end(ap);
|
|
Packit |
c5a612 |
return erec;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void erec_print(struct output_ctx *octx, const struct error_record *erec,
|
|
Packit |
c5a612 |
unsigned int debug_mask)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const struct location *loc = erec->locations, *iloc;
|
|
Packit |
c5a612 |
const struct input_descriptor *indesc = loc->indesc, *tmp;
|
|
Packit |
c5a612 |
const char *line = NULL;
|
|
Packit |
c5a612 |
char buf[1024] = {};
|
|
Packit |
c5a612 |
char *pbuf = NULL;
|
|
Packit |
c5a612 |
unsigned int i, end;
|
|
Packit |
c5a612 |
FILE *f;
|
|
Packit |
c5a612 |
int l;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (indesc->type) {
|
|
Packit |
c5a612 |
case INDESC_BUFFER:
|
|
Packit |
c5a612 |
case INDESC_CLI:
|
|
Packit |
c5a612 |
line = indesc->data;
|
|
Packit |
c5a612 |
*strchrnul(line, '\n') = '\0';
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case INDESC_FILE:
|
|
Packit |
c5a612 |
f = fopen(indesc->name, "r");
|
|
Packit |
c5a612 |
if (!f)
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!fseek(f, loc->line_offset, SEEK_SET) &&
|
|
Packit |
c5a612 |
fread(buf, 1, sizeof(buf) - 1, f) > 0) {
|
|
Packit |
c5a612 |
*strchrnul(buf, '\n') = '\0';
|
|
Packit |
c5a612 |
line = buf;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
fclose(f);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case INDESC_INTERNAL:
|
|
Packit |
c5a612 |
case INDESC_NETLINK:
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
default:
|
|
Packit |
c5a612 |
BUG("invalid input descriptor type %u\n", indesc->type);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
f = octx->error_fp;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (indesc->type == INDESC_NETLINK) {
|
|
Packit |
c5a612 |
fprintf(f, "%s: ", indesc->name);
|
|
Packit |
c5a612 |
if (error_record_names[erec->type])
|
|
Packit |
c5a612 |
fprintf(f, "%s: ", error_record_names[erec->type]);
|
|
Packit |
c5a612 |
fprintf(f, "%s\n", erec->msg);
|
|
Packit |
c5a612 |
for (l = 0; l < (int)erec->num_locations; l++) {
|
|
Packit |
c5a612 |
loc = &erec->locations[l];
|
|
Packit |
c5a612 |
netlink_dump_expr(loc->nle, f, debug_mask);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
return;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (indesc->location.indesc != NULL) {
|
|
Packit |
c5a612 |
const char *prefix = "In file included from";
|
|
Packit |
c5a612 |
iloc = &indesc->location;
|
|
Packit |
c5a612 |
for (tmp = iloc->indesc;
|
|
Packit |
c5a612 |
tmp != NULL && tmp->type != INDESC_INTERNAL;
|
|
Packit |
c5a612 |
tmp = iloc->indesc) {
|
|
Packit |
c5a612 |
fprintf(f, "%s %s:%u:%u-%u:\n", prefix,
|
|
Packit |
c5a612 |
tmp->name,
|
|
Packit |
c5a612 |
iloc->first_line, iloc->first_column,
|
|
Packit |
c5a612 |
iloc->last_column);
|
|
Packit |
c5a612 |
prefix = " from";
|
|
Packit |
c5a612 |
iloc = &tmp->location;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
if (indesc->name != NULL)
|
|
Packit |
c5a612 |
fprintf(f, "%s:%u:%u-%u: ", indesc->name,
|
|
Packit |
c5a612 |
loc->first_line, loc->first_column,
|
|
Packit |
c5a612 |
loc->last_column);
|
|
Packit |
c5a612 |
if (error_record_names[erec->type])
|
|
Packit |
c5a612 |
fprintf(f, "%s: ", error_record_names[erec->type]);
|
|
Packit |
c5a612 |
fprintf(f, "%s\n", erec->msg);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (line) {
|
|
Packit |
c5a612 |
fprintf(f, "%s\n", line);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
end = 0;
|
|
Packit |
c5a612 |
for (l = erec->num_locations - 1; l >= 0; l--) {
|
|
Packit |
c5a612 |
loc = &erec->locations[l];
|
|
Packit |
c5a612 |
end = max(end, loc->last_column);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
pbuf = xmalloc(end + 1);
|
|
Packit |
c5a612 |
memset(pbuf, ' ', end + 1);
|
|
Packit |
c5a612 |
for (i = 0; i < end && line[i]; i++) {
|
|
Packit |
c5a612 |
if (line[i] == '\t')
|
|
Packit |
c5a612 |
pbuf[i] = '\t';
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
for (l = erec->num_locations - 1; l >= 0; l--) {
|
|
Packit |
c5a612 |
loc = &erec->locations[l];
|
|
Packit |
c5a612 |
for (i = loc->first_column ? loc->first_column - 1 : 0;
|
|
Packit |
c5a612 |
i < loc->last_column; i++)
|
|
Packit |
c5a612 |
pbuf[i] = l ? '~' : '^';
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
pbuf[end] = '\0';
|
|
Packit |
c5a612 |
fprintf(f, "%s", pbuf);
|
|
Packit |
c5a612 |
xfree(pbuf);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
fprintf(f, "\n");
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void erec_print_list(struct output_ctx *octx, struct list_head *list,
|
|
Packit |
c5a612 |
unsigned int debug_mask)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct error_record *erec, *next;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
list_for_each_entry_safe(erec, next, list, list) {
|
|
Packit |
c5a612 |
list_del(&erec->list);
|
|
Packit |
c5a612 |
erec_print(octx, erec, debug_mask);
|
|
Packit |
c5a612 |
erec_destroy(erec);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int __fmtstring(4, 5) __stmt_binary_error(struct eval_ctx *ctx,
|
|
Packit |
c5a612 |
const struct location *l1,
|
|
Packit |
c5a612 |
const struct location *l2,
|
|
Packit |
c5a612 |
const char *fmt, ...)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct error_record *erec;
|
|
Packit |
c5a612 |
va_list ap;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
va_start(ap, fmt);
|
|
Packit |
c5a612 |
erec = erec_vcreate(EREC_ERROR, l1, fmt, ap);
|
|
Packit |
c5a612 |
if (l2 != NULL)
|
|
Packit |
c5a612 |
erec_add_location(erec, l2);
|
|
Packit |
c5a612 |
va_end(ap);
|
|
Packit |
c5a612 |
erec_queue(erec, ctx->msgs);
|
|
Packit |
c5a612 |
return -1;
|
|
Packit |
c5a612 |
}
|