file_cmds-60.tar.gz
[apple/file_cmds.git] / file / fsmagic.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /* $OpenBSD: fsmagic.c,v 1.3 1997/02/09 23:58:24 millert Exp $ */
25
26 /*
27 * fsmagic - magic based on filesystem info - directory, special files, etc.
28 *
29 * Copyright (c) Ian F. Darwin, 1987.
30 * Written by Ian F. Darwin.
31 *
32 * This software is not subject to any license of the American Telephone
33 * and Telegraph Company or of the Regents of the University of California.
34 *
35 * Permission is granted to anyone to use this software for any purpose on
36 * any computer system, and to alter it and redistribute it freely, subject
37 * to the following restrictions:
38 *
39 * 1. The author is not responsible for the consequences of use of this
40 * software, no matter how awful, even if they arise from flaws in it.
41 *
42 * 2. The origin of this software must not be misrepresented, either by
43 * explicit claim or by omission. Since few users ever read sources,
44 * credits must appear in the documentation.
45 *
46 * 3. Altered versions must be plainly marked as such, and must not be
47 * misrepresented as being the original software. Since few users
48 * ever read sources, credits must appear in the documentation.
49 *
50 * 4. This notice may not be removed or altered.
51 */
52
53 #include <stdio.h>
54 #include <string.h>
55 #include <sys/types.h>
56 #include <sys/stat.h>
57 #include <unistd.h>
58 #include <stdlib.h>
59 #ifndef major
60 # if defined(__SVR4) || defined(_SVR4_SOURCE)
61 # include <sys/mkdev.h>
62 # endif
63 #endif
64 #ifndef major /* if `major' not defined in types.h, */
65 #include <sys/sysmacros.h> /* try this one. */
66 #endif
67 #ifndef major /* still not defined? give up, manual intervention needed */
68 /* If cc tries to compile this, read and act on it. */
69 /* On most systems cpp will discard it automatically */
70 Congratulations, you have found a portability bug.
71 Please grep /usr/include/sys and edit the above #include
72 to point at the file that defines the "major" macro.
73 #endif /*major*/
74
75 #include "file.h"
76
77 #ifndef lint
78 #if 0
79 static char *moduleid = "$OpenBSD: fsmagic.c,v 1.3 1997/02/09 23:58:24 millert Exp $";
80 #endif
81 #endif /* lint */
82
83 int
84 fsmagic(fn, sb)
85 const char *fn;
86 struct stat *sb;
87 {
88 int ret = 0;
89
90 /*
91 * Fstat is cheaper but fails for files you don't have read perms on.
92 * On 4.2BSD and similar systems, use lstat() to identify symlinks.
93 */
94 #ifdef S_IFLNK
95 if (!lflag)
96 ret = lstat(fn, sb);
97 else
98 #endif
99 ret = stat(fn, sb); /* don't merge into if; see "ret =" above */
100
101 if (ret) {
102 ckfprintf(stdout,
103 /* Yes, I do mean stdout. */
104 /* No \n, caller will provide. */
105 "can't stat `%s' (%s).", fn, strerror(errno));
106 return 1;
107 }
108
109 if (sb->st_mode & S_ISUID) ckfputs("setuid ", stdout);
110 if (sb->st_mode & S_ISGID) ckfputs("setgid ", stdout);
111 if (sb->st_mode & S_ISVTX) ckfputs("sticky ", stdout);
112
113 switch (sb->st_mode & S_IFMT) {
114 case S_IFDIR:
115 ckfputs("directory", stdout);
116 return 1;
117 case S_IFCHR:
118 (void) printf("character special (%ld/%ld)",
119 (long) major(sb->st_rdev), (long) minor(sb->st_rdev));
120 return 1;
121 case S_IFBLK:
122 (void) printf("block special (%ld/%ld)",
123 (long) major(sb->st_rdev), (long) minor(sb->st_rdev));
124 return 1;
125 /* TODO add code to handle V7 MUX and Blit MUX files */
126 #ifdef S_IFIFO
127 case S_IFIFO:
128 ckfputs("fifo (named pipe)", stdout);
129 return 1;
130 #endif
131 #ifdef S_IFLNK
132 case S_IFLNK:
133 {
134 char buf[BUFSIZ+4];
135 register int nch;
136 struct stat tstatbuf;
137
138 if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) {
139 ckfprintf(stdout, "unreadable symlink (%s).",
140 strerror(errno));
141 return 1;
142 }
143 buf[nch] = '\0'; /* readlink(2) forgets this */
144
145 /* If broken symlink, say so and quit early. */
146 if (*buf == '/') {
147 if (stat(buf, &tstatbuf) < 0) {
148 ckfprintf(stdout,
149 "broken symbolic link to %s", buf);
150 return 1;
151 }
152 }
153 else {
154 char *tmp;
155 char buf2[BUFSIZ+BUFSIZ+4];
156
157 if ((tmp = strrchr(fn, '/')) == NULL) {
158 tmp = buf; /* in current directory anyway */
159 }
160 else {
161 strcpy (buf2, fn); /* take directory part */
162 buf2[tmp-fn+1] = '\0';
163 strcat (buf2, buf); /* plus (relative) symlink */
164 tmp = buf2;
165 }
166 if (stat(tmp, &tstatbuf) < 0) {
167 ckfprintf(stdout,
168 "broken symbolic link to %s", buf);
169 return 1;
170 }
171 }
172
173 /* Otherwise, handle it. */
174 if (lflag) {
175 process(buf, strlen(buf));
176 return 1;
177 } else { /* just print what it points to */
178 ckfputs("symbolic link to ", stdout);
179 ckfputs(buf, stdout);
180 }
181 }
182 return 1;
183 #endif
184 #ifdef S_IFSOCK
185 #ifndef __COHERENT__
186 case S_IFSOCK:
187 ckfputs("socket", stdout);
188 return 1;
189 #endif
190 #endif
191 case S_IFREG:
192 break;
193 default:
194 error("invalid mode 0%o.\n", sb->st_mode);
195 /*NOTREACHED*/
196 }
197
198 /*
199 * regular file, check next possibility
200 */
201 if (sb->st_size == 0) {
202 ckfputs("empty", stdout);
203 return 1;
204 }
205 return 0;
206 }
207