fsmagic.c revision 133359
168349Sobrien/* 2133359Sobrien * Copyright (c) Ian F. Darwin 1986-1995. 3133359Sobrien * Software written by Ian F. Darwin and others; 4133359Sobrien * maintained 1995-present by Christos Zoulas and others. 5133359Sobrien * 6133359Sobrien * Redistribution and use in source and binary forms, with or without 7133359Sobrien * modification, are permitted provided that the following conditions 8133359Sobrien * are met: 9133359Sobrien * 1. Redistributions of source code must retain the above copyright 10133359Sobrien * notice immediately at the beginning of the file, without modification, 11133359Sobrien * this list of conditions, and the following disclaimer. 12133359Sobrien * 2. Redistributions in binary form must reproduce the above copyright 13133359Sobrien * notice, this list of conditions and the following disclaimer in the 14133359Sobrien * documentation and/or other materials provided with the distribution. 15133359Sobrien * 3. All advertising materials mentioning features or use of this software 16133359Sobrien * must display the following acknowledgement: 17133359Sobrien * This product includes software developed by Ian F. Darwin and others. 18133359Sobrien * 4. The name of the author may not be used to endorse or promote products 19133359Sobrien * derived from this software without specific prior written permission. 20133359Sobrien * 21133359Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22133359Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23133359Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24133359Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 25133359Sobrien * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26133359Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27133359Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28133359Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29133359Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30133359Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31133359Sobrien * SUCH DAMAGE. 32133359Sobrien */ 33133359Sobrien/* 3468349Sobrien * fsmagic - magic based on filesystem info - directory, special files, etc. 3568349Sobrien */ 3668349Sobrien 3768349Sobrien#include "file.h" 38133359Sobrien#include "magic.h" 3968349Sobrien#include <string.h> 4068349Sobrien#ifdef HAVE_UNISTD_H 4168349Sobrien#include <unistd.h> 4268349Sobrien#endif 4368349Sobrien#include <stdlib.h> 44133359Sobrien#include <sys/stat.h> 45133359Sobrien/* Since major is a function on SVR4, we cannot use `ifndef major'. */ 4668349Sobrien#ifdef MAJOR_IN_MKDEV 4768349Sobrien# include <sys/mkdev.h> 4868349Sobrien# define HAVE_MAJOR 4968349Sobrien#endif 5068349Sobrien#ifdef MAJOR_IN_SYSMACROS 5168349Sobrien# include <sys/sysmacros.h> 5268349Sobrien# define HAVE_MAJOR 5368349Sobrien#endif 5468349Sobrien#ifdef major /* Might be defined in sys/types.h. */ 5568349Sobrien# define HAVE_MAJOR 5668349Sobrien#endif 5768349Sobrien 5868349Sobrien#ifndef HAVE_MAJOR 5968349Sobrien# define major(dev) (((dev) >> 8) & 0xff) 6068349Sobrien# define minor(dev) ((dev) & 0xff) 6168349Sobrien#endif 6268349Sobrien#undef HAVE_MAJOR 6368349Sobrien 6468349Sobrien#ifndef lint 65133359SobrienFILE_RCSID("@(#)$Id: fsmagic.c,v 1.43 2003/10/14 19:29:55 christos Exp $") 6668349Sobrien#endif /* lint */ 6768349Sobrien 68133359Sobrienprotected int 69133359Sobrienfile_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb) 7068349Sobrien{ 7168349Sobrien int ret = 0; 72133359Sobrien#ifdef S_IFLNK 73133359Sobrien char buf[BUFSIZ+4]; 74133359Sobrien int nch; 75133359Sobrien struct stat tstatbuf; 76133359Sobrien#endif 7768349Sobrien 78133359Sobrien if (fn == NULL) 79133359Sobrien return 0; 80133359Sobrien 8168349Sobrien /* 8268349Sobrien * Fstat is cheaper but fails for files you don't have read perms on. 8368349Sobrien * On 4.2BSD and similar systems, use lstat() to identify symlinks. 8468349Sobrien */ 8568349Sobrien#ifdef S_IFLNK 86133359Sobrien if ((ms->flags & MAGIC_SYMLINK) == 0) 8768349Sobrien ret = lstat(fn, sb); 8868349Sobrien else 8968349Sobrien#endif 9068349Sobrien ret = stat(fn, sb); /* don't merge into if; see "ret =" above */ 9168349Sobrien 9268349Sobrien if (ret) { 93133359Sobrien if (ms->flags & MAGIC_ERROR) { 94133359Sobrien file_error(ms, errno, "cannot stat `%s'", fn); 95133359Sobrien return -1; 96133359Sobrien } 97133359Sobrien if (file_printf(ms, "cannot open (%s)", 98133359Sobrien fn, strerror(errno)) == -1) 99133359Sobrien return -1; 10068349Sobrien return 1; 10168349Sobrien } 10268349Sobrien 103133359Sobrien if ((ms->flags & MAGIC_MIME) != 0) { 10468349Sobrien if ((sb->st_mode & S_IFMT) != S_IFREG) { 105133359Sobrien if (file_printf(ms, "application/x-not-regular-file") 106133359Sobrien == -1) 107133359Sobrien return -1; 10868349Sobrien return 1; 10968349Sobrien } 11068349Sobrien } 11168349Sobrien else { 11268349Sobrien#ifdef S_ISUID 113133359Sobrien if (sb->st_mode & S_ISUID) 114133359Sobrien if (file_printf(ms, "setuid ") == -1) 115133359Sobrien return -1; 11668349Sobrien#endif 11768349Sobrien#ifdef S_ISGID 118133359Sobrien if (sb->st_mode & S_ISGID) 119133359Sobrien if (file_printf(ms, "setgid ") == -1) 120133359Sobrien return -1; 12168349Sobrien#endif 12268349Sobrien#ifdef S_ISVTX 123133359Sobrien if (sb->st_mode & S_ISVTX) 124133359Sobrien if (file_printf(ms, "sticky ") == -1) 125133359Sobrien return -1; 12668349Sobrien#endif 12768349Sobrien } 12868349Sobrien 12968349Sobrien switch (sb->st_mode & S_IFMT) { 13068349Sobrien case S_IFDIR: 131133359Sobrien if (file_printf(ms, "directory") == -1) 132133359Sobrien return -1; 13368349Sobrien return 1; 13468349Sobrien#ifdef S_IFCHR 13568349Sobrien case S_IFCHR: 13668349Sobrien /* 13768349Sobrien * If -s has been specified, treat character special files 13868349Sobrien * like ordinary files. Otherwise, just report that they 13968349Sobrien * are block special files and go on to the next file. 14068349Sobrien */ 141133359Sobrien if ((ms->flags & MAGIC_DEVICES) != 0) 14268349Sobrien break; 14368349Sobrien#ifdef HAVE_ST_RDEV 14468349Sobrien# ifdef dv_unit 145133359Sobrien if (file_printf(ms, "character special (%d/%d/%d)", 146133359Sobrien major(sb->st_rdev), dv_unit(sb->st_rdev), 147133359Sobrien dv_subunit(sb->st_rdev)) == -1) 148133359Sobrien return -1; 14968349Sobrien# else 150133359Sobrien if (file_printf(ms, "character special (%ld/%ld)", 151133359Sobrien (long) major(sb->st_rdev), (long) minor(sb->st_rdev)) == -1) 152133359Sobrien return -1; 15368349Sobrien# endif 15468349Sobrien#else 155133359Sobrien if (file_printf(ms, "character special") == -1) 156133359Sobrien return -1; 15768349Sobrien#endif 15868349Sobrien return 1; 15968349Sobrien#endif 16068349Sobrien#ifdef S_IFBLK 16168349Sobrien case S_IFBLK: 16268349Sobrien /* 16368349Sobrien * If -s has been specified, treat block special files 16468349Sobrien * like ordinary files. Otherwise, just report that they 16568349Sobrien * are block special files and go on to the next file. 16668349Sobrien */ 167133359Sobrien if ((ms->flags & MAGIC_DEVICES) != 0) 16868349Sobrien break; 16968349Sobrien#ifdef HAVE_ST_RDEV 17068349Sobrien# ifdef dv_unit 171133359Sobrien if (file_printf(ms, "block special (%d/%d/%d)", 172133359Sobrien major(sb->st_rdev), dv_unit(sb->st_rdev), 173133359Sobrien dv_subunit(sb->st_rdev)) == -1) 174133359Sobrien return -1; 17568349Sobrien# else 176133359Sobrien if (file_printf(ms, "block special (%ld/%ld)", 177133359Sobrien (long)major(sb->st_rdev), (long)minor(sb->st_rdev)) == -1) 178133359Sobrien return -1; 17968349Sobrien# endif 18068349Sobrien#else 181133359Sobrien if (file_printf(ms, "block special") == -1) 182133359Sobrien return -1; 18368349Sobrien#endif 18468349Sobrien return 1; 18568349Sobrien#endif 18668349Sobrien /* TODO add code to handle V7 MUX and Blit MUX files */ 18768349Sobrien#ifdef S_IFIFO 18868349Sobrien case S_IFIFO: 189133359Sobrien if (file_printf(ms, "fifo (named pipe)") == -1) 190133359Sobrien return -1; 19168349Sobrien return 1; 19268349Sobrien#endif 19368349Sobrien#ifdef S_IFDOOR 19468349Sobrien case S_IFDOOR: 195133359Sobrien if (file_printf(ms, "door") == -1) 196133359Sobrien return -1; 19768349Sobrien return 1; 19868349Sobrien#endif 19968349Sobrien#ifdef S_IFLNK 20068349Sobrien case S_IFLNK: 201133359Sobrien if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) { 202133359Sobrien if (ms->flags & MAGIC_ERROR) { 203133359Sobrien file_error(ms, errno, "unreadable symlink `%s'", 204133359Sobrien fn); 205133359Sobrien return -1; 20668349Sobrien } 207133359Sobrien if (file_printf(ms, 208133359Sobrien "unreadable symlink `%s' (%s)", fn, 209133359Sobrien strerror(errno)) == -1) 210133359Sobrien return -1; 211133359Sobrien return 1; 212133359Sobrien } 213133359Sobrien buf[nch] = '\0'; /* readlink(2) forgets this */ 21468349Sobrien 215133359Sobrien /* If broken symlink, say so and quit early. */ 216133359Sobrien if (*buf == '/') { 217133359Sobrien if (stat(buf, &tstatbuf) < 0) { 218133359Sobrien if (ms->flags & MAGIC_ERROR) { 219133359Sobrien file_error(ms, errno, 220133359Sobrien "broken symbolic link to `%s'", buf); 221133359Sobrien return -1; 222133359Sobrien } 223133359Sobrien if (file_printf(ms, "broken symbolic link to `%s'", 224133359Sobrien buf) == -1) 225133359Sobrien return -1; 226133359Sobrien return 1; 227133359Sobrien } 228133359Sobrien } 229133359Sobrien else { 230133359Sobrien char *tmp; 231133359Sobrien char buf2[BUFSIZ+BUFSIZ+4]; 23268349Sobrien 233133359Sobrien if ((tmp = strrchr(fn, '/')) == NULL) { 23468349Sobrien tmp = buf; /* in current directory anyway */ 235133359Sobrien } else { 236133359Sobrien if (tmp - fn + 1 > BUFSIZ) { 237133359Sobrien if (ms->flags & MAGIC_ERROR) { 238133359Sobrien file_error(ms, 0, 239133359Sobrien "path too long: `%s'", buf); 240133359Sobrien return -1; 241133359Sobrien } 242133359Sobrien if (file_printf(ms, 243133359Sobrien "path too long: `%s'", fn) == -1) 244133359Sobrien return -1; 245133359Sobrien return 1; 246133359Sobrien } 247133359Sobrien (void)strcpy(buf2, fn); /* take dir part */ 248133359Sobrien buf2[tmp - fn + 1] = '\0'; 249133359Sobrien (void)strcat(buf2, buf); /* plus (rel) link */ 25068349Sobrien tmp = buf2; 251133359Sobrien } 252133359Sobrien if (stat(tmp, &tstatbuf) < 0) { 253133359Sobrien if (ms->flags & MAGIC_ERROR) { 254133359Sobrien file_error(ms, errno, 255133359Sobrien "broken symbolic link to `%s'", 256133359Sobrien buf); 257133359Sobrien return -1; 258133359Sobrien } 259133359Sobrien if (file_printf(ms, 260133359Sobrien "broken symbolic link to `%s'", buf) == -1) 261133359Sobrien return -1; 26268349Sobrien return 1; 26368349Sobrien } 26468349Sobrien } 265133359Sobrien 266133359Sobrien /* Otherwise, handle it. */ 267133359Sobrien if ((ms->flags & MAGIC_SYMLINK) != 0) { 268133359Sobrien const char *p; 269133359Sobrien ms->flags &= MAGIC_SYMLINK; 270133359Sobrien p = magic_file(ms, buf); 271133359Sobrien ms->flags |= MAGIC_SYMLINK; 272133359Sobrien return p != NULL ? 1 : -1; 273133359Sobrien } else { /* just print what it points to */ 274133359Sobrien if (file_printf(ms, "symbolic link to `%s'", 275133359Sobrien buf) == -1) 276133359Sobrien return -1; 277133359Sobrien } 278133359Sobrien return 1; 27968349Sobrien#endif 28068349Sobrien#ifdef S_IFSOCK 28168349Sobrien#ifndef __COHERENT__ 28268349Sobrien case S_IFSOCK: 283133359Sobrien if (file_printf(ms, "socket") == -1) 284133359Sobrien return -1; 28568349Sobrien return 1; 28668349Sobrien#endif 28768349Sobrien#endif 28868349Sobrien case S_IFREG: 28968349Sobrien break; 29068349Sobrien default: 291133359Sobrien file_error(ms, 0, "invalid mode 0%o", sb->st_mode); 292133359Sobrien return -1; 29368349Sobrien /*NOTREACHED*/ 29468349Sobrien } 29568349Sobrien 29668349Sobrien /* 29768349Sobrien * regular file, check next possibility 29868349Sobrien * 29968349Sobrien * If stat() tells us the file has zero length, report here that 30068349Sobrien * the file is empty, so we can skip all the work of opening and 30168349Sobrien * reading the file. 30268349Sobrien * But if the -s option has been given, we skip this optimization, 30368349Sobrien * since on some systems, stat() reports zero size for raw disk 30468349Sobrien * partitions. (If the block special device really has zero length, 30568349Sobrien * the fact that it is empty will be detected and reported correctly 30668349Sobrien * when we read the file.) 30768349Sobrien */ 308133359Sobrien if ((ms->flags & MAGIC_DEVICES) == 0 && sb->st_size == 0) { 309133359Sobrien if (file_printf(ms, (ms->flags & MAGIC_MIME) ? 310133359Sobrien "application/x-empty" : "empty") == -1) 311133359Sobrien return -1; 31268349Sobrien return 1; 31368349Sobrien } 31468349Sobrien return 0; 31568349Sobrien} 316