fsmagic.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. * fsmagic - magic based on filesystem info - directory, special files, etc.
  3. *
  4. * Copyright (c) Ian F. Darwin, 1987.
  5. * Written by Ian F. Darwin.
  6. *
  7. * This software is not subject to any license of the American Telephone
  8. * and Telegraph Company or of the Regents of the University of California.
  9. *
  10. * Permission is granted to anyone to use this software for any purpose on
  11. * any computer system, and to alter it and redistribute it freely, subject
  12. * to the following restrictions:
  13. *
  14. * 1. The author is not responsible for the consequences of use of this
  15. * software, no matter how awful, even if they arise from flaws in it.
  16. *
  17. * 2. The origin of this software must not be misrepresented, either by
  18. * explicit claim or by omission. Since few users ever read sources,
  19. * credits must appear in the documentation.
  20. *
  21. * 3. Altered versions must be plainly marked as such, and must not be
  22. * misrepresented as being the original software. Since few users
  23. * ever read sources, credits must appear in the documentation.
  24. *
  25. * 4. This notice may not be removed or altered.
  26. */
  27. #include "file.h"
  28. #ifdef __CYGWIN__
  29. #include <errno.h>
  30. #endif
  31. #include <stdio.h>
  32. #include <string.h>
  33. #include <sys/types.h>
  34. #include <sys/stat.h>
  35. #ifdef HAVE_UNISTD_H
  36. #include <unistd.h>
  37. #endif
  38. #include <stdlib.h>
  39. /* Since major is a function on SVR4, we can't use `ifndef major'. */
  40. #ifdef MAJOR_IN_MKDEV
  41. # include <sys/mkdev.h>
  42. # define HAVE_MAJOR
  43. #endif
  44. #ifdef MAJOR_IN_SYSMACROS
  45. # include <sys/sysmacros.h>
  46. # define HAVE_MAJOR
  47. #endif
  48. #ifdef major /* Might be defined in sys/types.h. */
  49. # define HAVE_MAJOR
  50. #endif
  51. #ifndef HAVE_MAJOR
  52. # define major(dev) (((dev) >> 8) & 0xff)
  53. # define minor(dev) ((dev) & 0xff)
  54. #endif
  55. #undef HAVE_MAJOR
  56. #ifndef lint
  57. FILE_RCSID("@(#)$Id: fsmagic.c,v 1.30 1999/10/31 22:23:03 christos Exp $")
  58. #endif /* lint */
  59. int
  60. fsmagic(fn, sb)
  61. const char *fn;
  62. struct stat *sb;
  63. {
  64. int ret = 0;
  65. /*
  66. * Fstat is cheaper but fails for files you don't have read perms on.
  67. * On 4.2BSD and similar systems, use lstat() to identify symlinks.
  68. */
  69. #ifdef S_IFLNK
  70. if (!lflag)
  71. ret = lstat(fn, sb);
  72. else
  73. #endif
  74. ret = stat(fn, sb); /* don't merge into if; see "ret =" above */
  75. if (ret) {
  76. ckfprintf(stdout,
  77. /* Yes, I do mean stdout. */
  78. /* No \n, caller will provide. */
  79. "can't stat `%s' (%s).", fn, strerror(errno));
  80. return 1;
  81. }
  82. #ifdef S_ISUID
  83. if (sb->st_mode & S_ISUID) ckfputs("setuid ", stdout);
  84. #endif
  85. #ifdef S_ISGID
  86. if (sb->st_mode & S_ISGID) ckfputs("setgid ", stdout);
  87. #endif
  88. #ifdef S_ISVTX
  89. if (sb->st_mode & S_ISVTX) ckfputs("sticky ", stdout);
  90. #endif
  91. switch (sb->st_mode & S_IFMT) {
  92. case S_IFDIR:
  93. ckfputs("directory", stdout);
  94. return 1;
  95. #ifdef S_IFCHR
  96. case S_IFCHR:
  97. /*
  98. * If -s has been specified, treat character special files
  99. * like ordinary files. Otherwise, just report that they
  100. * are block special files and go on to the next file.
  101. */
  102. if (sflag)
  103. break;
  104. #ifdef HAVE_ST_RDEV
  105. # ifdef dv_unit
  106. (void) printf("character special (%d/%d/%d)",
  107. major(sb->st_rdev),
  108. dv_unit(sb->st_rdev),
  109. dv_subunit(sb->st_rdev));
  110. # else
  111. (void) printf("character special (%ld/%ld)",
  112. (long) major(sb->st_rdev), (long) minor(sb->st_rdev));
  113. # endif
  114. #else
  115. (void) printf("character special");
  116. #endif
  117. return 1;
  118. #endif
  119. #ifdef S_IFBLK
  120. case S_IFBLK:
  121. /*
  122. * If -s has been specified, treat block special files
  123. * like ordinary files. Otherwise, just report that they
  124. * are block special files and go on to the next file.
  125. */
  126. if (sflag)
  127. break;
  128. #ifdef HAVE_ST_RDEV
  129. # ifdef dv_unit
  130. (void) printf("block special (%d/%d/%d)",
  131. major(sb->st_rdev),
  132. dv_unit(sb->st_rdev),
  133. dv_subunit(sb->st_rdev));
  134. # else
  135. (void) printf("block special (%ld/%ld)",
  136. (long) major(sb->st_rdev), (long) minor(sb->st_rdev));
  137. # endif
  138. #else
  139. (void) printf("block special");
  140. #endif
  141. return 1;
  142. #endif
  143. /* TODO add code to handle V7 MUX and Blit MUX files */
  144. #ifdef S_IFIFO
  145. case S_IFIFO:
  146. ckfputs("fifo (named pipe)", stdout);
  147. return 1;
  148. #endif
  149. #ifdef S_IFDOOR
  150. case S_IFDOOR:
  151. ckfputs("door", stdout);
  152. return 1;
  153. #endif
  154. #ifdef S_IFLNK
  155. case S_IFLNK:
  156. {
  157. char buf[BUFSIZ+4];
  158. register int nch;
  159. struct stat tstatbuf;
  160. if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) {
  161. ckfprintf(stdout, "unreadable symlink (%s).",
  162. strerror(errno));
  163. return 1;
  164. }
  165. buf[nch] = '\0'; /* readlink(2) forgets this */
  166. /* If broken symlink, say so and quit early. */
  167. if (*buf == '/') {
  168. if (stat(buf, &tstatbuf) < 0) {
  169. ckfprintf(stdout,
  170. "broken symbolic link to %s", buf);
  171. return 1;
  172. }
  173. }
  174. else {
  175. char *tmp;
  176. char buf2[BUFSIZ+BUFSIZ+4];
  177. if ((tmp = strrchr(fn, '/')) == NULL) {
  178. tmp = buf; /* in current directory anyway */
  179. }
  180. else {
  181. strcpy (buf2, fn); /* take directory part */
  182. buf2[tmp-fn+1] = '\0';
  183. strcat (buf2, buf); /* plus (relative) symlink */
  184. tmp = buf2;
  185. }
  186. if (stat(tmp, &tstatbuf) < 0) {
  187. ckfprintf(stdout,
  188. "broken symbolic link to %s", buf);
  189. return 1;
  190. }
  191. }
  192. /* Otherwise, handle it. */
  193. if (lflag) {
  194. process(buf, strlen(buf));
  195. return 1;
  196. } else { /* just print what it points to */
  197. ckfputs("symbolic link to ", stdout);
  198. ckfputs(buf, stdout);
  199. }
  200. }
  201. return 1;
  202. #endif
  203. #ifdef S_IFSOCK
  204. #ifndef __COHERENT__
  205. case S_IFSOCK:
  206. ckfputs("socket", stdout);
  207. return 1;
  208. #endif
  209. #endif
  210. case S_IFREG:
  211. break;
  212. default:
  213. error("invalid mode 0%o.\n", sb->st_mode);
  214. /*NOTREACHED*/
  215. }
  216. /*
  217. * regular file, check next possibility
  218. *
  219. * If stat() tells us the file has zero length, report here that
  220. * the file is empty, so we can skip all the work of opening and
  221. * reading the file.
  222. * But if the -s option has been given, we skip this optimization,
  223. * since on some systems, stat() reports zero size for raw disk
  224. * partitions. (If the block special device really has zero length,
  225. * the fact that it is empty will be detected and reported correctly
  226. * when we read the file.)
  227. */
  228. if (!sflag && sb->st_size == 0) {
  229. ckfputs("empty", stdout);
  230. return 1;
  231. }
  232. return 0;
  233. }