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