libexplain
1.4.D001
|
00001 /* 00002 * libexplain - Explain errno values returned by libc functions 00003 * Copyright (C) 2008-2010, 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/signal.h> 00023 #include <libexplain/ac/sys/resource.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/efbig.h> 00030 #include <libexplain/buffer/eintr.h> 00031 #include <libexplain/buffer/eio.h> 00032 #include <libexplain/buffer/enospc.h> 00033 #include <libexplain/buffer/errno/generic.h> 00034 #include <libexplain/buffer/errno/write.h> 00035 #include <libexplain/buffer/fildes_not_open_for_writing.h> 00036 #include <libexplain/buffer/fildes_to_pathname.h> 00037 #include <libexplain/buffer/gettext.h> 00038 #include <libexplain/buffer/mount_point.h> 00039 #include <libexplain/buffer/open_flags.h> 00040 #include <libexplain/buffer/pointer.h> 00041 #include <libexplain/buffer/pretty_size.h> 00042 #include <libexplain/buffer/rlimit.h> 00043 #include <libexplain/explanation.h> 00044 #include <libexplain/option.h> 00045 #include <libexplain/string_buffer.h> 00046 00047 00048 static void 00049 explain_buffer_errno_write_system_call(explain_string_buffer_t *sb, 00050 int errnum, int fildes, const void *data, size_t data_size) 00051 { 00052 (void)errnum; 00053 explain_string_buffer_printf(sb, "write(fildes = %d", fildes); 00054 explain_buffer_fildes_to_pathname(sb, fildes); 00055 explain_string_buffer_puts(sb, ", data = "); 00056 explain_buffer_pointer(sb, data); 00057 explain_string_buffer_printf 00058 ( 00059 sb, 00060 ", data_size = %lld)", 00061 (long long)data_size 00062 ); 00063 } 00064 00065 #if defined(__alpha__) && defined(__osf__) 00066 #define TRUE64 1 00067 #endif 00068 00069 #ifndef OFF_T_MAX 00070 #define OFF_T_MAX ((~(off_t)0) >> 1) 00071 #endif 00072 00073 00074 void 00075 explain_buffer_errno_write_explanation(explain_string_buffer_t *sb, 00076 int errnum, const char *syscall_name, int fildes, const void *data, 00077 size_t data_size) 00078 { 00079 switch (errnum) 00080 { 00081 case EAGAIN: 00082 explain_string_buffer_puts 00083 ( 00084 sb, 00085 /* FIXME: i18n */ 00086 "the file descriptor has been marked non-blocking " 00087 "(O_NONBLOCK) and the write would block" 00088 ); 00089 break; 00090 00091 case EBADF: 00092 if (explain_buffer_fildes_not_open_for_writing(sb, fildes, "fildes")) 00093 explain_buffer_ebadf(sb, fildes, "fildes"); 00094 break; 00095 00096 case EFAULT: 00097 explain_buffer_efault(sb, "data"); 00098 break; 00099 00100 case EFBIG: 00101 { 00102 off_t max_file_size; 00103 off_t pos; 00104 00105 pos = lseek(fildes, 0, SEEK_CUR); 00106 if (pos == (off_t)-1) 00107 pos = 0; 00108 max_file_size = explain_get_max_file_size_by_fildes(fildes); 00109 if (pos >= 0 && pos + (off_t)data_size > max_file_size) 00110 { 00111 explain_string_buffer_puts 00112 ( 00113 sb, 00114 /* FIXME: i18n */ 00115 "an attempt was made to write a file that " 00116 "exceeds the process's file size limit" 00117 ); 00118 } 00119 else 00120 { 00121 explain_string_buffer_puts 00122 ( 00123 sb, 00124 /* FIXME: i18n */ 00125 "an attempt was made to write at a position past the " 00126 "process's file size limit" 00127 ); 00128 } 00129 if (explain_option_dialect_specific()) 00130 { 00131 explain_string_buffer_puts(sb, " ("); 00132 explain_buffer_pretty_size(sb, max_file_size); 00133 explain_string_buffer_putc(sb, ')'); 00134 } 00135 } 00136 break; 00137 00138 case EINTR: 00139 explain_buffer_eintr(sb, syscall_name); 00140 break; 00141 00142 case EINVAL: 00143 #if TRU64 00144 if (INT_MAX < OFF_T_MAX) 00145 { 00146 if (data_size > INT_MAX) 00147 { 00148 explain_string_buffer_puts 00149 ( 00150 sb, 00151 /* 00152 * xgettext: Work around a bug in Tru64 5.1. 00153 * Attempting to read more than INT_MAX 00154 * bytes fails with errno == EINVAL. See 00155 <http://lists.gnu.org/archive/html/bug-gnu-utils/2002-04/msg00010.html>. 00156 */ 00157 "there is a bug in the TRU64 kernel, limiting it" 00158 "to reading at most (2**31-1) bytes at a time" 00159 ); 00160 explain_string_buffer_puts(sb->footnotes, "; "); 00161 explain_string_buffer_puts 00162 ( 00163 sb->footnotes, 00164 "break your read() call into smaller pieces" 00165 ); 00166 return; 00167 } 00168 } 00169 #endif 00170 { 00171 int flags = fcntl(fildes, F_GETFL); 00172 if (flags >= 0) 00173 { 00174 if ((flags & O_ACCMODE) == O_RDONLY) 00175 { 00176 explain_string_buffer_puts 00177 ( 00178 sb, 00179 /* FIXME: i18n */ 00180 "the file descriptor is attached to an object " 00181 "which is unsuitable for writing (" 00182 ); 00183 explain_buffer_open_flags(sb, flags); 00184 explain_string_buffer_putc(sb, ')'); 00185 } 00186 else 00187 { 00188 long alignment; 00189 off_t pos; 00190 00191 explain_string_buffer_puts 00192 ( 00193 sb, 00194 /* FIXME: i18n */ 00195 "the file was opened with the O_DIRECT flag, " 00196 "and either the address specified in data is not " 00197 "suitably aligned, the value specified in count " 00198 "is not suitably aligned, or the current file " 00199 "offset is not suitably aligned" 00200 ); 00201 00202 alignment = (long)data | (long)data_size; 00203 pos = lseek(fildes, 0, SEEK_CUR); 00204 if (pos != (off_t)-1) 00205 alignment |= (long)pos; 00206 alignment &= -alignment; 00207 if (alignment != 0) 00208 { 00209 explain_string_buffer_printf 00210 ( 00211 sb, 00212 " (0x%lX)", 00213 alignment 00214 ); 00215 } 00216 } 00217 } 00218 else 00219 { 00220 explain_string_buffer_puts 00221 ( 00222 sb, 00223 /* FIXME: i18n */ 00224 "the file descriptor is attached to an object which " 00225 "is unsuitable for writing; or, the file was opened " 00226 "with the O_DIRECT flag, and either the address " 00227 "specified in data is not suitably aligned, the " 00228 "value specified in count is not suitably aligned, " 00229 "or the current file offset is not suitably aligned" 00230 ); 00231 } 00232 } 00233 break; 00234 00235 case EIO: 00236 explain_buffer_eio_fildes(sb, fildes); 00237 break; 00238 00239 case ENOSPC: 00240 explain_buffer_enospc_fildes(sb, fildes, "fildes"); 00241 break; 00242 00243 case EPIPE: 00244 { 00245 sigset_t mask; 00246 struct sigaction sa; 00247 00248 explain_string_buffer_puts 00249 ( 00250 sb, 00251 /* FIXME: i18n */ 00252 "the file descriptor is connected to a pipe or " 00253 "socket whose reading end is closed, when this happens " 00254 "the writing process will also receive a SIGPIPE signal" 00255 ); 00256 if 00257 ( 00258 sigprocmask(SIG_BLOCK, 0, &mask) == 0 00259 && 00260 sigismember(&mask, SIGPIPE) 00261 ) 00262 { 00263 /* 00264 * FIXME: The use of sigprocmask() is undefined in a 00265 * multithreaded process; see pthread_sigmask(3). 00266 */ 00267 explain_string_buffer_puts(sb->footnotes, "; "); 00268 explain_buffer_gettext 00269 ( 00270 sb->footnotes, 00271 /* 00272 * xgettext: This error message is used when a 00273 * process is blocking the SIGPIPE signal. 00274 */ 00275 i18n("note that this process is blocking the SIGPIPE " 00276 "signal") 00277 ); 00278 break; 00279 } 00280 if 00281 ( 00282 sigaction(SIGPIPE, 0, &sa) == 0 00283 && 00284 (sa.sa_flags & SA_SIGINFO) != 0 00285 ) 00286 { 00287 if (sa.sa_handler == SIG_IGN) 00288 { 00289 explain_string_buffer_puts(sb->footnotes, "; "); 00290 explain_buffer_gettext 00291 ( 00292 sb->footnotes, 00293 /* 00294 * xgettext: This error message is used when a 00295 * process is ignoring the SIGPIPE signal. 00296 */ 00297 i18n("note that this process is ignoring the SIGPIPE " 00298 "signal") 00299 ); 00300 break; 00301 } 00302 if (sa.sa_handler != SIG_DFL) 00303 { 00304 explain_string_buffer_puts(sb->footnotes, "; "); 00305 explain_buffer_gettext 00306 ( 00307 sb->footnotes, 00308 /* 00309 * xgettext: This error message is used when a 00310 * process is catching the SIGPIPE signal. 00311 */ 00312 i18n("note that this process is catching the SIGPIPE " 00313 "signal") 00314 ); 00315 break; 00316 } 00317 } 00318 explain_string_buffer_puts(sb->footnotes, "; "); 00319 explain_buffer_gettext 00320 ( 00321 sb->footnotes, 00322 /* 00323 * xgettext: This error message is used when a process 00324 * is catches, blocks or ignores the SIGPIPE signal, but 00325 * it is nopt possible to be more specific. 00326 */ 00327 i18n("note that this process catches, blocks or ignores the " 00328 "SIGPIPE signal") 00329 ); 00330 } 00331 break; 00332 00333 case ENOENT: 00334 /* FIXME: i18n */ 00335 explain_string_buffer_puts 00336 ( 00337 sb, 00338 "the file is on a file system" 00339 ); 00340 explain_buffer_mount_point_fd(sb, fildes); 00341 explain_string_buffer_puts 00342 ( 00343 sb, 00344 " which does not support Unix open file semantics, and the " 00345 "file has been deleted from underneath you" 00346 ); 00347 break; 00348 00349 default: 00350 explain_buffer_errno_generic(sb, errnum, syscall_name); 00351 break; 00352 } 00353 } 00354 00355 00356 void 00357 explain_buffer_errno_write(explain_string_buffer_t *sb, int errnum, 00358 int fildes, const void *data, size_t data_size) 00359 { 00360 explain_explanation_t exp; 00361 00362 explain_explanation_init(&exp, errnum); 00363 explain_buffer_errno_write_system_call 00364 ( 00365 &exp.system_call_sb, 00366 errnum, 00367 fildes, 00368 data, 00369 data_size 00370 ); 00371 explain_buffer_errno_write_explanation 00372 ( 00373 &exp.explanation_sb, 00374 errnum, 00375 "write", 00376 fildes, 00377 data, 00378 data_size 00379 ); 00380 explain_explanation_assemble(&exp, sb); 00381 } 00382 00383 00384 /* vim: set ts=8 sw=4 et : */