libexplain  1.4.D001
libexplain/buffer/file_type.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2008, 2009, 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/limits.h> /* for PATH_MAX on Solaris */
00021 #include <libexplain/ac/stdio.h>
00022 #include <libexplain/ac/stdlib.h>
00023 #include <libexplain/ac/string.h>
00024 #include <libexplain/ac/sys/param.h> /* for PATH_MAX except Solaris */
00025 #include <libexplain/ac/sys/stat.h> /* for major()/minor() except Solaris */
00026 #include <libexplain/ac/sys/sysmacros.h> /* for major()/minor() on Solaris */
00027 #include <libexplain/ac/unistd.h>
00028 
00029 #include <libexplain/buffer/file_type.h>
00030 #include <libexplain/buffer/gettext.h>
00031 #include <libexplain/option.h>
00032 
00033 
00034 void
00035 explain_buffer_file_type(explain_string_buffer_t *sb, int mode)
00036 {
00037     if (sb->maximum < FILE_TYPE_BUFFER_SIZE_MIN)
00038     {
00039         explain_string_buffer_printf
00040         (
00041             sb->footnotes,
00042             "; bug (file %s, line %d) explain_buffer_file_type buffer too "
00043                 "small (%d < %d)",
00044             __FILE__,
00045             __LINE__,
00046             (int)sb->maximum,
00047             FILE_TYPE_BUFFER_SIZE_MIN
00048         );
00049     }
00050 
00051     mode &= S_IFMT;
00052     switch (mode)
00053     {
00054 #ifdef __linux__
00055     case 0:
00056         explain_buffer_gettext
00057         (
00058             sb,
00059             /*
00060              * xgettext:  This string is the type of a file (see stat(2) for
00061              * more information) when that file is a Linux kernel special file.
00062              */
00063             i18n("kernel special file")
00064         );
00065         break;
00066 #endif
00067 
00068     case S_IFSOCK:
00069         explain_buffer_gettext
00070         (
00071             sb,
00072             /*
00073              * xgettext:  This string is the type of a file (see stat(2)
00074              * for more information) when that file is a network socket.
00075              */
00076             i18n("socket")
00077         );
00078         break;
00079 
00080     case S_IFLNK:
00081         explain_buffer_gettext
00082         (
00083             sb,
00084             /*
00085              * xgettext:  This string is the type of a file (see stat(2)
00086              * for more information) when that file is a symbolic link.
00087              */
00088             i18n("symbolic link")
00089         );
00090         break;
00091 
00092     case S_IFREG:
00093         explain_buffer_gettext
00094         (
00095             sb,
00096             /*
00097              * xgettext:  This string is the type of a file (see stat(2)
00098              * for more information) when that file is a regular file.
00099              */
00100             i18n("regular file")
00101         );
00102         break;
00103 
00104     case S_IFBLK:
00105         /* FIXME: on :inux, use /proc/devices to be more specific */
00106         explain_buffer_gettext
00107         (
00108             sb,
00109             /*
00110              * xgettext:  This string is the type of a file (see stat(2)
00111              * for more information) when that file is a block special
00112              * device.
00113              */
00114             i18n("block special device")
00115         );
00116         break;
00117 
00118     case S_IFDIR:
00119         explain_buffer_gettext
00120         (
00121             sb,
00122             /*
00123              * xgettext:  This string is the type of a file (see stat(2)
00124              * for more information) when that file is a directory.
00125              */
00126             i18n("directory")
00127         );
00128         break;
00129 
00130     case S_IFCHR:
00131         /* FIXME: on Linux, use /proc/devices to be more specific */
00132         explain_buffer_gettext
00133         (
00134             sb,
00135             /*
00136              * xgettext:  This string is the type of a file (see stat(2)
00137              * for more information) when that file is a character
00138              * special device.
00139              */
00140             i18n("character special device")
00141         );
00142         break;
00143 
00144     case S_IFIFO:
00145         explain_buffer_gettext
00146         (
00147             sb,
00148             /*
00149              * xgettext:  This string is the type of a file (see stat(2)
00150              * for more information) when that file is a fifo.
00151              */
00152             i18n("named pipe")
00153         );
00154         break;
00155 
00156 #ifdef S_IFMPC
00157     case S_IFMPC:
00158         explain_buffer_gettext
00159         (
00160             sb,
00161             /*
00162              * xgettext:  This string is the type of a file (see stat(2)
00163              * for more information) when that file is a multiplexed
00164              * character special device.
00165              * Not present on all POSIX implementations.
00166              */
00167             i18n("multiplexed character special device")
00168         );
00169         break;
00170 #endif
00171 
00172 #ifdef S_IFNAM
00173     case S_IFNAM:
00174         explain_buffer_gettext
00175         (
00176             sb,
00177             /*
00178              * xgettext:  This string is the type of a file (see stat(2)
00179              * for more information) when that file is a named special
00180              * file.  Not present on all POSIX implementations.
00181              */
00182             i18n("named special file")
00183         );
00184         /*
00185          * with two subtypes, distinguished by st_rdev values 1, 2
00186          * 0001   S_INSEM    s    000001   XENIX semaphore subtype of IFNAM
00187          * 0002   S_INSHD    m    000002   XENIX shared data subtype of IFNAM
00188          */
00189         break;
00190 #endif
00191 
00192 #ifdef S_IFMPB
00193     case S_IFMPB:
00194         explain_buffer_gettext
00195         (
00196             sb,
00197             /*
00198              * xgettext:  This string is the type of a file (see
00199              * stat(2) for more information) when that file is a
00200              * multiplexed block special device.  Not present on all
00201              * POSIX implementations.
00202              */
00203             i18n("multiplexed block special device")
00204         );
00205         break;
00206 #endif
00207 
00208 #ifdef S_IFCMP
00209     case S_IFCMP:
00210         explain_buffer_gettext
00211         (
00212             sb,
00213             /*
00214              * xgettext:  This string is the type of a file (see stat(2)
00215              * for more information) when that file is a VxFS compressed
00216              * file.  Not present on all POSIX implementations.
00217              */
00218             i18n("VxFS compressed file")
00219         );
00220         break;
00221 #endif
00222 
00223 #ifdef S_IFNWK
00224     case S_IFNWK:
00225         explain_buffer_gettext
00226         (
00227             sb,
00228             /*
00229              * xgettext:  This string is the type of a file (see stat(2)
00230              * for more information) when that file is a network special
00231              * file.  Not present on all POSIX implementations.
00232              */
00233             i18n("network special file")
00234         );
00235         break;
00236 #endif
00237 
00238 #ifdef S_IFDOOR
00239     case S_IFDOOR:
00240         explain_buffer_gettext
00241         (
00242             sb,
00243             /*
00244              * xgettext:  This string is the type of a file (see stat(2)
00245              * for more information) when that file is a Solaris door.
00246              * Not present on all POSIX implementations.
00247              */
00248             i18n("Solaris door")
00249         );
00250         break;
00251 #endif
00252 
00253 #ifdef S_IFWHT
00254     case S_IFWHT:
00255         explain_buffer_gettext
00256         (
00257             sb,
00258             /*
00259              * xgettext:  This string is the type of a file (see stat(2)
00260              * for more information) when that file is a BSD whiteout
00261              * file, used by the union file system.  Not present on all
00262              * POSIX implementations.
00263              */
00264             i18n("BSD whiteout")
00265         );
00266         break;
00267 #endif
00268 
00269     default:
00270         explain_buffer_gettext
00271         (
00272             sb,
00273             /*
00274              * xgettext:  This string is the type of a file (see stat(2)
00275              * for more information) when that file is of an unknown
00276              * type, often the result of a bad inode block on a hard disk.
00277              */
00278             i18n("unknown file type")
00279         );
00280         explain_string_buffer_printf(sb, " (%#o)", mode);
00281         break;
00282     }
00283 }
00284 
00285 
00286 static int
00287 proc_devices(char *buffer, size_t buffer_size, dev_t st_rdev, int pref)
00288 {
00289     int             dev_major;
00290     FILE            *fp;
00291     char            line[100];
00292 
00293     if (buffer_size < 2)
00294         return 0;
00295     dev_major = major(st_rdev);
00296     fp = fopen("/proc/devices", "r");
00297     if (!fp)
00298         return 0;
00299 
00300     for (;;)
00301     {
00302         if (!fgets(line, sizeof(line), fp))
00303         {
00304             fclose(fp);
00305             return 0;
00306         }
00307         if (line[0] == pref)
00308             break;
00309     }
00310     for (;;)
00311     {
00312         char            *ep;
00313         long            n;
00314 
00315         if (!fgets(line, sizeof(line), fp) || line[0] == '\n')
00316         {
00317             fclose(fp);
00318             return 0;
00319         }
00320         ep = 0;
00321         n = strtol(line, &ep, 10);
00322         if (ep > line && n == dev_major)
00323         {
00324             while (*ep == ' ')
00325                 ++ep;
00326             if (*ep != '/')
00327             {
00328                 char *end = ep;
00329                 while (*end && *end != '\n')
00330                     ++end;
00331                 if (end > ep)
00332                 {
00333                     size_t len = end - ep;
00334                     if (len > buffer_size - 1)
00335                         len = buffer_size - 1;
00336                     memcpy(buffer, ep, len);
00337                     buffer[len] = '\0';
00338                     fclose(fp);
00339                     return 1;
00340                 }
00341             }
00342         }
00343     }
00344 }
00345 
00346 
00347 static int
00348 proc_devices_blk(char *buffer, size_t buffer_size, dev_t st_rdev)
00349 {
00350     return proc_devices(buffer, buffer_size, st_rdev, 'B');
00351 }
00352 
00353 
00354 static int
00355 proc_devices_chr(char *buffer, size_t buffer_size, dev_t st_rdev)
00356 {
00357     return proc_devices(buffer, buffer_size, st_rdev, 'C');
00358 }
00359 
00360 
00361 static int
00362 usb_in_dev_symlink(const char *kind, dev_t st_rdev)
00363 {
00364     int             n;
00365     char            path[100];
00366     char            slink[PATH_MAX];
00367 
00368     snprintf
00369     (
00370         path,
00371         sizeof(path),
00372         "/sys/dev/%s/%d:%d",
00373         kind,
00374         (int)major(st_rdev),
00375         (int)minor(st_rdev)
00376     );
00377     n = readlink(path, slink, sizeof(slink) - 1);
00378     if (n <= 0)
00379         return 0;
00380     slink[n] = '\0';
00381     return (0 != strstr(slink, "usb"));
00382 }
00383 
00384 
00385 void
00386 explain_buffer_file_type_st(explain_string_buffer_t *sb, const struct stat *st)
00387 {
00388     if (!st)
00389     {
00390         explain_buffer_file_type(sb, -1);
00391         return;
00392     }
00393     if (!explain_option_extra_device_info())
00394     {
00395         explain_buffer_file_type(sb, st->st_mode);
00396         return;
00397     }
00398 
00399     switch (st->st_mode & S_IFMT)
00400     {
00401     case S_IFBLK:
00402         {
00403             char            buffer[FILE_TYPE_BUFFER_SIZE_MIN];
00404 
00405             if (usb_in_dev_symlink("block", st->st_rdev))
00406             {
00407                 explain_string_buffer_puts(sb, "usb ");
00408             }
00409             if (proc_devices_blk(buffer, sizeof(buffer), st->st_rdev))
00410             {
00411                 explain_string_buffer_puts(sb, buffer);
00412                 explain_string_buffer_putc(sb, ' ');
00413             }
00414             explain_buffer_file_type(sb, st->st_mode);
00415         }
00416         break;
00417 
00418     case S_IFCHR:
00419         {
00420             char            buffer[FILE_TYPE_BUFFER_SIZE_MIN];
00421 
00422             if (usb_in_dev_symlink("char", st->st_rdev))
00423             {
00424                 explain_string_buffer_puts(sb, "usb ");
00425             }
00426             if (proc_devices_chr(buffer, sizeof(buffer), st->st_rdev))
00427             {
00428                 explain_string_buffer_puts(sb, buffer);
00429                 explain_string_buffer_putc(sb, ' ');
00430             }
00431             explain_buffer_file_type(sb, st->st_mode);
00432         }
00433         break;
00434 
00435 #ifdef S_IFNAM
00436     case S_IFNAM:
00437         switch (st->st_rdev)
00438         {
00439         default:
00440             explain_buffer_file_type(sb, st->st_mode);
00441             break;
00442 
00443         case S_INSEM:
00444             /* FIXME: i18n */
00445             explain_string_buffer_puts(sb, "semaphore named special file");
00446             break;
00447 
00448         case S_INSHD:
00449             /* FIXME: i18n */
00450             explain_string_buffer_puts(sb, "shared data named special file");
00451             break;
00452         }
00453         break;
00454 #endif
00455 
00456     default:
00457         explain_buffer_file_type(sb, st->st_mode);
00458         break;
00459     }
00460 }
00461 
00462 
00463 /* vim: set ts=8 sw=4 et : */