/* * print information about a named file * * Matt Bishop, Dept. of Computer Sciences, Purdue University * updated for 4.2 BSD UNIX at Megatest Corp., July 28, 1983 * updated for ULTRIX at UC Davis, Nov. 10, 1997 */ #include #include #include #include #include #include #define BSD4_2 #define GOOD 0 /* exit code (success) */ #define BAD 1 /* exit code (failure) */ #define BLKSIZ 1024 /* bytes per block */ #ifdef BSD4_2 # define STAT lstat /* follow symbolic links */ int lstat(char *, struct stat *); int readlink(char *, char *, int); #endif BSD4_2 /* * external functions */ #ifndef __STDC__ struct group *getgrgid(); struct passwd *getpwuid(); char *ctime(), *strcpy(); #endif /* * the types of files * note the #defined constants MUST have as values the position of * the corresponding entry in the array type[] */ char *type[] = { "Directory", "Block special", "Character special", "Regular file", #ifdef BSD4_1 "Multiplexed block special", "Multiplexed character special", #endif BSD4_1 #ifdef BSD4_2 "Symbolic link", "Socket", #endif BSD4_2 "Unknown type" }; #define DIR 0 /* Directory */ #define BLK 1 /* Block special */ #define CHR 2 /* Character special */ #define REG 3 /* Regular file */ #ifdef BSD4_1 # define MPB 4 /* Multiplexed block */ # define MPC 5 /* Multiplexed character */ #endif BSD4_1 #ifdef BSD4_2 # define LNK 4 /* Symbolic link */ # define SOCK 5 /* Socket */ #endif BSD4_2 #define UNK 6 /* Unknown type */ /* * forward declarations */ #ifdef __STDC__ void fildat(char *); #endif /* * main routine */ #ifdef __STDC__ int main(int argc, char *argv[]) #else int main(argc, argv) int argc; char *argv[]; #endif { register int i; /* counter in a for loop */ /* * if no args, print a diagnostic */ if (argc == 1){ fprintf(stderr, "Usage: %s file1 file2 ...\n", argv[0]); exit(BAD); } /* * process each file */ for(i = 1; i < argc; i++) fildat(argv[i]); if (argc == 1) fprintf(stderr, "Usage: %s [files]\n", argv[0]); exit(GOOD); } #ifdef __STDC__ void fildat(char *str) #else void fildat(str) char *str; /* file name */ #endif { register struct group *gp; /* pointer to file group info */ register struct passwd *up; /* pointer to file owner info */ register int ftype; /* type of file */ struct stat stbuf; /* buffer for stat of file */ char tmp[BUFSIZ]; /* buffer used for various things */ int l; /* length of file linked to by LNK */ /* * stat the file */ if (STAT(str, &stbuf) < 0){ fprintf(stderr, "%s: status not available\n", str); return; } /* * get its type */ switch(stbuf.st_mode & S_IFMT){ case S_IFREG: ftype = REG; break; case S_IFBLK: ftype = BLK; break; case S_IFDIR: ftype = DIR; break; case S_IFCHR: ftype = CHR; break; #ifdef BSD4_1 case S_IFMPB: ftype = MPB; break; case S_IFMPC: ftype = MPC; break; #endif BSD4_1 #ifdef BSD4_2 case S_IFLNK: ftype = LNK; break; case S_IFSOCK: ftype = SOCK; break; #endif BSD4_2 default: ftype = UNK; break; } /* * print out the first batch of info */ printf("File name: %s\n", str); printf("Device: %d\n", stbuf.st_dev); printf("Inode number: %ld\n", stbuf.st_ino); printf("Number of links: %d\n", stbuf.st_nlink); printf("Type of file: %s", type[ftype]); #ifdef BSD4_2 /* * trace any symbolic links, too */ if (ftype == LNK && (l = readlink(str, tmp, BUFSIZ)) > 0){ tmp[l] = '\0'; printf(" [to %s]", tmp); } putchar('\n'); #endif BSD4_2 /* * now print the owner and the group * use names if you can, numeric IDs if you must */ if ((up = getpwuid(stbuf.st_uid)) == NULL) printf("Owner of file: %d (no name available)\n", stbuf.st_uid); else printf("Owner of file: %s (%d)\n", up->pw_name, stbuf.st_uid); if ((gp = getgrgid(stbuf.st_gid)) == NULL) printf("Group of file: %d (no name available)\n", stbuf.st_gid); else printf("Group of file: %s (%d)\n", gp->gr_name, stbuf.st_gid); /* * now note if it's a setuid or setgid file */ tmp[0] = '\0'; if (stbuf.st_mode & S_ISGID) if (stbuf.st_mode & S_ISUID) strcpy(tmp, "User, group ids "); else strcpy(tmp, "Group id "); else if (stbuf.st_mode & S_ISUID) strcpy(tmp, "User id "); if (tmp[0]) printf("%s set on execution\n", tmp); /* * sticky bit set */ if (stbuf.st_mode & S_ISVTX) printf("Save swapped text even after use\n"); /* * print out the protection modes */ printf("Owner rights:"); if ((stbuf.st_mode & 0700) == 0) printf(" none"); if (stbuf.st_mode & 0400) printf(" read"); if (stbuf.st_mode & 0200) printf(" write"); if (stbuf.st_mode & 0100) printf(" execute"); printf("\n"); printf("Group rights:"); if ((stbuf.st_mode & 070) == 0) printf(" none"); if (stbuf.st_mode & 040) printf(" read"); if (stbuf.st_mode & 020) printf(" write"); if (stbuf.st_mode & 010) printf(" execute"); printf("\n"); printf("Other rights:"); if ((stbuf.st_mode & 07) == 0) printf(" none"); if (stbuf.st_mode & 04) printf(" read"); if (stbuf.st_mode & 02) printf(" write"); if (stbuf.st_mode & 01) printf(" execute"); printf("\n"); /* * now for devices, print the device type */ #ifdef BSD4_1 if (ftype == CHR || ftype == BLK || ftype == MPB || ftype == MPC){ #endif BSD4_1 #ifdef BSD4_2 if (ftype == CHR || ftype == BLK || ftype == SOCK){ #endif BSD4_2 printf("Major device number: %d\n", major((int) stbuf.st_rdev)); printf("Minor device number: %d\n", minor((int) stbuf.st_rdev)); } /* * if it's a directory, regular file, or symbolic link * print its size */ #ifdef BSD4_1 if (ftype == DIR || ftype == REG){ #endif BSD4_1 #ifdef BSD4_2 if (ftype == DIR || ftype == REG || ftype == LNK){ #endif BSD4_2 printf("Size in bytes: %d\n", stbuf.st_size); printf("Size in blocks: %d\n", stbuf.st_size / BLKSIZ + (stbuf.st_size % BLKSIZ > 0)); } /* * print important dates */ printf("Date of last read: %s", ctime(&(stbuf.st_atime))); printf("Date of last write: %s", ctime(&(stbuf.st_mtime))); printf("Date of creation: %s", ctime(&(stbuf.st_ctime))); #ifdef BSD4_2 /* * print best I/O block size */ printf("Optimal block size for file I/O: %ld bytes\n", stbuf.st_blksize); #endif BSD4_2 }