libexplain
1.4.D001
|
00001 /* 00002 * libexplain - Explain errno values returned by libc functions 00003 * Copyright (C) 2008-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/stdio.h> /* for snprintf */ 00022 #include <libexplain/ac/sys/stat.h> 00023 #include <libexplain/ac/unistd.h> /* for fpathconf */ 00024 00025 #include <libexplain/buffer/ebadf.h> 00026 #include <libexplain/buffer/einval.h> 00027 #include <libexplain/buffer/enosys.h> 00028 #include <libexplain/buffer/errno/generic.h> 00029 #include <libexplain/buffer/errno/lseek.h> 00030 #include <libexplain/buffer/fildes.h> 00031 #include <libexplain/buffer/file_type.h> 00032 #include <libexplain/buffer/lseek_whence.h> 00033 #include <libexplain/buffer/off_t.h> 00034 #include <libexplain/explanation.h> 00035 00036 00037 static void 00038 explain_buffer_errno_lseek_system_call(explain_string_buffer_t *sb, 00039 int errnum, int fildes, off_t offset, int whence) 00040 { 00041 (void)errnum; 00042 explain_string_buffer_puts(sb, "lseek(fildes = "); 00043 explain_buffer_fildes(sb, fildes); 00044 explain_string_buffer_puts(sb, ", offset = "); 00045 explain_buffer_off_t(sb, offset); 00046 explain_string_buffer_puts(sb, ", whence = "); 00047 explain_buffer_lseek_whence(sb, whence); 00048 explain_string_buffer_putc(sb, ')'); 00049 } 00050 00051 00052 #if defined(SEEK_HOLE) || defined(SEEK_DATA) 00053 00054 static int 00055 holes_are_supported(int fildes) 00056 { 00057 #ifdef _PC_MIN_HOLE_SIZE 00058 long result; 00059 00060 errno = 0; 00061 result = fpathconf(fildes, _PC_MIN_HOLE_SIZE); 00062 if (result == -1 && errno != 0) 00063 { 00064 switch (errno) 00065 { 00066 case EINVAL: 00067 case ENOSYS: 00068 /* holes are not supported */ 00069 return 0; 00070 00071 case EBADF: 00072 default: 00073 /* can't tell */ 00074 return -1; 00075 } 00076 } 00077 if (result <= 0) 00078 { 00079 /* holes are not supported */ 00080 return 0; 00081 } 00082 /* holes are supported */ 00083 return 1; 00084 #else 00085 /* can't tell */ 00086 (void)fildes; 00087 return -1; 00088 #endif 00089 } 00090 00091 #endif 00092 00093 00094 void 00095 explain_buffer_errno_lseek_explanation(explain_string_buffer_t *sb, 00096 int errnum, const char *syscall_name, int fildes, off_t offset, int whence) 00097 { 00098 switch (errnum) 00099 { 00100 case EBADF: 00101 explain_buffer_ebadf(sb, fildes, "fildes"); 00102 break; 00103 00104 case EINVAL: 00105 { 00106 long long current_position; 00107 long long destination; 00108 00109 current_position = lseek(fildes, 0, SEEK_CUR); 00110 switch (whence) 00111 { 00112 default: 00113 explain_string_buffer_puts 00114 ( 00115 sb, 00116 /* FIXME: i18n */ 00117 "'whence' is not one of SEEK_SET, SEEK_CUR, SEEK_END" 00118 #ifdef SEEK_HOLE 00119 ", SEEK_HOLE" 00120 #endif 00121 #ifdef SEEK_DATA 00122 ", SEEK_DATA" 00123 #endif 00124 ); 00125 return; 00126 00127 #ifdef SEEK_HOLE 00128 case SEEK_HOLE: 00129 if (!holes_are_supported(fildes)) 00130 goto seek_hole_enosys; 00131 if (offset < 0) 00132 { 00133 explain_buffer_einval_too_small(sb, "offset", offset); 00134 return; 00135 } 00136 destination = lseek(fildes, offset, whence); 00137 offset = 0; 00138 break; 00139 #endif 00140 00141 #ifdef SEEK_DATA 00142 case SEEK_DATA: 00143 if (!holes_are_supported(fildes)) 00144 goto seek_data_enosys; 00145 if (offset < 0) 00146 { 00147 explain_buffer_einval_too_small(sb, "offset", offset); 00148 return; 00149 } 00150 destination = lseek(fildes, offset, whence); 00151 offset = 0; 00152 break; 00153 #endif 00154 00155 case SEEK_SET: 00156 current_position = 0; 00157 destination = offset; 00158 break; 00159 00160 case SEEK_CUR: 00161 destination = current_position + offset; 00162 break; 00163 00164 case SEEK_END: 00165 destination = lseek(fildes, 0, SEEK_END); 00166 if (destination < 0) 00167 { 00168 current_position = -1; 00169 destination = 0; 00170 } 00171 else 00172 { 00173 current_position = 0; 00174 destination += offset; 00175 } 00176 break; 00177 } 00178 00179 if (current_position != (off_t)-1) 00180 { 00181 if (destination < 0) 00182 { 00183 explain_string_buffer_puts 00184 ( 00185 sb, 00186 /* FIXME: i18n */ 00187 "the resulting file offset would be " 00188 "negative" 00189 ); 00190 } 00191 else 00192 { 00193 explain_string_buffer_puts 00194 ( 00195 sb, 00196 /* FIXME: i18n */ 00197 "the resulting offset would be beyond " 00198 "the end of a seekable device" 00199 ); 00200 } 00201 explain_string_buffer_printf 00202 ( 00203 sb, 00204 " (%lld)", 00205 (long long)destination 00206 ); 00207 break; 00208 } 00209 00210 explain_string_buffer_puts 00211 ( 00212 sb, 00213 /* FIXME: i18n */ 00214 "the resulting file offset would be negative, " 00215 "or beyond the end of a seekable device" 00216 ); 00217 } 00218 break; 00219 00220 case ENXIO: 00221 #ifdef SEEK_HOLE 00222 if (whence == SEEK_HOLE) 00223 { 00224 explain_string_buffer_puts 00225 ( 00226 sb, 00227 /* FIXME: i18n */ 00228 "there is no hole extent beyond the current file position" 00229 ); 00230 } 00231 #endif 00232 #ifdef SEEK_DATA 00233 if (whence == SEEK_DATA) 00234 { 00235 explain_string_buffer_puts 00236 ( 00237 sb, 00238 /* FIXME: i18n */ 00239 "there is no data extent beyond the current file position" 00240 ); 00241 } 00242 #endif 00243 goto generic; 00244 00245 case EOVERFLOW: 00246 explain_string_buffer_puts 00247 ( 00248 sb, 00249 /* FIXME: i18n */ 00250 "the resulting file offset cannot be represented in an off_t" 00251 ); 00252 break; 00253 00254 case ESPIPE: 00255 { 00256 struct stat st; 00257 00258 if (fstat(fildes, &st) == 0) 00259 { 00260 explain_string_buffer_puts 00261 ( 00262 sb, 00263 /* FIXME: i18n */ 00264 "the file descriptor is associated with a " 00265 ); 00266 explain_buffer_file_type_st(sb, &st); 00267 } 00268 else 00269 { 00270 explain_string_buffer_puts 00271 ( 00272 sb, 00273 /* FIXME: i18n */ 00274 "the file descriptor is associated with a " 00275 "pipe, socket, or FIFO" 00276 ); 00277 } 00278 } 00279 break; 00280 00281 case ENOSYS: 00282 #if defined(EOPNOTSUPP) && EOPNOTSUPP != ENOSYS 00283 case EOPNOTSUPP: 00284 #endif 00285 #ifdef SEEK_HOLE 00286 if (whence == SEEK_HOLE && !holes_are_supported(fildes)) 00287 { 00288 char temp[50]; 00289 00290 seek_hole_enosys: 00291 snprintf(temp, sizeof(temp), "%s SEEK_HOLE", syscall_name); 00292 explain_buffer_enosys_fildes(sb, fildes, "fildes", temp); 00293 break; 00294 } 00295 #endif 00296 #ifdef SEEK_DATA 00297 if (whence == SEEK_DATA && !holes_are_supported(fildes)) 00298 { 00299 char temp[50]; 00300 00301 seek_data_enosys: 00302 snprintf(temp, sizeof(temp), "%s SEEK_DATA", syscall_name); 00303 explain_buffer_enosys_fildes(sb, fildes, "fildes", temp); 00304 break; 00305 } 00306 #endif 00307 explain_buffer_enosys_fildes(sb, fildes, "fildes", syscall_name); 00308 break; 00309 00310 default: 00311 generic: 00312 explain_buffer_errno_generic(sb, errnum, syscall_name); 00313 break; 00314 } 00315 } 00316 00317 00318 void 00319 explain_buffer_errno_lseek(explain_string_buffer_t *sb, int errnum, 00320 int fildes, off_t offset, int whence) 00321 { 00322 explain_explanation_t exp; 00323 00324 explain_explanation_init(&exp, errnum); 00325 explain_buffer_errno_lseek_system_call 00326 ( 00327 &exp.system_call_sb, 00328 errnum, 00329 fildes, 00330 offset, 00331 whence 00332 ); 00333 explain_buffer_errno_lseek_explanation 00334 ( 00335 &exp.explanation_sb, 00336 errnum, 00337 "lseek", 00338 fildes, 00339 offset, 00340 whence 00341 ); 00342 explain_explanation_assemble(&exp, sb); 00343 } 00344 00345 00346 /* vim: set ts=8 sw=4 et : */