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