libexplain  1.4.D001
libexplain/buffer/errno/readlink.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2008-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/sys/stat.h>
00021 
00022 #include <libexplain/buffer/eacces.h>
00023 #include <libexplain/buffer/efault.h>
00024 #include <libexplain/buffer/einval.h>
00025 #include <libexplain/buffer/eio.h>
00026 #include <libexplain/buffer/eloop.h>
00027 #include <libexplain/buffer/enametoolong.h>
00028 #include <libexplain/buffer/enoent.h>
00029 #include <libexplain/buffer/enomem.h>
00030 #include <libexplain/buffer/enotdir.h>
00031 #include <libexplain/buffer/errno/generic.h>
00032 #include <libexplain/buffer/errno/path_resolution.h>
00033 #include <libexplain/buffer/errno/readlink.h>
00034 #include <libexplain/buffer/file_type.h>
00035 #include <libexplain/buffer/off_t.h>
00036 #include <libexplain/buffer/pathname.h>
00037 #include <libexplain/buffer/pointer.h>
00038 #include <libexplain/buffer/size_t.h>
00039 #include <libexplain/explanation.h>
00040 #include <libexplain/is_efault.h>
00041 
00042 
00043 static void
00044 explain_buffer_errno_readlink_system_call(explain_string_buffer_t *sb,
00045     int errnum, const char *pathname, char *data, size_t data_size)
00046 {
00047     (void)errnum;
00048     explain_string_buffer_puts(sb, "readlink(pathname = ");
00049     explain_buffer_pathname(sb, pathname);
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 off_t
00059 get_actual_size(const char *pathname)
00060 {
00061     struct stat     st;
00062 
00063     /*
00064      * According to coreutils...
00065      * some systems fail to set st_size for symlinks.
00066      */
00067     st.st_size = 0;
00068 
00069     if (lstat(pathname, &st) < 0)
00070         return -1;
00071     if (!S_ISLNK(st.st_mode))
00072         return -1;
00073     return st.st_size;
00074 }
00075 
00076 
00077 static void
00078 explain_buffer_errno_readlink_explanation(explain_string_buffer_t *sb,
00079     int errnum, const char *pathname, char *data, size_t data_size)
00080 {
00081     explain_final_t final_component;
00082 
00083     (void)data;
00084     explain_final_init(&final_component);
00085     final_component.want_to_read = 1;
00086     final_component.follow_symlink = 0;
00087 
00088     switch (errnum)
00089     {
00090     case EACCES:
00091         explain_buffer_eacces(sb, pathname, "pathname", &final_component);
00092         break;
00093 
00094     case EFAULT:
00095         if (explain_is_efault_path(pathname))
00096         {
00097             explain_buffer_efault(sb, "pathname");
00098             break;
00099         }
00100         explain_buffer_efault(sb, "data");
00101         break;
00102 
00103     case EINVAL:
00104         if ((ssize_t)data_size <= 0)
00105         {
00106             explain_buffer_einval_too_small
00107             (
00108                 sb,
00109                 "data_size",
00110                 (ssize_t)data_size
00111             );
00112         }
00113         else
00114         {
00115             struct stat     st;
00116 
00117             /* FIXME: explain_buffer_wrong_file_type */
00118             if (lstat(pathname, &st) >= 0)
00119             {
00120                 explain_string_buffer_puts(sb, "pathname is a ");
00121                 explain_buffer_file_type_st(sb, &st);
00122                 explain_string_buffer_puts(sb, ", not a ");
00123                 explain_buffer_file_type(sb, S_IFLNK);
00124             }
00125             else
00126             {
00127                 explain_string_buffer_puts(sb, "pathname is not a ");
00128                 explain_buffer_file_type(sb, S_IFLNK);
00129             }
00130         }
00131         break;
00132 
00133     case EIO:
00134         explain_buffer_eio_path(sb, pathname);
00135         break;
00136 
00137     case ELOOP:
00138     case EMLINK: /* BSD */
00139         explain_buffer_eloop(sb, pathname, "pathname", &final_component);
00140         break;
00141 
00142     case ENAMETOOLONG:
00143         explain_buffer_enametoolong
00144         (
00145             sb,
00146             pathname,
00147             "pathname",
00148             &final_component
00149         );
00150         break;
00151 
00152     case ENOENT:
00153         explain_buffer_enoent(sb, pathname, "pathname", &final_component);
00154         break;
00155 
00156     case ENOMEM:
00157         explain_buffer_enomem_kernel(sb);
00158         break;
00159 
00160     case ENOTDIR:
00161         explain_buffer_enotdir(sb, pathname, "pathname", &final_component);
00162         break;
00163 
00164     case ERANGE:
00165         {
00166             off_t           actual_size;
00167 
00168             /*
00169              * According to coreutils...
00170              * On AIX 5L v5.3 and HP-UX 11i v2 04/09, readlink returns -1
00171              * with errno == ERANGE if the buffer is too small.
00172              */
00173             explain_buffer_einval_too_small(sb, "data_size", data_size);
00174 
00175             /*
00176              * Provide the actual size, if available.
00177              */
00178             actual_size = get_actual_size(pathname);
00179             if (actual_size > 0 && (off_t)data_size < actual_size)
00180             {
00181                 explain_string_buffer_puts(sb, " (");
00182                 explain_buffer_off_t(sb, actual_size);
00183                 explain_string_buffer_putc(sb, ')');
00184             }
00185         }
00186         break;
00187 
00188     default:
00189         explain_buffer_errno_generic(sb, errnum, "readlink");
00190         break;
00191     }
00192 }
00193 
00194 
00195 void
00196 explain_buffer_errno_readlink(explain_string_buffer_t *sb, int errnum,
00197     const char *pathname, char *data, size_t data_size)
00198 {
00199     explain_explanation_t exp;
00200 
00201     explain_explanation_init(&exp, errnum);
00202     explain_buffer_errno_readlink_system_call
00203     (
00204         &exp.system_call_sb,
00205         errnum,
00206         pathname,
00207         data,
00208         data_size
00209     );
00210     explain_buffer_errno_readlink_explanation
00211     (
00212         &exp.explanation_sb,
00213         errnum,
00214         pathname,
00215         data,
00216         data_size
00217     );
00218     explain_explanation_assemble(&exp, sb);
00219 }
00220 
00221 
00222 /* vim: set ts=8 sw=4 et : */