libexplain  1.4.D001
libexplain/buffer/errno/link.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  * 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/sys/param.h>
00022 #include <libexplain/ac/sys/stat.h>
00023 
00024 #include <libexplain/buffer/eexist.h>
00025 #include <libexplain/buffer/efault.h>
00026 #include <libexplain/buffer/eio.h>
00027 #include <libexplain/buffer/eloop.h>
00028 #include <libexplain/buffer/emlink.h>
00029 #include <libexplain/buffer/enametoolong.h>
00030 #include <libexplain/buffer/enoent.h>
00031 #include <libexplain/buffer/enomem.h>
00032 #include <libexplain/buffer/enospc.h>
00033 #include <libexplain/buffer/enotdir.h>
00034 #include <libexplain/buffer/erofs.h>
00035 #include <libexplain/buffer/errno/link.h>
00036 #include <libexplain/buffer/errno/generic.h>
00037 #include <libexplain/buffer/errno/path_resolution.h>
00038 #include <libexplain/buffer/exdev.h>
00039 #include <libexplain/buffer/mount_point.h>
00040 #include <libexplain/buffer/note/still_exists.h>
00041 #include <libexplain/buffer/pathname.h>
00042 #include <libexplain/dirname.h>
00043 #include <libexplain/explanation.h>
00044 #include <libexplain/is_efault.h>
00045 #include <libexplain/string_buffer.h>
00046 
00047 
00048 static int
00049 get_mode(const char *pathname)
00050 {
00051     struct stat     st;
00052 
00053     if (stat(pathname, &st) < 0)
00054         return S_IFREG;
00055     return st.st_mode;
00056 }
00057 
00058 
00059 static void
00060 explain_buffer_errno_link_system_call(explain_string_buffer_t *sb,
00061     int errnum, const char *oldpath, const char *newpath)
00062 {
00063     (void)errnum;
00064     explain_string_buffer_printf(sb, "link(oldpath = ");
00065     explain_buffer_pathname(sb, oldpath);
00066     explain_string_buffer_puts(sb, ", newpath = ");
00067     explain_buffer_pathname(sb, newpath);
00068     explain_string_buffer_putc(sb, ')');
00069 }
00070 
00071 
00072 static void
00073 explain_buffer_errno_link_explanation(explain_string_buffer_t *sb,
00074     int errnum, const char *oldpath, const char *newpath)
00075 {
00076     explain_final_t oldpath_final_component;
00077     explain_final_t newpath_final_component;
00078 
00079     explain_final_init(&oldpath_final_component);
00080     explain_final_init(&newpath_final_component);
00081     newpath_final_component.must_exist = 0;
00082     newpath_final_component.want_to_create = 1;
00083     newpath_final_component.st_mode = get_mode(oldpath);
00084 
00085     switch (errnum)
00086     {
00087     case EACCES:
00088         if
00089         (
00090             explain_buffer_errno_path_resolution
00091             (
00092                 sb,
00093                 errnum,
00094                 oldpath,
00095                 "oldpath",
00096                 &oldpath_final_component
00097             )
00098         &&
00099             explain_buffer_errno_path_resolution
00100             (
00101                 sb,
00102                 errnum,
00103                 newpath,
00104                 "newpath",
00105                 &newpath_final_component
00106             )
00107         )
00108         {
00109             /*
00110              * Unable to pin point an exact cause, go with the generic
00111              * explanation.
00112              */
00113             explain_string_buffer_puts
00114             (
00115                 sb,
00116                 "write access to the directory containing newpath is "
00117                 "denied, or search permission is denied for one of the "
00118                 "directories in the path prefix of oldpath or newpath "
00119             );
00120         }
00121         break;
00122 
00123     case EEXIST:
00124         explain_buffer_eexist(sb, newpath);
00125         break;
00126 
00127     case EFAULT:
00128         if (explain_is_efault_path(oldpath))
00129         {
00130             explain_buffer_efault(sb, "oldpath");
00131             break;
00132         }
00133         if (explain_is_efault_path(newpath))
00134         {
00135             explain_buffer_efault(sb, "newpath");
00136             break;
00137         }
00138         explain_buffer_efault(sb, "oldpath or newpath");
00139         break;
00140 
00141     case EIO:
00142         explain_buffer_eio_path(sb, oldpath);
00143         break;
00144 
00145     case ELOOP:
00146         explain_buffer_eloop2
00147         (
00148             sb,
00149             oldpath,
00150             "oldpath",
00151             &oldpath_final_component,
00152             newpath,
00153             "newpath",
00154             &newpath_final_component
00155         );
00156         break;
00157 
00158     case EMLINK:
00159         explain_buffer_emlink(sb, oldpath, newpath);
00160         break;
00161 
00162     case ENAMETOOLONG:
00163         explain_buffer_enametoolong2
00164         (
00165             sb,
00166             oldpath,
00167             "oldpath",
00168             &oldpath_final_component,
00169             newpath,
00170             "newpath",
00171             &newpath_final_component
00172         );
00173         break;
00174 
00175     case ENOENT:
00176         explain_buffer_enoent2
00177         (
00178             sb,
00179             oldpath,
00180             "oldpath",
00181             &oldpath_final_component,
00182             newpath,
00183             "newpath",
00184             &newpath_final_component
00185         );
00186         break;
00187 
00188     case ENOMEM:
00189         explain_buffer_enomem_kernel(sb);
00190         break;
00191 
00192     case ENOSPC:
00193         explain_buffer_enospc(sb, newpath, "newpath");
00194         break;
00195 
00196     case ENOTDIR:
00197         explain_buffer_enotdir2
00198         (
00199             sb,
00200             oldpath,
00201             "oldpath",
00202             &oldpath_final_component,
00203             newpath,
00204             "newpath",
00205             &newpath_final_component
00206         );
00207         break;
00208 
00209     case EPERM:
00210         {
00211             struct stat     oldpath_st;
00212 
00213             if (stat(oldpath, &oldpath_st) >= 0)
00214             {
00215                 if (S_ISDIR(oldpath_st.st_mode))
00216                 {
00217                     explain_string_buffer_puts
00218                     (
00219                         sb,
00220                         "oldpath is a directory and it is not possible "
00221                         "to make hard links to directories; have you "
00222                         "considered using a symbolic link?"
00223                     );
00224                 }
00225                 else
00226                 {
00227                     explain_string_buffer_puts
00228                     (
00229                         sb,
00230                         "the file system containing oldpath and newpath "
00231                         "does not support the creation of hard links"
00232                     );
00233                 }
00234             }
00235             else
00236             {
00237                 /*
00238                  * Unable to pin point a specific cause,
00239                  * issue the generic explanation.
00240                  */
00241                 explain_string_buffer_puts
00242                 (
00243                     sb,
00244                     "oldpath is a directory; or, the file system "
00245                     "containing oldpath and newpath does not support "
00246                     "the creation of hard links"
00247                 );
00248             }
00249         }
00250         break;
00251 
00252     case EROFS:
00253         explain_buffer_erofs(sb, oldpath, "oldpath");
00254         break;
00255 
00256     case EXDEV:
00257         explain_buffer_exdev(sb, oldpath, newpath, "link");
00258         break;
00259 
00260     default:
00261         explain_buffer_errno_generic(sb, errnum, "link");
00262         break;
00263     }
00264 
00265     /*
00266      * Let the user know where things stand after the failure.
00267      */
00268     explain_buffer_note_if_exists(sb, newpath, "newpath");
00269 }
00270 
00271 
00272 void
00273 explain_buffer_errno_link(explain_string_buffer_t *sb, int errnum,
00274     const char *oldpath, const char *newpath)
00275 {
00276     explain_explanation_t exp;
00277 
00278     explain_explanation_init(&exp, errnum);
00279     explain_buffer_errno_link_system_call
00280     (
00281         &exp.system_call_sb,
00282         errnum,
00283         oldpath,
00284         newpath
00285     );
00286     explain_buffer_errno_link_explanation
00287     (
00288         &exp.explanation_sb,
00289         errnum,
00290         oldpath,
00291         newpath
00292     );
00293     explain_explanation_assemble(&exp, sb);
00294 }
00295 
00296 
00297 /* vim: set ts=8 sw=4 et : */