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 00008 * published by the Free Software Foundation; either version 3 of the 00009 * License, or (at 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/assert.h> 00021 #include <libexplain/ac/dirent.h> 00022 #include <libexplain/ac/fcntl.h> 00023 #include <libexplain/ac/limits.h> /* for PATH_MAX on solaris */ 00024 #include <libexplain/ac/string.h> 00025 #include <libexplain/ac/sys/param.h> /* for PATH_MAX except solaris */ 00026 #include <libexplain/ac/sys/stat.h> 00027 #include <libexplain/ac/unistd.h> 00028 00029 #include <libexplain/ac/sys/mtio.h> 00030 #ifdef __linux__ 00031 #include <libexplain/ac/linux/hdreg.h> 00032 #endif 00033 #include <libexplain/ac/termios.h> 00034 00035 #include <libexplain/buffer/device_name.h> 00036 #include <libexplain/buffer/eio.h> 00037 #include <libexplain/buffer/file_type.h> 00038 #include <libexplain/buffer/gettext.h> 00039 #include <libexplain/dirname.h> 00040 00041 00042 static void 00043 possibly_as_a_result_of_a_preceding(explain_string_buffer_t *sb, int fildes) 00044 { 00045 int flags; 00046 00047 flags = fcntl(fildes, F_GETFL); 00048 if (flags < 0) 00049 flags = O_RDWR; 00050 explain_string_buffer_puts(sb, ", "); 00051 switch (flags & O_ACCMODE) 00052 { 00053 case O_RDONLY: 00054 explain_buffer_gettext 00055 ( 00056 sb, 00057 /* 00058 * xgettext: This message is used when explaining an EIO 00059 * error, for a file open only for reading. 00060 */ 00061 i18n("possibly as a result of a preceding read(2) system call") 00062 ); 00063 break; 00064 00065 case O_WRONLY: 00066 explain_buffer_gettext 00067 ( 00068 sb, 00069 /* 00070 * xgettext: This message is used when explaining an EIO 00071 * error, for a file open only for writing. 00072 */ 00073 i18n("possibly as a result of a preceding write(2) system call") 00074 ); 00075 break; 00076 00077 default: 00078 explain_buffer_gettext 00079 ( 00080 sb, 00081 /* 00082 * xgettext: This message is used when explaining an EIO 00083 * error, for a file open for both reading and writing. 00084 */ 00085 i18n("possibly as a result of a preceding read(2) or " 00086 "write(2) system call") 00087 ); 00088 break; 00089 } 00090 } 00091 00092 00093 static void 00094 explain_buffer_eio_generic(explain_string_buffer_t *sb, int fildes) 00095 { 00096 explain_buffer_gettext 00097 ( 00098 sb, 00099 /* 00100 * xgettext: This message is used when explaining an EIO error. 00101 * Such errors are usually related to the underlying hardware of 00102 * the device being used, or the special device that contains 00103 * the file system the file is stored in. 00104 */ 00105 i18n("a low-level I/O error occurred, probably in hardware") 00106 ); 00107 possibly_as_a_result_of_a_preceding(sb, fildes); 00108 } 00109 00110 00111 void 00112 explain_buffer_eio(explain_string_buffer_t *sb) 00113 { 00114 explain_buffer_eio_generic(sb, -1); 00115 } 00116 00117 00118 static int 00119 dev_stat(dev_t dev, struct stat *st, explain_string_buffer_t *dev_buf) 00120 { 00121 return explain_buffer_device_name(dev_buf, dev, st); 00122 } 00123 00124 00125 static void 00126 a_low_level_io_error_occurred(explain_string_buffer_t *sb, 00127 const char *device_path, const struct stat *st) 00128 { 00129 char ftype[FILE_TYPE_BUFFER_SIZE_MIN]; 00130 explain_string_buffer_t ftype_sb; 00131 00132 explain_string_buffer_init(&ftype_sb, ftype, sizeof(ftype)); 00133 if (device_path[0]) 00134 { 00135 explain_string_buffer_puts_quoted(&ftype_sb, device_path); 00136 explain_string_buffer_putc(&ftype_sb, ' '); 00137 } 00138 explain_buffer_file_type_st(&ftype_sb, st); 00139 00140 explain_string_buffer_printf_gettext 00141 ( 00142 sb, 00143 /* 00144 * xgettext: This message is used when explaining an EIO error. 00145 * Such errors are usually related to the underlying hardware of 00146 * the device being used, or the special device that contains 00147 * the file system the file is stored in. 00148 * 00149 * %1$s => The device named and device's file type 00150 */ 00151 i18n("a low-level I/O error occurred in the %s"), 00152 ftype 00153 ); 00154 } 00155 00156 00157 static void 00158 explain_buffer_eio_stat(explain_string_buffer_t *sb, int fildes, 00159 struct stat *st) 00160 { 00161 char dev_path[150]; 00162 explain_string_buffer_t dev_buf; 00163 00164 explain_string_buffer_init(&dev_buf, dev_path, sizeof(dev_path)); 00165 assert(dev_path[0] == '\0'); 00166 switch (st->st_mode & S_IFMT) 00167 { 00168 case S_IFDIR: 00169 case S_IFREG: 00170 if (dev_stat(st->st_dev, st, &dev_buf) < 0) 00171 { 00172 explain_buffer_eio(sb); 00173 return; 00174 } 00175 break; 00176 00177 default: 00178 dev_stat(st->st_rdev, st, &dev_buf); 00179 /* no problem if it failed, use the st we were given */ 00180 break; 00181 } 00182 00183 switch (st->st_mode & S_IFMT) 00184 { 00185 case S_IFBLK: 00186 case S_IFCHR: 00187 a_low_level_io_error_occurred(sb, dev_path, st); 00188 possibly_as_a_result_of_a_preceding(sb, fildes); 00189 break; 00190 00191 default: 00192 explain_buffer_eio_generic(sb, fildes); 00193 break; 00194 } 00195 } 00196 00197 00198 void 00199 explain_buffer_eio_fildes(explain_string_buffer_t *sb, int fildes) 00200 { 00201 struct stat st; 00202 00203 if (fstat(fildes, &st) < 0) 00204 explain_buffer_eio(sb); 00205 else 00206 explain_buffer_eio_stat(sb, fildes, &st); 00207 } 00208 00209 00210 void 00211 explain_buffer_eio_path(explain_string_buffer_t *sb, const char *path) 00212 { 00213 struct stat st; 00214 00215 if (stat(path, &st) < 0 && lstat(path, &st) < 0) 00216 explain_buffer_eio(sb); 00217 else 00218 explain_buffer_eio_stat(sb, -1, &st); 00219 } 00220 00221 00222 void 00223 explain_buffer_eio_path_dirname(explain_string_buffer_t *sb, 00224 const char *path) 00225 { 00226 char path_dir[PATH_MAX + 1]; 00227 00228 explain_dirname(path_dir, path, sizeof(path_dir)); 00229 explain_buffer_eio_path(sb, path_dir); 00230 } 00231 00232 00233 /* vim: set ts=8 sw=4 et : */