Re-work level setting on checks code

Currently each of the semantic checks in checks.c has a "level" between
IGNORE and ERROR.  This single level makes it awkward to implement the
semantics we want for toggling the checks on the command line.

This patch reworks the code to instead have separate boolean flags for
warning and error.  At present having both flags set will have the same
effect as having just the error flag set, but this can change in the
future.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
David Gibson 2012-07-08 23:25:21 +10:00 committed by Jon Loeliger
parent f67dfe8459
commit 511dedd40f
2 changed files with 62 additions and 54 deletions

107
checks.c
View file

@ -31,12 +31,6 @@
#define TRACE(c, fmt, ...) do { } while (0) #define TRACE(c, fmt, ...) do { } while (0)
#endif #endif
enum checklevel {
IGNORE = 0,
WARN = 1,
ERROR = 2,
};
enum checkstatus { enum checkstatus {
UNCHECKED = 0, UNCHECKED = 0,
PREREQ, PREREQ,
@ -57,14 +51,14 @@ struct check {
node_check_fn node_fn; node_check_fn node_fn;
prop_check_fn prop_fn; prop_check_fn prop_fn;
void *data; void *data;
enum checklevel level; bool warn, error;
enum checkstatus status; enum checkstatus status;
int inprogress; int inprogress;
int num_prereqs; int num_prereqs;
struct check **prereq; struct check **prereq;
}; };
#define CHECK(nm, tfn, nfn, pfn, d, lvl, ...) \ #define CHECK(nm, tfn, nfn, pfn, d, w, e, ...) \
static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \ static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \
static struct check nm = { \ static struct check nm = { \
.name = #nm, \ .name = #nm, \
@ -72,20 +66,29 @@ struct check {
.node_fn = (nfn), \ .node_fn = (nfn), \
.prop_fn = (pfn), \ .prop_fn = (pfn), \
.data = (d), \ .data = (d), \
.level = (lvl), \ .warn = (w), \
.error = (e), \
.status = UNCHECKED, \ .status = UNCHECKED, \
.num_prereqs = ARRAY_SIZE(nm##_prereqs), \ .num_prereqs = ARRAY_SIZE(nm##_prereqs), \
.prereq = nm##_prereqs, \ .prereq = nm##_prereqs, \
}; };
#define WARNING(nm, tfn, nfn, pfn, d, ...) \
CHECK(nm, tfn, nfn, pfn, d, true, false, __VA_ARGS__)
#define ERROR(nm, tfn, nfn, pfn, d, ...) \
CHECK(nm, tfn, nfn, pfn, d, false, true, __VA_ARGS__)
#define TREE_CHECK(nm, d, lvl, ...) \ #define TREE_WARNING(nm, d, ...) \
CHECK(nm, check_##nm, NULL, NULL, d, lvl, __VA_ARGS__) WARNING(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
#define NODE_CHECK(nm, d, lvl, ...) \ #define TREE_ERROR(nm, d, ...) \
CHECK(nm, NULL, check_##nm, NULL, d, lvl, __VA_ARGS__) ERROR(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
#define PROP_CHECK(nm, d, lvl, ...) \ #define NODE_WARNING(nm, d, ...) \
CHECK(nm, NULL, NULL, check_##nm, d, lvl, __VA_ARGS__) WARNING(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
#define BATCH_CHECK(nm, lvl, ...) \ #define NODE_ERROR(nm, d, ...) \
CHECK(nm, NULL, NULL, NULL, NULL, lvl, __VA_ARGS__) ERROR(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
#define PROP_WARNING(nm, d, ...) \
WARNING(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
#define PROP_ERROR(nm, d, ...) \
ERROR(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
#ifdef __GNUC__ #ifdef __GNUC__
static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3))); static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
@ -95,13 +98,13 @@ static inline void check_msg(struct check *c, const char *fmt, ...)
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
if ((c->level < WARN) || (c->level <= quiet)) if ((c->warn && (quiet < 1))
return; /* Suppress message */ || (c->error && (quiet < 2))) {
fprintf(stderr, "%s (%s): ", fprintf(stderr, "%s (%s): ",
(c->level == ERROR) ? "ERROR" : "Warning", c->name); (c->error) ? "ERROR" : "Warning", c->name);
vfprintf(stderr, fmt, ap); vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
}
} }
#define FAIL(c, ...) \ #define FAIL(c, ...) \
@ -167,7 +170,7 @@ static int run_check(struct check *c, struct node *dt)
out: out:
c->inprogress = 0; c->inprogress = 0;
if ((c->status != PASSED) && (c->level == ERROR)) if ((c->status != PASSED) && (c->error))
error = 1; error = 1;
return error; return error;
} }
@ -190,8 +193,10 @@ static void check_is_string(struct check *c, struct node *root,
FAIL(c, "\"%s\" property in %s is not a string", FAIL(c, "\"%s\" property in %s is not a string",
propname, node->fullpath); propname, node->fullpath);
} }
#define CHECK_IS_STRING(nm, propname, lvl) \ #define WARNING_IF_NOT_STRING(nm, propname) \
CHECK(nm, NULL, check_is_string, NULL, (propname), (lvl)) WARNING(nm, NULL, check_is_string, NULL, (propname))
#define ERROR_IF_NOT_STRING(nm, propname) \
ERROR(nm, NULL, check_is_string, NULL, (propname))
static void check_is_cell(struct check *c, struct node *root, static void check_is_cell(struct check *c, struct node *root,
struct node *node) struct node *node)
@ -207,8 +212,10 @@ static void check_is_cell(struct check *c, struct node *root,
FAIL(c, "\"%s\" property in %s is not a single cell", FAIL(c, "\"%s\" property in %s is not a single cell",
propname, node->fullpath); propname, node->fullpath);
} }
#define CHECK_IS_CELL(nm, propname, lvl) \ #define WARNING_IF_NOT_CELL(nm, propname) \
CHECK(nm, NULL, check_is_cell, NULL, (propname), (lvl)) WARNING(nm, NULL, check_is_cell, NULL, (propname))
#define ERROR_IF_NOT_CELL(nm, propname) \
ERROR(nm, NULL, check_is_cell, NULL, (propname))
/* /*
* Structural check functions * Structural check functions
@ -227,7 +234,7 @@ static void check_duplicate_node_names(struct check *c, struct node *dt,
FAIL(c, "Duplicate node name %s", FAIL(c, "Duplicate node name %s",
child->fullpath); child->fullpath);
} }
NODE_CHECK(duplicate_node_names, NULL, ERROR); NODE_ERROR(duplicate_node_names, NULL);
static void check_duplicate_property_names(struct check *c, struct node *dt, static void check_duplicate_property_names(struct check *c, struct node *dt,
struct node *node) struct node *node)
@ -240,7 +247,7 @@ static void check_duplicate_property_names(struct check *c, struct node *dt,
FAIL(c, "Duplicate property name %s in %s", FAIL(c, "Duplicate property name %s in %s",
prop->name, node->fullpath); prop->name, node->fullpath);
} }
NODE_CHECK(duplicate_property_names, NULL, ERROR); NODE_ERROR(duplicate_property_names, NULL);
#define LOWERCASE "abcdefghijklmnopqrstuvwxyz" #define LOWERCASE "abcdefghijklmnopqrstuvwxyz"
#define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ" #define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@ -256,7 +263,7 @@ static void check_node_name_chars(struct check *c, struct node *dt,
FAIL(c, "Bad character '%c' in node %s", FAIL(c, "Bad character '%c' in node %s",
node->name[n], node->fullpath); node->name[n], node->fullpath);
} }
NODE_CHECK(node_name_chars, PROPNODECHARS "@", ERROR); NODE_ERROR(node_name_chars, PROPNODECHARS "@");
static void check_node_name_format(struct check *c, struct node *dt, static void check_node_name_format(struct check *c, struct node *dt,
struct node *node) struct node *node)
@ -265,7 +272,7 @@ static void check_node_name_format(struct check *c, struct node *dt,
FAIL(c, "Node %s has multiple '@' characters in name", FAIL(c, "Node %s has multiple '@' characters in name",
node->fullpath); node->fullpath);
} }
NODE_CHECK(node_name_format, NULL, ERROR, &node_name_chars); NODE_ERROR(node_name_format, NULL, &node_name_chars);
static void check_property_name_chars(struct check *c, struct node *dt, static void check_property_name_chars(struct check *c, struct node *dt,
struct node *node, struct property *prop) struct node *node, struct property *prop)
@ -276,7 +283,7 @@ static void check_property_name_chars(struct check *c, struct node *dt,
FAIL(c, "Bad character '%c' in property name \"%s\", node %s", FAIL(c, "Bad character '%c' in property name \"%s\", node %s",
prop->name[n], prop->name, node->fullpath); prop->name[n], prop->name, node->fullpath);
} }
PROP_CHECK(property_name_chars, PROPNODECHARS, ERROR); PROP_ERROR(property_name_chars, PROPNODECHARS);
#define DESCLABEL_FMT "%s%s%s%s%s" #define DESCLABEL_FMT "%s%s%s%s%s"
#define DESCLABEL_ARGS(node,prop,mark) \ #define DESCLABEL_ARGS(node,prop,mark) \
@ -331,8 +338,8 @@ static void check_duplicate_label_prop(struct check *c, struct node *dt,
for_each_marker_of_type(m, LABEL) for_each_marker_of_type(m, LABEL)
check_duplicate_label(c, dt, m->ref, node, prop, m); check_duplicate_label(c, dt, m->ref, node, prop, m);
} }
CHECK(duplicate_label, NULL, check_duplicate_label_node, ERROR(duplicate_label, NULL, check_duplicate_label_node,
check_duplicate_label_prop, NULL, ERROR); check_duplicate_label_prop, NULL);
static void check_explicit_phandles(struct check *c, struct node *root, static void check_explicit_phandles(struct check *c, struct node *root,
struct node *node, struct property *prop) struct node *node, struct property *prop)
@ -391,7 +398,7 @@ static void check_explicit_phandles(struct check *c, struct node *root,
node->phandle = phandle; node->phandle = phandle;
} }
PROP_CHECK(explicit_phandles, NULL, ERROR); PROP_ERROR(explicit_phandles, NULL);
static void check_name_properties(struct check *c, struct node *root, static void check_name_properties(struct check *c, struct node *root,
struct node *node) struct node *node)
@ -420,8 +427,8 @@ static void check_name_properties(struct check *c, struct node *root,
free(prop); free(prop);
} }
} }
CHECK_IS_STRING(name_is_string, "name", ERROR); ERROR_IF_NOT_STRING(name_is_string, "name");
NODE_CHECK(name_properties, NULL, ERROR, &name_is_string); NODE_ERROR(name_properties, NULL, &name_is_string);
/* /*
* Reference fixup functions * Reference fixup functions
@ -448,7 +455,7 @@ static void fixup_phandle_references(struct check *c, struct node *dt,
*((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
} }
} }
CHECK(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ERROR, ERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL,
&duplicate_node_names, &explicit_phandles); &duplicate_node_names, &explicit_phandles);
static void fixup_path_references(struct check *c, struct node *dt, static void fixup_path_references(struct check *c, struct node *dt,
@ -473,19 +480,19 @@ static void fixup_path_references(struct check *c, struct node *dt,
strlen(path) + 1); strlen(path) + 1);
} }
} }
CHECK(path_references, NULL, NULL, fixup_path_references, NULL, ERROR, ERROR(path_references, NULL, NULL, fixup_path_references, NULL,
&duplicate_node_names); &duplicate_node_names);
/* /*
* Semantic checks * Semantic checks
*/ */
CHECK_IS_CELL(address_cells_is_cell, "#address-cells", WARN); WARNING_IF_NOT_CELL(address_cells_is_cell, "#address-cells");
CHECK_IS_CELL(size_cells_is_cell, "#size-cells", WARN); WARNING_IF_NOT_CELL(size_cells_is_cell, "#size-cells");
CHECK_IS_CELL(interrupt_cells_is_cell, "#interrupt-cells", WARN); WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells");
CHECK_IS_STRING(device_type_is_string, "device_type", WARN); WARNING_IF_NOT_STRING(device_type_is_string, "device_type");
CHECK_IS_STRING(model_is_string, "model", WARN); WARNING_IF_NOT_STRING(model_is_string, "model");
CHECK_IS_STRING(status_is_string, "status", WARN); WARNING_IF_NOT_STRING(status_is_string, "status");
static void fixup_addr_size_cells(struct check *c, struct node *dt, static void fixup_addr_size_cells(struct check *c, struct node *dt,
struct node *node) struct node *node)
@ -503,7 +510,7 @@ static void fixup_addr_size_cells(struct check *c, struct node *dt,
if (prop) if (prop)
node->size_cells = propval_cell(prop); node->size_cells = propval_cell(prop);
} }
CHECK(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, WARN, WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL,
&address_cells_is_cell, &size_cells_is_cell); &address_cells_is_cell, &size_cells_is_cell);
#define node_addr_cells(n) \ #define node_addr_cells(n) \
@ -538,7 +545,7 @@ static void check_reg_format(struct check *c, struct node *dt,
"(#address-cells == %d, #size-cells == %d)", "(#address-cells == %d, #size-cells == %d)",
node->fullpath, prop->val.len, addr_cells, size_cells); node->fullpath, prop->val.len, addr_cells, size_cells);
} }
NODE_CHECK(reg_format, NULL, WARN, &addr_size_cells); NODE_WARNING(reg_format, NULL, &addr_size_cells);
static void check_ranges_format(struct check *c, struct node *dt, static void check_ranges_format(struct check *c, struct node *dt,
struct node *node) struct node *node)
@ -579,7 +586,7 @@ static void check_ranges_format(struct check *c, struct node *dt,
p_addr_cells, c_addr_cells, c_size_cells); p_addr_cells, c_addr_cells, c_size_cells);
} }
} }
NODE_CHECK(ranges_format, NULL, WARN, &addr_size_cells); NODE_WARNING(ranges_format, NULL, &addr_size_cells);
/* /*
* Style checks * Style checks
@ -606,7 +613,7 @@ static void check_avoid_default_addr_size(struct check *c, struct node *dt,
FAIL(c, "Relying on default #size-cells value for %s", FAIL(c, "Relying on default #size-cells value for %s",
node->fullpath); node->fullpath);
} }
NODE_CHECK(avoid_default_addr_size, NULL, WARN, &addr_size_cells); NODE_WARNING(avoid_default_addr_size, NULL, &addr_size_cells);
static void check_obsolete_chosen_interrupt_controller(struct check *c, static void check_obsolete_chosen_interrupt_controller(struct check *c,
struct node *dt) struct node *dt)
@ -623,7 +630,7 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c,
FAIL(c, "/chosen has obsolete \"interrupt-controller\" " FAIL(c, "/chosen has obsolete \"interrupt-controller\" "
"property"); "property");
} }
TREE_CHECK(obsolete_chosen_interrupt_controller, NULL, WARN); TREE_WARNING(obsolete_chosen_interrupt_controller, NULL);
static struct check *check_table[] = { static struct check *check_table[] = {
&duplicate_node_names, &duplicate_property_names, &duplicate_node_names, &duplicate_property_names,
@ -653,7 +660,7 @@ void process_checks(int force, struct boot_info *bi)
for (i = 0; i < ARRAY_SIZE(check_table); i++) { for (i = 0; i < ARRAY_SIZE(check_table); i++) {
struct check *c = check_table[i]; struct check *c = check_table[i];
if (c->level != IGNORE) if (c->warn || c->error)
error = error || run_check(c, dt); error = error || run_check(c, dt);
} }

1
dtc.h
View file

@ -25,6 +25,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include <stdarg.h> #include <stdarg.h>
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>