libexplain
1.4.D001
|
00001 /* 00002 * libexplain - Explain errno values returned by libc functions 00003 * Copyright (C) 2009, 2010, 2013 Peter Miller 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU Lesser General Public License as 00007 * published by the Free Software Foundation; either version 3 of the 00008 * License, or (at 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/fcntl.h> 00020 #include <libexplain/ac/linux/cdrom.h> 00021 #include <libexplain/ac/linux/fd.h> 00022 #include <libexplain/ac/linux/kdev_t.h> 00023 #include <libexplain/ac/linux/major.h> 00024 #include <libexplain/ac/string.h> 00025 #include <libexplain/ac/sys/ioctl.h> 00026 #include <libexplain/ac/sys/mtio.h> 00027 #include <libexplain/ac/sys/stat.h> 00028 #include <libexplain/ac/unistd.h> 00029 00030 #include <libexplain/buffer/enomedium.h> 00031 #include <libexplain/buffer/gettext.h> 00032 #include <libexplain/sizeof.h> 00033 00034 00035 #ifdef FDGETDRVTYP 00036 00037 static const char * 00038 translate_drive_type(const char *code_name) 00039 { 00040 typedef struct table_t table_t; 00041 struct table_t 00042 { 00043 const char *code_name; 00044 const char *human_readable; 00045 }; 00046 00047 static const table_t table[] = 00048 { 00049 { "(null)", "" }, 00050 { "d360", "360KB PC" }, 00051 { "h1200", "1.2MB AT" }, 00052 { "D360", "360KB SS 3.5\"" }, 00053 { "D720", "720KB 3.5\"" }, 00054 { "h360", "360KB AT" }, 00055 { "h720", "720KB AT" }, 00056 { "H1440", "1.44MB 3.5\"" }, 00057 { "E2880", "2.88MB 3.5\"" }, 00058 { "E3120", "3.12MB 3.5\"" }, 00059 { "h1440", "1.44MB 5.25\"" }, 00060 { "H1680", "1.68MB 3.5\"" }, 00061 { "h410", "410KB 5.25\"" }, 00062 { "H820", "820KB 3.5\"" }, 00063 { "h1476", "1.48MB 5.25\"" }, 00064 { "H1722", "1.72MB 3.5\"" }, 00065 { "h420", "420KB 5.25\"" }, 00066 { "H830", "830KB 3.5\"" }, 00067 { "h1494", "1.49MB 5.25\"" }, 00068 { "H1743", "1.74 MB 3.5\"" }, 00069 { "h880", "880KB 5.25\"" }, 00070 { "D1040", "1.04MB 3.5\"" }, 00071 { "D1120", "1.12MB 3.5\"" }, 00072 { "h1600", "1.6MB 5.25\"" }, 00073 { "H1760", "1.76MB 3.5\"" }, 00074 { "H1920", "1.92MB 3.5\"" }, 00075 { "E3200", "3.20MB 3.5\"" }, 00076 { "E3520", "3.52MB 3.5\"" }, 00077 { "E3840", "3.84MB 3.5\"" }, 00078 { "H1840", "1.84MB 3.5\"" }, 00079 { "D800", "800KB 3.5\"" }, 00080 { "H1600", "1.6MB 3.5\"" }, 00081 }; 00082 00083 const table_t *tp; 00084 00085 for (tp = table; tp < ENDOF(table); ++tp) 00086 { 00087 if (0 == strcmp(code_name, tp->code_name)) 00088 return tp->human_readable; 00089 } 00090 return code_name; 00091 } 00092 00093 #endif 00094 #ifdef MMC_BLOCK_MAJOR 00095 00096 static void 00097 explain_buffer_enomedium_sdmmc(explain_string_buffer_t *sb) 00098 { 00099 explain_buffer_gettext 00100 ( 00101 sb, 00102 /* 00103 * xgettext: This error message is issued to explain an ENOMEDIUM 00104 * error, in the case of a SD/MMC slot (or similar). 00105 */ 00106 i18n("there does not appear to be a card in the SD/MMC slot") 00107 ); 00108 } 00109 00110 #endif 00111 00112 static int 00113 explain_buffer_enomedium_fildes_q(explain_string_buffer_t *sb, int fildes) 00114 { 00115 #ifdef CDROM_GET_CAPABILITY 00116 { 00117 int cap; 00118 00119 cap = 0; 00120 if (ioctl(fildes, CDROM_GET_CAPABILITY, &cap) >= 0) 00121 { 00122 const char *drive_type; 00123 00124 /* 00125 * FIXME: we could be even more informative, if the 00126 * CDROM_DRIVE_STATUS ioctl is supported: 00127 * CDS_NO_INFO if not implemented 00128 * CDS_NO_DISC 00129 * CDS_TRAY_OPEN 00130 */ 00131 drive_type = "CD-ROM"; 00132 if (cap & (CDC_DVD | CDC_DVD_R | CDC_DVD_RAM)) 00133 drive_type = "DVD"; 00134 00135 /* 00136 * Definitely a CD-ROM drive, or similar. 00137 * 00138 * Remember: in English it's is a "disc" with-a-C when it's 00139 * a CD or a DVD (blame the French, it started out as their 00140 * standard), and it's a "disk" with-a-K in every other case. 00141 */ 00142 explain_string_buffer_printf_gettext 00143 ( 00144 sb, 00145 /* 00146 * xgettext: This error message is issued to explain an 00147 * ENOMEDIUM error, in the case of a CD-ROM drive (or 00148 * similar). 00149 * 00150 * %1$s => the type of drive, "CD-ROM" or "DVD". 00151 */ 00152 i18n("there does not appear to be a disc in the %s drive"), 00153 drive_type 00154 ); 00155 return 0; 00156 } 00157 } 00158 #endif 00159 00160 #ifdef FDGETDRVTYP 00161 { 00162 floppy_drive_name fdt; 00163 00164 if (ioctl(fildes, FDGETDRVTYP, &fdt) >= 0) 00165 { 00166 const char *drive_type; 00167 00168 drive_type = translate_drive_type(fdt); 00169 explain_string_buffer_printf_gettext 00170 ( 00171 sb, 00172 /* 00173 * xgettext: This error message is issued to explain an 00174 * ENOMEDIUM error, in the case of a floppy drive (or 00175 * similar). 00176 * 00177 * %1$s => the type of floppy drive, e.g. "3 1/2" 00178 */ 00179 i18n("there does not appear to be a disk in the %s floppy " 00180 "drive"), 00181 drive_type 00182 ); 00183 return 0; 00184 } 00185 } 00186 #endif 00187 00188 #ifdef MTIOCGET 00189 { 00190 struct mtget status; 00191 00192 if (ioctl(fildes, MTIOCGET, &status) >= 0) 00193 { 00194 #if defined(MT_ISSCSI1) || defined(MT_ISSCSI2) 00195 switch (status.mt_type) 00196 { 00197 #ifdef MT_ISSCSI1 00198 case MT_ISSCSI1: 00199 #endif 00200 #ifdef MT_ISSCSI2 00201 case MT_ISSCSI2: 00202 #endif 00203 /* 00204 * FIXME: could we get more information into the type name? 00205 * Particularly if it is a SCSI device, the mode pages will have 00206 * more information. 00207 */ 00208 explain_buffer_gettext 00209 ( 00210 sb, 00211 /* 00212 * xgettext: This error message is issued to explain an 00213 * ENOMEDIUM error, in the case of a SCSI tape drive 00214 * (or similar). 00215 */ 00216 i18n("there does not appear to be a tape in the SCSI tape " 00217 "drive") 00218 ); 00219 break; 00220 00221 default: 00222 #endif 00223 explain_buffer_gettext 00224 ( 00225 sb, 00226 /* 00227 * xgettext: This error message is issued to explain an 00228 * ENOMEDIUM error, in the case of a magnetic tape drive 00229 * (or similar). 00230 */ 00231 i18n("there does not appear to be a tape in the magnetic " 00232 "tape drive") 00233 ); 00234 #if defined(MT_ISSCSI1) || defined(MT_ISSCSI2) 00235 break; 00236 } 00237 #endif 00238 return 0; 00239 } 00240 } 00241 #endif 00242 00243 #ifdef MMC_BLOCK_MAJOR 00244 { 00245 struct stat st; 00246 00247 if 00248 ( 00249 fstat(fildes, &st) >= 0 00250 && 00251 S_ISBLK(st.st_mode) 00252 && 00253 MAJOR(st.st_rdev) == MMC_BLOCK_MAJOR 00254 ) 00255 { 00256 explain_buffer_enomedium_sdmmc(sb); 00257 return 0; 00258 } 00259 } 00260 #endif 00261 00262 /* 00263 * report that we failed 00264 */ 00265 return -1; 00266 } 00267 00268 00269 void 00270 explain_buffer_enomedium_fildes(explain_string_buffer_t *sb, int fildes) 00271 { 00272 if (explain_buffer_enomedium_fildes_q(sb, fildes)) 00273 explain_buffer_enomedium_generic(sb); 00274 } 00275 00276 00277 void 00278 explain_buffer_enomedium(explain_string_buffer_t *sb, const char *pathname) 00279 { 00280 #if defined(CDROM_GET_CAPABILITY) || defined(FDGETDRVTYP) || defined(MTIOCGET) 00281 int fildes; 00282 00283 /* 00284 * On modern versions of Linux, if you open a CD-ROM drive with the 00285 * O_NONBLOCK flag, it works even when there is no disc present. 00286 * This permits all sorts of diagnostic information to be accessed. 00287 * 00288 * The same trick works for magnetic tapes. 00289 * 00290 * The linux kernel source reads as if this will work for floppy 00291 * disks, too, but I don't have one to experiment with any more. 00292 * 00293 * Note: this does NOT work with Linux SD/MMC device driver(s). 00294 */ 00295 fildes = open(pathname, O_RDONLY + O_NONBLOCK); 00296 if (fildes >= 0) 00297 { 00298 if (explain_buffer_enomedium_fildes_q(sb, fildes) >= 0) 00299 { 00300 close(fildes); 00301 return; 00302 } 00303 00304 /* 00305 * No luck, use the generic explanation. 00306 */ 00307 close(fildes); 00308 } 00309 #endif 00310 00311 #ifdef MMC_BLOCK_MAJOR 00312 { 00313 struct stat st; 00314 00315 if 00316 ( 00317 stat(pathname, &st) >= 0 00318 && 00319 S_ISBLK(st.st_mode) 00320 && 00321 MAJOR(st.st_rdev) == MMC_BLOCK_MAJOR 00322 ) 00323 { 00324 explain_buffer_enomedium_sdmmc(sb); 00325 return; 00326 } 00327 } 00328 #endif 00329 00330 explain_buffer_enomedium_generic(sb); 00331 } 00332 00333 00334 void 00335 explain_buffer_enomedium_generic(explain_string_buffer_t *sb) 00336 { 00337 explain_buffer_gettext 00338 ( 00339 sb, 00340 /* 00341 * xgettext: This error message is issued to explain an 00342 * ENOMEDIUM error, when a more specific explaination is not 00343 * available. 00344 */ 00345 i18n("the disk drive is a type that has removable disks, and there " 00346 "does not appear to be a disk in the drive") 00347 ); 00348 } 00349 00350 00351 /* vim: set ts=8 sw=4 et : */