libexplain
1.4.D001
|
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 : */