libexplain
1.4.D001
|
00001 /* 00002 * libexplain - Explain errno values returned by libc functions 00003 * Copyright (C) 2010, 2011, 2013 Peter Miller 00004 * 00005 * This program is free software; you can redistribute it and/or modify it 00006 * under the terms of the GNU Lesser General Public License as published by 00007 * the Free Software Foundation; either version 3 of the License, or (at 00008 * your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, but 00011 * WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 00013 * General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public License 00016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00017 */ 00018 00019 #include <libexplain/ac/errno.h> 00020 #include <libexplain/ac/fcntl.h> 00021 #include <libexplain/ac/sys/mman.h> 00022 #include <libexplain/ac/sys/resource.h> 00023 #include <libexplain/ac/sys/stat.h> 00024 00025 #include <libexplain/buffer/eacces.h> 00026 #include <libexplain/buffer/eagain.h> 00027 #include <libexplain/buffer/ebadf.h> 00028 #include <libexplain/buffer/einval.h> 00029 #include <libexplain/buffer/enfile.h> 00030 #include <libexplain/buffer/enodev.h> 00031 #include <libexplain/buffer/enomem.h> 00032 #include <libexplain/buffer/eperm.h> 00033 #include <libexplain/buffer/errno/generic.h> 00034 #include <libexplain/buffer/errno/mmap.h> 00035 #include <libexplain/buffer/etxtbsy.h> 00036 #include <libexplain/buffer/fildes.h> 00037 #include <libexplain/buffer/gettext.h> 00038 #include <libexplain/buffer/int.h> 00039 #include <libexplain/buffer/mmap_flags.h> 00040 #include <libexplain/buffer/mmap_prot.h> 00041 #include <libexplain/buffer/mount_point.h> 00042 #include <libexplain/buffer/must_be_multiple_of_page_size.h> 00043 #include <libexplain/buffer/off_t.h> 00044 #include <libexplain/buffer/open_flags.h> 00045 #include <libexplain/buffer/pointer.h> 00046 #include <libexplain/buffer/size_t.h> 00047 #include <libexplain/buffer/wrong_file_type.h> 00048 #include <libexplain/explanation.h> 00049 #include <libexplain/getpagesize.h> 00050 #include <libexplain/parse_bits.h> 00051 00052 00053 static void 00054 explain_buffer_errno_mmap_system_call(explain_string_buffer_t *sb, int errnum, 00055 void *data, size_t data_size, int prot, int flags, int fildes, off_t offset) 00056 { 00057 (void)errnum; 00058 explain_string_buffer_puts(sb, "mmap(data = "); 00059 explain_buffer_pointer(sb, data); 00060 explain_string_buffer_puts(sb, ", data_size = "); 00061 explain_buffer_size_t(sb, data_size); 00062 explain_string_buffer_puts(sb, ", prot = "); 00063 explain_buffer_mmap_prot(sb, prot); 00064 explain_string_buffer_puts(sb, ", flags = "); 00065 explain_buffer_mmap_flags(sb, flags); 00066 explain_string_buffer_puts(sb, ", fildes = "); 00067 #ifdef MAP_ANONYMOUS 00068 if (flags & MAP_ANONYMOUS) 00069 explain_buffer_int(sb, fildes); 00070 else 00071 #endif 00072 #ifdef MAP_ANON 00073 if (flags & MAP_ANON) 00074 explain_buffer_int(sb, fildes); 00075 else 00076 #endif 00077 explain_buffer_fildes(sb, fildes); 00078 explain_string_buffer_puts(sb, ", offset = "); 00079 explain_buffer_off_t(sb, offset); 00080 explain_string_buffer_putc(sb, ')'); 00081 } 00082 00083 00084 void 00085 explain_buffer_errno_mmap_explanation(explain_string_buffer_t *sb, int errnum, 00086 const char *syscall_name, void *data, size_t data_size, int prot, int flags, 00087 int fildes, off_t offset) 00088 { 00089 /* 00090 * http://www.opengroup.org/onlinepubs/009695399/functions/mmap.html 00091 */ 00092 switch (errnum) 00093 { 00094 case EACCES: 00095 { 00096 struct stat st; 00097 if (fstat(fildes, &st) == 0 && !S_ISREG(st.st_mode)) 00098 { 00099 /* 00100 * The file descriptor refers to a non-regular file. 00101 */ 00102 explain_buffer_wrong_file_type_st 00103 ( 00104 sb, 00105 &st, 00106 "fildes", 00107 S_IFREG 00108 ); 00109 break; 00110 } 00111 } 00112 00113 /* 00114 * Or MAP_PRIVATE was requested, but fd is not open for reading. 00115 */ 00116 #ifdef MAP_PRIVATE 00117 if (flags & MAP_PRIVATE) 00118 { 00119 int omode = fcntl(fildes, F_GETFD, 0); 00120 if (omode >= 0 && (omode & O_ACCMODE) == O_WRONLY) 00121 { 00122 explain_buffer_ebadf_not_open_for_reading(sb, "fildes", omode); 00123 break; 00124 } 00125 } 00126 #endif 00127 00128 #ifdef PROT_WRITE 00129 if (prot & PROT_WRITE) 00130 { 00131 int omode = fcntl(fildes, F_GETFD, 0); 00132 if (omode >= 0) 00133 { 00134 #ifdef MAP_SHARED 00135 if (flags & MAP_SHARED) 00136 { 00137 /* 00138 * Or MAP_SHARED was requested and PROT_WRITE is set, but 00139 * fildes is not open in read/write (O_RDWR) mode. 00140 */ 00141 if ((omode & O_ACCMODE) != O_RDWR) 00142 { 00143 explain_buffer_gettext 00144 ( 00145 sb, 00146 /* 00147 * xgettext: This message is used when an attempt is 00148 * made to mmap shared access to a file descriptor 00149 * that was not opened for both reading and writing. 00150 * The actual open mode will be printed separately. 00151 */ 00152 i18n("the file descriptor is not open for both " 00153 "reading and writing") 00154 ); 00155 explain_string_buffer_puts(sb, " ("); 00156 explain_buffer_open_flags(sb, omode); 00157 explain_string_buffer_putc(sb, ')'); 00158 break; 00159 } 00160 } 00161 #endif 00162 00163 /* 00164 * Or PROT_WRITE is set, but the file is append-only. 00165 */ 00166 if (omode & O_APPEND) 00167 { 00168 explain_buffer_gettext 00169 ( 00170 sb, 00171 /* 00172 * xgettext: This message is used when an attempt is 00173 * made to mmap write access to a file descriptor that 00174 * is opened for append only. The actual open mode will 00175 * be printed separately. 00176 */ 00177 i18n("the file descriptor is open for append") 00178 ); 00179 explain_string_buffer_puts(sb, " ("); 00180 explain_buffer_open_flags(sb, omode); 00181 explain_string_buffer_putc(sb, ')'); 00182 break; 00183 } 00184 } 00185 } 00186 #endif 00187 goto generic; 00188 00189 case EAGAIN: 00190 #if defined(EWOULDBLOCK) && EAGAIN != EWOULDBLOCK 00191 case EWOULDBLOCK: 00192 #endif 00193 /* 00194 * the file has been locked, or too much memory has been locked 00195 */ 00196 #ifdef MAP_LOCKED 00197 if (flags & MAP_LOCKED) 00198 { 00199 if (explain_buffer_enomem_rlimit_exceeded(sb, data_size)) 00200 return; 00201 } 00202 #endif 00203 /* FIXME: locked by whom? */ 00204 explain_buffer_gettext 00205 ( 00206 sb, 00212 i18n("the file is locked") 00213 ); 00214 break; 00215 00216 case EBADF: 00217 /* 00218 * fildes is not a valid file descriptor (and MAP_ANONYMOUS was 00219 * not set). 00220 */ 00221 explain_buffer_ebadf(sb, fildes, "fildes"); 00222 /* assume this is an actual error, and do not check MAP_ANONYMOUS */ 00223 break; 00224 00225 case EINVAL: 00226 /* 00227 * We don't like addr, length, or offset (e.g., they are too large, 00228 * or not aligned on a page boundary). 00229 * 00230 * or (since Linux 2.6.12) length was 0 00231 */ 00232 #ifdef HAVE_GETPAGESIZE 00233 { 00234 int page_size; 00235 00236 page_size = explain_getpagesize(); 00237 if (page_size > 0) 00238 { 00239 unsigned mask; 00240 00241 mask = (page_size - 1); 00242 if ((unsigned long)data & mask) 00243 { 00244 explain_buffer_must_be_multiple_of_page_size(sb, "data"); 00245 break; 00246 } 00247 if ((unsigned long)data_size & mask) 00248 { 00249 explain_buffer_must_be_multiple_of_page_size 00250 ( 00251 sb, 00252 "data_size" 00253 ); 00254 break; 00255 } 00256 if ((unsigned long)offset & mask) 00257 { 00258 explain_buffer_must_be_multiple_of_page_size(sb, "offset"); 00259 break; 00260 } 00261 } 00262 } 00263 #endif 00264 if (data_size == 0) 00265 { 00266 explain_buffer_einval_too_small(sb, "data_size", data_size); 00267 break; 00268 } 00269 00270 /* 00271 * or flags contained neither MAP_PRIVATE or MAP_SHARED, or contained 00272 * both of these values. 00273 */ 00274 switch (flags & (MAP_PRIVATE | MAP_SHARED)) 00275 { 00276 case 0: 00277 case MAP_PRIVATE | MAP_SHARED: 00278 explain_buffer_gettext 00279 ( 00280 sb, 00281 /* 00282 * xgettext: This message is used to explain in EINVAL error 00283 * reported by mmap(2), in the case where the flags did not 00284 * contain exactly one of MAP_PRIVATE or MAP_SHARED. 00285 */ 00286 i18n("you must specify exactly one of MAP_PRIVATE or " 00287 "MAP_SHARED") 00288 ); 00289 return; 00290 00291 default: 00292 break; 00293 } 00294 goto generic; 00295 00296 case ENFILE: 00297 /* 00298 * The system limit on the total number of open files has been reached. 00299 */ 00300 explain_buffer_enfile(sb); 00301 break; 00302 00303 #ifdef ENOTSUP 00304 case ENOTSUP: 00305 #endif 00306 #ifdef EOPNOTSUP 00307 case EOPNOTSUP: 00308 #endif 00309 case ENODEV: 00310 explain_buffer_gettext 00311 ( 00312 sb, 00313 /* 00314 * xgettext: This message is used to explain in ENODEV error 00315 * reported by mmap(2), in the case where the underlying 00316 * file system of the specified file does not support memory 00317 * mapping. 00318 */ 00319 i18n("the underlying file system does not support memory mapping") 00320 ); 00321 explain_buffer_mount_point_fd(sb, fildes); 00322 break; 00323 00324 case ENOMEM: 00325 /* 00326 * No memory is available, or 00327 * the process's maximum number of mappings would have been exceeded. 00328 */ 00329 if (explain_buffer_enomem_rlimit_exceeded(sb, data_size)) 00330 return; 00331 explain_buffer_enomem_kernel(sb); 00332 break; 00333 00334 case EPERM: 00335 #ifdef PROT_EXEC 00336 if (prot & PROT_EXEC) 00337 { 00338 explain_buffer_gettext 00339 ( 00340 sb, 00347 i18n("the underlying file system does not permit execution") 00348 ); 00349 explain_buffer_mount_point_fd(sb, fildes); 00350 break; 00351 } 00352 #endif 00353 goto generic; 00354 00355 case ETXTBSY: 00356 #ifdef MAP_DENYWRITE 00357 if (flags & MAP_DENYWRITE) 00358 { 00359 int omode = fcntl(fildes, F_GETFD, 0); 00360 if (omode >= 0) 00361 { 00362 switch (omode & O_ACCMODE) 00363 { 00364 case O_WRONLY: 00365 case O_RDWR: 00366 explain_buffer_gettext 00367 ( 00368 sb, 00376 i18n("the mapping flag MAP_DENYWRITE is incompatible " 00377 "with the open mode of the file descriptor") 00378 ); 00379 explain_string_buffer_puts(sb, " ("); 00380 explain_buffer_open_flags(sb, omode); 00381 explain_string_buffer_putc(sb, ')'); 00382 return; 00383 00384 default: 00385 break; 00386 } 00387 } 00388 } 00389 #endif 00390 goto generic; 00391 00392 default: 00393 generic: 00394 explain_buffer_errno_generic(sb, errnum, syscall_name); 00395 break; 00396 } 00397 } 00398 00399 00400 void 00401 explain_buffer_errno_mmap(explain_string_buffer_t *sb, int errnum, void *data, 00402 size_t data_size, int prot, int flags, int fildes, off_t offset) 00403 { 00404 explain_explanation_t exp; 00405 00406 explain_explanation_init(&exp, errnum); 00407 explain_buffer_errno_mmap_system_call(&exp.system_call_sb, errnum, data, 00408 data_size, prot, flags, fildes, offset); 00409 explain_buffer_errno_mmap_explanation(&exp.explanation_sb, errnum, "mmap", 00410 data, data_size, prot, flags, fildes, offset); 00411 explain_explanation_assemble(&exp, sb); 00412 } 00413 00414 00415 /* vim: set ts=8 sw=4 et : */