libexplain  1.4.D001
libexplain/buffer/errno/select.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  *
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,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Lesser 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/stdio.h>
00022 
00023 #include <libexplain/buffer/ebadf.h>
00024 #include <libexplain/buffer/efault.h>
00025 #include <libexplain/buffer/eintr.h>
00026 #include <libexplain/buffer/enomem.h>
00027 #include <libexplain/buffer/errno/generic.h>
00028 #include <libexplain/buffer/errno/select.h>
00029 #include <libexplain/buffer/fd_set.h>
00030 #include <libexplain/buffer/timeval.h>
00031 #include <libexplain/explanation.h>
00032 #include <libexplain/option.h>
00033 #include <libexplain/is_efault.h>
00034 
00035 
00036 static void
00037 explain_buffer_errno_select_system_call(explain_string_buffer_t *sb,
00038     int errnum, int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
00039     struct timeval *timeout)
00040 {
00041     (void)errnum;
00042     explain_string_buffer_printf(sb, "select(nfds = %d", nfds);
00043     explain_string_buffer_puts(sb, ", readfds = ");
00044     explain_buffer_fd_set(sb, nfds, readfds);
00045     explain_string_buffer_puts(sb, ", writefds = ");
00046     explain_buffer_fd_set(sb, nfds, writefds);
00047     explain_string_buffer_puts(sb, ", exceptfds = ");
00048     explain_buffer_fd_set(sb, nfds, exceptfds);
00049     explain_string_buffer_puts(sb, ", timeout = ");
00050     explain_buffer_timeval(sb, timeout);
00051     explain_string_buffer_putc(sb, ')');
00052 }
00053 
00054 
00055 static int
00056 file_descriptor_is_open(int fildes)
00057 {
00058     int             err;
00059 
00060     err = fcntl(fildes, F_GETFL);
00061     return (err >= 0);
00062 }
00063 
00064 
00065 static void
00066 explain_buffer_errno_select_explanation(explain_string_buffer_t *sb,
00067     int errnum, const char *syscall_name, int nfds, fd_set *readfds,
00068     fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
00069 {
00070     /*
00071      * http://www.opengroup.org/onlinepubs/009695399/functions/select.html
00072      */
00073     switch (errnum)
00074     {
00075     case EBADF:
00076         {
00077             int             fildes;
00078 
00079             for (fildes = 0; fildes < nfds; ++fildes)
00080             {
00081                 if
00082                 (
00083                     (
00084                         (readfds && FD_ISSET(fildes, readfds))
00085                     ||
00086                         (writefds && FD_ISSET(fildes, writefds))
00087                     ||
00088                         (exceptfds && FD_ISSET(fildes, exceptfds))
00089                     )
00090                 &&
00091                     !file_descriptor_is_open(fildes)
00092                 )
00093                     break;
00094             }
00095             if (fildes < nfds)
00096             {
00097                 char            caption[40];
00098 
00099                 snprintf(caption, sizeof(caption), "fildes %d", fildes);
00100                 explain_buffer_ebadf(sb, fildes, caption);
00101             }
00102             else
00103             {
00104                 explain_string_buffer_puts
00105                 (
00106                     sb,
00107                     "an invalid file descriptor was given in one of the sets; "
00108                     "perhaps a file descriptor that was already closed, or one "
00109                     "on which an error has occurred"
00110                 );
00111             }
00112         }
00113         break;
00114 
00115     case EFAULT:
00116         if (readfds && explain_is_efault_pointer(readfds, sizeof(*readfds)))
00117         {
00118             explain_buffer_efault(sb, "readfds");
00119             break;
00120         }
00121         if
00122         (
00123             writefds
00124         &&
00125             explain_is_efault_pointer(writefds, sizeof(*writefds))
00126         )
00127         {
00128             explain_buffer_efault(sb, "writefds");
00129             break;
00130         }
00131         if
00132         (
00133             exceptfds
00134         &&
00135             explain_is_efault_pointer(exceptfds, sizeof(*exceptfds))
00136         )
00137         {
00138             explain_buffer_efault(sb, "exceptfds");
00139             break;
00140         }
00141         if (timeout && explain_is_efault_pointer(timeout, sizeof(*timeout)))
00142         {
00143             explain_buffer_efault(sb, "timeout");
00144             break;
00145         }
00146         break;
00147 
00148     case EINTR:
00149         explain_buffer_eintr(sb, syscall_name);
00150         break;
00151 
00152     case EINVAL:
00153         if (nfds < 0)
00154         {
00155             explain_string_buffer_puts(sb, "nfds is negative");
00156             break;
00157         }
00158         if ((unsigned)nfds > (unsigned)FD_SETSIZE)
00159         {
00160             explain_string_buffer_puts
00161             (
00162                 sb,
00163                 "nfds is greater than FD_SETSIZE"
00164             );
00165             if (explain_option_dialect_specific())
00166                 explain_string_buffer_printf(sb, " (%d)", FD_SETSIZE);
00167             break;
00168         }
00169         if (timeout && (timeout->tv_sec < 0 || timeout->tv_usec < 0))
00170         {
00171             explain_string_buffer_puts(sb, "timeout is invalid");
00172             break;
00173         }
00174         break;
00175 
00176     case ENOMEM:
00177         explain_buffer_enomem_kernel(sb);
00178         break;
00179 
00180     default:
00181         explain_buffer_errno_generic(sb, errnum, syscall_name);
00182         break;
00183     }
00184 }
00185 
00186 
00187 void
00188 explain_buffer_errno_select(explain_string_buffer_t *sb, int errnum,
00189     int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
00190     struct timeval *timeout)
00191 {
00192     explain_explanation_t exp;
00193 
00194     explain_explanation_init(&exp, errnum);
00195     explain_buffer_errno_select_system_call
00196     (
00197         &exp.system_call_sb,
00198         errnum,
00199         nfds,
00200         readfds,
00201         writefds,
00202         exceptfds,
00203         timeout
00204     );
00205     explain_buffer_errno_select_explanation
00206     (
00207         &exp.explanation_sb,
00208         errnum,
00209         "select",
00210         nfds,
00211         readfds,
00212         writefds,
00213         exceptfds,
00214         timeout
00215     );
00216     explain_explanation_assemble(&exp, sb);
00217 }
00218 
00219 
00220 /* vim: set ts=8 sw=4 et : */