libexplain
1.4.D001
|
00001 /* 00002 * libexplain - Explain errno values returned by libc functions 00003 * Copyright (C) 2008-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 published by 00008 * the Free Software Foundation; either version 3 of the License, or (at 00009 * 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/assert.h> 00021 #include <libexplain/ac/errno.h> 00022 #include <libexplain/ac/fcntl.h> 00023 #include <libexplain/ac/sys/stat.h> /* for major()/minor() except Solaris */ 00024 #include <libexplain/ac/sys/sysmacros.h> /* for major()/minor() on Solaris */ 00025 #include <libexplain/ac/unistd.h> 00026 00027 #include <libexplain/buffer/dac.h> 00028 #include <libexplain/buffer/eexist.h> 00029 #include <libexplain/buffer/efault.h> 00030 #include <libexplain/buffer/einval.h> 00031 #include <libexplain/buffer/eisdir.h> 00032 #include <libexplain/buffer/eloop.h> 00033 #include <libexplain/buffer/emfile.h> 00034 #include <libexplain/buffer/enametoolong.h> 00035 #include <libexplain/buffer/enfile.h> 00036 #include <libexplain/buffer/enoent.h> 00037 #include <libexplain/buffer/enomedium.h> 00038 #include <libexplain/buffer/enomem.h> 00039 #include <libexplain/buffer/enospc.h> 00040 #include <libexplain/buffer/enotdir.h> 00041 #include <libexplain/buffer/erofs.h> 00042 #include <libexplain/buffer/errno/generic.h> 00043 #include <libexplain/buffer/errno/open.h> 00044 #include <libexplain/buffer/errno/path_resolution.h> 00045 #include <libexplain/buffer/etxtbsy.h> 00046 #include <libexplain/buffer/file_type.h> 00047 #include <libexplain/buffer/gettext.h> 00048 #include <libexplain/buffer/mount_point.h> 00049 #include <libexplain/buffer/open_flags.h> 00050 #include <libexplain/buffer/path_to_pid.h> 00051 #include <libexplain/buffer/permission_mode.h> 00052 #include <libexplain/buffer/pointer.h> 00053 #include <libexplain/buffer/pretty_size.h> 00054 #include <libexplain/buffer/uid.h> 00055 #include <libexplain/capability.h> 00056 #include <libexplain/explanation.h> 00057 #include <libexplain/option.h> 00058 #include <libexplain/string_buffer.h> 00059 00060 00061 static void 00062 explain_buffer_errno_open_system_call(explain_string_buffer_t *sb, 00063 int errnum, const char *pathname, int flags, int mode) 00064 { 00065 explain_string_buffer_printf(sb, "open(pathname = "); 00066 if (errnum == EFAULT) 00067 explain_buffer_pointer(sb, pathname); 00068 else 00069 explain_string_buffer_puts_quoted(sb, pathname); 00070 explain_string_buffer_puts(sb, ", flags = "); 00071 explain_buffer_open_flags(sb, flags); 00072 if (flags & O_CREAT) 00073 { 00074 explain_string_buffer_puts(sb, ", mode = "); 00075 explain_buffer_permission_mode(sb, mode); 00076 } 00077 explain_string_buffer_putc(sb, ')'); 00078 } 00079 00080 00081 static void 00082 you_can_not_open_a_socket(explain_string_buffer_t *sb) 00083 { 00084 explain_buffer_gettext 00085 ( 00086 sb, 00087 /* 00088 * xgettext: This message is used when open(2) received an 00089 * ENODEV error, and the pathname it attempted to open was a 00090 * socket (first character "s" is ls(1) long output). They 00091 * probably meant to use a named pipe (first character "p" in 00092 * ls(1) long outout). 00093 */ 00094 i18n("you cannot use open(2) to open socket files, you must use " 00095 "connect(2) instead; a named pipe may be what was intended") 00096 ); 00097 } 00098 00099 00100 static void 00101 no_corresponding_device(explain_string_buffer_t *sb, const struct stat *st) 00102 { 00103 char ftype[FILE_TYPE_BUFFER_SIZE_MIN]; 00104 char numbers[40]; 00105 explain_string_buffer_t ftype_sb; 00106 explain_string_buffer_t numbers_sb; 00107 00108 explain_string_buffer_init(&ftype_sb, ftype, sizeof(ftype)); 00109 explain_buffer_file_type_st(&ftype_sb, st); 00110 00111 explain_string_buffer_init(&numbers_sb, numbers, sizeof(numbers)); 00112 explain_string_buffer_printf 00113 ( 00114 &numbers_sb, 00115 "(%ld, %ld)", 00116 (long)major(st->st_dev), 00117 (long)minor(st->st_dev) 00118 ); 00119 explain_string_buffer_printf_gettext 00120 ( 00121 sb, 00122 /* 00123 * xgettext: This message is used to explain an ENODEV error reported by 00124 * an open(2) system call, and the device does not actually exist. 00125 * 00126 * %1$s => the file type of the special file, 00127 * already translated. 00128 * %2$s => the major and minor device numbers 00129 * 00130 * Example: "pathname refers to a block special file (42, 13) and no 00131 * corresponding device exists" 00132 */ 00133 i18n("pathname refers to a %s %s and no corresponding device exists"), 00134 ftype, 00135 numbers 00136 ); 00137 } 00138 00139 00140 static int 00141 is_device_file(const struct stat *st) 00142 { 00143 switch (st->st_mode & S_IFMT) 00144 { 00145 case S_IFCHR: 00146 case S_IFBLK: 00147 #ifdef S_IFMPC 00148 case S_IFMPC: 00149 #endif 00150 #ifdef S_IFMPB 00151 case S_IFMPB: 00152 #endif 00153 return 1; 00154 00155 default: 00156 break; 00157 } 00158 return 0; 00159 } 00160 00161 00162 void 00163 explain_buffer_errno_open_explanation(explain_string_buffer_t *sb, 00164 int errnum, const char *syscall_name, const char *pathname, int flags, 00165 int mode) 00166 { 00167 explain_final_t final_component; 00168 00169 (void)mode; 00170 explain_final_init(&final_component); 00171 switch (flags & O_ACCMODE) 00172 { 00173 case O_RDONLY: 00174 final_component.want_to_read = 1; 00175 break; 00176 00177 case O_RDWR: 00178 final_component.want_to_read = 1; 00179 final_component.want_to_write = 1; 00180 break; 00181 00182 case O_WRONLY: 00183 final_component.want_to_write = 1; 00184 break; 00185 00186 default: 00187 assert(!"unknown open access mode"); 00188 break; 00189 } 00190 if (flags & O_CREAT) 00191 { 00192 final_component.want_to_create = 1; 00193 final_component.must_exist = 0; 00194 if (flags & O_EXCL) 00195 final_component.must_not_exist = 1; 00196 } 00197 if (flags & O_DIRECTORY) 00198 { 00199 final_component.must_be_a_st_mode = 1; 00200 final_component.st_mode = S_IFDIR; 00201 } 00202 if (flags & O_NOFOLLOW) 00203 final_component.follow_symlink = 0; 00204 00205 switch (errnum) 00206 { 00207 case EACCES: 00208 if 00209 ( 00210 explain_buffer_errno_path_resolution 00211 ( 00212 sb, 00213 errnum, 00214 pathname, 00215 "pathname", 00216 &final_component 00217 ) 00218 ) 00219 { 00220 struct stat st; 00221 00222 if 00223 ( 00224 stat(pathname, &st) >= 0 00225 && 00226 is_device_file(&st) 00227 && 00228 explain_mount_point_nodev(&st) 00229 ) 00230 { 00231 explain_string_buffer_t file_type_sb; 00232 char file_type[FILE_TYPE_BUFFER_SIZE_MIN]; 00233 00234 explain_string_buffer_init(&file_type_sb, file_type, 00235 sizeof(file_type)); 00236 explain_buffer_file_type_st(&file_type_sb, &st); 00237 explain_string_buffer_printf_gettext 00238 ( 00239 sb, 00240 /* 00241 * xgettext: This message is used when explaining an EACCES 00242 * error returned by an open(2) system call, in the case 00243 * where the file is a character special device or a block 00244 * special device, and the file system has been mounted with 00245 * the "nodev" option. 00246 * 00247 * %1$s => the file type (character sepcial device, etc) 00248 * already translated. 00249 */ 00250 i18n("the %s is on a file system mounted with the " 00251 "\"nodev\" option"), 00252 file_type 00253 ); 00254 explain_buffer_mount_point_stat(sb, &st); 00255 break; 00256 } 00257 00258 explain_buffer_gettext 00259 ( 00260 sb, 00261 /* 00262 * xgettext: This message is used when explaining an 00263 * EACCES error returned by an open(2) system call. 00264 * Usually path_resolution(7) will have a better 00265 * explanation, this explanation is only used when a 00266 * more specific explanation is not available. 00267 */ 00268 i18n("the requested access to the file is not allowed, or " 00269 "search permission is denied for one of the directories " 00270 "in the path prefix of pathname, or the file did not " 00271 "exist yet and write access to the parent directory is " 00272 "not allowed") 00273 ); 00274 } 00275 break; 00276 00277 case EINVAL: 00278 explain_buffer_einval_bits(sb, "flags"); 00279 break; 00280 00281 case EEXIST: 00282 if 00283 ( 00284 explain_buffer_errno_path_resolution 00285 ( 00286 sb, 00287 errnum, 00288 pathname, 00289 "pathname", 00290 &final_component 00291 ) 00292 ) 00293 { 00294 explain_buffer_eexist(sb, pathname); 00295 } 00296 break; 00297 00298 case EFAULT: 00299 explain_buffer_efault(sb, "pathname"); 00300 break; 00301 00302 #if defined(O_LARGEFILE) && (O_LARGEFILE != 0) 00303 case EFBIG: 00304 case EOVERFLOW: 00305 if (!(flags & O_LARGEFILE)) 00306 { 00307 struct stat st; 00308 00309 if (stat(pathname, &st) >= 0 && S_ISREG(st.st_mode)) 00310 { 00311 char siz[20]; 00312 explain_string_buffer_t siz_sb; 00313 00314 explain_string_buffer_init(&siz_sb, siz, sizeof(siz)); 00315 { 00316 explain_string_buffer_putc(sb, '('); 00317 explain_buffer_pretty_size(sb, st.st_size); 00318 explain_string_buffer_putc(sb, ')'); 00319 } 00320 explain_string_buffer_printf_gettext 00321 ( 00322 sb, 00323 /* 00324 * xgettext: This message is used to explain an EFBIG 00325 * or EOVERFLOW error reported by and open(2) system 00326 * call. The file is, in fact, too large to be opened 00327 * without the O_LARGEFILE flag. 00328 * 00329 * %1$s => The size of the file, in parentheses 00330 */ 00331 i18n("pathname referes to a regular file that is too large " 00332 "to be opened %s, the O_LARGEFILE flag is necessary"), 00333 siz 00334 ); 00335 } 00336 } 00337 break; 00338 #endif 00339 00340 case EISDIR: 00341 if ((flags & O_ACCMODE) != O_RDONLY) 00342 { 00343 if (explain_buffer_eisdir(sb, pathname, "pathname")) 00344 break; 00345 } 00346 goto generic; 00347 00348 case ELOOP: 00349 case EMLINK: /* BSD */ 00350 if (flags & O_NOFOLLOW) 00351 { 00352 struct stat st; 00353 00354 if (lstat(pathname, &st) >= 0 && S_ISLNK(st.st_mode)) 00355 { 00356 explain_buffer_gettext 00357 ( 00358 sb, 00359 /* 00360 * xgettext: This message is used to explain an 00361 * ELOOP or EMLINK error reported by an open(2) 00362 * system call, in the case where the O_NOFOLLOW 00363 * flags was specified but the final path component 00364 * was a symbolic link. 00365 */ 00366 i18n("O_NOFOLLOW was specified but pathname refers to a " 00367 "symbolic link") 00368 ); 00369 /* FIXME: mention this may indicate some kind of attack? */ 00370 break; 00371 } 00372 } 00373 explain_buffer_eloop(sb, pathname, "pathname", &final_component); 00374 break; 00375 00376 case EMFILE: 00377 explain_buffer_emfile(sb); 00378 break; 00379 00380 case ENAMETOOLONG: 00381 explain_buffer_enametoolong 00382 ( 00383 sb, 00384 pathname, 00385 "pathname", 00386 &final_component 00387 ); 00388 break; 00389 00390 case ENFILE: 00391 explain_buffer_enfile(sb); 00392 break; 00393 00394 case ENOENT: 00395 explain_buffer_enoent(sb, pathname, "pathname", &final_component); 00396 break; 00397 00398 #ifdef ENOMEDIUM 00399 case ENOMEDIUM: 00400 explain_buffer_enomedium(sb, pathname); 00401 break; 00402 #endif 00403 00404 case ENOMEM: 00405 explain_buffer_enomem_kernel(sb); 00406 break; 00407 00408 case ENOSPC: 00409 explain_buffer_enospc(sb, pathname, "pathname"); 00410 break; 00411 00412 case ENOTDIR: 00413 explain_buffer_enotdir(sb, pathname, "pathname", &final_component); 00414 break; 00415 00416 case ENXIO: 00417 { 00418 struct stat st; 00419 00420 if (stat(pathname, &st) < 0) 00421 { 00422 enxio_generic: 00423 explain_buffer_gettext 00424 ( 00425 sb, 00426 /* 00427 * xgettext: This message is used to explain an 00428 * ENXIO error returned by an open(2) system call. 00429 * This is the generic explanation, used when no 00430 * more specific cause can be determined. 00431 */ 00432 i18n("O_NONBLOCK | O_WRONLY is set, the named file " 00433 "is a FIFO and no process has the file open for " 00434 "reading; or, the file is a device special file and " 00435 "no corresponding device exists") 00436 ); 00437 break; 00438 } 00439 switch (st.st_mode & S_IFMT) 00440 { 00441 case S_IFIFO: 00442 explain_buffer_gettext 00443 ( 00444 sb, 00445 /* 00446 * xgettext: This message is used to explain an 00447 * ENXIO error returned by an open(2) system call, 00448 * in the case where a named pipe has no readers, 00449 * and a non-blocking writer tried to open it. 00450 */ 00451 i18n("O_NONBLOCK | O_WRONLY is set, and the named file " 00452 "is a FIFO, and no process has the file open for " 00453 "reading") 00454 ); 00455 /* FIXME: what happens if you open a named pipe O_RDWR? */ 00456 break; 00457 00458 case S_IFCHR: 00459 case S_IFBLK: 00460 no_corresponding_device(sb, &st); 00461 break; 00462 00463 case S_IFSOCK: 00464 you_can_not_open_a_socket(sb); 00465 break; 00466 00467 default: 00468 goto enxio_generic; 00469 } 00470 } 00471 break; 00472 00473 #if defined(O_NOATIME) && (O_NOATIME != 0) 00474 case EPERM: 00475 if (flags & O_NOATIME) 00476 { 00477 struct stat st; 00478 explain_string_buffer_t puid_sb; 00479 explain_string_buffer_t ftype_sb; 00480 explain_string_buffer_t fuid_sb; 00481 char puid[100]; 00482 char ftype[FILE_TYPE_BUFFER_SIZE_MIN]; 00483 char fuid[100]; 00484 00485 explain_string_buffer_init(&puid_sb, puid, sizeof(puid)); 00486 explain_buffer_uid(&puid_sb, geteuid()); 00487 explain_string_buffer_init(&ftype_sb, ftype, sizeof(ftype)); 00488 explain_string_buffer_init(&fuid_sb, fuid, sizeof(fuid)); 00489 if (stat(pathname, &st) >= 0) 00490 { 00491 explain_buffer_file_type_st(&ftype_sb, &st); 00492 explain_buffer_uid(&fuid_sb, st.st_uid); 00493 } 00494 else 00495 explain_buffer_file_type(&ftype_sb, S_IFREG); 00496 explain_string_buffer_printf_gettext 00497 ( 00498 sb, 00499 /* 00500 * xgettext: This message is used when an EPERM erro is 00501 * returned by an open(2) system call, and the O_NOATIME 00502 * open flag was specified, but the process lacked the 00503 * permissions required. 00504 * 00505 * %1$s => the number and name of the process effective UID, 00506 * already quoted if needed 00507 * %2$s => the file type of the file in question, 00508 * almost always "regular file" (already translated) 00509 * %3$s => the number and name of the file owner UID, 00510 * already quoted if needed 00511 */ 00512 i18n("the O_NOATIME flags was specified, but the process " 00513 "effective UID %s does not match the %s owner UID %s"), 00514 puid, 00515 ftype, 00516 fuid 00517 ); 00518 00519 /* 00520 * also explain the necessary priviledge 00521 */ 00522 explain_buffer_dac_fowner(sb); 00523 } 00524 break; 00525 #endif 00526 00527 case EROFS: 00528 explain_buffer_erofs(sb, pathname, "pathname"); 00529 break; 00530 00531 case ETXTBSY: 00532 explain_buffer_etxtbsy(sb, pathname); 00533 break; 00534 00535 case EWOULDBLOCK: 00536 if (flags & O_NONBLOCK) 00537 { 00538 explain_buffer_gettext 00539 ( 00540 sb, 00541 /* 00542 * xgettext: This message is used to explain an 00543 * EWOULDBLOCK error returned by an open(2) system call, 00544 * when the use of thr O_NONBLOCK flags would otherwise 00545 * cause the open(2) system call to block. 00546 */ 00547 i18n("the O_NONBLOCK flag was specified, and an " 00548 "incompatible lease was held on the file") 00549 ); 00550 00551 /* 00552 * Look for other processes with this file open, 00553 * and list their PIDs. 00554 */ 00555 explain_buffer_path_to_pid(sb, pathname); 00556 } 00557 break; 00558 00559 case ENODEV: 00560 { 00561 struct stat st; 00562 00563 if (stat(pathname, &st) >= 0) 00564 { 00565 switch (st.st_mode & S_IFMT) 00566 { 00567 case S_IFSOCK: 00568 you_can_not_open_a_socket(sb); 00569 break; 00570 00571 case S_IFBLK: 00572 case S_IFCHR: 00573 no_corresponding_device(sb, &st); 00574 #ifdef __linux__ 00575 if (explain_option_dialect_specific()) 00576 { 00577 explain_string_buffer_puts(sb->footnotes, "; "); 00578 explain_buffer_gettext 00579 ( 00580 sb->footnotes, 00581 /* 00582 * xgettext: This message is used to explain an 00583 * ENODEV error reported by an open(2) system 00584 * call, which shoudl actually have been a ENXIO 00585 * error instead. They are easy to confuse, 00586 * they have exactly the same English text 00587 * returned from strerror(3). 00588 */ 00589 i18n("this is a Linux kernel bug, in this " 00590 "situation POSIX says ENXIO should have been " 00591 "returned") 00592 ); 00593 } 00594 #endif 00595 break; 00596 00597 default: 00598 break; 00599 } 00600 } 00601 } 00602 break; 00603 00604 default: 00605 generic: 00606 explain_buffer_errno_generic(sb, errnum, syscall_name); 00607 break; 00608 } 00609 00610 if (flags & O_TRUNC) 00611 { 00612 if ((flags & O_ACCMODE) == O_RDONLY) 00613 { 00614 explain_string_buffer_puts(sb->footnotes, "; "); 00615 explain_buffer_gettext 00616 ( 00617 sb->footnotes, 00618 /* 00619 * xgettext: This message is used to supplement an explanation 00620 * for an error reported by open(2) system call, in the case 00621 * where the caller used a flags combination with explicitly 00622 * undefined behavior. 00623 */ 00624 i18n("note that the behavior of (O_RDONLY | O_TRUNC) is " 00625 "undefined") 00626 ); 00627 } 00628 else 00629 { 00630 struct stat st; 00631 00632 if (stat(pathname, &st) >= 0) 00633 { 00634 explain_string_buffer_t file_type_sb; 00635 char file_type[FILE_TYPE_BUFFER_SIZE_MIN]; 00636 00637 explain_string_buffer_init(&file_type_sb, file_type, 00638 sizeof(file_type)); 00639 explain_buffer_file_type_st(&file_type_sb, &st); 00640 00641 switch (st.st_mode & S_IFMT) 00642 { 00643 default: 00644 break; 00645 00646 case S_IFSOCK: 00647 case S_IFIFO: 00648 /* explicitly ignored */ 00649 { 00650 explain_string_buffer_puts(sb->footnotes, "; "); 00651 explain_string_buffer_printf_gettext 00652 ( 00653 sb->footnotes, 00654 /* 00655 * xgettext: This message is used to supplement an 00656 * explanation for an error reported by open(2) 00657 * system call, in the case where the caller used 00658 * O_TRUNC in a combination that explicitly 00659 * ignores O_TRUNC. 00660 * 00661 * %1$s => the type of the special file, already 00662 * translated 00663 */ 00664 i18n("note that a %s will ignore the O_TRUNC flag"), 00665 file_type 00666 ); 00667 } 00668 break; 00669 00670 case S_IFCHR: 00671 /* 00672 * The O_TRUNC flags is explicitly ignored for TTY devices, 00673 * but is undefined for all other character devices. Since 00674 * we can't tell which case we have at this moment, we fall 00675 * through... 00676 */ 00677 00678 case S_IFBLK: 00679 #ifdef S_IFMPC 00680 case S_IFMPC: 00681 #endif 00682 #ifdef S_IFMPB 00683 case S_IFMPB: 00684 #endif 00685 /* explicitly undefined */ 00686 { 00687 explain_string_buffer_puts(sb->footnotes, "; "); 00688 explain_string_buffer_printf_gettext 00689 ( 00690 sb->footnotes, 00691 /* 00692 * xgettext: This message is used to supplement an 00693 * explanation for an error reported by open(2) 00694 * system call, in the case where the caller used 00695 * O_TRUNC in a combination with explicitly 00696 * undefined behavior. 00697 * 00698 * %1$s => the type of the special file, already 00699 * translated 00700 */ 00701 i18n("note that the behavior of O_TRUNC on a %s is " 00702 "undefined"), 00703 file_type 00704 ); 00705 } 00706 break; 00707 } 00708 } 00709 } 00710 } 00711 00712 if ((flags & O_EXCL) && !(flags & O_CREAT)) 00713 { 00714 explain_string_buffer_puts(sb->footnotes, "; "); 00715 /* FIXME: except for a TTY, where it means single open */ 00716 explain_buffer_gettext 00717 ( 00718 sb->footnotes, 00719 /* 00720 * xgettext: This message is used to supplement an explanation for 00721 * an error reported by open(2) system call, and the caller used a 00722 * flags combination with explicitly undefined behavior. 00723 */ 00724 i18n("note that the behavior of O_EXCL is undefined if " 00725 "O_CREAT is not specified") 00726 ); 00727 } 00728 } 00729 00730 00731 void 00732 explain_buffer_errno_open(explain_string_buffer_t *sb, int errnum, 00733 const char *pathname, int flags, int mode) 00734 { 00735 explain_explanation_t exp; 00736 00737 explain_explanation_init(&exp, errnum); 00738 explain_buffer_errno_open_system_call 00739 ( 00740 &exp.system_call_sb, 00741 errnum, 00742 pathname, 00743 flags, 00744 mode 00745 ); 00746 explain_buffer_errno_open_explanation 00747 ( 00748 &exp.explanation_sb, 00749 errnum, 00750 "open", 00751 pathname, 00752 flags, 00753 mode 00754 ); 00755 explain_explanation_assemble(&exp, sb); 00756 } 00757 00758 00759 /* vim: set ts=8 sw=4 et : */