libexplain
1.4.D001
|
00001 /* 00002 * libexplain - Explain errno values returned by libc functions 00003 * Copyright (C) 2008, 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 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/errno.h> 00021 #include <libexplain/ac/fcntl.h> 00022 #include <libexplain/ac/sys/ioctl.h> 00023 #include <libexplain/ac/sys/mtio.h> 00024 #include <libexplain/ac/sys/stat.h> 00025 #include <libexplain/ac/unistd.h> 00026 00027 #include <libexplain/buffer/ebadf.h> 00028 #include <libexplain/buffer/efault.h> 00029 #include <libexplain/buffer/eio.h> 00030 #include <libexplain/buffer/eintr.h> 00031 #include <libexplain/buffer/errno/generic.h> 00032 #include <libexplain/buffer/errno/read.h> 00033 #include <libexplain/buffer/fildes.h> 00034 #include <libexplain/buffer/gettext.h> 00035 #include <libexplain/buffer/mount_point.h> 00036 #include <libexplain/buffer/pointer.h> 00037 #include <libexplain/buffer/size_t.h> 00038 #include <libexplain/explanation.h> 00039 #include <libexplain/is_same_inode.h> 00040 #include <libexplain/string_buffer.h> 00041 00042 00043 static void 00044 explain_buffer_errno_read_system_call(explain_string_buffer_t *sb, int errnum, 00045 int fildes, const void *data, size_t data_size) 00046 { 00047 (void)errnum; 00048 explain_string_buffer_puts(sb, "read(fildes = "); 00049 explain_buffer_fildes(sb, fildes); 00050 explain_string_buffer_puts(sb, ", data = "); 00051 explain_buffer_pointer(sb, data); 00052 explain_string_buffer_puts(sb, ", data_size = "); 00053 explain_buffer_size_t(sb, data_size); 00054 explain_string_buffer_putc(sb, ')'); 00055 } 00056 00057 00058 static int 00059 is_a_tape(int fildes) 00060 { 00061 struct mtop args; 00062 00063 args.mt_op = MTNOP; 00064 args.mt_count = 0; 00065 return (ioctl(fildes, MTIOCTOP, &args) >= 0); 00066 } 00067 00068 00069 void 00070 explain_buffer_errno_read_explanation(explain_string_buffer_t *sb, int errnum, 00071 const char *syscall_name, int fildes, const void *data, size_t data_size) 00072 { 00073 (void)data; 00074 (void)data_size; 00075 switch (errnum) 00076 { 00077 case EAGAIN: 00078 explain_string_buffer_puts 00079 ( 00080 sb, 00081 /* FIXME: i18n */ 00082 "non-blocking I/O has been selected using " 00083 "O_NONBLOCK and no data was immediately available for " 00084 "reading" 00085 ); 00086 break; 00087 00088 case EBADF: 00089 { 00090 int flags; 00091 00092 flags = fcntl(fildes, F_GETFL); 00093 if (flags >= 0) 00094 { 00095 explain_buffer_ebadf_not_open_for_reading(sb, "fildes", flags); 00096 } 00097 else 00098 { 00099 explain_buffer_ebadf(sb, fildes, "fildes"); 00100 } 00101 } 00102 break; 00103 00104 case EFAULT: 00105 explain_buffer_efault(sb, "data"); 00106 break; 00107 00108 case EINTR: 00109 explain_buffer_eintr(sb, syscall_name); 00110 break; 00111 00112 case EINVAL: 00113 { 00114 int flags; 00115 00116 flags = fcntl(fildes, F_GETFL); 00117 if (flags >= 0) 00118 { 00119 if ((flags & O_ACCMODE) == O_WRONLY) 00120 { 00121 explain_buffer_ebadf_not_open_for_reading 00122 ( 00123 sb, 00124 "fildes", 00125 flags 00126 ); 00127 } 00128 #ifdef O_DIRECT 00129 else if (flags & O_DIRECT) 00130 { 00131 /* FIXME: figure out which */ 00132 explain_string_buffer_puts 00133 ( 00134 sb, 00135 /* FIXME: i18n */ 00136 "the file was opened with the O_DIRECT flag, " 00137 "and either the address specified in data is " 00138 "not suitably aligned, or the value specified " 00139 "in data_size is not suitably aligned, or the " 00140 "current file offset is not suitably aligned" 00141 ); 00142 } 00143 #endif 00144 else 00145 { 00146 explain_string_buffer_puts 00147 ( 00148 sb, 00149 /* FIXME: i18n */ 00150 "the file descriptor was created via a call to " 00151 "timerfd_create(2) and the wrong size buffer was " 00152 "given" 00153 ); 00154 } 00155 } 00156 else 00157 { 00158 explain_string_buffer_puts 00159 ( 00160 sb, 00161 /* FIXME: i18n */ 00162 "the file desriptor is attached to an object " 00163 "which is unsuitable for reading; or, the file was " 00164 "opened with the O_DIRECT flag, and either the " 00165 "address specified in data, the value specified " 00166 "in data_size, or the current file offset is not" 00167 "suitably aligned; or, the file descriptor was " 00168 "created via a call to timerfd_create(2) and the " 00169 "wrong size buffer was given" 00170 ); 00171 } 00172 } 00173 00174 /* 00175 * There is a bug in Tru64 5.1. Attempting to read more than 00176 * INT_MAX bytes fails with errno == EINVAL. 00177 */ 00178 if (data_size > INT_MAX) 00179 { 00180 explain_string_buffer_puts 00181 ( 00182 sb, 00183 /* FIXME: i18n */ 00184 "you have tripped over a bug in Tru64 5.1 where it is unable " 00185 "to read more than INT_MAX bytes at a time" 00186 ); 00187 explain_string_buffer_printf 00188 ( 00189 sb, 00190 " (%zd > %d)", 00191 data_size, 00192 INT_MAX 00193 ); 00194 break; 00195 } 00196 break; 00197 00198 case EIO: 00199 { 00200 pid_t process_group = getpgid(0); 00201 int controlling_tty_fd = open("/dev/tty", O_RDWR); 00202 pid_t tty_process_group = tcgetpgrp(controlling_tty_fd); 00203 00204 /* if reading controlling tty */ 00205 if 00206 ( 00207 process_group >= 0 00208 && 00209 controlling_tty_fd >= 0 00210 && 00211 process_group != tty_process_group 00212 ) 00213 { 00214 struct stat st1; 00215 struct stat st2; 00216 00217 if 00218 ( 00219 fstat(fildes, &st1) == 0 00220 && 00221 fstat(controlling_tty_fd, &st2) == 0 00222 && 00223 explain_is_same_inode(&st1, &st2) 00224 ) 00225 { 00226 explain_string_buffer_puts 00227 ( 00228 sb, 00229 /* FIXME: i18n */ 00230 "the process is in a background process group, and " 00231 "tried to read from its controlling tty, and the " 00232 "controlling tty is either ignoring or blocking SIGTTIN" 00233 ); 00234 close(controlling_tty_fd); 00235 break; 00236 } 00237 } 00238 if (controlling_tty_fd < 0) 00239 { 00240 explain_string_buffer_puts 00241 ( 00242 sb, 00243 /* FIXME: i18n */ 00244 "the process is in an orphaned process " 00245 "group and tried to read from its controlling tty" 00246 ); 00247 break; 00248 } 00249 close(controlling_tty_fd); 00250 00251 explain_buffer_eio_fildes(sb, fildes); 00252 } 00253 break; 00254 00255 case EISDIR: 00256 explain_string_buffer_puts 00257 ( 00258 sb, 00259 /* FIXME: i18n */ 00260 "fildes refers to a directory, and you must use getdents(2) to " 00261 "read directories, preferably via the higher-level interface " 00262 "provided by readdir(3)" 00263 ); 00264 break; 00265 00266 case ENOENT: 00267 explain_string_buffer_puts 00268 ( 00269 sb, 00270 /* FIXME: i18n */ 00271 "the file is on a file system" 00272 ); 00273 explain_buffer_mount_point_fd(sb, fildes); 00274 explain_string_buffer_puts 00275 ( 00276 sb, 00277 " that does not support Unix open file semantics, and the " 00278 "file has been deleted from underneath you" 00279 ); 00280 break; 00281 00282 case EOVERFLOW: 00283 if (data_size > ((size_t)1 << 16) && is_a_tape(fildes)) 00284 { 00285 explain_string_buffer_printf 00286 ( 00287 sb, 00288 /* FIXME: i18n */ 00289 "the tape read operation was supplied with a %ld byte " 00290 "buffer, however the kernal has been compiled with a limit " 00291 "smaller than this; you need to reconfigure your system, " 00292 "or recompile your tape device driver, to have a fixed " 00293 "limit of at least 64KiB", 00294 (long)data_size 00295 ); 00296 } 00297 break; 00298 00299 default: 00300 explain_buffer_errno_generic(sb, errnum, syscall_name); 00301 break; 00302 } 00303 } 00304 00305 00306 void 00307 explain_buffer_errno_read(explain_string_buffer_t *sb, int errnum, 00308 int fildes, const void *data, size_t data_size) 00309 { 00310 explain_explanation_t exp; 00311 00312 explain_explanation_init(&exp, errnum); 00313 explain_buffer_errno_read_system_call 00314 ( 00315 &exp.system_call_sb, 00316 errnum, 00317 fildes, 00318 data, 00319 data_size 00320 ); 00321 explain_buffer_errno_read_explanation 00322 ( 00323 &exp.explanation_sb, 00324 errnum, 00325 "read", 00326 fildes, 00327 data, 00328 data_size 00329 ); 00330 explain_explanation_assemble(&exp, sb); 00331 } 00332 00333 00334 /* vim: set ts=8 sw=4 et : */