libexplain  1.4.D001
libexplain/buffer/device_name.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2009-2011, 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/dirent.h>
00020 #include <libexplain/ac/limits.h> /* for PATH_MAX on Solaris */
00021 #include <libexplain/ac/sys/param.h> /* for PATH_MAX except Solaris  */
00022 
00023 #include <libexplain/buffer/device_name.h>
00024 #include <libexplain/buffer/pointer.h>
00025 #include <libexplain/is_efault.h>
00026 
00027 
00046 static int
00047 dev_stat_rec(explain_string_buffer_t *dev_path, dev_t dev,
00048     struct stat *st, explain_string_buffer_t *shortest_dev_path)
00049 {
00050     DIR             *dp;
00051     int             pos;
00052     int             result;
00053 
00054     result = -1;
00055     dp = opendir(dev_path->message);
00056     if (!dp)
00057         return -1;
00058     pos = dev_path->position;
00059     for (;;)
00060     {
00061         struct dirent   *dep;
00062         struct stat     st2;
00063 
00064         dep = readdir(dp);
00065         if (!dep)
00066             break;
00067         if
00068         (
00069             dep->d_name[0] == '.'
00070         &&
00071             (
00072                 dep->d_name[1] == '\0'
00073             ||
00074                 (dep->d_name[1] == '.' && dep->d_name[2] == '\0')
00075             )
00076         )
00077             continue;
00078         dev_path->position = pos;
00079         dev_path->message[pos] = '\0';
00080         explain_string_buffer_path_join(dev_path, dep->d_name);
00081         if (lstat(dev_path->message, &st2) >= 0)
00082         {
00083             switch (st2.st_mode & S_IFMT)
00084             {
00085             case S_IFDIR:
00086                 if (dev_stat_rec(dev_path, dev, st, shortest_dev_path) >= 0)
00087                 {
00088                     result = 0;
00089                 }
00090                 break;
00091 
00092             case S_IFBLK:
00093             case S_IFCHR:
00094                 if (dev == st2.st_rdev)
00095                 {
00096                     if
00097                     (
00098                         !shortest_dev_path->position
00099                     ||
00100                         dev_path->position < shortest_dev_path->position
00101                     )
00102                     {
00103                         shortest_dev_path->position = 0;
00104                         *st = st2;
00105                         explain_string_buffer_write
00106                         (
00107                             shortest_dev_path,
00108                             dev_path->message,
00109                             dev_path->position
00110                         );
00111                     }
00112                     result = 0;
00113                 }
00114                 break;
00115 
00116             default:
00117                 /* ignore everything else */
00118                 break;
00119             }
00120         }
00121     }
00122     closedir(dp);
00123     dev_path->position = pos;
00124     dev_path->message[pos] = '\0';
00125     return result;
00126 }
00127 
00128 
00129 int
00130 explain_buffer_device_name(explain_string_buffer_t *sb, dev_t dev,
00131     struct stat *st)
00132 {
00133     explain_string_buffer_t dev_path_buf;
00134     char            dev_path[PATH_MAX + 1];
00135 
00136     explain_string_buffer_init(&dev_path_buf, dev_path, sizeof(dev_path));
00137     explain_string_buffer_puts(&dev_path_buf, "/dev");
00138     return dev_stat_rec(&dev_path_buf, dev, st, sb);
00139 }
00140 
00141 
00142 /* vim: set ts=8 sw=4 et : */