libexplain
1.4.D001
|
00001 /* 00002 * libexplain - Explain errno values returned by libc functions 00003 * Copyright (C) 2008-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 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/unistd.h> 00023 00024 #include <libexplain/buffer/check_fildes_range.h> 00025 #include <libexplain/buffer/ebadf.h> 00026 #include <libexplain/buffer/efault.h> 00027 #include <libexplain/buffer/eintr.h> 00028 #include <libexplain/buffer/einval.h> 00029 #include <libexplain/buffer/emfile.h> 00030 #include <libexplain/buffer/errno/fcntl.h> 00031 #include <libexplain/buffer/errno/generic.h> 00032 #include <libexplain/buffer/fildes_to_pathname.h> 00033 #include <libexplain/buffer/flock.h> 00034 #include <libexplain/buffer/is_the_null_pointer.h> 00035 #include <libexplain/buffer/open_flags.h> 00036 #include <libexplain/buffer/pid_t_star.h> 00037 #include <libexplain/buffer/pointer.h> 00038 #include <libexplain/buffer/signal.h> 00039 #include <libexplain/explanation.h> 00040 #include <libexplain/fcntl.h> 00041 #include <libexplain/is_efault.h> 00042 #include <libexplain/parse_bits.h> 00043 #include <libexplain/sizeof.h> 00044 #include <libexplain/string_buffer.h> 00045 00046 00047 static const explain_parse_bits_table_t table[] = 00048 { 00049 { "F_DUPFD", F_DUPFD, }, 00050 #ifdef F_DUPFD_CLOEXEC 00051 { "F_DUPFD_CLOEXEC", F_DUPFD_CLOEXEC, }, 00052 #endif 00053 { "F_GETFD", F_GETFD, }, 00054 { "F_SETFD", F_SETFD, }, 00055 { "F_GETFL", F_GETFL, }, 00056 { "F_SETFL", F_SETFL, }, 00057 { "F_GETLK", F_GETLK, }, 00058 { "F_SETLK", F_SETLK, }, 00059 { "F_SETLKW", F_SETLKW, }, 00060 { "F_SETOWN", F_SETOWN, }, 00061 { "F_GETOWN", F_GETOWN, }, 00062 #ifdef F_SETSIG 00063 { "F_SETSIG", F_SETSIG, }, 00064 #endif 00065 #ifdef F_GETSIG 00066 { "F_GETSIG", F_GETSIG, }, 00067 #endif 00068 #ifdef F_INPROGRESS 00069 { "F_INPROGRESS", F_INPROGRESS, }, 00070 #endif 00071 #ifdef F_GETLEASE 00072 { "F_GETLEASE", F_GETLEASE, }, 00073 #endif 00074 #ifdef F_SETLEASE 00075 { "F_SETLEASE", F_SETLEASE, }, 00076 #endif 00077 #ifdef F_GETLK64 00078 #if F_GETLK64 != F_GETLK 00079 { "F_GETLK64", F_GETLK64, }, 00080 { "F_SETLK64", F_SETLK64, }, 00081 { "F_SETLKW64", F_SETLKW64, }, 00082 #endif 00083 #endif 00084 #ifdef F_NOTIFY 00085 { "F_NOTIFY", F_NOTIFY, }, 00086 #endif 00087 }; 00088 00089 00090 int 00091 explain_fcntl_command_parse_or_die(const char *text, const char *caption) 00092 { 00093 return explain_parse_bits_or_die(text, table, sizeof(table), caption); 00094 } 00095 00096 00097 static void 00098 explain_buffer_errno_fcntl_system_call(explain_string_buffer_t *sb, 00099 int errnum, int fildes, int command, long data) 00100 { 00101 const explain_parse_bits_table_t *tp; 00102 00103 explain_string_buffer_printf(sb, "fcntl(fildes = %d", fildes); 00104 explain_buffer_fildes_to_pathname(sb, fildes); 00105 explain_string_buffer_puts(sb, ", command = "); 00106 tp = explain_parse_bits_find_by_value(command, table, SIZEOF(table)); 00107 if (tp) 00108 explain_string_buffer_puts(sb, tp->name); 00109 else 00110 explain_string_buffer_printf(sb, "%d", command); 00111 switch (command) 00112 { 00113 default: 00114 break; 00115 00116 case F_DUPFD: 00117 #ifdef F_DUPFD_CLOEXEC 00118 case F_DUPFD_CLOEXEC: 00119 #endif 00120 explain_string_buffer_printf(sb, ", data = %ld", data); 00121 break; 00122 00123 case F_SETFD: 00124 explain_string_buffer_puts(sb, ", data = "); 00125 explain_buffer_open_flags(sb, data); 00126 break; 00127 00128 case F_SETOWN: 00129 explain_string_buffer_puts(sb, ", data = "); 00130 explain_buffer_pid_t(sb, data); 00131 break; 00132 00133 #ifdef F_SETSIG 00134 case F_SETSIG: 00135 explain_string_buffer_puts(sb, ", data = "); 00136 explain_buffer_signal(sb, data); 00137 break; 00138 #endif 00139 00140 #ifdef F_SETLEASE 00141 case F_SETLEASE: 00142 /* FIXME: decode lease flag */ 00143 explain_string_buffer_printf(sb, ", data = %ld", data); 00144 break; 00145 #endif 00146 00147 #ifdef F_NOTIFY 00148 case F_NOTIFY: 00149 /* FIXME: decode notify bits */ 00150 explain_string_buffer_printf(sb, ", data = %ld", data); 00151 break; 00152 #endif 00153 00154 case F_SETFL: 00155 explain_string_buffer_puts(sb, ", data = "); 00156 explain_buffer_open_flags(sb, data); 00157 break; 00158 00159 case F_GETLK: 00160 case F_SETLK: 00161 case F_SETLKW: 00162 { 00163 const struct flock *p; 00164 00165 p = (const struct flock *)data; 00166 explain_string_buffer_puts(sb, ", data = "); 00167 if (errnum == EFAULT) 00168 explain_buffer_pointer(sb, p); 00169 else 00170 explain_buffer_flock(sb, p); 00171 } 00172 break; 00173 00174 #ifdef F_GETLK64 00175 #if F_GETLK64 != F_GETLK 00176 case F_GETLK64: 00177 case F_SETLK64: 00178 case F_SETLKW64: 00179 { 00180 const struct flock64 *p; 00181 00182 p = (const struct flock64 *)data; 00183 explain_string_buffer_puts(sb, ", data = "); 00184 if (errnum == EFAULT) 00185 explain_buffer_pointer(sb, p); 00186 else 00187 explain_buffer_flock64(sb, p); 00188 } 00189 break; 00190 #endif 00191 #endif 00192 } 00193 explain_string_buffer_putc(sb, ')'); 00194 } 00195 00196 00197 static void 00198 explain_buffer_errno_fcntl_explanation(explain_string_buffer_t *sb, 00199 int errnum, int fildes, int command, long data) 00200 { 00201 switch (errnum) 00202 { 00203 case EACCES: 00204 /* FIXME: what other processes? */ 00205 explain_string_buffer_puts 00206 ( 00207 sb, 00208 /* FIXME: i18n */ 00209 "the operation is prohibited by locks held by other processes" 00210 ); 00211 break; 00212 00213 case EAGAIN: 00214 /* FIXME: what other processes? */ 00215 explain_string_buffer_puts 00216 ( 00217 sb, 00218 /* FIXME: i18n */ 00219 "the operation is prohibited by locks held by other " 00220 "processes; or, the operation is prohibited because the " 00221 "file has been memory-mapped by another process" 00222 ); 00223 break; 00224 00225 case EBADF: 00226 if (fcntl(fildes, F_GETFL) < 0) 00227 { 00228 explain_buffer_ebadf(sb, fildes, "fildes"); 00229 break; 00230 } 00231 switch (command) 00232 { 00233 case F_SETLK: 00234 case F_SETLKW: 00235 explain_string_buffer_puts 00236 ( 00237 sb, 00238 /* FIXME: i18n */ 00239 "the file descriptor open flags" 00240 ); 00241 { 00242 /* 00243 * Insert the actual open mode here, if we can get it. 00244 */ 00245 int n = fcntl(fildes, F_GETFL); 00246 if (n >= 0) 00247 { 00248 explain_string_buffer_puts(sb, " ("); 00249 explain_buffer_open_flags(sb, n); 00250 explain_string_buffer_putc(sb, ')'); 00251 } 00252 } 00253 explain_string_buffer_puts 00254 ( 00255 sb, 00256 " do not match the type of lock requested" 00257 ); 00258 break; 00259 00260 default: 00261 goto generic; 00262 } 00263 break; 00264 00265 case EDEADLK: 00266 /* FIXME: which other process? */ 00267 explain_string_buffer_puts 00268 ( 00269 sb, 00270 /* FIXME: i18n */ 00271 "it was detected that the specified F_SETLKW " 00272 "command would cause a deadlock" 00273 ); 00274 break; 00275 00276 case EFAULT: 00277 explain_buffer_efault(sb, "data"); 00278 break; 00279 00280 case EINTR: 00281 switch (command) 00282 { 00283 default: 00284 explain_buffer_eintr(sb, "command"); 00285 break; 00286 00287 case F_SETLK: 00288 case F_GETLK: 00289 explain_string_buffer_puts 00290 ( 00291 sb, 00292 /* FIXME: i18n */ 00293 "the command was interrupted by a signal " 00294 "before the lock was checked or acquired; most likely " 00295 "when locking a remote file (e.g. locking over NFS), " 00296 "but can sometimes happen locally" 00297 ); 00298 break; 00299 } 00300 break; 00301 00302 case EINVAL: 00303 switch (command) 00304 { 00305 case F_DUPFD: 00306 #ifdef F_DUPFD_CLOEXEC 00307 case F_DUPFD_CLOEXEC: 00308 #endif 00309 if (explain_buffer_check_fildes_range(sb, data, "data") < 0) 00310 { 00311 explain_buffer_einval_vague(sb, "data"); 00312 } 00313 break; 00314 00315 #ifdef F_SETSIG 00316 case F_SETSIG: 00317 /* FIXME: devode signal number */ 00318 explain_string_buffer_printf 00319 ( 00320 sb, 00321 /* FIXME: i18n */ 00322 "the %s argument is not an allowable signal number", 00323 "data" 00324 ); 00325 break; 00326 #endif 00327 00328 case F_GETLK: 00329 case F_SETLK: 00330 case F_SETLKW: 00331 { 00332 struct flock *f; 00333 00334 f = (struct flock *)data; 00335 if (!f) 00336 { 00337 explain_buffer_is_the_null_pointer(sb, "data"); 00338 break; 00339 } 00340 if (explain_is_efault_pointer(f, sizeof(*f))) 00341 { 00342 explain_buffer_efault(sb, "data"); 00343 break; 00344 } 00345 switch (f->l_type) 00346 { 00347 case F_RDLCK: 00348 case F_WRLCK: 00349 case F_UNLCK: 00350 #ifdef F_UNLKSYS 00351 case F_UNLKSYS: 00352 #endif 00353 break; 00354 00355 default: 00356 explain_buffer_einval_vague(sb, "data->l_type"); 00357 goto done; 00358 } 00359 switch (f->l_whence) 00360 { 00361 case SEEK_SET: 00362 case SEEK_CUR: 00363 case SEEK_END: 00364 break; 00365 00366 default: 00367 explain_buffer_einval_vague(sb, "data->l_whence"); 00368 goto done; 00369 } 00370 goto generic; 00371 } 00372 00373 default: 00374 goto generic; 00375 } 00376 break; 00377 00378 case EMFILE: 00379 switch (command) 00380 { 00381 case F_DUPFD: 00382 #ifdef F_DUPFD_CLOEXEC 00383 case F_DUPFD_CLOEXEC: 00384 #endif 00385 if (explain_buffer_check_fildes_range(sb, data, "data")) 00386 explain_buffer_emfile(sb); 00387 break; 00388 00389 default: 00390 goto generic; 00391 } 00392 break; 00393 00394 case ENOLCK: 00395 explain_string_buffer_puts 00396 ( 00397 sb, 00398 /* FIXME: i18n */ 00399 "too many segment locks are open, or the lock table is full, " 00400 "or a remote locking protocol failed (e.g. locking over " 00401 "NFS)" 00402 ); 00403 break; 00404 00405 case EPERM: 00406 explain_string_buffer_puts 00407 ( 00408 sb, 00409 /* FIXME: i18n */ 00410 "it was attempted to clear the O_APPEND flag on a file " 00411 "that has the append-only attribute set" 00412 ); 00413 break; 00414 00415 default: 00416 generic: 00417 explain_buffer_errno_generic(sb, errnum, "fcntl"); 00418 break; 00419 } 00420 done:; 00421 } 00422 00423 00424 void 00425 explain_buffer_errno_fcntl(explain_string_buffer_t *sb, int errnum, 00426 int fildes, int command, long data) 00427 { 00428 explain_explanation_t exp; 00429 00430 explain_explanation_init(&exp, errnum); 00431 explain_buffer_errno_fcntl_system_call 00432 ( 00433 &exp.system_call_sb, 00434 errnum, 00435 fildes, 00436 command, 00437 data 00438 ); 00439 explain_buffer_errno_fcntl_explanation 00440 ( 00441 &exp.explanation_sb, 00442 errnum, 00443 fildes, 00444 command, 00445 data 00446 ); 00447 explain_explanation_assemble(&exp, sb); 00448 } 00449 00450 00451 /* vim: set ts=8 sw=4 et : */