This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / usr.bin / file / fsmagic.c
CommitLineData
15637ed4
RG
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
28#include <stdio.h>
286a6f32 29#include <string.h>
15637ed4 30#include <sys/types.h>
286a6f32
C
31#include <sys/stat.h>
32#include <unistd.h>
33#include <stdlib.h>
15637ed4
RG
34#ifndef major /* if `major' not defined in types.h, */
35#include <sys/sysmacros.h> /* try this one. */
36#endif
37#ifndef major /* still not defined? give up, manual intervention needed */
38 /* If cc tries to compile this, read and act on it. */
39 /* On most systems cpp will discard it automatically */
40 Congratulations, you have found a portability bug.
41 Please grep /usr/include/sys and edit the above #include
286a6f32 42 to point at the file that defines the "major" macro.
15637ed4 43#endif /*major*/
286a6f32 44
15637ed4
RG
45#include "file.h"
46
47#ifndef lint
48static char *moduleid =
286a6f32 49 "@(#)fsmagic.c,v 1.3 1993/06/10 00:38:10 jtc Exp";
15637ed4
RG
50#endif /* lint */
51
286a6f32
C
52int
53fsmagic(fn, sb)
54const char *fn;
55struct stat *sb;
15637ed4 56{
286a6f32 57 int ret = 0;
15637ed4
RG
58
59 /*
60 * Fstat is cheaper but fails for files you don't have read perms on.
286a6f32 61 * On 4.2BSD and similar systems, use lstat() to identify symlinks.
15637ed4
RG
62 */
63#ifdef S_IFLNK
286a6f32
C
64 if (!lflag)
65 ret = lstat(fn, sb);
66 else
15637ed4 67#endif
286a6f32 68 ret = stat(fn, sb); /* don't merge into if; see "ret =" above */
15637ed4 69
286a6f32
C
70 if (ret) {
71 ckfprintf(stdout,
72 /* Yes, I do mean stdout. */
73 /* No \n, caller will provide. */
74 "can't stat `%s' (%s).", fn, strerror(errno));
75 return 1;
76 }
77
78 if (sb->st_mode & S_ISUID) ckfputs("setuid ", stdout);
79 if (sb->st_mode & S_ISGID) ckfputs("setgid ", stdout);
80 if (sb->st_mode & S_ISVTX) ckfputs("sticky ", stdout);
15637ed4 81
286a6f32 82 switch (sb->st_mode & S_IFMT) {
15637ed4
RG
83 case S_IFDIR:
84 ckfputs("directory", stdout);
85 return 1;
86 case S_IFCHR:
87 (void) printf("character special (%d/%d)",
286a6f32 88 major(sb->st_rdev), minor(sb->st_rdev));
15637ed4
RG
89 return 1;
90 case S_IFBLK:
91 (void) printf("block special (%d/%d)",
286a6f32 92 major(sb->st_rdev), minor(sb->st_rdev));
15637ed4
RG
93 return 1;
94 /* TODO add code to handle V7 MUX and Blit MUX files */
95#ifdef S_IFIFO
96 case S_IFIFO:
97 ckfputs("fifo (named pipe)", stdout);
98 return 1;
99#endif
100#ifdef S_IFLNK
101 case S_IFLNK:
286a6f32
C
102 {
103 char buf[BUFSIZ+4];
104 register int nch;
105 struct stat tstatbuf;
106
107 if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) {
108 ckfprintf(stdout, "unreadable symlink (%s).",
109 strerror(errno));
110 return 1;
111 }
112 buf[nch] = '\0'; /* readlink(2) forgets this */
113
114 /* If broken symlink, say so and quit early. */
115 if (*buf == '/') {
116 if (stat(buf, &tstatbuf) < 0) {
117 ckfprintf(stdout,
118 "broken symbolic link to %s", buf);
119 return 1;
120 }
121 }
122 else {
123 char *tmp;
124 char buf2[BUFSIZ+BUFSIZ+4];
125
126 if ((tmp = strrchr(fn, '/')) == NULL) {
127 tmp = buf; /* in current directory anyway */
128 }
129 else {
130 strcpy (buf2, fn); /* take directory part */
131 buf2[tmp-fn+1] = '\0';
132 strcat (buf2, buf); /* plus (relative) symlink */
133 tmp = buf2;
134 }
135 if (stat(tmp, &tstatbuf) < 0) {
136 ckfprintf(stdout,
137 "broken symbolic link to %s", buf);
138 return 1;
139 }
140 }
141
142 /* Otherwise, handle it. */
143 if (lflag) {
144 process(buf, strlen(buf));
145 return 1;
146 } else { /* just print what it points to */
147 ckfputs("symbolic link to ", stdout);
148 ckfputs(buf, stdout);
149 }
150 }
15637ed4
RG
151 return 1;
152#endif
153#ifdef S_IFSOCK
154 case S_IFSOCK:
155 ckfputs("socket", stdout);
156 return 1;
157#endif
158 case S_IFREG:
159 break;
160 default:
286a6f32
C
161 error("invalid mode 0%o.\n", sb->st_mode);
162 /*NOTREACHED*/
15637ed4
RG
163 }
164
165 /*
166 * regular file, check next possibility
167 */
286a6f32 168 if (sb->st_size == 0) {
15637ed4
RG
169 ckfputs("empty", stdout);
170 return 1;
171 }
172 return 0;
173}
174