libexplain
1.4.D001
|
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 : */