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