libexplain  1.4.D001
libexplain/buffer/enomedium.c
Go to the documentation of this file.
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 : */