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 00008 * published by the Free Software Foundation; either version 3 of the 00009 * License, or (at 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/ctype.h> 00021 #include <libexplain/ac/errno.h> 00022 #include <libexplain/ac/stdio.h> 00023 #include <libexplain/ac/string.h> 00024 00025 #include <libexplain/buffer/eintr.h> 00026 #include <libexplain/buffer/emfile.h> 00027 #include <libexplain/buffer/enfile.h> 00028 #include <libexplain/buffer/enobufs.h> 00029 #include <libexplain/buffer/enomedium.h> 00030 #include <libexplain/buffer/enomem.h> 00031 #include <libexplain/buffer/enosys.h> 00032 #include <libexplain/buffer/eoverflow.h> 00033 #include <libexplain/buffer/erange.h> 00034 #include <libexplain/buffer/errno/generic.h> 00035 #include <libexplain/buffer/ewouldblock.h> 00036 #include <libexplain/buffer/gettext.h> 00037 #include <libexplain/option.h> 00038 00039 00040 static void 00041 downcase(char *dst, size_t dst_size, const char *src) 00042 { 00043 if (dst_size == 0) 00044 return; 00045 while (dst_size > 1) 00046 { 00047 unsigned char c = *src++; 00048 if (!c) 00049 break; 00050 if (isupper(c)) 00051 c = tolower(c); 00052 *dst++ = c; 00053 --dst_size; 00054 } 00055 *dst = '\0'; 00056 } 00057 00058 00059 static int 00060 is_alpha(int c) 00061 { 00062 return isalpha((unsigned char)c); 00063 } 00064 00065 00066 void 00067 explain_buffer_errno_generic(explain_string_buffer_t *sb, int errnum, 00068 const char *syscall_name) 00069 { 00070 switch (errnum) 00071 { 00072 case 0: 00073 /* no error */ 00074 break; 00075 00076 case EAGAIN: 00077 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN 00078 case EWOULDBLOCK: 00079 #endif 00080 explain_buffer_ewouldblock(sb, syscall_name); 00081 break; 00082 00083 case EMFILE: 00084 explain_buffer_emfile(sb); 00085 break; 00086 00087 case ENFILE: 00088 explain_buffer_enfile(sb); 00089 break; 00090 00091 case EPERM: 00092 explain_string_buffer_printf_gettext 00093 ( 00094 sb, 00095 /* 00096 * xgettext: This message is used as a generic explanation 00097 * of an EPERM error returned by any system call that does 00098 * not provide a more specific explanation. 00099 * 00100 * %1$s => the name of the offending system call 00101 */ 00102 i18n("the process does not have the appropriate " 00103 "privileges to use the %s system call"), 00104 syscall_name 00105 ); 00106 break; 00107 00108 case EINTR: 00109 explain_buffer_eintr(sb, syscall_name); 00110 break; 00111 00112 #ifdef ENOMEDIUM 00113 case ENOMEDIUM: 00114 explain_buffer_enomedium_generic(sb); 00115 break; 00116 #endif 00117 00118 case ENOMEM: 00119 /* 00120 * This is ambiguous, some system calls with the kernel out of 00121 * memory. This is probably less likely than user-space running 00122 * out of memory. 00123 */ 00124 explain_buffer_enomem_user(sb, 0); 00125 break; 00126 00127 case ENOBUFS: 00128 explain_buffer_enobufs(sb); 00129 break; 00130 00131 case ENOSYS: 00132 case ENOTTY: 00133 #if defined(EOPNOTSUPP) && EOPNOTSUPP != ENOSYS 00134 case EOPNOTSUPP: 00135 #endif 00136 #if defined(ENOTSUP) && (ENOTSUP != EOPNOTSUPP) 00137 case ENOTSUP: 00138 #endif 00139 #ifdef ENOIOCTL 00140 case ENOIOCTL: 00141 #endif 00142 explain_buffer_enosys_vague(sb, syscall_name); 00143 break; 00144 00145 case ERANGE: 00146 explain_buffer_erange(sb); 00147 break; 00148 00149 case EOVERFLOW: 00150 explain_buffer_eoverflow(sb); 00151 break; 00152 00153 case EFAULT: 00154 explain_string_buffer_puts 00155 ( 00156 sb, 00157 /* FIXME: i18n */ 00158 "one or more arguments referred to memory outside the " 00159 "address space of the process" 00160 ); 00161 break; 00162 00163 default: 00164 /* 00165 * no additional information for other errno values 00166 */ 00167 if (explain_option_debug()) 00168 { 00169 char src[100]; 00170 00171 explain_string_buffer_printf 00172 ( 00173 sb, 00174 /* FIXME: i18n */ 00175 "something weird happened, cause unknown" 00176 ); 00177 00178 /* 00179 * Figure out a suitable source file name to direct the user to. 00180 */ 00181 if (0 == memcmp(syscall_name, "ioctl ", 6)) 00182 { 00183 char ioctl_name[100]; 00184 00185 /* 00186 * This is supposed to the the inverse of 00187 * explain_iocontrol_fake_syscall_name so that we can extract 00188 * the ioctl request name. 00189 */ 00190 downcase(ioctl_name, sizeof(ioctl_name), syscall_name + 6); 00191 if (strchr(ioctl_name, '(') || !is_alpha(ioctl_name[0])) 00192 { 00193 snprintf(src, sizeof(src), "libexplain/iocontrol/*.c"); 00194 } 00195 else 00196 { 00197 snprintf 00198 ( 00199 src, 00200 sizeof(src), 00201 "libexplain/iocontrol/%s.c", 00202 ioctl_name 00203 ); 00204 } 00205 } 00206 else 00207 { 00208 snprintf 00209 ( 00210 src, 00211 sizeof(src), 00212 "libexplain/buffer/errno/%s.c", 00213 syscall_name 00214 ); 00215 } 00216 00217 /* 00218 * Suggest a file that the user could improve. We think the 00219 * user is a developer, and thus capable of contributing, 00220 * because they deliberately turned on the "debug" flag. 00221 */ 00222 explain_string_buffer_puts(sb->footnotes, "; "); 00223 explain_string_buffer_printf 00224 ( 00225 sb->footnotes, 00226 /* FIXME: i18n */ 00227 "this error is undocumented for the %s system call, you could " 00228 "improve libexplain by contributing code to explain this " 00229 "error, see the %s source file", 00230 syscall_name, 00231 src 00232 ); 00233 } 00234 break; 00235 } 00236 } 00237 00238 00239 /* vim: set ts=8 sw=4 et : */