fsmagic.c revision 103373
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 "file.h" 29#include <string.h> 30#ifdef HAVE_UNISTD_H 31#include <unistd.h> 32#endif 33#include <stdlib.h> 34/* Since major is a function on SVR4, we can't use `ifndef major'. */ 35#ifdef MAJOR_IN_MKDEV 36# include <sys/mkdev.h> 37# define HAVE_MAJOR 38#endif 39#ifdef MAJOR_IN_SYSMACROS 40# include <sys/sysmacros.h> 41# define HAVE_MAJOR 42#endif 43#ifdef major /* Might be defined in sys/types.h. */ 44# define HAVE_MAJOR 45#endif 46 47#ifndef HAVE_MAJOR 48# define major(dev) (((dev) >> 8) & 0xff) 49# define minor(dev) ((dev) & 0xff) 50#endif 51#undef HAVE_MAJOR 52 53#ifndef lint 54FILE_RCSID("@(#)$Id: fsmagic.c,v 1.36 2002/07/03 19:00:41 christos Exp $") 55#endif /* lint */ 56 57int 58fsmagic(const char *fn, struct stat *sb) 59{ 60 int ret = 0; 61 62 /* 63 * Fstat is cheaper but fails for files you don't have read perms on. 64 * On 4.2BSD and similar systems, use lstat() to identify symlinks. 65 */ 66#ifdef S_IFLNK 67 if (!lflag) 68 ret = lstat(fn, sb); 69 else 70#endif 71 ret = stat(fn, sb); /* don't merge into if; see "ret =" above */ 72 73 if (ret) { 74 ckfprintf(stdout, 75 /* Yes, I do mean stdout. */ 76 /* No \n, caller will provide. */ 77 "can't stat `%s' (%s).", fn, strerror(errno)); 78 return 1; 79 } 80 81 if (iflag) { 82 if ((sb->st_mode & S_IFMT) != S_IFREG) { 83 ckfputs("application/x-not-regular-file", stdout); 84 return 1; 85 } 86 } 87 else { 88#ifdef S_ISUID 89 if (sb->st_mode & S_ISUID) ckfputs("setuid ", stdout); 90#endif 91#ifdef S_ISGID 92 if (sb->st_mode & S_ISGID) ckfputs("setgid ", stdout); 93#endif 94#ifdef S_ISVTX 95 if (sb->st_mode & S_ISVTX) ckfputs("sticky ", stdout); 96#endif 97 } 98 99 switch (sb->st_mode & S_IFMT) { 100 case S_IFDIR: 101 ckfputs("directory", stdout); 102 return 1; 103#ifdef S_IFCHR 104 case S_IFCHR: 105 /* 106 * If -s has been specified, treat character special files 107 * like ordinary files. Otherwise, just report that they 108 * are block special files and go on to the next file. 109 */ 110 if (sflag) 111 break; 112#ifdef HAVE_ST_RDEV 113# ifdef dv_unit 114 (void) printf("character special (%d/%d/%d)", 115 major(sb->st_rdev), 116 dv_unit(sb->st_rdev), 117 dv_subunit(sb->st_rdev)); 118# else 119 (void) printf("character special (%ld/%ld)", 120 (long) major(sb->st_rdev), (long) minor(sb->st_rdev)); 121# endif 122#else 123 (void) printf("character special"); 124#endif 125 return 1; 126#endif 127#ifdef S_IFBLK 128 case S_IFBLK: 129 /* 130 * If -s has been specified, treat block special files 131 * like ordinary files. Otherwise, just report that they 132 * are block special files and go on to the next file. 133 */ 134 if (sflag) 135 break; 136#ifdef HAVE_ST_RDEV 137# ifdef dv_unit 138 (void) printf("block special (%d/%d/%d)", 139 major(sb->st_rdev), 140 dv_unit(sb->st_rdev), 141 dv_subunit(sb->st_rdev)); 142# else 143 (void) printf("block special (%ld/%ld)", 144 (long) major(sb->st_rdev), (long) minor(sb->st_rdev)); 145# endif 146#else 147 (void) printf("block special"); 148#endif 149 return 1; 150#endif 151 /* TODO add code to handle V7 MUX and Blit MUX files */ 152#ifdef S_IFIFO 153 case S_IFIFO: 154 ckfputs("fifo (named pipe)", stdout); 155 return 1; 156#endif 157#ifdef S_IFDOOR 158 case S_IFDOOR: 159 ckfputs("door", stdout); 160 return 1; 161#endif 162#ifdef S_IFLNK 163 case S_IFLNK: 164 { 165 char buf[BUFSIZ+4]; 166 int nch; 167 struct stat tstatbuf; 168 169 if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) { 170 ckfprintf(stdout, "unreadable symlink (%s).", 171 strerror(errno)); 172 return 1; 173 } 174 buf[nch] = '\0'; /* readlink(2) forgets this */ 175 176 /* If broken symlink, say so and quit early. */ 177 if (*buf == '/') { 178 if (stat(buf, &tstatbuf) < 0) { 179 ckfprintf(stdout, 180 "broken symbolic link to %s", buf); 181 return 1; 182 } 183 } 184 else { 185 char *tmp; 186 char buf2[BUFSIZ+BUFSIZ+4]; 187 188 if ((tmp = strrchr(fn, '/')) == NULL) { 189 tmp = buf; /* in current directory anyway */ 190 } 191 else { 192 strcpy (buf2, fn); /* take directory part */ 193 buf2[tmp-fn+1] = '\0'; 194 strcat (buf2, buf); /* plus (relative) symlink */ 195 tmp = buf2; 196 } 197 if (stat(tmp, &tstatbuf) < 0) { 198 ckfprintf(stdout, 199 "broken symbolic link to %s", buf); 200 return 1; 201 } 202 } 203 204 /* Otherwise, handle it. */ 205 if (lflag) { 206 process(buf, strlen(buf)); 207 return 1; 208 } else { /* just print what it points to */ 209 ckfputs("symbolic link to ", stdout); 210 ckfputs(buf, stdout); 211 } 212 } 213 return 1; 214#endif 215#ifdef S_IFSOCK 216#ifndef __COHERENT__ 217 case S_IFSOCK: 218 ckfputs("socket", stdout); 219 return 1; 220#endif 221#endif 222 case S_IFREG: 223 break; 224 default: 225 error("invalid mode 0%o.\n", sb->st_mode); 226 /*NOTREACHED*/ 227 } 228 229 /* 230 * regular file, check next possibility 231 * 232 * If stat() tells us the file has zero length, report here that 233 * the file is empty, so we can skip all the work of opening and 234 * reading the file. 235 * But if the -s option has been given, we skip this optimization, 236 * since on some systems, stat() reports zero size for raw disk 237 * partitions. (If the block special device really has zero length, 238 * the fact that it is empty will be detected and reported correctly 239 * when we read the file.) 240 */ 241 if (!sflag && sb->st_size == 0) { 242 ckfputs(iflag ? "application/x-empty" : "empty", stdout); 243 return 1; 244 } 245 return 0; 246} 247