libexplain  1.4.D001
libexplain/iocontrol/generic.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2009-2011, 2013, 2014 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 it
00007  * under the terms of the GNU Lesser General Public License as published by
00008  * the Free Software Foundation; either version 3 of the License, or (at your
00009  * option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful, but WITHOUT
00012  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00013  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00014  * 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/ctype.h>
00021 #include <libexplain/ac/errno.h>
00022 #include <libexplain/ac/stdint.h>
00023 #include <libexplain/ac/stdlib.h>
00024 #include <libexplain/ac/sys/ioctl.h>
00025 
00026 #include <libexplain/buffer/dac.h>
00027 #include <libexplain/buffer/eacces.h>
00028 #include <libexplain/buffer/ebadf.h>
00029 #include <libexplain/buffer/ebusy.h>
00030 #include <libexplain/buffer/efault.h>
00031 #include <libexplain/buffer/eio.h>
00032 #include <libexplain/buffer/enomedium.h>
00033 #include <libexplain/buffer/enosys.h>
00034 #include <libexplain/buffer/erofs.h>
00035 #include <libexplain/buffer/errno/generic.h>
00036 #include <libexplain/buffer/gettext.h>
00037 #include <libexplain/buffer/int.h>
00038 #include <libexplain/buffer/int8.h>
00039 #include <libexplain/buffer/int64_t.h>
00040 #include <libexplain/buffer/is_the_null_pointer.h>
00041 #include <libexplain/buffer/long.h>
00042 #include <libexplain/buffer/pointer.h>
00043 #include <libexplain/buffer/short.h>
00044 #include <libexplain/iocontrol/generic.h>
00045 #include <libexplain/parse_bits.h>
00046 #include <libexplain/sizeof.h>
00047 #include <libexplain/string_buffer.h>
00048 
00049 
00050 #if defined(_IOC_DIR) || defined(IOC_DIRMASK)
00051 
00052 static const explain_parse_bits_table_t ioc_dir_table[] =
00053 {
00054 #ifdef _IOC_NONE
00055     { "_IOC_NONE", _IOC_NONE },
00056 #endif
00057 #ifdef _IOC_WRITE
00058     { "_IOC_WRITE", _IOC_WRITE },
00059 #endif
00060 #ifdef _IOC_READ
00061     { "_IOC_READ", _IOC_READ },
00062 #endif
00063 #ifdef IOC_VOID
00064     { "IOC_VOID", IOC_VOID },
00065 #endif
00066 #ifdef IOC_OUT
00067     { "IOC_OUT", IOC_OUT },
00068 #endif
00069 #ifdef IOC_IN
00070     { "IOC_IN", IOC_IN },
00071 #endif
00072 #ifdef IOC_INOUT
00073     { "IOC_INOUT", IOC_INOUT },
00074 #endif
00075 };
00076 
00077 
00078 static void
00079 explain_buffer_ioc_dir(explain_string_buffer_t *sb, int ioc_dir)
00080 {
00081     const explain_parse_bits_table_t *tp;
00082 
00083     tp =
00084         explain_parse_bits_find_by_value
00085         (
00086             ioc_dir,
00087             ioc_dir_table,
00088             SIZEOF(ioc_dir_table)
00089         );
00090     if (tp)
00091         explain_string_buffer_puts(sb, tp->name);
00092     else
00093         explain_string_buffer_printf(sb, "%d", ioc_dir);
00094 }
00095 
00096 
00097 static void
00098 char_or_hex(explain_string_buffer_t *sb, int value)
00099 {
00100     if (value >= 0 && value < 256 && isprint(value))
00101         explain_string_buffer_putc_quoted(sb, value);
00102     else
00103         explain_string_buffer_printf(sb, "0x%02X", value);
00104 }
00105 
00106 
00107 static void
00108 tsize(explain_string_buffer_t *sb, int nbytes)
00109 {
00110     div_t           d;
00111 
00112     if (nbytes == 0)
00113     {
00114         explain_string_buffer_puts(sb, "char[0]");
00115         return;
00116     }
00117     d = div(nbytes, sizeof(int));
00118     if (d.rem == 0)
00119     {
00120         if (d.quot == 1)
00121             explain_string_buffer_puts(sb, "int");
00122         else
00123             explain_string_buffer_printf(sb, "int[%d]", d.quot);
00124         return;
00125     }
00126     d = div(nbytes, sizeof(long));
00127     if (d.rem == 0)
00128     {
00129         if (d.quot == 1)
00130             explain_string_buffer_puts(sb, "long");
00131         else
00132             explain_string_buffer_printf(sb, "long[%d]", d.quot);
00133         return;
00134     }
00135     d = div(nbytes, sizeof(short));
00136     if (d.rem == 0)
00137     {
00138         if (d.quot == 1)
00139             explain_string_buffer_puts(sb, "short");
00140         else
00141             explain_string_buffer_printf(sb, "short[%d]", d.quot);
00142         return;
00143     }
00144     explain_string_buffer_printf(sb, "char[%d]", nbytes);
00145 }
00146 
00147 
00148 static void
00149 io(explain_string_buffer_t *sb, int type, int nr)
00150 {
00151     explain_string_buffer_puts(sb, "_IO(");
00152     char_or_hex(sb, type);
00153     explain_string_buffer_printf(sb, ", %d)", nr);
00154 }
00155 
00156 
00157 static void
00158 ioc(explain_string_buffer_t *sb, int dir, int type, int nr, int size)
00159 {
00160     explain_string_buffer_puts(sb, "_IOC(");
00161     explain_buffer_ioc_dir(sb, dir);
00162     explain_string_buffer_puts(sb, ", ");
00163     char_or_hex(sb, type);
00164     explain_string_buffer_printf(sb, ", %d, ", nr);
00165     tsize(sb, size);
00166     explain_string_buffer_putc(sb, ')');
00167 }
00168 
00169 
00170 static void
00171 ior(explain_string_buffer_t *sb, int type, int nr, int size)
00172 {
00173     explain_string_buffer_puts(sb, "_IOR(");
00174     char_or_hex(sb, type);
00175     explain_string_buffer_printf(sb, ", %d, ", nr);
00176     tsize(sb, size);
00177     explain_string_buffer_putc(sb, ')');
00178 }
00179 
00180 
00181 static void
00182 iow(explain_string_buffer_t *sb, int type, int nr, int size)
00183 {
00184     explain_string_buffer_puts(sb, "_IOW(");
00185     char_or_hex(sb, type);
00186     explain_string_buffer_printf(sb, ", %d, ", nr);
00187     tsize(sb, size);
00188     explain_string_buffer_putc(sb, ')');
00189 }
00190 
00191 
00192 static void
00193 iorw(explain_string_buffer_t *sb, int type, int nr, int size)
00194 {
00195     explain_string_buffer_puts(sb, "_IORW(");
00196     char_or_hex(sb, type);
00197     explain_string_buffer_printf(sb, ", %d, ", nr);
00198     tsize(sb, size);
00199     explain_string_buffer_putc(sb, ')');
00200 }
00201 
00202 #endif
00203 
00204 
00205 void
00206 explain_iocontrol_generic_print_hash_define(explain_string_buffer_t *sb,
00207     int request)
00208 {
00209 #ifdef SIOCDEVPRIVATE
00210     if (SIOCDEVPRIVATE <= request && request < SIOCDEVPRIVATE + 16)
00211     {
00212         explain_string_buffer_printf
00213         (
00214             sb,
00215             "SIOCDEVPRIVATE + %d",
00216             request - SIOCDEVPRIVATE
00217         );
00218         return;
00219     }
00220 #endif
00221 #ifdef SIOCPROTOPRIVATE
00222     if (SIOCPROTOPRIVATE <= request && request < SIOCPROTOPRIVATE + 16)
00223     {
00224         explain_string_buffer_printf
00225         (
00226             sb,
00227             "SIOCPROTOPRIVATE + %d",
00228             request - SIOCPROTOPRIVATE
00229         );
00230         return;
00231     }
00232 #endif
00233     if (request == 0)
00234     {
00235         /* special case for zero */
00236         explain_string_buffer_putc(sb, '0');
00237         return;
00238     }
00239 #if defined(_IOC_DIR) || defined(IOC_DIRMASK)
00240     {
00241         int             ioc_dir;
00242         int             ioc_type;
00243         int             ioc_nr;
00244         int             ioc_size;
00245 
00246 #ifdef _IOC_DIR
00247         ioc_dir = _IOC_DIR(request);
00248 #else
00249         ioc_dir = request & IOC_DIRMASK;
00250 #endif
00251 #ifdef _IOC_TYPE
00252         ioc_type = _IOC_TYPE(request);
00253 #else
00254         ioc_type = IOCGROUP(request);
00255 #endif
00256 #ifdef _IOC_NR
00257         ioc_nr = _IOC_NR(request);
00258 #else
00259         ioc_nr = request & 0xFF;
00260 #endif
00261 #ifdef _IOC_SIZE
00262         ioc_size = _IOC_SIZE(request);
00263 #else
00264         ioc_size = IOCPARM_LEN(request);
00265 #endif
00266         switch (ioc_dir)
00267         {
00268 #ifdef _IOC_NONE
00269         case _IOC_NONE:
00270 #endif
00271 #ifdef IOC_VOID
00272         case IOC_VOID:
00273 #endif
00274             if (ioc_size != 0)
00275                 ioc(sb, ioc_dir, ioc_type, ioc_nr, ioc_size);
00276             else
00277                 io(sb, ioc_type, ioc_nr);
00278             return;
00279 
00280 #ifdef _IOC_READ
00281         case _IOC_READ:
00282 #endif
00283 #ifdef IOC_OUT
00284         case IOC_OUT:
00285 #endif
00286             if (ioc_size != 0)
00287             {
00288                 ior(sb, ioc_type, ioc_nr, ioc_size);
00289                 return;
00290             }
00291             break;
00292 
00293 #ifdef _IOC_WRITE
00294         case _IOC_WRITE:
00295 #endif
00296 #ifdef IOC_IN
00297         case IOC_IN:
00298 #endif
00299             if (ioc_size != 0)
00300             {
00301                 iow(sb, ioc_type, ioc_nr, ioc_size);
00302                 return;
00303             }
00304             break;
00305 
00306 #ifdef IOC_INOUT
00307         case IOC_INOUT:
00308 #endif
00309 #if defined(_IOC_READ) && defined(_IOC_WRITE)
00310         case _IOC_READ | _IOC_WRITE:
00311 #endif
00312             if (ioc_size != 0)
00313             {
00314                 iorw(sb, ioc_type, ioc_nr, ioc_size);
00315                 return;
00316             }
00317             break;
00318 
00319         default:
00320             if (ioc_size != 0)
00321             {
00322                 ioc(sb, ioc_dir, ioc_type, ioc_nr, ioc_size);
00323                 return;
00324             }
00325             break;
00326         }
00327     }
00328 #endif
00329     {
00330         int             prec;
00331 
00332         prec = 2;
00333         if (request >= 0x10000)
00334             prec = 8;
00335         else if (request >= 0x100)
00336             prec = 4;
00337         explain_string_buffer_printf(sb, "0x%.*X", prec, request);
00338     }
00339 }
00340 
00341 
00342 static void
00343 print_name(const explain_iocontrol_t *p, explain_string_buffer_t *sb,
00344     int errnum, int fildes, int request, const void *data)
00345 {
00346     (void)p;
00347     (void)errnum;
00348     (void)fildes;
00349     (void)data;
00350     explain_iocontrol_generic_print_hash_define(sb, request);
00351 }
00352 
00353 
00354 void
00355 explain_iocontrol_fake_syscall_name(char *name, int name_size,
00356     const explain_iocontrol_t *p, int request)
00357 {
00358     explain_string_buffer_t name_buf;
00359 
00360     explain_string_buffer_init(&name_buf, name, name_size);
00361     explain_string_buffer_puts(&name_buf, "ioctl ");
00362     if (!p)
00363         explain_iocontrol_generic_print_hash_define(&name_buf, request);
00364     else if (p->name)
00365         explain_string_buffer_puts(&name_buf, p->name);
00366     else if (p->print_name)
00367         p->print_name(p, &name_buf, 0, 0, request, 0);
00368     else
00369         explain_iocontrol_generic_print_hash_define(&name_buf, request);
00370 }
00371 
00372 
00373 void
00374 explain_iocontrol_generic_print_explanation(const explain_iocontrol_t *p,
00375     explain_string_buffer_t *sb, int errnum, int fildes, int request,
00376     const void *data)
00377 {
00378     char            name[40];
00379 
00380     /*
00381      * http://www.opengroup.org/onlinepubs/009695399/functions/ioctl.html
00382      */
00383     (void)data;
00384     switch (errnum)
00385     {
00386     case EACCES:
00387         explain_iocontrol_fake_syscall_name(name, sizeof(name), p, request);
00388         explain_buffer_eacces_syscall(sb, name);
00389         explain_buffer_dac_sys_admin(sb);
00390         break;
00391 
00392     case EBADF:
00393         explain_buffer_ebadf(sb, fildes, "fildes");
00394         break;
00395 
00396     case EBUSY:
00397         explain_iocontrol_fake_syscall_name(name, sizeof(name), p, request);
00398         explain_buffer_ebusy_fildes(sb, fildes, "fildes", name);
00399         break;
00400 
00401     case EFAULT:
00402         explain_buffer_efault(sb, "data");
00403         break;
00404 
00405     case EIO:
00406         explain_buffer_eio_fildes(sb, fildes);
00407         break;
00408 
00409     case EINVAL:
00410         if (!data)
00411         {
00412             explain_buffer_is_the_null_pointer(sb, "data");
00413             break;
00414         }
00415         explain_buffer_gettext
00416         (
00417             sb,
00418             /*
00419              * xgettext:  This message is used to explain an EINVAL
00420              * error reported by an ioctl(2) system call, when a more
00421              * specific explanation is not availble.
00422              */
00423             i18n("ioctl request or ioctl data is not valid")
00424             /*
00425              * We can't exclude "ioctl request or" from the text, because Linux
00426              * is somewhat schitzophrenic is this regard, and annoyingly returns
00427              * EINVAL in many situtions where ENOTTY is patently more suitable.
00428              *
00429              * We could, of course, put #ifdef __linux__ around it, since this
00430              * brain damage is mostly limited to Linux.
00431              */
00432         );
00433         break;
00434 
00435 #ifdef ENOMEDIUM
00436     case ENOMEDIUM:
00437         explain_buffer_enomedium_fildes(sb, fildes);
00438         break;
00439 #endif
00440 
00441     case ENOTTY:
00442     case ENOSYS:
00443 #if defined(EOPNOTSUPP) && EOPNOTSUPP != ENOSYS
00444     case EOPNOTSUPP:
00445 #endif
00446 #if defined(ENOIOCTLCMD) && ENOIOCTLCMD != ENOTTY
00447         /*
00448          * The Linux kernel (well, parts of it) annoyingly returns EINVAL
00449          * in many situtions where ENOTTY is patently more suitable.
00450          * Linus Torvalds suggested that the correct course of action is
00451          *
00452          *     #define ENOIOCTLCMD ENOTTY
00453          *
00454          * and return this value to user space.
00455          * http://article.gmane.org/gmane.linux.kernel/1160917
00456          */
00457     case ENOIOCTLCMD:
00458 #endif
00459 #if defined(ENOIOCTL) && ENOIOCTL != ENOTTY
00460     case ENOIOCTL:
00461 #endif
00462         explain_iocontrol_fake_syscall_name(name, sizeof(name), p, request);
00463         explain_buffer_enosys_fildes(sb, fildes, "fildes", name);
00464         break;
00465 
00466     case EROFS:
00467         explain_buffer_erofs_fildes(sb, fildes, "fildes");
00468         break;
00469 
00470     default:
00471         explain_iocontrol_fake_syscall_name(name, sizeof(name), p, request);
00472         explain_buffer_errno_generic(sb, errnum, name);
00473         break;
00474     }
00475 }
00476 
00477 
00478 /*
00479  * The third argument is an untyped pointer to memory.  It's
00480  * traditionally char *argp (from the days before "void *" was valid C).
00481  * So for undefined ioctl requets, we will interpret and print a generic
00482  * pointer for the third argument (print_data).
00483  */
00484 const explain_iocontrol_t explain_iocontrol_generic =
00485 {
00486     0, /* name */
00487     0, /* value */
00488     0, /* disambiguate */
00489     print_name,
00490     explain_iocontrol_generic_print_data_pointer, /* print data */
00491     explain_iocontrol_generic_print_explanation, /* print_explanation */
00492     0, /* print_data_returned */
00493     VOID_STAR, /* data_size */
00494     "void *", /* data_type */
00495     0, /* flags */
00496     __FILE__,
00497     __LINE__,
00498 };
00499 
00500 
00501 void
00502 explain_iocontrol_generic_print_data_int(const explain_iocontrol_t *p,
00503     explain_string_buffer_t *sb, int errnum, int fildes, int request,
00504     const void *data)
00505 {
00506     (void)p;
00507     (void)errnum;
00508     (void)fildes;
00509     (void)request;
00510     explain_buffer_int(sb, (intptr_t)data);
00511 }
00512 
00513 
00514 void
00515 explain_iocontrol_generic_print_data_uint(const explain_iocontrol_t *p,
00516     explain_string_buffer_t *sb, int errnum, int fildes, int request,
00517     const void *data)
00518 {
00519     (void)p;
00520     (void)errnum;
00521     (void)fildes;
00522     (void)request;
00523     explain_buffer_uint(sb, (intptr_t)data);
00524 }
00525 
00526 
00527 void
00528 explain_iocontrol_generic_print_data_int_star(const explain_iocontrol_t *p,
00529     explain_string_buffer_t *sb, int errnum, int fildes, int request,
00530     const void *data)
00531 {
00532     (void)p;
00533     (void)errnum;
00534     (void)fildes;
00535     (void)request;
00536     explain_buffer_int_star(sb, data);
00537 }
00538 
00539 
00540 void
00541 explain_iocontrol_generic_print_data_uint_star(const explain_iocontrol_t *p,
00542     explain_string_buffer_t *sb, int errnum, int fildes, int request,
00543     const void *data)
00544 {
00545     (void)p;
00546     (void)errnum;
00547     (void)fildes;
00548     (void)request;
00549     explain_buffer_uint_star(sb, data);
00550 }
00551 
00552 
00553 void
00554 explain_iocontrol_generic_print_data_long(const explain_iocontrol_t *p,
00555     explain_string_buffer_t *sb, int errnum, int fildes, int request,
00556     const void *data)
00557 {
00558     (void)p;
00559     (void)errnum;
00560     (void)fildes;
00561     (void)request;
00562     explain_buffer_long(sb, (intptr_t)data);
00563 }
00564 
00565 
00566 void
00567 explain_iocontrol_generic_print_data_ulong(const explain_iocontrol_t *p,
00568     explain_string_buffer_t *sb, int errnum, int fildes, int request,
00569     const void *data)
00570 {
00571     (void)p;
00572     (void)errnum;
00573     (void)fildes;
00574     (void)request;
00575     explain_buffer_ulong(sb, (intptr_t)data);
00576 }
00577 
00578 
00579 void
00580 explain_iocontrol_generic_print_data_long_star(const explain_iocontrol_t *p,
00581     explain_string_buffer_t *sb, int errnum, int fildes, int request,
00582     const void *data)
00583 {
00584     (void)p;
00585     (void)errnum;
00586     (void)fildes;
00587     (void)request;
00588     explain_buffer_long_star(sb, data);
00589 }
00590 
00591 
00592 void
00593 explain_iocontrol_generic_print_data_ulong_star(const explain_iocontrol_t *p,
00594     explain_string_buffer_t *sb, int errnum, int fildes, int request,
00595     const void *data)
00596 {
00597     (void)p;
00598     (void)errnum;
00599     (void)fildes;
00600     (void)request;
00601     explain_buffer_ulong_star(sb, data);
00602 }
00603 
00604 
00605 void
00606 explain_iocontrol_generic_print_data_pointer(const explain_iocontrol_t *p,
00607     explain_string_buffer_t *sb, int errnum, int fildes, int request,
00608     const void *data)
00609 {
00610     (void)p;
00611     (void)errnum;
00612     (void)fildes;
00613     (void)request;
00614     explain_buffer_pointer(sb, data);
00615 }
00616 
00617 
00618 void
00619 explain_iocontrol_generic_print_data_int64_star(const explain_iocontrol_t *p,
00620     explain_string_buffer_t *sb, int errnum, int fildes, int request,
00621     const void *data)
00622 {
00623     (void)p;
00624     (void)errnum;
00625     (void)fildes;
00626     (void)request;
00627     explain_buffer_int64_array(sb, data, 1);
00628 }
00629 
00630 
00631 void
00632 explain_iocontrol_generic_print_data_uint64_star(const explain_iocontrol_t *p,
00633     explain_string_buffer_t *sb, int errnum, int fildes, int request,
00634     const void *data)
00635 {
00636     (void)p;
00637     (void)errnum;
00638     (void)fildes;
00639     (void)request;
00640     explain_buffer_uint64_array(sb, data, 1);
00641 }
00642 
00643 
00644 void
00645 explain_iocontrol_generic_print_data_ignored(const explain_iocontrol_t *p,
00646     explain_string_buffer_t *sb, int errnum, int fildes, int request,
00647     const void *data)
00648 {
00649     (void)p;
00650     (void)errnum;
00651     (void)fildes;
00652     (void)request;
00653     explain_buffer_pointer(sb, data);
00654     if (data)
00655         explain_string_buffer_puts(sb, " ignored");
00656 }
00657 
00658 
00659 void
00660 explain_iocontrol_generic_print_data_short_star(const explain_iocontrol_t *p,
00661     explain_string_buffer_t *sb, int errnum, int fildes, int request,
00662     const void *data)
00663 {
00664     (void)p;
00665     (void)errnum;
00666     (void)fildes;
00667     (void)request;
00668     explain_buffer_short_star(sb, data, 1);
00669 }
00670 
00671 
00672 void
00673 explain_iocontrol_generic_print_data_ushort_star(const explain_iocontrol_t *p,
00674     explain_string_buffer_t *sb, int errnum, int fildes, int request,
00675     const void *data)
00676 {
00677     (void)p;
00678     (void)errnum;
00679     (void)fildes;
00680     (void)request;
00681     explain_buffer_ushort_star(sb, data, 1);
00682 }
00683 
00684 
00685 void
00686 explain_iocontrol_generic_print_data_int8_star(const explain_iocontrol_t *p,
00687     explain_string_buffer_t *sb, int errnum, int fildes, int request,
00688     const void *data)
00689 {
00690     (void)p;
00691     (void)errnum;
00692     (void)fildes;
00693     (void)request;
00694     explain_buffer_int8_star(sb, data, 1);
00695 }
00696 
00697 
00698 void
00699 explain_iocontrol_generic_print_data_uint8_star(const explain_iocontrol_t *p,
00700     explain_string_buffer_t *sb, int errnum, int fildes, int request,
00701     const void *data)
00702 {
00703     (void)p;
00704     (void)errnum;
00705     (void)fildes;
00706     (void)request;
00707     explain_buffer_uint8_star(sb, data, 1);
00708 }
00709 
00710 
00711 /* vim: set ts=8 sw=4 et : */