libexplain  1.4.D001
libexplain/buffer/errno/generic.c
Go to the documentation of this file.
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 : */