libexplain
1.4.D001
|
00001 /* 00002 * libexplain - Explain errno values returned by libc functions 00003 * Copyright (C) 2009-2011, 2013 Peter Miller 00004 * Written by Peter Miller <pmiller@opensource.org.au> 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU Lesser General Public License as 00008 * published by the Free Software Foundation; either version 3 of the 00009 * License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public License 00017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00018 */ 00019 00020 #include <libexplain/ac/stdio.h> 00021 #include <libexplain/ac/stdlib.h> 00022 #include <libexplain/ac/net/if.h> 00023 #include <libexplain/ac/string.h> 00024 #include <libexplain/ac/sys/ioctl.h> 00025 00026 #include <libexplain/iocontrol/generic.h> 00027 #include <libexplain/iocontrol/table.h> 00028 #include <libexplain/string_buffer.h> 00029 00030 00031 static int 00032 bogus_request_number(int request) 00033 { 00034 if (request == 0) 00035 return 1; 00036 #ifdef _IOC_SIZE 00037 return (_IOC_SIZE(request) == _IOC_SIZEMASK); 00038 #else 00039 return (request == -1); 00040 #endif 00041 } 00042 00043 00044 static const char * 00045 explode_hash_define(int request) 00046 { 00047 explain_string_buffer_t sb; 00048 static char buffer[100]; 00049 00050 explain_string_buffer_init(&sb, buffer, sizeof(buffer)); 00051 explain_iocontrol_generic_print_hash_define(&sb, request); 00052 return buffer; 00053 } 00054 00055 00056 static int 00057 looks_like_a_pointer(const char *s) 00058 { 00059 return (strchr(s, '*') || strchr(s, '[')); 00060 } 00061 00062 00063 void 00064 explain_iocontrol_check_conflicts(void) 00065 { 00066 const explain_iocontrol_t *const *tpp1; 00067 const explain_iocontrol_t *const *end; 00068 unsigned number_of_errors; 00069 00070 end = explain_iocontrol_table + explain_iocontrol_table_size; 00071 number_of_errors = 0; 00072 for (tpp1 = explain_iocontrol_table; tpp1 < end; ++tpp1) 00073 { 00074 const explain_iocontrol_t *tp1; 00075 const explain_iocontrol_t *const *tpp2; 00076 int disambiguate_already_mentioned; 00077 00078 disambiguate_already_mentioned = 0; 00079 tp1 = *tpp1; 00080 if (!tp1->name) 00081 { 00082 if (tp1->number) 00083 { 00084 fprintf 00085 ( 00086 stderr, 00087 "%s: %d: request number not zero\n", 00088 tp1->file, 00089 tp1->line - 9 00090 ); 00091 ++number_of_errors; 00092 } 00093 continue; 00094 } 00095 if (bogus_request_number(tp1->number)) 00096 { 00097 fprintf 00098 ( 00099 stderr, 00100 "%s: %d: bogus request number 0x%04X\n", 00101 tp1->file, 00102 tp1->line - 9, 00103 tp1->number 00104 ); 00105 ++number_of_errors; 00106 continue; 00107 } 00108 if (!(tp1->flags & IOCONTROL_FLAG_NON_META)) 00109 { 00110 unsigned ioc_dir; 00111 unsigned ioc_size; 00112 00113 #ifdef _IOC_DIR 00114 ioc_dir = _IOC_DIR(tp1->number); 00115 #else 00116 #ifdef IOC_DIRMASK 00117 ioc_dir = tp1->number & IOC_DIRMASK; 00118 #else 00119 ioc_dir = 0; 00120 #endif 00121 #endif 00122 #ifdef _IOC_SIZE 00123 ioc_size = _IOC_SIZE(tp1->number); 00124 #else 00125 #ifdef IOCPARM_LEN 00126 ioc_size = IOCPARM_LEN(tp1->number); 00127 #else 00128 ioc_size = 0; 00129 #endif 00130 #endif 00131 switch (ioc_dir) 00132 { 00133 #ifdef _IOC_NONE 00134 case _IOC_NONE: 00135 #endif 00136 #ifdef IOC_VOID 00137 case IOC_VOID: 00138 #endif 00139 #if !defined(_IOC_NONE) && !defined(IOC_VOID) 00140 case 0: 00141 #endif 00142 if 00143 ( 00144 tp1->data_size != NOT_A_POINTER 00145 && 00146 !(tp1->flags & IOCONTROL_FLAG_SIZE_DOES_NOT_AGREE) 00147 ) 00148 { 00149 fprintf 00150 ( 00151 stderr, 00152 "%s: %d: %s indicates that data_size should be " 00153 "NOT_A_POINTER\n", 00154 tp1->file, 00155 tp1->line - 4, 00156 explode_hash_define(tp1->number) 00157 ); 00158 ++number_of_errors; 00159 } 00160 break; 00161 00162 #ifdef _IOC_READ 00163 case _IOC_READ: 00164 #endif 00165 #ifdef IOC_OUT 00166 case IOC_OUT: 00167 #endif 00168 if 00169 ( 00170 ioc_size != tp1->data_size 00171 && 00172 !(tp1->flags & IOCONTROL_FLAG_SIZE_DOES_NOT_AGREE) 00173 ) 00174 { 00175 fprintf 00176 ( 00177 stderr, 00178 "%s: %d: %s indicates that data_size should be %d " 00179 "(not %d)\n", 00180 tp1->file, 00181 tp1->line - 4, 00182 explode_hash_define(tp1->number), 00183 ioc_size, 00184 tp1->data_size 00185 ); 00186 ++number_of_errors; 00187 } 00188 if 00189 ( 00190 tp1->print_data != 00191 explain_iocontrol_generic_print_data_pointer 00192 && 00193 !(tp1->flags & IOCONTROL_FLAG_RW) 00194 ) 00195 { 00196 fprintf 00197 ( 00198 stderr, 00199 "%s: %d: %s indicates that print_data should be " 00200 "explain_iocontrol_generic_print_data_pointer " 00201 "(%s: %d)\n", 00202 tp1->file, 00203 tp1->line - 7, 00204 explode_hash_define(tp1->number), 00205 __FILE__, 00206 __LINE__ 00207 ); 00208 ++number_of_errors; 00209 } 00210 if (tp1->print_data_returned == NULL) 00211 { 00212 fprintf 00213 ( 00214 stderr, 00215 "%s: %d: %s indicates that print_data_returned should " 00216 "not be NULL (%s: %d)\n", 00217 tp1->file, 00218 tp1->line - 5, 00219 explode_hash_define(tp1->number), 00220 __FILE__, 00221 __LINE__ 00222 ); 00223 ++number_of_errors; 00224 } 00225 break; 00226 00227 #ifdef _IOC_WRITE 00228 case _IOC_WRITE: 00229 #endif 00230 #ifdef IOC_IN 00231 case IOC_IN: 00232 #endif 00233 if (!(tp1->flags & IOCONTROL_FLAG_SIZE_DOES_NOT_AGREE)) 00234 { 00235 if (ioc_size != tp1->data_size) 00236 { 00237 fprintf 00238 ( 00239 stderr, 00240 "%s: %d: %s indicates that data_size should be " 00241 "%d (not %d)\n", 00242 tp1->file, 00243 tp1->line - 4, 00244 explode_hash_define(tp1->number), 00245 ioc_size, 00246 tp1->data_size 00247 ); 00248 ++number_of_errors; 00249 } 00250 } 00251 if 00252 ( 00253 tp1->print_data == 00254 explain_iocontrol_generic_print_data_pointer 00255 ) 00256 { 00257 fprintf 00258 ( 00259 stderr, 00260 "%s: %d: %s indicates that print_data should not be " 00261 "explain_iocontrol_generic_print_data_pointer " 00262 "(%s: %d)\n", 00263 tp1->file, 00264 tp1->line - 7, 00265 explode_hash_define(tp1->number), 00266 __FILE__, 00267 __LINE__ 00268 ); 00269 ++number_of_errors; 00270 } 00271 if 00272 ( 00273 tp1->print_data_returned != NULL 00274 && 00275 !(tp1->flags & IOCONTROL_FLAG_RW) 00276 ) 00277 { 00278 fprintf 00279 ( 00280 stderr, 00281 "%s: %d: %s indicates that print_data_returned should " 00282 "be NULL (%s: %d)\n", 00283 tp1->file, 00284 tp1->line - 5, 00285 explode_hash_define(tp1->number), 00286 __FILE__, 00287 __LINE__ 00288 ); 00289 ++number_of_errors; 00290 } 00291 break; 00292 00293 #ifdef IOC_INOUT 00294 case IOC_INOUT: 00295 #endif 00296 #if defined(_IOC_READ) && defined(_IOC_WRITE) 00297 case _IOC_READ | _IOC_WRITE: 00298 #endif 00299 if 00300 ( 00301 ioc_size != tp1->data_size 00302 && 00303 !(tp1->flags & IOCONTROL_FLAG_SIZE_DOES_NOT_AGREE) 00304 ) 00305 { 00306 fprintf 00307 ( 00308 stderr, 00309 "%s: %d: %s indicates that data_size should be %d " 00310 "(not %d)\n", 00311 tp1->file, 00312 tp1->line - 4, 00313 explode_hash_define(tp1->number), 00314 ioc_size, 00315 tp1->data_size 00316 ); 00317 ++number_of_errors; 00318 } 00319 if 00320 ( 00321 tp1->print_data == 00322 explain_iocontrol_generic_print_data_pointer 00323 ) 00324 { 00325 fprintf 00326 ( 00327 stderr, 00328 "%s: %d: %s indicates that print_data should not be " 00329 "explain_iocontrol_generic_print_data_pointer " 00330 "(%s: %d)\n", 00331 tp1->file, 00332 tp1->line - 7, 00333 explode_hash_define(tp1->number), 00334 __FILE__, 00335 __LINE__ 00336 ); 00337 ++number_of_errors; 00338 } 00339 if (tp1->print_data_returned == NULL) 00340 { 00341 fprintf 00342 ( 00343 stderr, 00344 "%s: %d: %s indicates that print_data_returned should " 00345 "not be NULL (%s: %d)\n", 00346 tp1->file, 00347 tp1->line - 5, 00348 explode_hash_define(tp1->number), 00349 __FILE__, 00350 __LINE__ 00351 ); 00352 ++number_of_errors; 00353 } 00354 break; 00355 00356 default: 00357 break; 00358 } 00359 } 00360 00361 if (!tp1->data_type || !*tp1->data_type) 00362 { 00363 fprintf 00364 ( 00365 stderr, 00366 "%s: %d: must set the data_type\n", 00367 tp1->file, 00368 tp1->line - 3 00369 ); 00370 ++number_of_errors; 00371 continue; 00372 } 00373 00374 #ifdef SIOCDEVPRIVATE 00375 if 00376 ( 00377 tp1->number >= SIOCDEVPRIVATE 00378 && 00379 tp1->number < SIOCDEVPRIVATE + 16 00380 && 00381 !(tp1->flags & IOCONTROL_FLAG_SIZE_DOES_NOT_AGREE) 00382 ) 00383 { 00384 if (tp1->data_size != sizeof(struct ifreq)) 00385 { 00386 fprintf 00387 ( 00388 stderr, 00389 "%s: %d: the data_size must be sizeof(struct ifreq)\n", 00390 tp1->file, 00391 tp1->line - 4 00392 ); 00393 ++number_of_errors; 00394 } 00395 if (0 != strcmp(tp1->data_type, "struct ifreq *")) 00396 { 00397 fprintf 00398 ( 00399 stderr, 00400 "%s: %d: the data_type must be \"struct ifreq *\"\n", 00401 tp1->file, 00402 tp1->line - 3 00403 ); 00404 ++number_of_errors; 00405 } 00406 } 00407 #endif 00408 00409 if (tp1->data_size == 0) 00410 { 00411 fprintf 00412 ( 00413 stderr, 00414 "%s: %d: you must define data_size, " 00415 "or set it to NOT_A_POINTER\n", 00416 tp1->file, 00417 tp1->line - 6 00418 ); 00419 ++number_of_errors; 00420 } 00421 else if (tp1->data_size == NOT_A_POINTER) 00422 { 00423 expain_iocontrol_print_func_t f; 00424 expain_iocontrol_print_func_t rf; 00425 00426 f = tp1->print_data; 00427 if (!f) 00428 { 00429 fprintf 00430 ( 00431 stderr, 00432 "%s: %d: you must define print_data, " 00433 "e.g. explain_iocontrol_generic_print_data_int\n", 00434 tp1->file, 00435 tp1->line - 7 00436 ); 00437 ++number_of_errors; 00438 } 00439 else if 00440 ( 00441 f == explain_iocontrol_generic_print_data_pointer 00442 || 00443 f == explain_iocontrol_generic_print_data_int_star 00444 || 00445 f == explain_iocontrol_generic_print_data_uint_star 00446 || 00447 f == explain_iocontrol_generic_print_data_long_star 00448 || 00449 f == explain_iocontrol_generic_print_data_ulong_star 00450 ) 00451 { 00452 fprintf 00453 ( 00454 stderr, 00455 "%s: %d: weird value for print_data, did you mean" 00456 "explain_iocontrol_generic_print_data_int\n", 00457 tp1->file, 00458 tp1->line - 7 00459 ); 00460 ++number_of_errors; 00461 } 00462 00463 rf = tp1->print_data_returned; 00464 if (rf) 00465 { 00466 fprintf 00467 ( 00468 stderr, 00469 "%s: %d: you must not define print_data_returned\n", 00470 tp1->file, 00471 tp1->line - 5 00472 ); 00473 ++number_of_errors; 00474 } 00475 00476 if (0 != strcmp(tp1->data_type, "intptr_t")) 00477 { 00478 /* 00479 * It must be an integer type that is exactly the same 00480 * size as a void*, and the C99 standard only defines 00481 * one type with that property: intptr_t 00482 * 00483 * Many folks wrongly think "int" has this property. 00484 */ 00485 fprintf 00486 ( 00487 stderr, 00488 "%s: %d: you must use \"intptr_t\" for the data_type\n", 00489 tp1->file, 00490 tp1->line - 3 00491 ); 00492 ++number_of_errors; 00493 } 00494 } 00495 else 00496 { 00497 if (!looks_like_a_pointer(tp1->data_type)) 00498 { 00499 fprintf 00500 ( 00501 stderr, 00502 "%s: %d: the data_type must be a pointer\n", 00503 tp1->file, 00504 tp1->line - 4 00505 ); 00506 ++number_of_errors; 00507 } 00508 if (tp1->print_data == explain_iocontrol_generic_print_data_ignored) 00509 { 00510 if (tp1->print_data_returned) 00511 { 00512 fprintf 00513 ( 00514 stderr, 00515 "%s: %d: should be " 00516 "explain_iocontrol_generic_print_data_pointer\n", 00517 tp1->file, 00518 tp1->line - 7 00519 ); 00520 } 00521 else 00522 { 00523 fprintf 00524 ( 00525 stderr, 00526 "%s: %d: ignored data should be NOT_A_POINTER\n", 00527 tp1->file, 00528 tp1->line - 4 00529 ); 00530 } 00531 ++number_of_errors; 00532 } 00533 if (!tp1->print_data) 00534 { 00535 fprintf 00536 ( 00537 stderr, 00538 "%s: %d: you must define print_data\n", 00539 tp1->file, 00540 tp1->line - 7 00541 ); 00542 ++number_of_errors; 00543 } 00544 if (tp1->print_data_returned) 00545 { 00546 expain_iocontrol_print_func_t f; 00547 00548 f = tp1->print_data; 00549 if 00550 ( 00551 !f 00552 || 00553 f == explain_iocontrol_generic_print_data_ignored 00554 || 00555 f == explain_iocontrol_generic_print_data_int 00556 || 00557 f == explain_iocontrol_generic_print_data_uint 00558 || 00559 f == explain_iocontrol_generic_print_data_long 00560 || 00561 f == explain_iocontrol_generic_print_data_ulong 00562 ) 00563 { 00564 fprintf 00565 ( 00566 stderr, 00567 "%s: %d: print_data must be a pointer, did you mean " 00568 "explain_iocontrol_generic_print_data_pointer\n", 00569 tp1->file, 00570 tp1->line - 7 00571 ); 00572 ++number_of_errors; 00573 } 00574 } 00575 } 00576 00577 for (tpp2 = tpp1 + 1; tpp2 < end; ++tpp2) 00578 { 00579 const explain_iocontrol_t *tp2; 00580 00581 tp2 = *tpp2; 00582 if (!tp2->name) 00583 continue; 00584 if (tp1->number == tp2->number) 00585 { 00586 /* 00587 * Potential conflict. 00588 */ 00589 if (!tp1->disambiguate || !tp2->disambiguate) 00590 { 00591 fprintf 00592 ( 00593 stderr, 00594 "%s: %d: conflict: %s vs %s\n", 00595 tp1->file, 00596 tp1->line - 9, 00597 tp1->name, 00598 tp2->name 00599 ); 00600 ++number_of_errors; 00601 if (!tp1->disambiguate && !disambiguate_already_mentioned) 00602 { 00603 disambiguate_already_mentioned = 1; 00604 fprintf 00605 ( 00606 stderr, 00607 "%s: %d: %s has no disambiguate function\n", 00608 tp1->file, 00609 tp1->line - 7, 00610 tp1->name 00611 ); 00612 } 00613 if (!tp2->disambiguate) 00614 { 00615 fprintf 00616 ( 00617 stderr, 00618 "%s: %d: %s has no disambiguate function\n", 00619 tp2->file, 00620 tp2->line - 7, 00621 tp2->name 00622 ); 00623 } 00624 } 00625 } 00626 } 00627 } 00628 if (number_of_errors > 0) 00629 { 00630 fprintf 00631 ( 00632 stderr, 00633 "found %u error%s\n", 00634 number_of_errors, 00635 (number_of_errors == 1 ? "" : "s") 00636 ); 00637 exit(1); 00638 } 00639 } 00640 00641 00642 /* vim: set ts=8 sw=4 et : */