libexplain
1.4.D001
|
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 : */