libexplain
1.4.D001
|
00001 /* 00002 * libexplain - Explain errno values returned by libc functions 00003 * Copyright (C) 2008-2010, 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/eloop.h> 00025 #include <libexplain/buffer/enametoolong.h> 00026 #include <libexplain/buffer/enoent.h> 00027 #include <libexplain/buffer/enomem.h> 00028 #include <libexplain/buffer/enotdir.h> 00029 #include <libexplain/buffer/eperm.h> 00030 #include <libexplain/buffer/erofs.h> 00031 #include <libexplain/buffer/errno/generic.h> 00032 #include <libexplain/buffer/errno/path_resolution.h> 00033 #include <libexplain/buffer/errno/rmdir.h> 00034 #include <libexplain/buffer/gettext.h> 00035 #include <libexplain/buffer/note/still_exists.h> 00036 #include <libexplain/buffer/path_to_pid.h> 00037 #include <libexplain/buffer/pointer.h> 00038 #include <libexplain/capability.h> 00039 #include <libexplain/explanation.h> 00040 #include <libexplain/count_directory_entries.h> 00041 #include <libexplain/option.h> 00042 00043 00044 static void 00045 explain_buffer_errno_rmdir_system_call(explain_string_buffer_t *sb, 00046 int errnum, const char *pathname) 00047 { 00048 explain_string_buffer_puts(sb, "rmdir(pathname = "); 00049 if (errnum == EFAULT) 00050 explain_buffer_pointer(sb, pathname); 00051 else 00052 explain_string_buffer_puts_quoted(sb, pathname); 00053 explain_string_buffer_putc(sb, ')'); 00054 } 00055 00056 00057 static int 00058 last_component_is_dotdot(const char *pathname) 00059 { 00060 while (*pathname == '/') 00061 ++pathname; 00062 for (;;) 00063 { 00064 const char *begin; 00065 const char *end; 00066 00067 begin = pathname; 00068 ++pathname; 00069 while (*pathname && *pathname != '/') 00070 ++pathname; 00071 end = pathname; 00072 while (*pathname == '/') 00073 ++pathname; 00074 if (!*pathname) 00075 { 00076 /* we are at end of pathname */ 00077 return (end - begin == 2 && begin[0] == '.' && begin[1] == '.'); 00078 } 00079 } 00080 } 00081 00082 00083 static int 00084 last_component_is_dot(const char *pathname) 00085 { 00086 while (*pathname == '/') 00087 ++pathname; 00088 for (;;) 00089 { 00090 const char *begin; 00091 const char *end; 00092 00093 begin = pathname; 00094 ++pathname; 00095 while (*pathname && *pathname != '/') 00096 ++pathname; 00097 end = pathname; 00098 while (*pathname == '/') 00099 ++pathname; 00100 if (!*pathname) 00101 { 00102 /* we are at end of pathname */ 00103 return (end - begin == 1 && begin[0] == '.'); 00104 } 00105 } 00106 } 00107 00108 00109 void 00110 explain_buffer_errno_rmdir_explanation(explain_string_buffer_t *sb, 00111 int errnum, const char *syscall_name, const char *pathname) 00112 { 00113 explain_final_t final_component; 00114 00115 explain_final_init(&final_component); 00116 final_component.want_to_unlink = 1; 00117 final_component.must_be_a_st_mode = 1; 00118 final_component.st_mode = S_IFDIR; 00119 00120 switch (errnum) 00121 { 00122 case EACCES: 00123 explain_buffer_eacces(sb, pathname, "pathname", &final_component); 00124 break; 00125 00126 case EBUSY: 00127 if (last_component_is_dot(pathname)) 00128 { 00129 /* BSD */ 00130 goto case_einval; 00131 } 00132 explain_buffer_gettext 00133 ( 00134 sb, 00135 /* 00136 * xgettext: This error message is used when the rmdir(2) 00137 * system call returns EBUSY. 00138 */ 00139 i18n("pathname is currently in use by the system or some process " 00140 "that prevents its removal") 00141 ); 00142 explain_buffer_path_to_pid(sb, pathname); 00143 #ifdef __linux__ 00144 if (explain_option_dialect_specific()) 00145 { 00146 explain_string_buffer_puts(sb->footnotes, "; "); 00147 explain_buffer_gettext 00148 ( 00149 sb->footnotes, 00150 /* 00151 * xgettext: This error message is used when the rmdir(2) 00152 * system call returns EBUSY, on a Linux system. 00153 */ 00154 i18n("note that pathname is currently used as a mount point " 00155 "or is the root directory of the calling process") 00156 ); 00157 } 00158 #endif 00159 break; 00160 00161 case EFAULT: 00162 explain_buffer_efault(sb, "pathname"); 00163 break; 00164 00165 case EINVAL: 00166 case_einval: 00167 explain_buffer_gettext 00168 ( 00169 sb, 00170 /* 00171 * xgettext: This error message is used when the rmdir(2) 00172 * system call returns EINVAL, in the case where the final 00173 * path component is "." 00174 */ 00175 i18n("pathname has \".\" as last component") 00176 ); 00177 break; 00178 00179 case ELOOP: 00180 case EMLINK: /* BSD */ 00181 explain_buffer_eloop(sb, pathname, "pathname", &final_component); 00182 break; 00183 00184 case ENAMETOOLONG: 00185 explain_buffer_enametoolong 00186 ( 00187 sb, 00188 pathname, 00189 "pathname", 00190 &final_component 00191 ); 00192 break; 00193 00194 case ENOENT: 00195 explain_buffer_enoent(sb, pathname, "pathname", &final_component); 00196 break; 00197 00198 case ENOMEM: 00199 explain_buffer_enomem_kernel(sb); 00200 break; 00201 00202 case ENOTDIR: 00203 explain_buffer_enotdir(sb, pathname, "pathname", &final_component); 00204 break; 00205 00206 case EEXIST: 00207 case ENOTEMPTY: 00208 if (last_component_is_dotdot(pathname)) 00209 { 00210 explain_buffer_gettext 00211 ( 00212 sb, 00213 /* 00214 * xgettext: This error message is used when the rmdir(2) 00215 * system call returns EINVAL, in the case where the final 00216 * path component is ".." 00217 */ 00218 i18n("pathname has \"..\" as its final component") 00219 ); 00220 } 00221 else 00222 { 00223 int count; 00224 00225 explain_buffer_gettext 00226 ( 00227 sb, 00228 /* 00229 * xgettext: This error message is used when the 00230 * rmdir(2) system call returns EEXIST or ENOTEMPTY, in 00231 * the case where pathname is not an empty directory; 00232 * that is, it contains entries other than "." and ".." 00233 */ 00234 i18n("pathname is not an empty directory; that is, it " 00235 "contains entries other than \".\" and \"..\"") 00236 ); 00237 count = explain_count_directory_entries(pathname); 00238 if (count > 0) 00239 explain_string_buffer_printf(sb, " (%d)", count); 00240 } 00241 break; 00242 00243 case EPERM: 00244 if 00245 ( 00246 explain_buffer_errno_path_resolution 00247 ( 00248 sb, 00249 errnum, 00250 pathname, 00251 "pathname", 00252 &final_component 00253 ) 00254 ) 00255 { 00256 explain_buffer_eperm_unlink(sb, pathname, "pathname", syscall_name); 00257 } 00258 break; 00259 00260 case EROFS: 00261 explain_buffer_erofs(sb, pathname, "pathname"); 00262 break; 00263 00264 default: 00265 explain_buffer_errno_generic(sb, errnum, syscall_name); 00266 break; 00267 } 00268 00269 explain_buffer_note_if_still_exists(sb, pathname, "pathname"); 00270 } 00271 00272 00273 void 00274 explain_buffer_errno_rmdir(explain_string_buffer_t *sb, int errnum, 00275 const char *pathname) 00276 { 00277 explain_explanation_t exp; 00278 00279 explain_explanation_init(&exp, errnum); 00280 explain_buffer_errno_rmdir_system_call 00281 ( 00282 &exp.system_call_sb, 00283 errnum, 00284 pathname 00285 ); 00286 explain_buffer_errno_rmdir_explanation 00287 ( 00288 &exp.explanation_sb, 00289 errnum, 00290 "rmdir", 00291 pathname 00292 ); 00293 explain_explanation_assemble(&exp, sb); 00294 } 00295 00296 00297 /* vim: set ts=8 sw=4 et : */