libexplain  1.4.D001
libexplain/buffer/errno/fcntl.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2008-2011, 2013, 2014 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/unistd.h>
00023 
00024 #include <libexplain/buffer/check_fildes_range.h>
00025 #include <libexplain/buffer/ebadf.h>
00026 #include <libexplain/buffer/efault.h>
00027 #include <libexplain/buffer/eintr.h>
00028 #include <libexplain/buffer/einval.h>
00029 #include <libexplain/buffer/emfile.h>
00030 #include <libexplain/buffer/errno/fcntl.h>
00031 #include <libexplain/buffer/errno/generic.h>
00032 #include <libexplain/buffer/fildes_to_pathname.h>
00033 #include <libexplain/buffer/flock.h>
00034 #include <libexplain/buffer/is_the_null_pointer.h>
00035 #include <libexplain/buffer/open_flags.h>
00036 #include <libexplain/buffer/pid_t_star.h>
00037 #include <libexplain/buffer/pointer.h>
00038 #include <libexplain/buffer/signal.h>
00039 #include <libexplain/explanation.h>
00040 #include <libexplain/fcntl.h>
00041 #include <libexplain/is_efault.h>
00042 #include <libexplain/parse_bits.h>
00043 #include <libexplain/sizeof.h>
00044 #include <libexplain/string_buffer.h>
00045 
00046 
00047 static const explain_parse_bits_table_t table[] =
00048 {
00049     { "F_DUPFD",         F_DUPFD,         },
00050 #ifdef F_DUPFD_CLOEXEC
00051     { "F_DUPFD_CLOEXEC", F_DUPFD_CLOEXEC, },
00052 #endif
00053     { "F_GETFD",         F_GETFD,         },
00054     { "F_SETFD",         F_SETFD,         },
00055     { "F_GETFL",         F_GETFL,         },
00056     { "F_SETFL",         F_SETFL,         },
00057     { "F_GETLK",         F_GETLK,         },
00058     { "F_SETLK",         F_SETLK,         },
00059     { "F_SETLKW",        F_SETLKW,        },
00060     { "F_SETOWN",        F_SETOWN,        },
00061     { "F_GETOWN",        F_GETOWN,        },
00062 #ifdef F_SETSIG
00063     { "F_SETSIG",        F_SETSIG,        },
00064 #endif
00065 #ifdef F_GETSIG
00066     { "F_GETSIG",        F_GETSIG,        },
00067 #endif
00068 #ifdef F_INPROGRESS
00069     { "F_INPROGRESS",    F_INPROGRESS,    },
00070 #endif
00071 #ifdef F_GETLEASE
00072     { "F_GETLEASE",      F_GETLEASE,      },
00073 #endif
00074 #ifdef F_SETLEASE
00075     { "F_SETLEASE",      F_SETLEASE,      },
00076 #endif
00077 #ifdef F_GETLK64
00078 #if F_GETLK64 != F_GETLK
00079     { "F_GETLK64",       F_GETLK64,       },
00080     { "F_SETLK64",       F_SETLK64,       },
00081     { "F_SETLKW64",      F_SETLKW64,      },
00082 #endif
00083 #endif
00084 #ifdef F_NOTIFY
00085     { "F_NOTIFY",        F_NOTIFY,        },
00086 #endif
00087 };
00088 
00089 
00090 int
00091 explain_fcntl_command_parse_or_die(const char *text, const char *caption)
00092 {
00093     return explain_parse_bits_or_die(text, table, sizeof(table), caption);
00094 }
00095 
00096 
00097 static void
00098 explain_buffer_errno_fcntl_system_call(explain_string_buffer_t *sb,
00099     int errnum, int fildes, int command, long data)
00100 {
00101     const explain_parse_bits_table_t *tp;
00102 
00103     explain_string_buffer_printf(sb, "fcntl(fildes = %d", fildes);
00104     explain_buffer_fildes_to_pathname(sb, fildes);
00105     explain_string_buffer_puts(sb, ", command = ");
00106     tp = explain_parse_bits_find_by_value(command, table, SIZEOF(table));
00107     if (tp)
00108         explain_string_buffer_puts(sb, tp->name);
00109     else
00110         explain_string_buffer_printf(sb, "%d", command);
00111     switch (command)
00112     {
00113     default:
00114         break;
00115 
00116     case F_DUPFD:
00117 #ifdef F_DUPFD_CLOEXEC
00118     case F_DUPFD_CLOEXEC:
00119 #endif
00120         explain_string_buffer_printf(sb, ", data = %ld", data);
00121         break;
00122 
00123     case F_SETFD:
00124         explain_string_buffer_puts(sb, ", data = ");
00125         explain_buffer_open_flags(sb, data);
00126         break;
00127 
00128     case F_SETOWN:
00129         explain_string_buffer_puts(sb, ", data = ");
00130         explain_buffer_pid_t(sb, data);
00131         break;
00132 
00133 #ifdef F_SETSIG
00134     case F_SETSIG:
00135         explain_string_buffer_puts(sb, ", data = ");
00136         explain_buffer_signal(sb, data);
00137         break;
00138 #endif
00139 
00140 #ifdef F_SETLEASE
00141     case F_SETLEASE:
00142         /* FIXME: decode lease flag */
00143         explain_string_buffer_printf(sb, ", data = %ld", data);
00144         break;
00145 #endif
00146 
00147 #ifdef F_NOTIFY
00148     case F_NOTIFY:
00149         /* FIXME: decode notify bits */
00150         explain_string_buffer_printf(sb, ", data = %ld", data);
00151         break;
00152 #endif
00153 
00154     case F_SETFL:
00155         explain_string_buffer_puts(sb, ", data = ");
00156         explain_buffer_open_flags(sb, data);
00157         break;
00158 
00159     case F_GETLK:
00160     case F_SETLK:
00161     case F_SETLKW:
00162         {
00163             const struct flock *p;
00164 
00165             p = (const struct flock *)data;
00166             explain_string_buffer_puts(sb, ", data = ");
00167             if (errnum == EFAULT)
00168                 explain_buffer_pointer(sb, p);
00169             else
00170                 explain_buffer_flock(sb, p);
00171         }
00172         break;
00173 
00174 #ifdef F_GETLK64
00175 #if F_GETLK64 != F_GETLK
00176     case F_GETLK64:
00177     case F_SETLK64:
00178     case F_SETLKW64:
00179         {
00180             const struct flock64 *p;
00181 
00182             p = (const struct flock64 *)data;
00183             explain_string_buffer_puts(sb, ", data = ");
00184             if (errnum == EFAULT)
00185                 explain_buffer_pointer(sb, p);
00186             else
00187                 explain_buffer_flock64(sb, p);
00188         }
00189         break;
00190 #endif
00191 #endif
00192     }
00193     explain_string_buffer_putc(sb, ')');
00194 }
00195 
00196 
00197 static void
00198 explain_buffer_errno_fcntl_explanation(explain_string_buffer_t *sb,
00199     int errnum, int fildes, int command, long data)
00200 {
00201     switch (errnum)
00202     {
00203     case EACCES:
00204         /* FIXME: what other processes? */
00205         explain_string_buffer_puts
00206         (
00207             sb,
00208             /* FIXME: i18n */
00209             "the operation is prohibited by locks held by other processes"
00210         );
00211         break;
00212 
00213     case EAGAIN:
00214         /* FIXME: what other processes? */
00215         explain_string_buffer_puts
00216         (
00217             sb,
00218             /* FIXME: i18n */
00219             "the operation is prohibited by locks held by other "
00220             "processes; or, the operation is prohibited because the "
00221             "file has been memory-mapped by another process"
00222         );
00223         break;
00224 
00225     case EBADF:
00226         if (fcntl(fildes, F_GETFL) < 0)
00227         {
00228             explain_buffer_ebadf(sb, fildes, "fildes");
00229             break;
00230         }
00231         switch (command)
00232         {
00233         case F_SETLK:
00234         case F_SETLKW:
00235             explain_string_buffer_puts
00236             (
00237                 sb,
00238                 /* FIXME: i18n */
00239                 "the file descriptor open flags"
00240             );
00241             {
00242                 /*
00243                  *  Insert the actual open mode here, if we can get it.
00244                  */
00245                 int n = fcntl(fildes, F_GETFL);
00246                 if (n >= 0)
00247                 {
00248                     explain_string_buffer_puts(sb, " (");
00249                     explain_buffer_open_flags(sb, n);
00250                     explain_string_buffer_putc(sb, ')');
00251                 }
00252             }
00253             explain_string_buffer_puts
00254             (
00255                 sb,
00256                 " do not match the type of lock requested"
00257             );
00258             break;
00259 
00260         default:
00261             goto generic;
00262         }
00263         break;
00264 
00265     case EDEADLK:
00266         /* FIXME: which other process? */
00267         explain_string_buffer_puts
00268         (
00269             sb,
00270             /* FIXME: i18n */
00271             "it was detected that the specified F_SETLKW "
00272             "command would cause a deadlock"
00273         );
00274         break;
00275 
00276     case EFAULT:
00277         explain_buffer_efault(sb, "data");
00278         break;
00279 
00280     case EINTR:
00281         switch (command)
00282         {
00283         default:
00284             explain_buffer_eintr(sb, "command");
00285             break;
00286 
00287         case F_SETLK:
00288         case F_GETLK:
00289             explain_string_buffer_puts
00290             (
00291                 sb,
00292                 /* FIXME: i18n */
00293                 "the command was interrupted by a signal "
00294                 "before the lock was checked or acquired; most likely "
00295                 "when locking a remote file (e.g. locking over NFS), "
00296                 "but can sometimes happen locally"
00297             );
00298             break;
00299         }
00300         break;
00301 
00302     case EINVAL:
00303         switch (command)
00304         {
00305         case F_DUPFD:
00306 #ifdef F_DUPFD_CLOEXEC
00307         case F_DUPFD_CLOEXEC:
00308 #endif
00309             if (explain_buffer_check_fildes_range(sb, data, "data") < 0)
00310             {
00311                 explain_buffer_einval_vague(sb, "data");
00312             }
00313             break;
00314 
00315 #ifdef F_SETSIG
00316         case F_SETSIG:
00317             /* FIXME: devode signal number */
00318             explain_string_buffer_printf
00319             (
00320                 sb,
00321                 /* FIXME: i18n */
00322                 "the %s argument is not an allowable signal number",
00323                 "data"
00324             );
00325             break;
00326 #endif
00327 
00328         case F_GETLK:
00329         case F_SETLK:
00330         case F_SETLKW:
00331             {
00332                 struct flock    *f;
00333 
00334                 f = (struct flock *)data;
00335                 if (!f)
00336                 {
00337                     explain_buffer_is_the_null_pointer(sb, "data");
00338                     break;
00339                 }
00340                 if (explain_is_efault_pointer(f, sizeof(*f)))
00341                 {
00342                     explain_buffer_efault(sb, "data");
00343                     break;
00344                 }
00345                 switch (f->l_type)
00346                 {
00347                 case F_RDLCK:
00348                 case F_WRLCK:
00349                 case F_UNLCK:
00350 #ifdef F_UNLKSYS
00351                 case F_UNLKSYS:
00352 #endif
00353                     break;
00354 
00355                 default:
00356                     explain_buffer_einval_vague(sb, "data->l_type");
00357                     goto done;
00358                 }
00359                 switch (f->l_whence)
00360                 {
00361                 case SEEK_SET:
00362                 case SEEK_CUR:
00363                 case SEEK_END:
00364                     break;
00365 
00366                 default:
00367                     explain_buffer_einval_vague(sb, "data->l_whence");
00368                     goto done;
00369                 }
00370                 goto generic;
00371             }
00372 
00373         default:
00374             goto generic;
00375         }
00376         break;
00377 
00378     case EMFILE:
00379         switch (command)
00380         {
00381         case F_DUPFD:
00382 #ifdef F_DUPFD_CLOEXEC
00383         case F_DUPFD_CLOEXEC:
00384 #endif
00385             if (explain_buffer_check_fildes_range(sb, data, "data"))
00386                 explain_buffer_emfile(sb);
00387             break;
00388 
00389         default:
00390             goto generic;
00391         }
00392         break;
00393 
00394     case ENOLCK:
00395         explain_string_buffer_puts
00396         (
00397             sb,
00398             /* FIXME: i18n */
00399             "too many segment locks are open, or the lock table is full, "
00400             "or a remote locking protocol failed (e.g. locking over "
00401             "NFS)"
00402         );
00403         break;
00404 
00405     case EPERM:
00406         explain_string_buffer_puts
00407         (
00408             sb,
00409             /* FIXME: i18n */
00410             "it was attempted to clear the O_APPEND flag on a file "
00411             "that has the append-only attribute set"
00412         );
00413         break;
00414 
00415     default:
00416         generic:
00417         explain_buffer_errno_generic(sb, errnum, "fcntl");
00418         break;
00419     }
00420     done:;
00421 }
00422 
00423 
00424 void
00425 explain_buffer_errno_fcntl(explain_string_buffer_t *sb, int errnum,
00426     int fildes, int command, long data)
00427 {
00428     explain_explanation_t exp;
00429 
00430     explain_explanation_init(&exp, errnum);
00431     explain_buffer_errno_fcntl_system_call
00432     (
00433         &exp.system_call_sb,
00434         errnum,
00435         fildes,
00436         command,
00437         data
00438     );
00439     explain_buffer_errno_fcntl_explanation
00440     (
00441         &exp.explanation_sb,
00442         errnum,
00443         fildes,
00444         command,
00445         data
00446     );
00447     explain_explanation_assemble(&exp, sb);
00448 }
00449 
00450 
00451 /* vim: set ts=8 sw=4 et : */