libexplain  1.4.D001
libexplain/buffer/errno/readv.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2009, 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
00012  * ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNULesser
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/limits.h>
00021 #include <libexplain/ac/stdio.h>
00022 #include <libexplain/ac/sys/uio.h>
00023 #include <libexplain/ac/unistd.h>
00024 
00025 #include <libexplain/buffer/efault.h>
00026 #include <libexplain/buffer/eintr.h>
00027 #include <libexplain/buffer/einval.h>
00028 #include <libexplain/buffer/enosys.h>
00029 #include <libexplain/buffer/errno/read.h>
00030 #include <libexplain/buffer/errno/readv.h>
00031 #include <libexplain/buffer/fildes.h>
00032 #include <libexplain/buffer/int.h>
00033 #include <libexplain/buffer/iovec.h>
00034 #include <libexplain/buffer/long_long.h>
00035 #include <libexplain/buffer/ssize_t.h>
00036 #include <libexplain/explanation.h>
00037 #include <libexplain/is_efault.h>
00038 #include <libexplain/option.h>
00039 
00040 
00041 static void
00042 explain_buffer_errno_readv_system_call(explain_string_buffer_t *sb, int errnum,
00043     int fildes, const struct iovec *data, int data_size)
00044 {
00045     (void)errnum;
00046     explain_string_buffer_puts(sb, "readv(fildes = ");
00047     explain_buffer_fildes(sb, fildes);
00048     explain_string_buffer_puts(sb, ", data = ");
00049     explain_buffer_iovec(sb, data, data_size);
00050     explain_string_buffer_puts(sb, ", data_size = ");
00051     explain_buffer_int(sb, data_size);
00052     explain_string_buffer_putc(sb, ')');
00053 }
00054 
00055 
00056 static void
00057 explain_buffer_errno_readv_explanation(explain_string_buffer_t *sb, int errnum,
00058     const char *syscall_name, int fildes, const struct iovec *data,
00059     int data_size)
00060 {
00061     void            *data2;
00062     size_t          data2_size;
00063     int             j;
00064 
00065     /*
00066      * http://www.opengroup.org/onlinepubs/009695399/functions/readv.html
00067      */
00068     switch (errnum)
00069     {
00070     case EFAULT:
00071         if (explain_is_efault_pointer(data, data_size * sizeof(*data)))
00072         {
00073             explain_buffer_efault(sb, "data");
00074             return;
00075         }
00076         for (j = 0; j < data_size; ++j)
00077         {
00078             const struct iovec *p = data + j;
00079             if (explain_is_efault_pointer(p->iov_base, p->iov_len))
00080             {
00081                 char            buffer[60];
00082 
00083                 snprintf(buffer, sizeof(buffer), "data[%d].iov_base", j);
00084                 explain_buffer_efault(sb, buffer);
00085                 return;
00086             }
00087         }
00088         return;
00089 
00090     case EINTR:
00091         explain_buffer_eintr(sb, syscall_name);
00092         return;
00093 
00094     case EINVAL:
00095         if (data_size < 0)
00096         {
00097             explain_buffer_einval_too_small(sb, "data_size", data_size);
00098             return;
00099         }
00100 
00101         /*
00102          * Linux readv(2) says
00103          * "POSIX.1-2001 allows an implementation to place a limit
00104          * on the number of items that can be passed in data.  An
00105          * implementation can advertise its limit by defining IOV_MAX
00106          * in <limits.h> or at run time via the return value from
00107          * sysconf(_SC_IOV_MAX).
00108          *
00109          * "On Linux, the limit advertised by these mechanisms is 1024,
00110          * which is the true kernel limit.  However, the glibc wrapper
00111          * functions do some extra work [to hide it]."
00112          */
00113         {
00114             long            iov_max;
00115 
00116             iov_max = -1;
00117 #ifdef _SC_IOV_MAX
00118             iov_max = sysconf(_SC_IOV_MAX);
00119 #endif
00120 #if IOV_MAX > 0
00121             if (iov_max <= 0)
00122                 iov_max = IOV_MAX;
00123 #endif
00124             if (iov_max > 0 && data_size > iov_max)
00125             {
00126                 explain_buffer_einval_too_large2(sb, "data_size", iov_max);
00127                 return;
00128             }
00129         }
00130 
00131         /*
00132          * The total size must fit into a ssize_t return value.
00133          */
00134         {
00135             ssize_t max = (~(size_t)0) >> 1;
00136             long long total = 0;
00137             for (j = 0; j < data_size; ++j)
00138                 total += data[j].iov_len;
00139             if (total > max)
00140             {
00141                 explain_buffer_einval_too_large(sb, "data[*].iov_len");
00142                 if (explain_option_dialect_specific())
00143                 {
00144                     explain_string_buffer_puts(sb, " (");
00145                     explain_buffer_long_long(sb, total);
00146                     explain_string_buffer_puts(sb, " > ");
00147                     explain_buffer_ssize_t(sb, max);
00148                     explain_string_buffer_putc(sb, ')');
00149                 }
00150                 return;
00151             }
00152         }
00153         break;
00154 
00155     case ENOSYS:
00156 #if defined(EOPNOTSUPP) && EOPNOTSUPP != ENOSYS
00157     case EOPNOTSUPP:
00158 #endif
00159         explain_buffer_enosys_vague(sb, syscall_name);
00160         return;
00161 
00162     default:
00163         break;
00164     }
00165 
00166     /*
00167      * We know the size fits, because we would otherwise get an EINVAL
00168      * error, and that would have been handled already.
00169      */
00170     data2 = (data_size > 0 ? data[0].iov_base : 0);
00171     data2_size = 0;
00172     for (j = 0; j < data_size; ++j)
00173         data2_size += data[j].iov_len;
00174     explain_buffer_errno_read_explanation
00175     (
00176         sb,
00177         errnum,
00178         syscall_name,
00179         fildes,
00180         data2,
00181         data2_size
00182     );
00183 }
00184 
00185 
00186 void
00187 explain_buffer_errno_readv(explain_string_buffer_t *sb, int errnum, int fildes,
00188     const struct iovec *data, int data_size)
00189 {
00190     explain_explanation_t exp;
00191 
00192     explain_explanation_init(&exp, errnum);
00193     explain_buffer_errno_readv_system_call(&exp.system_call_sb, errnum, fildes,
00194         data, data_size);
00195     explain_buffer_errno_readv_explanation(&exp.explanation_sb, errnum, "readv",
00196         fildes, data, data_size);
00197     explain_explanation_assemble(&exp, sb);
00198 }
00199 
00200 
00201 /* vim: set ts=8 sw=4 et : */