libexplain  1.4.D001
libexplain/buffer/errno/write.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2008-2010, 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/signal.h>
00023 #include <libexplain/ac/sys/resource.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/efbig.h>
00030 #include <libexplain/buffer/eintr.h>
00031 #include <libexplain/buffer/eio.h>
00032 #include <libexplain/buffer/enospc.h>
00033 #include <libexplain/buffer/errno/generic.h>
00034 #include <libexplain/buffer/errno/write.h>
00035 #include <libexplain/buffer/fildes_not_open_for_writing.h>
00036 #include <libexplain/buffer/fildes_to_pathname.h>
00037 #include <libexplain/buffer/gettext.h>
00038 #include <libexplain/buffer/mount_point.h>
00039 #include <libexplain/buffer/open_flags.h>
00040 #include <libexplain/buffer/pointer.h>
00041 #include <libexplain/buffer/pretty_size.h>
00042 #include <libexplain/buffer/rlimit.h>
00043 #include <libexplain/explanation.h>
00044 #include <libexplain/option.h>
00045 #include <libexplain/string_buffer.h>
00046 
00047 
00048 static void
00049 explain_buffer_errno_write_system_call(explain_string_buffer_t *sb,
00050     int errnum, int fildes, const void *data, size_t data_size)
00051 {
00052     (void)errnum;
00053     explain_string_buffer_printf(sb, "write(fildes = %d", fildes);
00054     explain_buffer_fildes_to_pathname(sb, fildes);
00055     explain_string_buffer_puts(sb, ", data = ");
00056     explain_buffer_pointer(sb, data);
00057     explain_string_buffer_printf
00058     (
00059         sb,
00060         ", data_size = %lld)",
00061         (long long)data_size
00062     );
00063 }
00064 
00065 #if defined(__alpha__) && defined(__osf__)
00066 #define TRUE64 1
00067 #endif
00068 
00069 #ifndef OFF_T_MAX
00070 #define OFF_T_MAX ((~(off_t)0) >> 1)
00071 #endif
00072 
00073 
00074 void
00075 explain_buffer_errno_write_explanation(explain_string_buffer_t *sb,
00076     int errnum, const char *syscall_name, int fildes, const void *data,
00077     size_t data_size)
00078 {
00079     switch (errnum)
00080     {
00081     case EAGAIN:
00082         explain_string_buffer_puts
00083         (
00084             sb,
00085             /* FIXME: i18n */
00086             "the file descriptor has been marked non-blocking "
00087             "(O_NONBLOCK) and the write would block"
00088         );
00089         break;
00090 
00091     case EBADF:
00092         if (explain_buffer_fildes_not_open_for_writing(sb, fildes, "fildes"))
00093             explain_buffer_ebadf(sb, fildes, "fildes");
00094         break;
00095 
00096     case EFAULT:
00097         explain_buffer_efault(sb, "data");
00098         break;
00099 
00100     case EFBIG:
00101         {
00102             off_t         max_file_size;
00103             off_t         pos;
00104 
00105             pos = lseek(fildes, 0, SEEK_CUR);
00106             if (pos == (off_t)-1)
00107                 pos = 0;
00108             max_file_size = explain_get_max_file_size_by_fildes(fildes);
00109             if (pos >= 0 && pos + (off_t)data_size > max_file_size)
00110             {
00111                 explain_string_buffer_puts
00112                 (
00113                     sb,
00114                     /* FIXME: i18n */
00115                     "an attempt was made to write a file that "
00116                     "exceeds the process's file size limit"
00117                 );
00118             }
00119             else
00120             {
00121                 explain_string_buffer_puts
00122                 (
00123                     sb,
00124                     /* FIXME: i18n */
00125                     "an attempt was made to write at a position past the "
00126                     "process's file size limit"
00127                 );
00128             }
00129             if (explain_option_dialect_specific())
00130             {
00131                 explain_string_buffer_puts(sb, " (");
00132                 explain_buffer_pretty_size(sb, max_file_size);
00133                 explain_string_buffer_putc(sb, ')');
00134             }
00135         }
00136         break;
00137 
00138     case EINTR:
00139         explain_buffer_eintr(sb, syscall_name);
00140         break;
00141 
00142     case EINVAL:
00143 #if TRU64
00144         if (INT_MAX < OFF_T_MAX)
00145         {
00146             if (data_size > INT_MAX)
00147             {
00148                 explain_string_buffer_puts
00149                 (
00150                     sb,
00151                     /*
00152                      * xgettext: Work around a bug in Tru64 5.1.
00153                      * Attempting to read more than INT_MAX
00154                      * bytes fails with errno == EINVAL.  See
00155     <http://lists.gnu.org/archive/html/bug-gnu-utils/2002-04/msg00010.html>.
00156                      */
00157                     "there is a bug in the TRU64 kernel, limiting it"
00158                     "to reading at most (2**31-1) bytes at a time"
00159                 );
00160                 explain_string_buffer_puts(sb->footnotes, "; ");
00161                 explain_string_buffer_puts
00162                 (
00163                     sb->footnotes,
00164                     "break your read() call into smaller pieces"
00165                 );
00166                 return;
00167             }
00168         }
00169 #endif
00170         {
00171             int flags = fcntl(fildes, F_GETFL);
00172             if (flags >= 0)
00173             {
00174                 if ((flags & O_ACCMODE) == O_RDONLY)
00175                 {
00176                     explain_string_buffer_puts
00177                     (
00178                         sb,
00179                         /* FIXME: i18n */
00180                         "the file descriptor is attached to an object "
00181                         "which is unsuitable for writing ("
00182                     );
00183                     explain_buffer_open_flags(sb, flags);
00184                     explain_string_buffer_putc(sb, ')');
00185                 }
00186                 else
00187                 {
00188                     long            alignment;
00189                     off_t           pos;
00190 
00191                     explain_string_buffer_puts
00192                     (
00193                         sb,
00194                         /* FIXME: i18n */
00195                         "the file was opened with the O_DIRECT flag, "
00196                         "and either the address specified in data is not "
00197                         "suitably aligned, the value specified in count "
00198                         "is not suitably aligned, or the current file "
00199                         "offset is not suitably aligned"
00200                     );
00201 
00202                     alignment = (long)data | (long)data_size;
00203                     pos = lseek(fildes, 0, SEEK_CUR);
00204                     if (pos != (off_t)-1)
00205                         alignment |= (long)pos;
00206                     alignment &= -alignment;
00207                     if (alignment != 0)
00208                     {
00209                         explain_string_buffer_printf
00210                         (
00211                             sb,
00212                             " (0x%lX)",
00213                             alignment
00214                         );
00215                     }
00216                 }
00217             }
00218             else
00219             {
00220                 explain_string_buffer_puts
00221                 (
00222                     sb,
00223                     /* FIXME: i18n */
00224                     "the file descriptor is attached to an object which "
00225                     "is unsuitable for writing; or, the file was opened "
00226                     "with the O_DIRECT flag, and either the address "
00227                     "specified in data is not suitably aligned, the "
00228                     "value specified in count is not suitably aligned, "
00229                     "or the current file offset is not suitably aligned"
00230                 );
00231             }
00232         }
00233         break;
00234 
00235     case EIO:
00236         explain_buffer_eio_fildes(sb, fildes);
00237         break;
00238 
00239     case ENOSPC:
00240         explain_buffer_enospc_fildes(sb, fildes, "fildes");
00241         break;
00242 
00243     case EPIPE:
00244         {
00245             sigset_t mask;
00246             struct sigaction sa;
00247 
00248             explain_string_buffer_puts
00249             (
00250                 sb,
00251                 /* FIXME: i18n */
00252                 "the file descriptor is connected to a pipe or "
00253                 "socket whose reading end is closed, when this happens "
00254                 "the writing process will also receive a SIGPIPE signal"
00255             );
00256             if
00257             (
00258                 sigprocmask(SIG_BLOCK, 0, &mask) == 0
00259             &&
00260                 sigismember(&mask, SIGPIPE)
00261             )
00262             {
00263                 /*
00264                  * FIXME: The use of sigprocmask() is undefined in a
00265                  * multithreaded process; see pthread_sigmask(3).
00266                  */
00267                 explain_string_buffer_puts(sb->footnotes, "; ");
00268                 explain_buffer_gettext
00269                 (
00270                     sb->footnotes,
00271                     /*
00272                      * xgettext:  This error message is used when a
00273                      * process is blocking the SIGPIPE signal.
00274                      */
00275                     i18n("note that this process is blocking the SIGPIPE "
00276                         "signal")
00277                 );
00278                 break;
00279             }
00280             if
00281             (
00282                 sigaction(SIGPIPE, 0, &sa) == 0
00283             &&
00284                 (sa.sa_flags & SA_SIGINFO) != 0
00285             )
00286             {
00287                 if (sa.sa_handler == SIG_IGN)
00288                 {
00289                     explain_string_buffer_puts(sb->footnotes, "; ");
00290                     explain_buffer_gettext
00291                     (
00292                         sb->footnotes,
00293                         /*
00294                          * xgettext:  This error message is used when a
00295                          * process is ignoring the SIGPIPE signal.
00296                          */
00297                         i18n("note that this process is ignoring the SIGPIPE "
00298                             "signal")
00299                     );
00300                     break;
00301                 }
00302                 if (sa.sa_handler != SIG_DFL)
00303                 {
00304                     explain_string_buffer_puts(sb->footnotes, "; ");
00305                     explain_buffer_gettext
00306                     (
00307                         sb->footnotes,
00308                         /*
00309                          * xgettext:  This error message is used when a
00310                          * process is catching the SIGPIPE signal.
00311                          */
00312                         i18n("note that this process is catching the SIGPIPE "
00313                             "signal")
00314                     );
00315                     break;
00316                 }
00317             }
00318             explain_string_buffer_puts(sb->footnotes, "; ");
00319             explain_buffer_gettext
00320             (
00321                 sb->footnotes,
00322                 /*
00323                  * xgettext:  This error message is used when a process
00324                  * is catches, blocks or ignores the SIGPIPE signal, but
00325                  * it is nopt possible to be more specific.
00326                  */
00327                 i18n("note that this process catches, blocks or ignores the "
00328                     "SIGPIPE signal")
00329             );
00330         }
00331         break;
00332 
00333     case ENOENT:
00334         /* FIXME: i18n */
00335         explain_string_buffer_puts
00336         (
00337             sb,
00338             "the file is on a file system"
00339         );
00340         explain_buffer_mount_point_fd(sb, fildes);
00341         explain_string_buffer_puts
00342         (
00343             sb,
00344             " which does not support Unix open file semantics, and the "
00345             "file has been deleted from underneath you"
00346         );
00347         break;
00348 
00349     default:
00350         explain_buffer_errno_generic(sb, errnum, syscall_name);
00351         break;
00352     }
00353 }
00354 
00355 
00356 void
00357 explain_buffer_errno_write(explain_string_buffer_t *sb, int errnum,
00358     int fildes, const void *data, size_t data_size)
00359 {
00360     explain_explanation_t exp;
00361 
00362     explain_explanation_init(&exp, errnum);
00363     explain_buffer_errno_write_system_call
00364     (
00365         &exp.system_call_sb,
00366         errnum,
00367         fildes,
00368         data,
00369         data_size
00370     );
00371     explain_buffer_errno_write_explanation
00372     (
00373         &exp.explanation_sb,
00374         errnum,
00375         "write",
00376         fildes,
00377         data,
00378         data_size
00379     );
00380     explain_explanation_assemble(&exp, sb);
00381 }
00382 
00383 
00384 /* vim: set ts=8 sw=4 et : */