libexplain  1.4.D001
libexplain/buffer/errno/read.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 published by
00008  * the Free Software Foundation; either version 3 of the License, or (at
00009  * 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/errno.h>
00021 #include <libexplain/ac/fcntl.h>
00022 #include <libexplain/ac/sys/ioctl.h>
00023 #include <libexplain/ac/sys/mtio.h>
00024 #include <libexplain/ac/sys/stat.h>
00025 #include <libexplain/ac/unistd.h>
00026 
00027 #include <libexplain/buffer/ebadf.h>
00028 #include <libexplain/buffer/efault.h>
00029 #include <libexplain/buffer/eio.h>
00030 #include <libexplain/buffer/eintr.h>
00031 #include <libexplain/buffer/errno/generic.h>
00032 #include <libexplain/buffer/errno/read.h>
00033 #include <libexplain/buffer/fildes.h>
00034 #include <libexplain/buffer/gettext.h>
00035 #include <libexplain/buffer/mount_point.h>
00036 #include <libexplain/buffer/pointer.h>
00037 #include <libexplain/buffer/size_t.h>
00038 #include <libexplain/explanation.h>
00039 #include <libexplain/is_same_inode.h>
00040 #include <libexplain/string_buffer.h>
00041 
00042 
00043 static void
00044 explain_buffer_errno_read_system_call(explain_string_buffer_t *sb, int errnum,
00045     int fildes, const void *data, size_t data_size)
00046 {
00047     (void)errnum;
00048     explain_string_buffer_puts(sb, "read(fildes = ");
00049     explain_buffer_fildes(sb, fildes);
00050     explain_string_buffer_puts(sb, ", data = ");
00051     explain_buffer_pointer(sb, data);
00052     explain_string_buffer_puts(sb, ", data_size = ");
00053     explain_buffer_size_t(sb, data_size);
00054     explain_string_buffer_putc(sb, ')');
00055 }
00056 
00057 
00058 static int
00059 is_a_tape(int fildes)
00060 {
00061     struct mtop     args;
00062 
00063     args.mt_op = MTNOP;
00064     args.mt_count = 0;
00065     return (ioctl(fildes, MTIOCTOP, &args) >= 0);
00066 }
00067 
00068 
00069 void
00070 explain_buffer_errno_read_explanation(explain_string_buffer_t *sb, int errnum,
00071     const char *syscall_name, int fildes, const void *data, size_t data_size)
00072 {
00073     (void)data;
00074     (void)data_size;
00075     switch (errnum)
00076     {
00077     case EAGAIN:
00078         explain_string_buffer_puts
00079         (
00080             sb,
00081             /* FIXME: i18n */
00082             "non-blocking I/O has been selected using "
00083             "O_NONBLOCK and no data was immediately available for "
00084             "reading"
00085         );
00086         break;
00087 
00088     case EBADF:
00089         {
00090             int             flags;
00091 
00092             flags = fcntl(fildes, F_GETFL);
00093             if (flags >= 0)
00094             {
00095                 explain_buffer_ebadf_not_open_for_reading(sb, "fildes", flags);
00096             }
00097             else
00098             {
00099                 explain_buffer_ebadf(sb, fildes, "fildes");
00100             }
00101         }
00102         break;
00103 
00104     case EFAULT:
00105         explain_buffer_efault(sb, "data");
00106         break;
00107 
00108     case EINTR:
00109         explain_buffer_eintr(sb, syscall_name);
00110         break;
00111 
00112     case EINVAL:
00113         {
00114             int             flags;
00115 
00116             flags = fcntl(fildes, F_GETFL);
00117             if (flags >= 0)
00118             {
00119                 if ((flags & O_ACCMODE) == O_WRONLY)
00120                 {
00121                     explain_buffer_ebadf_not_open_for_reading
00122                     (
00123                         sb,
00124                         "fildes",
00125                         flags
00126                     );
00127                 }
00128 #ifdef O_DIRECT
00129                 else if (flags & O_DIRECT)
00130                 {
00131                     /* FIXME: figure out which */
00132                     explain_string_buffer_puts
00133                     (
00134                         sb,
00135                         /* FIXME: i18n */
00136                         "the file was opened with the O_DIRECT flag, "
00137                         "and either the address specified in data is "
00138                         "not suitably aligned, or the value specified "
00139                         "in data_size is not suitably aligned, or the "
00140                         "current file offset is not suitably aligned"
00141                     );
00142                 }
00143 #endif
00144                 else
00145                 {
00146                     explain_string_buffer_puts
00147                     (
00148                         sb,
00149                         /* FIXME: i18n */
00150                         "the file descriptor was created via a call to "
00151                         "timerfd_create(2) and the wrong size buffer was "
00152                         "given"
00153                     );
00154                 }
00155             }
00156             else
00157             {
00158                 explain_string_buffer_puts
00159                 (
00160                     sb,
00161                     /* FIXME: i18n */
00162                     "the file desriptor is attached to an object "
00163                     "which is unsuitable for reading; or, the file was "
00164                     "opened with the O_DIRECT flag, and either the "
00165                     "address specified in data, the value specified "
00166                     "in data_size, or the current file offset is not"
00167                     "suitably aligned; or, the file descriptor was "
00168                     "created via a call to timerfd_create(2) and the "
00169                     "wrong size buffer was given"
00170                 );
00171             }
00172         }
00173 
00174         /*
00175          * There is a bug in Tru64 5.1.  Attempting to read more than
00176          * INT_MAX bytes fails with errno == EINVAL.
00177          */
00178         if (data_size > INT_MAX)
00179         {
00180             explain_string_buffer_puts
00181             (
00182                 sb,
00183                 /* FIXME: i18n */
00184                 "you have tripped over a bug in Tru64 5.1 where it is unable "
00185                 "to read more than INT_MAX bytes at a time"
00186             );
00187             explain_string_buffer_printf
00188             (
00189                 sb,
00190                 " (%zd > %d)",
00191                 data_size,
00192                 INT_MAX
00193             );
00194             break;
00195         }
00196         break;
00197 
00198     case EIO:
00199         {
00200             pid_t process_group = getpgid(0);
00201             int controlling_tty_fd = open("/dev/tty", O_RDWR);
00202             pid_t tty_process_group = tcgetpgrp(controlling_tty_fd);
00203 
00204             /* if reading controlling tty */
00205             if
00206             (
00207                 process_group >= 0
00208             &&
00209                 controlling_tty_fd >= 0
00210             &&
00211                 process_group != tty_process_group
00212             )
00213             {
00214                 struct stat     st1;
00215                 struct stat     st2;
00216 
00217                 if
00218                 (
00219                     fstat(fildes, &st1) == 0
00220                 &&
00221                     fstat(controlling_tty_fd, &st2) == 0
00222                 &&
00223                     explain_is_same_inode(&st1, &st2)
00224                 )
00225                 {
00226                     explain_string_buffer_puts
00227                     (
00228                         sb,
00229                         /* FIXME: i18n */
00230                         "the process is in a background process group, and "
00231                         "tried to read from its controlling tty, and the "
00232                         "controlling tty is either ignoring or blocking SIGTTIN"
00233                     );
00234                     close(controlling_tty_fd);
00235                     break;
00236                 }
00237             }
00238             if (controlling_tty_fd < 0)
00239             {
00240                 explain_string_buffer_puts
00241                 (
00242                     sb,
00243                     /* FIXME: i18n */
00244                     "the process is in an orphaned process "
00245                     "group and tried to read from its controlling tty"
00246                 );
00247                 break;
00248             }
00249             close(controlling_tty_fd);
00250 
00251             explain_buffer_eio_fildes(sb, fildes);
00252         }
00253         break;
00254 
00255     case EISDIR:
00256         explain_string_buffer_puts
00257         (
00258             sb,
00259             /* FIXME: i18n */
00260             "fildes refers to a directory, and you must use getdents(2) to "
00261             "read directories, preferably via the higher-level interface "
00262             "provided by readdir(3)"
00263         );
00264         break;
00265 
00266     case ENOENT:
00267         explain_string_buffer_puts
00268         (
00269             sb,
00270             /* FIXME: i18n */
00271             "the file is on a file system"
00272         );
00273         explain_buffer_mount_point_fd(sb, fildes);
00274         explain_string_buffer_puts
00275         (
00276             sb,
00277             " that does not support Unix open file semantics, and the "
00278             "file has been deleted from underneath you"
00279         );
00280         break;
00281 
00282     case EOVERFLOW:
00283         if (data_size > ((size_t)1 << 16) && is_a_tape(fildes))
00284         {
00285             explain_string_buffer_printf
00286             (
00287                 sb,
00288                 /* FIXME: i18n */
00289                 "the tape read operation was supplied with a %ld byte "
00290                     "buffer, however the kernal has been compiled with a limit "
00291                     "smaller than this; you need to reconfigure your system, "
00292                     "or recompile your tape device driver, to have a fixed "
00293                     "limit of at least 64KiB",
00294                 (long)data_size
00295             );
00296         }
00297         break;
00298 
00299     default:
00300         explain_buffer_errno_generic(sb, errnum, syscall_name);
00301         break;
00302     }
00303 }
00304 
00305 
00306 void
00307 explain_buffer_errno_read(explain_string_buffer_t *sb, int errnum,
00308     int fildes, const void *data, size_t data_size)
00309 {
00310     explain_explanation_t exp;
00311 
00312     explain_explanation_init(&exp, errnum);
00313     explain_buffer_errno_read_system_call
00314     (
00315         &exp.system_call_sb,
00316         errnum,
00317         fildes,
00318         data,
00319         data_size
00320     );
00321     explain_buffer_errno_read_explanation
00322     (
00323         &exp.explanation_sb,
00324         errnum,
00325         "read",
00326         fildes,
00327         data,
00328         data_size
00329     );
00330     explain_explanation_assemble(&exp, sb);
00331 }
00332 
00333 
00334 /* vim: set ts=8 sw=4 et : */