1/* 2 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2007. 3 * 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation; either version 2 of the 8 * License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 18 * USA 19 */ 20 21#include "dtc.h" 22 23#ifdef TRACE_CHECKS 24#define TRACE(c, ...) \ 25 do { \ 26 fprintf(stderr, "=== %s: ", (c)->name); \ 27 fprintf(stderr, __VA_ARGS__); \ 28 fprintf(stderr, "\n"); \ 29 } while (0) 30#else 31#define TRACE(c, fmt, ...) do { } while (0) 32#endif 33 34enum checkstatus { 35 UNCHECKED = 0, 36 PREREQ, 37 PASSED, 38 FAILED, 39}; 40 41struct check; 42 43typedef void (*tree_check_fn)(struct check *c, struct node *dt); 44typedef void (*node_check_fn)(struct check *c, struct node *dt, struct node *node); 45typedef void (*prop_check_fn)(struct check *c, struct node *dt, 46 struct node *node, struct property *prop); 47 48struct check { 49 const char *name; 50 tree_check_fn tree_fn; 51 node_check_fn node_fn; 52 prop_check_fn prop_fn; 53 void *data; 54 bool warn, error; 55 enum checkstatus status; 56 int inprogress; 57 int num_prereqs; 58 struct check **prereq; 59}; 60 61#define CHECK_ENTRY(nm, tfn, nfn, pfn, d, w, e, ...) \ 62 static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \ 63 static struct check nm = { \ 64 .name = #nm, \ 65 .tree_fn = (tfn), \ 66 .node_fn = (nfn), \ 67 .prop_fn = (pfn), \ 68 .data = (d), \ 69 .warn = (w), \ 70 .error = (e), \ 71 .status = UNCHECKED, \ 72 .num_prereqs = ARRAY_SIZE(nm##_prereqs), \ 73 .prereq = nm##_prereqs, \ 74 }; 75#define WARNING(nm, tfn, nfn, pfn, d, ...) \ 76 CHECK_ENTRY(nm, tfn, nfn, pfn, d, true, false, __VA_ARGS__) 77#define ERROR(nm, tfn, nfn, pfn, d, ...) \ 78 CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, true, __VA_ARGS__) 79#define CHECK(nm, tfn, nfn, pfn, d, ...) \ 80 CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, false, __VA_ARGS__) 81 82#define TREE_WARNING(nm, d, ...) \ 83 WARNING(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) 84#define TREE_ERROR(nm, d, ...) \ 85 ERROR(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) 86#define TREE_CHECK(nm, d, ...) \ 87 CHECK(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) 88#define NODE_WARNING(nm, d, ...) \ 89 WARNING(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) 90#define NODE_ERROR(nm, d, ...) \ 91 ERROR(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) 92#define NODE_CHECK(nm, d, ...) \ 93 CHECK(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) 94#define PROP_WARNING(nm, d, ...) \ 95 WARNING(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) 96#define PROP_ERROR(nm, d, ...) \ 97 ERROR(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) 98#define PROP_CHECK(nm, d, ...) \ 99 CHECK(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) 100 101#ifdef __GNUC__ 102static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3))); 103#endif 104static inline void check_msg(struct check *c, const char *fmt, ...) 105{ 106 va_list ap; 107 va_start(ap, fmt); 108 109 if ((c->warn && (quiet < 1)) 110 || (c->error && (quiet < 2))) { 111 fprintf(stderr, "%s (%s): ", 112 (c->error) ? "ERROR" : "Warning", c->name); 113 vfprintf(stderr, fmt, ap); 114 fprintf(stderr, "\n"); 115 } 116} 117 118#define FAIL(c, ...) \ 119 do { \ 120 TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \ 121 (c)->status = FAILED; \ 122 check_msg((c), __VA_ARGS__); \ 123 } while (0) 124 125static void check_nodes_props(struct check *c, struct node *dt, struct node *node) 126{ 127 struct node *child; 128 struct property *prop; 129 130 TRACE(c, "%s", node->fullpath); 131 if (c->node_fn) 132 c->node_fn(c, dt, node); 133 134 if (c->prop_fn) 135 for_each_property(node, prop) { 136 TRACE(c, "%s\t'%s'", node->fullpath, prop->name); 137 c->prop_fn(c, dt, node, prop); 138 } 139 140 for_each_child(node, child) 141 check_nodes_props(c, dt, child); 142} 143 144static int run_check(struct check *c, struct node *dt) 145{ 146 int error = 0; 147 int i; 148 149 assert(!c->inprogress); 150 151 if (c->status != UNCHECKED) 152 goto out; 153 154 c->inprogress = 1; 155 156 for (i = 0; i < c->num_prereqs; i++) { 157 struct check *prq = c->prereq[i]; 158 error |= run_check(prq, dt); 159 if (prq->status != PASSED) { 160 c->status = PREREQ; 161 check_msg(c, "Failed prerequisite '%s'", 162 c->prereq[i]->name); 163 } 164 } 165 166 if (c->status != UNCHECKED) 167 goto out; 168 169 if (c->node_fn || c->prop_fn) 170 check_nodes_props(c, dt, dt); 171 172 if (c->tree_fn) 173 c->tree_fn(c, dt); 174 if (c->status == UNCHECKED) 175 c->status = PASSED; 176 177 TRACE(c, "\tCompleted, status %d", c->status); 178 179out: 180 c->inprogress = 0; 181 if ((c->status != PASSED) && (c->error)) 182 error = 1; 183 return error; 184} 185 186/* 187 * Utility check functions 188 */ 189 190/* A check which always fails, for testing purposes only */ 191static inline void check_always_fail(struct check *c, struct node *dt) 192{ 193 FAIL(c, "always_fail check"); 194} 195TREE_CHECK(always_fail, NULL); 196 197static void check_is_string(struct check *c, struct node *root, 198 struct node *node) 199{ 200 struct property *prop; 201 char *propname = c->data; 202 203 prop = get_property(node, propname); 204 if (!prop) 205 return; /* Not present, assumed ok */ 206 207 if (!data_is_one_string(prop->val)) 208 FAIL(c, "\"%s\" property in %s is not a string", 209 propname, node->fullpath); 210} 211#define WARNING_IF_NOT_STRING(nm, propname) \ 212 WARNING(nm, NULL, check_is_string, NULL, (propname)) 213#define ERROR_IF_NOT_STRING(nm, propname) \ 214 ERROR(nm, NULL, check_is_string, NULL, (propname)) 215 216static void check_is_cell(struct check *c, struct node *root, 217 struct node *node) 218{ 219 struct property *prop; 220 char *propname = c->data; 221 222 prop = get_property(node, propname); 223 if (!prop) 224 return; /* Not present, assumed ok */ 225 226 if (prop->val.len != sizeof(cell_t)) 227 FAIL(c, "\"%s\" property in %s is not a single cell", 228 propname, node->fullpath); 229} 230#define WARNING_IF_NOT_CELL(nm, propname) \ 231 WARNING(nm, NULL, check_is_cell, NULL, (propname)) 232#define ERROR_IF_NOT_CELL(nm, propname) \ 233 ERROR(nm, NULL, check_is_cell, NULL, (propname)) 234 235/* 236 * Structural check functions 237 */ 238 239static void check_duplicate_node_names(struct check *c, struct node *dt, 240 struct node *node) 241{ 242 struct node *child, *child2; 243 244 for_each_child(node, child) 245 for (child2 = child->next_sibling; 246 child2; 247 child2 = child2->next_sibling) 248 if (streq(child->name, child2->name)) 249 FAIL(c, "Duplicate node name %s", 250 child->fullpath); 251} 252NODE_ERROR(duplicate_node_names, NULL); 253 254static void check_duplicate_property_names(struct check *c, struct node *dt, 255 struct node *node) 256{ 257 struct property *prop, *prop2; 258 259 for_each_property(node, prop) { 260 for (prop2 = prop->next; prop2; prop2 = prop2->next) { 261 if (prop2->deleted) 262 continue; 263 if (streq(prop->name, prop2->name)) 264 FAIL(c, "Duplicate property name %s in %s", 265 prop->name, node->fullpath); 266 } 267 } 268} 269NODE_ERROR(duplicate_property_names, NULL); 270 271#define LOWERCASE "abcdefghijklmnopqrstuvwxyz" 272#define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 273#define DIGITS "0123456789" 274#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-" 275 276static void check_node_name_chars(struct check *c, struct node *dt, 277 struct node *node) 278{ 279 int n = strspn(node->name, c->data); 280 281 if (n < strlen(node->name)) 282 FAIL(c, "Bad character '%c' in node %s", 283 node->name[n], node->fullpath); 284} 285NODE_ERROR(node_name_chars, PROPNODECHARS "@"); 286 287static void check_node_name_format(struct check *c, struct node *dt, 288 struct node *node) 289{ 290 if (strchr(get_unitname(node), '@')) 291 FAIL(c, "Node %s has multiple '@' characters in name", 292 node->fullpath); 293} 294NODE_ERROR(node_name_format, NULL, &node_name_chars); 295 296static void check_property_name_chars(struct check *c, struct node *dt, 297 struct node *node, struct property *prop) 298{ 299 int n = strspn(prop->name, c->data); 300 301 if (n < strlen(prop->name)) 302 FAIL(c, "Bad character '%c' in property name \"%s\", node %s", 303 prop->name[n], prop->name, node->fullpath); 304} 305PROP_ERROR(property_name_chars, PROPNODECHARS); 306 307#define DESCLABEL_FMT "%s%s%s%s%s" 308#define DESCLABEL_ARGS(node,prop,mark) \ 309 ((mark) ? "value of " : ""), \ 310 ((prop) ? "'" : ""), \ 311 ((prop) ? (prop)->name : ""), \ 312 ((prop) ? "' in " : ""), (node)->fullpath 313 314static void check_duplicate_label(struct check *c, struct node *dt, 315 const char *label, struct node *node, 316 struct property *prop, struct marker *mark) 317{ 318 struct node *othernode = NULL; 319 struct property *otherprop = NULL; 320 struct marker *othermark = NULL; 321 322 othernode = get_node_by_label(dt, label); 323 324 if (!othernode) 325 otherprop = get_property_by_label(dt, label, &othernode); 326 if (!othernode) 327 othermark = get_marker_label(dt, label, &othernode, 328 &otherprop); 329 330 if (!othernode) 331 return; 332 333 if ((othernode != node) || (otherprop != prop) || (othermark != mark)) 334 FAIL(c, "Duplicate label '%s' on " DESCLABEL_FMT 335 " and " DESCLABEL_FMT, 336 label, DESCLABEL_ARGS(node, prop, mark), 337 DESCLABEL_ARGS(othernode, otherprop, othermark)); 338} 339 340static void check_duplicate_label_node(struct check *c, struct node *dt, 341 struct node *node) 342{ 343 struct label *l; 344 345 for_each_label(node->labels, l) 346 check_duplicate_label(c, dt, l->label, node, NULL, NULL); 347} 348static void check_duplicate_label_prop(struct check *c, struct node *dt, 349 struct node *node, struct property *prop) 350{ 351 struct marker *m = prop->val.markers; 352 struct label *l; 353 354 for_each_label(prop->labels, l) 355 check_duplicate_label(c, dt, l->label, node, prop, NULL); 356 357 for_each_marker_of_type(m, LABEL) 358 check_duplicate_label(c, dt, m->ref, node, prop, m); 359} 360ERROR(duplicate_label, NULL, check_duplicate_label_node, 361 check_duplicate_label_prop, NULL); 362 363static void check_explicit_phandles(struct check *c, struct node *root, 364 struct node *node, struct property *prop) 365{ 366 struct marker *m; 367 struct node *other; 368 cell_t phandle; 369 370 if (!streq(prop->name, "phandle") 371 && !streq(prop->name, "linux,phandle")) 372 return; 373 374 if (prop->val.len != sizeof(cell_t)) { 375 FAIL(c, "%s has bad length (%d) %s property", 376 node->fullpath, prop->val.len, prop->name); 377 return; 378 } 379 380 m = prop->val.markers; 381 for_each_marker_of_type(m, REF_PHANDLE) { 382 assert(m->offset == 0); 383 if (node != get_node_by_ref(root, m->ref)) 384 /* "Set this node's phandle equal to some 385 * other node's phandle". That's nonsensical 386 * by construction. */ { 387 FAIL(c, "%s in %s is a reference to another node", 388 prop->name, node->fullpath); 389 return; 390 } 391 /* But setting this node's phandle equal to its own 392 * phandle is allowed - that means allocate a unique 393 * phandle for this node, even if it's not otherwise 394 * referenced. The value will be filled in later, so 395 * no further checking for now. */ 396 return; 397 } 398 399 phandle = propval_cell(prop); 400 401 if ((phandle == 0) || (phandle == -1)) { 402 FAIL(c, "%s has bad value (0x%x) in %s property", 403 node->fullpath, phandle, prop->name); 404 return; 405 } 406 407 if (node->phandle && (node->phandle != phandle)) 408 FAIL(c, "%s has %s property which replaces existing phandle information", 409 node->fullpath, prop->name); 410 411 other = get_node_by_phandle(root, phandle); 412 if (other && (other != node)) { 413 FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)", 414 node->fullpath, phandle, other->fullpath); 415 return; 416 } 417 418 node->phandle = phandle; 419} 420PROP_ERROR(explicit_phandles, NULL); 421 422static void check_name_properties(struct check *c, struct node *root, 423 struct node *node) 424{ 425 struct property **pp, *prop = NULL; 426 427 for (pp = &node->proplist; *pp; pp = &((*pp)->next)) 428 if (streq((*pp)->name, "name")) { 429 prop = *pp; 430 break; 431 } 432 433 if (!prop) 434 return; /* No name property, that's fine */ 435 436 if ((prop->val.len != node->basenamelen+1) 437 || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) { 438 FAIL(c, "\"name\" property in %s is incorrect (\"%s\" instead" 439 " of base node name)", node->fullpath, prop->val.val); 440 } else { 441 /* The name property is correct, and therefore redundant. 442 * Delete it */ 443 *pp = prop->next; 444 free(prop->name); 445 data_free(prop->val); 446 free(prop); 447 } 448} 449ERROR_IF_NOT_STRING(name_is_string, "name"); 450NODE_ERROR(name_properties, NULL, &name_is_string); 451 452/* 453 * Reference fixup functions 454 */ 455 456static void fixup_phandle_references(struct check *c, struct node *dt, 457 struct node *node, struct property *prop) 458{ 459 struct marker *m = prop->val.markers; 460 struct node *refnode; 461 cell_t phandle; 462 463 for_each_marker_of_type(m, REF_PHANDLE) { 464 assert(m->offset + sizeof(cell_t) <= prop->val.len); 465 466 refnode = get_node_by_ref(dt, m->ref); 467 if (! refnode) { 468 FAIL(c, "Reference to non-existent node or label \"%s\"\n", 469 m->ref); 470 continue; 471 } 472 473 phandle = get_node_phandle(dt, refnode); 474 *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); 475 } 476} 477ERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL, 478 &duplicate_node_names, &explicit_phandles); 479 480static void fixup_path_references(struct check *c, struct node *dt, 481 struct node *node, struct property *prop) 482{ 483 struct marker *m = prop->val.markers; 484 struct node *refnode; 485 char *path; 486 487 for_each_marker_of_type(m, REF_PATH) { 488 assert(m->offset <= prop->val.len); 489 490 refnode = get_node_by_ref(dt, m->ref); 491 if (!refnode) { 492 FAIL(c, "Reference to non-existent node or label \"%s\"\n", 493 m->ref); 494 continue; 495 } 496 497 path = refnode->fullpath; 498 prop->val = data_insert_at_marker(prop->val, m, path, 499 strlen(path) + 1); 500 } 501} 502ERROR(path_references, NULL, NULL, fixup_path_references, NULL, 503 &duplicate_node_names); 504 505/* 506 * Semantic checks 507 */ 508WARNING_IF_NOT_CELL(address_cells_is_cell, "#address-cells"); 509WARNING_IF_NOT_CELL(size_cells_is_cell, "#size-cells"); 510WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells"); 511 512WARNING_IF_NOT_STRING(device_type_is_string, "device_type"); 513WARNING_IF_NOT_STRING(model_is_string, "model"); 514WARNING_IF_NOT_STRING(status_is_string, "status"); 515 516static void fixup_addr_size_cells(struct check *c, struct node *dt, 517 struct node *node) 518{ 519 struct property *prop; 520 521 node->addr_cells = -1; 522 node->size_cells = -1; 523 524 prop = get_property(node, "#address-cells"); 525 if (prop) 526 node->addr_cells = propval_cell(prop); 527 528 prop = get_property(node, "#size-cells"); 529 if (prop) 530 node->size_cells = propval_cell(prop); 531} 532WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, 533 &address_cells_is_cell, &size_cells_is_cell); 534 535#define node_addr_cells(n) \ 536 (((n)->addr_cells == -1) ? 2 : (n)->addr_cells) 537#define node_size_cells(n) \ 538 (((n)->size_cells == -1) ? 1 : (n)->size_cells) 539 540static void check_reg_format(struct check *c, struct node *dt, 541 struct node *node) 542{ 543 struct property *prop; 544 int addr_cells, size_cells, entrylen; 545 546 prop = get_property(node, "reg"); 547 if (!prop) 548 return; /* No "reg", that's fine */ 549 550 if (!node->parent) { 551 FAIL(c, "Root node has a \"reg\" property"); 552 return; 553 } 554 555 if (prop->val.len == 0) 556 FAIL(c, "\"reg\" property in %s is empty", node->fullpath); 557 558 addr_cells = node_addr_cells(node->parent); 559 size_cells = node_size_cells(node->parent); 560 entrylen = (addr_cells + size_cells) * sizeof(cell_t); 561 562 if ((prop->val.len % entrylen) != 0) 563 FAIL(c, "\"reg\" property in %s has invalid length (%d bytes) " 564 "(#address-cells == %d, #size-cells == %d)", 565 node->fullpath, prop->val.len, addr_cells, size_cells); 566} 567NODE_WARNING(reg_format, NULL, &addr_size_cells); 568 569static void check_ranges_format(struct check *c, struct node *dt, 570 struct node *node) 571{ 572 struct property *prop; 573 int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen; 574 575 prop = get_property(node, "ranges"); 576 if (!prop) 577 return; 578 579 if (!node->parent) { 580 FAIL(c, "Root node has a \"ranges\" property"); 581 return; 582 } 583 584 p_addr_cells = node_addr_cells(node->parent); 585 p_size_cells = node_size_cells(node->parent); 586 c_addr_cells = node_addr_cells(node); 587 c_size_cells = node_size_cells(node); 588 entrylen = (p_addr_cells + c_addr_cells + c_size_cells) * sizeof(cell_t); 589 590 if (prop->val.len == 0) { 591 if (p_addr_cells != c_addr_cells) 592 FAIL(c, "%s has empty \"ranges\" property but its " 593 "#address-cells (%d) differs from %s (%d)", 594 node->fullpath, c_addr_cells, node->parent->fullpath, 595 p_addr_cells); 596 if (p_size_cells != c_size_cells) 597 FAIL(c, "%s has empty \"ranges\" property but its " 598 "#size-cells (%d) differs from %s (%d)", 599 node->fullpath, c_size_cells, node->parent->fullpath, 600 p_size_cells); 601 } else if ((prop->val.len % entrylen) != 0) { 602 FAIL(c, "\"ranges\" property in %s has invalid length (%d bytes) " 603 "(parent #address-cells == %d, child #address-cells == %d, " 604 "#size-cells == %d)", node->fullpath, prop->val.len, 605 p_addr_cells, c_addr_cells, c_size_cells); 606 } 607} 608NODE_WARNING(ranges_format, NULL, &addr_size_cells); 609 610/* 611 * Style checks 612 */ 613static void check_avoid_default_addr_size(struct check *c, struct node *dt, 614 struct node *node) 615{ 616 struct property *reg, *ranges; 617 618 if (!node->parent) 619 return; /* Ignore root node */ 620 621 reg = get_property(node, "reg"); 622 ranges = get_property(node, "ranges"); 623 624 if (!reg && !ranges) 625 return; 626 627 if ((node->parent->addr_cells == -1)) 628 FAIL(c, "Relying on default #address-cells value for %s", 629 node->fullpath); 630 631 if ((node->parent->size_cells == -1)) 632 FAIL(c, "Relying on default #size-cells value for %s", 633 node->fullpath); 634} 635NODE_WARNING(avoid_default_addr_size, NULL, &addr_size_cells); 636 637static void check_obsolete_chosen_interrupt_controller(struct check *c, 638 struct node *dt) 639{ 640 struct node *chosen; 641 struct property *prop; 642 643 chosen = get_node_by_path(dt, "/chosen"); 644 if (!chosen) 645 return; 646 647 prop = get_property(chosen, "interrupt-controller"); 648 if (prop) 649 FAIL(c, "/chosen has obsolete \"interrupt-controller\" " 650 "property"); 651} 652TREE_WARNING(obsolete_chosen_interrupt_controller, NULL); 653 654static struct check *check_table[] = { 655 &duplicate_node_names, &duplicate_property_names, 656 &node_name_chars, &node_name_format, &property_name_chars, 657 &name_is_string, &name_properties, 658 659 &duplicate_label, 660 661 &explicit_phandles, 662 &phandle_references, &path_references, 663 664 &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell, 665 &device_type_is_string, &model_is_string, &status_is_string, 666 667 &addr_size_cells, ®_format, &ranges_format, 668 669 &avoid_default_addr_size, 670 &obsolete_chosen_interrupt_controller, 671 672 &always_fail, 673}; 674 675static void enable_warning_error(struct check *c, bool warn, bool error) 676{ 677 int i; 678 679 /* Raising level, also raise it for prereqs */ 680 if ((warn && !c->warn) || (error && !c->error)) 681 for (i = 0; i < c->num_prereqs; i++) 682 enable_warning_error(c->prereq[i], warn, error); 683 684 c->warn = c->warn || warn; 685 c->error = c->error || error; 686} 687 688static void disable_warning_error(struct check *c, bool warn, bool error) 689{ 690 int i; 691 692 /* Lowering level, also lower it for things this is the prereq 693 * for */ 694 if ((warn && c->warn) || (error && c->error)) { 695 for (i = 0; i < ARRAY_SIZE(check_table); i++) { 696 struct check *cc = check_table[i]; 697 int j; 698 699 for (j = 0; j < cc->num_prereqs; j++) 700 if (cc->prereq[j] == c) 701 disable_warning_error(cc, warn, error); 702 } 703 } 704 705 c->warn = c->warn && !warn; 706 c->error = c->error && !error; 707} 708 709void parse_checks_option(bool warn, bool error, const char *optarg) 710{ 711 int i; 712 const char *name = optarg; 713 bool enable = true; 714 715 if ((strncmp(optarg, "no-", 3) == 0) 716 || (strncmp(optarg, "no_", 3) == 0)) { 717 name = optarg + 3; 718 enable = false; 719 } 720 721 for (i = 0; i < ARRAY_SIZE(check_table); i++) { 722 struct check *c = check_table[i]; 723 724 if (streq(c->name, name)) { 725 if (enable) 726 enable_warning_error(c, warn, error); 727 else 728 disable_warning_error(c, warn, error); 729 return; 730 } 731 } 732 733 die("Unrecognized check name \"%s\"\n", name); 734} 735 736void process_checks(int force, struct boot_info *bi) 737{ 738 struct node *dt = bi->dt; 739 int i; 740 int error = 0; 741 742 for (i = 0; i < ARRAY_SIZE(check_table); i++) { 743 struct check *c = check_table[i]; 744 745 if (c->warn || c->error) 746 error = error || run_check(c, dt); 747 } 748 749 if (error) { 750 if (!force) { 751 fprintf(stderr, "ERROR: Input tree has errors, aborting " 752 "(use -f to force output)\n"); 753 exit(2); 754 } else if (quiet < 3) { 755 fprintf(stderr, "Warning: Input tree has errors, " 756 "output forced\n"); 757 } 758 } 759} 760