xref: /dragonfly/contrib/file/src/fsmagic.c (revision 3b9cdfa3)
1327e51cbSPeter Avalos /*
2327e51cbSPeter Avalos  * Copyright (c) Ian F. Darwin 1986-1995.
3327e51cbSPeter Avalos  * Software written by Ian F. Darwin and others;
4327e51cbSPeter Avalos  * maintained 1995-present by Christos Zoulas and others.
5327e51cbSPeter Avalos  *
6327e51cbSPeter Avalos  * Redistribution and use in source and binary forms, with or without
7327e51cbSPeter Avalos  * modification, are permitted provided that the following conditions
8327e51cbSPeter Avalos  * are met:
9327e51cbSPeter Avalos  * 1. Redistributions of source code must retain the above copyright
10327e51cbSPeter Avalos  *    notice immediately at the beginning of the file, without modification,
11327e51cbSPeter Avalos  *    this list of conditions, and the following disclaimer.
12327e51cbSPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
13327e51cbSPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
14327e51cbSPeter Avalos  *    documentation and/or other materials provided with the distribution.
15327e51cbSPeter Avalos  *
16327e51cbSPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17327e51cbSPeter Avalos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18327e51cbSPeter Avalos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19327e51cbSPeter Avalos  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20327e51cbSPeter Avalos  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21327e51cbSPeter Avalos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22327e51cbSPeter Avalos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23327e51cbSPeter Avalos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24327e51cbSPeter Avalos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25327e51cbSPeter Avalos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26327e51cbSPeter Avalos  * SUCH DAMAGE.
27327e51cbSPeter Avalos  */
28327e51cbSPeter Avalos /*
29327e51cbSPeter Avalos  * fsmagic - magic based on filesystem info - directory, special files, etc.
30327e51cbSPeter Avalos  */
31327e51cbSPeter Avalos 
32327e51cbSPeter Avalos #include "file.h"
3379343712SPeter Avalos 
3479343712SPeter Avalos #ifndef	lint
35*3b9cdfa3SAntonio Huete Jimenez FILE_RCSID("@(#)$File: fsmagic.c,v 1.82 2022/04/11 18:14:41 christos Exp $")
3679343712SPeter Avalos #endif	/* lint */
3779343712SPeter Avalos 
38327e51cbSPeter Avalos #include "magic.h"
39327e51cbSPeter Avalos #include <string.h>
40327e51cbSPeter Avalos #ifdef HAVE_UNISTD_H
41327e51cbSPeter Avalos #include <unistd.h>
42327e51cbSPeter Avalos #endif
43327e51cbSPeter Avalos #include <stdlib.h>
44327e51cbSPeter Avalos /* Since major is a function on SVR4, we cannot use `ifndef major'.  */
45327e51cbSPeter Avalos #ifdef MAJOR_IN_MKDEV
46327e51cbSPeter Avalos # include <sys/mkdev.h>
47327e51cbSPeter Avalos # define HAVE_MAJOR
48327e51cbSPeter Avalos #endif
496fca56fbSSascha Wildner #ifdef HAVE_SYS_SYSMACROS_H
50327e51cbSPeter Avalos # include <sys/sysmacros.h>
516fca56fbSSascha Wildner #endif
526fca56fbSSascha Wildner #ifdef MAJOR_IN_SYSMACROS
53327e51cbSPeter Avalos # define HAVE_MAJOR
54327e51cbSPeter Avalos #endif
556fca56fbSSascha Wildner #if defined(major) && !defined(HAVE_MAJOR)
566fca56fbSSascha Wildner /* Might be defined in sys/types.h.  */
57327e51cbSPeter Avalos # define HAVE_MAJOR
58327e51cbSPeter Avalos #endif
5982c5fa3eSPeter Avalos #ifdef WIN32
6082c5fa3eSPeter Avalos # define WIN32_LEAN_AND_MEAN
6182c5fa3eSPeter Avalos # include <windows.h>
6282c5fa3eSPeter Avalos #endif
63327e51cbSPeter Avalos 
64327e51cbSPeter Avalos #ifndef HAVE_MAJOR
65327e51cbSPeter Avalos # define major(dev)  (((dev) >> 8) & 0xff)
66327e51cbSPeter Avalos # define minor(dev)  ((dev) & 0xff)
67327e51cbSPeter Avalos #endif
68327e51cbSPeter Avalos #undef HAVE_MAJOR
69e4d4ce0cSPeter Avalos #ifdef	S_IFLNK
7079343712SPeter Avalos private int
bad_link(struct magic_set * ms,int err,char * buf)7179343712SPeter Avalos bad_link(struct magic_set *ms, int err, char *buf)
7279343712SPeter Avalos {
7379343712SPeter Avalos 	int mime = ms->flags & MAGIC_MIME;
7479343712SPeter Avalos 	if ((mime & MAGIC_MIME_TYPE) &&
75a96e001bSPeter Avalos 	    file_printf(ms, "inode/symlink")
7679343712SPeter Avalos 	    == -1)
7779343712SPeter Avalos 		return -1;
7879343712SPeter Avalos 	else if (!mime) {
7979343712SPeter Avalos 		if (ms->flags & MAGIC_ERROR) {
80a96e001bSPeter Avalos 			file_error(ms, err,
8182c5fa3eSPeter Avalos 				   "broken symbolic link to %s", buf);
8279343712SPeter Avalos 			return -1;
8379343712SPeter Avalos 		}
8482c5fa3eSPeter Avalos 		if (file_printf(ms, "broken symbolic link to %s", buf) == -1)
8579343712SPeter Avalos 			return -1;
8679343712SPeter Avalos 	}
8779343712SPeter Avalos 	return 1;
8879343712SPeter Avalos }
89e4d4ce0cSPeter Avalos #endif
9079343712SPeter Avalos private int
handle_mime(struct magic_set * ms,int mime,const char * str)9179343712SPeter Avalos handle_mime(struct magic_set *ms, int mime, const char *str)
9279343712SPeter Avalos {
9379343712SPeter Avalos 	if ((mime & MAGIC_MIME_TYPE)) {
94a96e001bSPeter Avalos 		if (file_printf(ms, "inode/%s", str) == -1)
9579343712SPeter Avalos 			return -1;
9679343712SPeter Avalos 		if ((mime & MAGIC_MIME_ENCODING) && file_printf(ms,
9779343712SPeter Avalos 		    "; charset=") == -1)
9879343712SPeter Avalos 			return -1;
9979343712SPeter Avalos 	}
10079343712SPeter Avalos 	if ((mime & MAGIC_MIME_ENCODING) && file_printf(ms, "binary") == -1)
10179343712SPeter Avalos 		return -1;
10279343712SPeter Avalos 	return 0;
10379343712SPeter Avalos }
104327e51cbSPeter Avalos 
105327e51cbSPeter Avalos protected int
file_fsmagic(struct magic_set * ms,const char * fn,struct stat * sb)106327e51cbSPeter Avalos file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb)
107327e51cbSPeter Avalos {
108e8af9738SPeter Avalos 	int ret, did = 0;
109327e51cbSPeter Avalos 	int mime = ms->flags & MAGIC_MIME;
110c30bd091SSascha Wildner 	int silent = ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION);
111327e51cbSPeter Avalos #ifdef	S_IFLNK
112327e51cbSPeter Avalos 	char buf[BUFSIZ+4];
113f72f8299SJan Lentfer 	ssize_t nch;
114327e51cbSPeter Avalos 	struct stat tstatbuf;
115327e51cbSPeter Avalos #endif
116327e51cbSPeter Avalos 
117327e51cbSPeter Avalos 	if (fn == NULL)
118327e51cbSPeter Avalos 		return 0;
119327e51cbSPeter Avalos 
120e8af9738SPeter Avalos #define COMMA	(did++ ? ", " : "")
121327e51cbSPeter Avalos 	/*
122327e51cbSPeter Avalos 	 * Fstat is cheaper but fails for files you don't have read perms on.
123327e51cbSPeter Avalos 	 * On 4.2BSD and similar systems, use lstat() to identify symlinks.
124327e51cbSPeter Avalos 	 */
125327e51cbSPeter Avalos #ifdef	S_IFLNK
126327e51cbSPeter Avalos 	if ((ms->flags & MAGIC_SYMLINK) == 0)
127327e51cbSPeter Avalos 		ret = lstat(fn, sb);
128327e51cbSPeter Avalos 	else
129327e51cbSPeter Avalos #endif
130327e51cbSPeter Avalos 	ret = stat(fn, sb);	/* don't merge into if; see "ret =" above */
131327e51cbSPeter Avalos 
13282c5fa3eSPeter Avalos #ifdef WIN32
13382c5fa3eSPeter Avalos 	{
13482c5fa3eSPeter Avalos 		HANDLE hFile = CreateFile((LPCSTR)fn, 0, FILE_SHARE_DELETE |
13582c5fa3eSPeter Avalos 		    FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0,
13682c5fa3eSPeter Avalos 		    NULL);
13782c5fa3eSPeter Avalos 		if (hFile != INVALID_HANDLE_VALUE) {
13882c5fa3eSPeter Avalos 			/*
13982c5fa3eSPeter Avalos 			 * Stat failed, but we can still open it - assume it's
14082c5fa3eSPeter Avalos 			 * a block device, if nothing else.
14182c5fa3eSPeter Avalos 			 */
14282c5fa3eSPeter Avalos 			if (ret) {
14382c5fa3eSPeter Avalos 				sb->st_mode = S_IFBLK;
14482c5fa3eSPeter Avalos 				ret = 0;
14582c5fa3eSPeter Avalos 			}
14682c5fa3eSPeter Avalos 			switch (GetFileType(hFile)) {
14782c5fa3eSPeter Avalos 			case FILE_TYPE_CHAR:
14882c5fa3eSPeter Avalos 				sb->st_mode |= S_IFCHR;
14982c5fa3eSPeter Avalos 				sb->st_mode &= ~S_IFREG;
15082c5fa3eSPeter Avalos 				break;
15182c5fa3eSPeter Avalos 			case FILE_TYPE_PIPE:
15282c5fa3eSPeter Avalos 				sb->st_mode |= S_IFIFO;
15382c5fa3eSPeter Avalos 				sb->st_mode &= ~S_IFREG;
15482c5fa3eSPeter Avalos 				break;
15582c5fa3eSPeter Avalos 			}
15682c5fa3eSPeter Avalos 			CloseHandle(hFile);
15782c5fa3eSPeter Avalos 		}
15882c5fa3eSPeter Avalos 	}
15982c5fa3eSPeter Avalos #endif
16082c5fa3eSPeter Avalos 
161327e51cbSPeter Avalos 	if (ret) {
162327e51cbSPeter Avalos 		if (ms->flags & MAGIC_ERROR) {
163327e51cbSPeter Avalos 			file_error(ms, errno, "cannot stat `%s'", fn);
164327e51cbSPeter Avalos 			return -1;
165327e51cbSPeter Avalos 		}
166327e51cbSPeter Avalos 		if (file_printf(ms, "cannot open `%s' (%s)",
167327e51cbSPeter Avalos 		    fn, strerror(errno)) == -1)
168327e51cbSPeter Avalos 			return -1;
169e8af9738SPeter Avalos 		return 0;
170327e51cbSPeter Avalos 	}
171327e51cbSPeter Avalos 
172e8af9738SPeter Avalos 	ret = 1;
173c30bd091SSascha Wildner 	if (!mime && !silent) {
174327e51cbSPeter Avalos #ifdef S_ISUID
175327e51cbSPeter Avalos 		if (sb->st_mode & S_ISUID)
176e8af9738SPeter Avalos 			if (file_printf(ms, "%ssetuid", COMMA) == -1)
177327e51cbSPeter Avalos 				return -1;
178327e51cbSPeter Avalos #endif
179327e51cbSPeter Avalos #ifdef S_ISGID
180327e51cbSPeter Avalos 		if (sb->st_mode & S_ISGID)
181e8af9738SPeter Avalos 			if (file_printf(ms, "%ssetgid", COMMA) == -1)
182327e51cbSPeter Avalos 				return -1;
183327e51cbSPeter Avalos #endif
184327e51cbSPeter Avalos #ifdef S_ISVTX
185327e51cbSPeter Avalos 		if (sb->st_mode & S_ISVTX)
186e8af9738SPeter Avalos 			if (file_printf(ms, "%ssticky", COMMA) == -1)
187327e51cbSPeter Avalos 				return -1;
188327e51cbSPeter Avalos #endif
189327e51cbSPeter Avalos 	}
190327e51cbSPeter Avalos 
191327e51cbSPeter Avalos 	switch (sb->st_mode & S_IFMT) {
192327e51cbSPeter Avalos 	case S_IFDIR:
19379343712SPeter Avalos 		if (mime) {
194a96e001bSPeter Avalos 			if (handle_mime(ms, mime, "directory") == -1)
19579343712SPeter Avalos 				return -1;
196c30bd091SSascha Wildner 		} else if (silent) {
197e8af9738SPeter Avalos 		} else if (file_printf(ms, "%sdirectory", COMMA) == -1)
198327e51cbSPeter Avalos 			return -1;
199e8af9738SPeter Avalos 		break;
200327e51cbSPeter Avalos #ifdef S_IFCHR
201327e51cbSPeter Avalos 	case S_IFCHR:
202327e51cbSPeter Avalos 		/*
203327e51cbSPeter Avalos 		 * If -s has been specified, treat character special files
204327e51cbSPeter Avalos 		 * like ordinary files.  Otherwise, just report that they
205327e51cbSPeter Avalos 		 * are block special files and go on to the next file.
206327e51cbSPeter Avalos 		 */
207e8af9738SPeter Avalos 		if ((ms->flags & MAGIC_DEVICES) != 0) {
208e8af9738SPeter Avalos 			ret = 0;
209327e51cbSPeter Avalos 			break;
210e8af9738SPeter Avalos 		}
21179343712SPeter Avalos 		if (mime) {
212a96e001bSPeter Avalos 			if (handle_mime(ms, mime, "chardevice") == -1)
21379343712SPeter Avalos 				return -1;
214c30bd091SSascha Wildner 		} else if (silent) {
21579343712SPeter Avalos 		} else {
21682c5fa3eSPeter Avalos #ifdef HAVE_STRUCT_STAT_ST_RDEV
217327e51cbSPeter Avalos # ifdef dv_unit
218e8af9738SPeter Avalos 			if (file_printf(ms, "%scharacter special (%d/%d/%d)",
219e8af9738SPeter Avalos 			    COMMA, major(sb->st_rdev), dv_unit(sb->st_rdev),
220327e51cbSPeter Avalos 					dv_subunit(sb->st_rdev)) == -1)
221327e51cbSPeter Avalos 				return -1;
222327e51cbSPeter Avalos # else
223e8af9738SPeter Avalos 			if (file_printf(ms, "%scharacter special (%ld/%ld)",
224e8af9738SPeter Avalos 			    COMMA, (long)major(sb->st_rdev),
225e8af9738SPeter Avalos 			    (long)minor(sb->st_rdev)) == -1)
226327e51cbSPeter Avalos 				return -1;
227327e51cbSPeter Avalos # endif
228327e51cbSPeter Avalos #else
229e8af9738SPeter Avalos 			if (file_printf(ms, "%scharacter special", COMMA) == -1)
230327e51cbSPeter Avalos 				return -1;
231327e51cbSPeter Avalos #endif
23279343712SPeter Avalos 		}
233e8af9738SPeter Avalos 		break;
234327e51cbSPeter Avalos #endif
235327e51cbSPeter Avalos #ifdef S_IFBLK
236327e51cbSPeter Avalos 	case S_IFBLK:
237327e51cbSPeter Avalos 		/*
238327e51cbSPeter Avalos 		 * If -s has been specified, treat block special files
239327e51cbSPeter Avalos 		 * like ordinary files.  Otherwise, just report that they
240327e51cbSPeter Avalos 		 * are block special files and go on to the next file.
241327e51cbSPeter Avalos 		 */
242e8af9738SPeter Avalos 		if ((ms->flags & MAGIC_DEVICES) != 0) {
243e8af9738SPeter Avalos 			ret = 0;
244327e51cbSPeter Avalos 			break;
245e8af9738SPeter Avalos 		}
24679343712SPeter Avalos 		if (mime) {
247a96e001bSPeter Avalos 			if (handle_mime(ms, mime, "blockdevice") == -1)
24879343712SPeter Avalos 				return -1;
249c30bd091SSascha Wildner 		} else if (silent) {
25079343712SPeter Avalos 		} else {
25182c5fa3eSPeter Avalos #ifdef HAVE_STRUCT_STAT_ST_RDEV
252327e51cbSPeter Avalos # ifdef dv_unit
253e8af9738SPeter Avalos 			if (file_printf(ms, "%sblock special (%d/%d/%d)",
254e8af9738SPeter Avalos 			    COMMA, major(sb->st_rdev), dv_unit(sb->st_rdev),
255327e51cbSPeter Avalos 			    dv_subunit(sb->st_rdev)) == -1)
256327e51cbSPeter Avalos 				return -1;
257327e51cbSPeter Avalos # else
258e8af9738SPeter Avalos 			if (file_printf(ms, "%sblock special (%ld/%ld)",
259e8af9738SPeter Avalos 			    COMMA, (long)major(sb->st_rdev),
260e8af9738SPeter Avalos 			    (long)minor(sb->st_rdev)) == -1)
261327e51cbSPeter Avalos 				return -1;
262327e51cbSPeter Avalos # endif
263327e51cbSPeter Avalos #else
264e8af9738SPeter Avalos 			if (file_printf(ms, "%sblock special", COMMA) == -1)
265327e51cbSPeter Avalos 				return -1;
266327e51cbSPeter Avalos #endif
26779343712SPeter Avalos 		}
268e8af9738SPeter Avalos 		break;
269327e51cbSPeter Avalos #endif
270327e51cbSPeter Avalos 	/* TODO add code to handle V7 MUX and Blit MUX files */
271327e51cbSPeter Avalos #ifdef	S_IFIFO
272327e51cbSPeter Avalos 	case S_IFIFO:
273327e51cbSPeter Avalos 		if((ms->flags & MAGIC_DEVICES) != 0)
274327e51cbSPeter Avalos 			break;
27579343712SPeter Avalos 		if (mime) {
276a96e001bSPeter Avalos 			if (handle_mime(ms, mime, "fifo") == -1)
27779343712SPeter Avalos 				return -1;
278c30bd091SSascha Wildner 		} else if (silent) {
279e8af9738SPeter Avalos 		} else if (file_printf(ms, "%sfifo (named pipe)", COMMA) == -1)
280327e51cbSPeter Avalos 			return -1;
281e8af9738SPeter Avalos 		break;
282327e51cbSPeter Avalos #endif
283327e51cbSPeter Avalos #ifdef	S_IFDOOR
284327e51cbSPeter Avalos 	case S_IFDOOR:
28579343712SPeter Avalos 		if (mime) {
286a96e001bSPeter Avalos 			if (handle_mime(ms, mime, "door") == -1)
28779343712SPeter Avalos 				return -1;
288c30bd091SSascha Wildner 		} else if (silent) {
289e8af9738SPeter Avalos 		} else if (file_printf(ms, "%sdoor", COMMA) == -1)
290327e51cbSPeter Avalos 			return -1;
291e8af9738SPeter Avalos 		break;
292327e51cbSPeter Avalos #endif
293327e51cbSPeter Avalos #ifdef	S_IFLNK
294327e51cbSPeter Avalos 	case S_IFLNK:
295327e51cbSPeter Avalos 		if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) {
296327e51cbSPeter Avalos 			if (ms->flags & MAGIC_ERROR) {
297327e51cbSPeter Avalos 			    file_error(ms, errno, "unreadable symlink `%s'",
298327e51cbSPeter Avalos 				fn);
299327e51cbSPeter Avalos 			    return -1;
300327e51cbSPeter Avalos 			}
30179343712SPeter Avalos 			if (mime) {
302a96e001bSPeter Avalos 				if (handle_mime(ms, mime, "symlink") == -1)
30379343712SPeter Avalos 					return -1;
304c30bd091SSascha Wildner 			} else if (silent) {
30579343712SPeter Avalos 			} else if (file_printf(ms,
306e8af9738SPeter Avalos 			    "%sunreadable symlink `%s' (%s)", COMMA, fn,
307327e51cbSPeter Avalos 			    strerror(errno)) == -1)
308327e51cbSPeter Avalos 				return -1;
309e8af9738SPeter Avalos 			break;
310327e51cbSPeter Avalos 		}
31179343712SPeter Avalos 		buf[nch] = '\0';	/* readlink(2) does not do this */
312327e51cbSPeter Avalos 
313327e51cbSPeter Avalos 		/* If broken symlink, say so and quit early. */
3146fca56fbSSascha Wildner #ifdef __linux__
3156fca56fbSSascha Wildner 		/*
3166fca56fbSSascha Wildner 		 * linux procfs/devfs makes symlinks like pipe:[3515864880]
3176fca56fbSSascha Wildner 		 * that we can't stat their readlink output, so stat the
3186fca56fbSSascha Wildner 		 * original filename instead.
3196fca56fbSSascha Wildner 		 */
3206fca56fbSSascha Wildner 		if (stat(fn, &tstatbuf) < 0)
3216fca56fbSSascha Wildner 			return bad_link(ms, errno, buf);
3226fca56fbSSascha Wildner #else
323327e51cbSPeter Avalos 		if (*buf == '/') {
32479343712SPeter Avalos 			if (stat(buf, &tstatbuf) < 0)
32579343712SPeter Avalos 				return bad_link(ms, errno, buf);
32679343712SPeter Avalos 		} else {
327327e51cbSPeter Avalos 			char *tmp;
328327e51cbSPeter Avalos 			char buf2[BUFSIZ+BUFSIZ+4];
329327e51cbSPeter Avalos 
330*3b9cdfa3SAntonio Huete Jimenez 			if ((tmp = CCAST(char *, strrchr(fn,  '/'))) == NULL) {
331327e51cbSPeter Avalos 				tmp = buf; /* in current directory anyway */
332327e51cbSPeter Avalos 			} else {
333327e51cbSPeter Avalos 				if (tmp - fn + 1 > BUFSIZ) {
334327e51cbSPeter Avalos 					if (ms->flags & MAGIC_ERROR) {
335327e51cbSPeter Avalos 						file_error(ms, 0,
336327e51cbSPeter Avalos 						    "path too long: `%s'", buf);
337327e51cbSPeter Avalos 						return -1;
338327e51cbSPeter Avalos 					}
33979343712SPeter Avalos 					if (mime) {
34079343712SPeter Avalos 						if (handle_mime(ms, mime,
34179343712SPeter Avalos 						    "x-path-too-long") == -1)
34279343712SPeter Avalos 							return -1;
343c30bd091SSascha Wildner 					} else if (silent) {
34479343712SPeter Avalos 					} else if (file_printf(ms,
345e8af9738SPeter Avalos 					    "%spath too long: `%s'", COMMA,
346e8af9738SPeter Avalos 					    fn) == -1)
347327e51cbSPeter Avalos 						return -1;
348e8af9738SPeter Avalos 					break;
349327e51cbSPeter Avalos 				}
35079343712SPeter Avalos 				/* take dir part */
35179343712SPeter Avalos 				(void)strlcpy(buf2, fn, sizeof buf2);
352327e51cbSPeter Avalos 				buf2[tmp - fn + 1] = '\0';
35379343712SPeter Avalos 				/* plus (rel) link */
35479343712SPeter Avalos 				(void)strlcat(buf2, buf, sizeof buf2);
355327e51cbSPeter Avalos 				tmp = buf2;
356327e51cbSPeter Avalos 			}
35779343712SPeter Avalos 			if (stat(tmp, &tstatbuf) < 0)
35879343712SPeter Avalos 				return bad_link(ms, errno, buf);
359327e51cbSPeter Avalos 		}
3606fca56fbSSascha Wildner #endif
361327e51cbSPeter Avalos 
362327e51cbSPeter Avalos 		/* Otherwise, handle it. */
363327e51cbSPeter Avalos 		if ((ms->flags & MAGIC_SYMLINK) != 0) {
364327e51cbSPeter Avalos 			const char *p;
365327e51cbSPeter Avalos 			ms->flags &= MAGIC_SYMLINK;
366327e51cbSPeter Avalos 			p = magic_file(ms, buf);
367327e51cbSPeter Avalos 			ms->flags |= MAGIC_SYMLINK;
368e8af9738SPeter Avalos 			if (p == NULL)
369e8af9738SPeter Avalos 				return -1;
370327e51cbSPeter Avalos 		} else { /* just print what it points to */
37179343712SPeter Avalos 			if (mime) {
372a96e001bSPeter Avalos 				if (handle_mime(ms, mime, "symlink") == -1)
37379343712SPeter Avalos 					return -1;
374c30bd091SSascha Wildner 			} else if (silent) {
37582c5fa3eSPeter Avalos 			} else if (file_printf(ms, "%ssymbolic link to %s",
376e8af9738SPeter Avalos 			    COMMA, buf) == -1)
377327e51cbSPeter Avalos 				return -1;
378327e51cbSPeter Avalos 		}
379e8af9738SPeter Avalos 		break;
380327e51cbSPeter Avalos #endif
381327e51cbSPeter Avalos #ifdef	S_IFSOCK
382327e51cbSPeter Avalos #ifndef __COHERENT__
383327e51cbSPeter Avalos 	case S_IFSOCK:
38479343712SPeter Avalos 		if (mime) {
385a96e001bSPeter Avalos 			if (handle_mime(ms, mime, "socket") == -1)
38679343712SPeter Avalos 				return -1;
387c30bd091SSascha Wildner 		} else if (silent) {
388e8af9738SPeter Avalos 		} else if (file_printf(ms, "%ssocket", COMMA) == -1)
389327e51cbSPeter Avalos 			return -1;
390e8af9738SPeter Avalos 		break;
391327e51cbSPeter Avalos #endif
392327e51cbSPeter Avalos #endif
393327e51cbSPeter Avalos 	case S_IFREG:
394327e51cbSPeter Avalos 		/*
395327e51cbSPeter Avalos 		 * regular file, check next possibility
396327e51cbSPeter Avalos 		 *
397327e51cbSPeter Avalos 		 * If stat() tells us the file has zero length, report here that
398327e51cbSPeter Avalos 		 * the file is empty, so we can skip all the work of opening and
399327e51cbSPeter Avalos 		 * reading the file.
400e8af9738SPeter Avalos 		 * But if the -s option has been given, we skip this
401e8af9738SPeter Avalos 		 * optimization, since on some systems, stat() reports zero
402e8af9738SPeter Avalos 		 * size for raw disk partitions. (If the block special device
403e8af9738SPeter Avalos 		 * really has zero length, the fact that it is empty will be
404e8af9738SPeter Avalos 		 * detected and reported correctly when we read the file.)
405327e51cbSPeter Avalos 		 */
406327e51cbSPeter Avalos 		if ((ms->flags & MAGIC_DEVICES) == 0 && sb->st_size == 0) {
40779343712SPeter Avalos 			if (mime) {
40879343712SPeter Avalos 				if (handle_mime(ms, mime, "x-empty") == -1)
40979343712SPeter Avalos 					return -1;
410c30bd091SSascha Wildner 			} else if (silent) {
411e8af9738SPeter Avalos 			} else if (file_printf(ms, "%sempty", COMMA) == -1)
412327e51cbSPeter Avalos 				return -1;
413e8af9738SPeter Avalos 			break;
414327e51cbSPeter Avalos 		}
415e8af9738SPeter Avalos 		ret = 0;
416e8af9738SPeter Avalos 		break;
417e8af9738SPeter Avalos 
418e8af9738SPeter Avalos 	default:
419e8af9738SPeter Avalos 		file_error(ms, 0, "invalid mode 0%o", sb->st_mode);
420e8af9738SPeter Avalos 		return -1;
421e8af9738SPeter Avalos 		/*NOTREACHED*/
422e8af9738SPeter Avalos 	}
423e8af9738SPeter Avalos 
424c30bd091SSascha Wildner 	if (!silent && !mime && did && ret == 0) {
425e8af9738SPeter Avalos 	    if (file_printf(ms, " ") == -1)
426e8af9738SPeter Avalos 		    return -1;
427e8af9738SPeter Avalos 	}
4286fca56fbSSascha Wildner 	/*
4296fca56fbSSascha Wildner 	 * If we were looking for extensions or apple (silent) it is not our
4306fca56fbSSascha Wildner 	 * job to print here, so don't count this as a match.
4316fca56fbSSascha Wildner 	 */
4326fca56fbSSascha Wildner 	if (ret == 1 && silent)
4336fca56fbSSascha Wildner 		return 0;
434e8af9738SPeter Avalos 	return ret;
435327e51cbSPeter Avalos }
436