libexplain  1.4.D001
libexplain/iocontrol/check_conflicts.c
Go to the documentation of this file.
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 : */