#include #include #include #include #include #include #include #include #include /* * should be defined in header files but . . . */ #define S_ISSOCK(x) ((x)&014) ssize_t readlink(const char *, char *, size_t); int lstat(const char *, struct stat *); /* * printing permissions */ /* how many bits to shift left to get the set needed */ #define PRIV 9 /* privilege bits */ #define USER 6 /* permissions for UID */ #define GROUP 3 /* permissions for GID */ #define OTHER 0 /* permissions for everyone else */ char *p_rights[] = { "setuid", "setgid", "sticky" }; char *f_rights[] = { "read", "write", "execute" }; char *d_rights[] = { "list", "modify", "search" }; char perm_buf[128]; /* big enough to hold response */ /* * print permissions in a readable fashion * note what we print depends on the file type */ char *perm(int what, mode_t f_perms) { char **rights; unsigned short bits; if (S_ISDIR(f_perms)) rights = d_rights; else rights = f_rights; switch(what){ case USER: case GROUP: case OTHER: bits = (f_perms>>what)&07; break; default: return("*** internal error ***"); } perm_buf[0] = '\0'; switch(bits){ case 7: /* read, write, and execute */ (void) strcpy(perm_buf, rights[0]); (void) strcat(perm_buf, ", "); (void) strcat(perm_buf, rights[1]); (void) strcat(perm_buf, ", and "); (void) strcat(perm_buf, rights[2]); break; case 6: /* read and write */ (void) strcpy(perm_buf, rights[0]); (void) strcat(perm_buf, " and "); (void) strcat(perm_buf, rights[1]); break; case 5: /* read and execute */ (void) strcpy(perm_buf, rights[0]); (void) strcat(perm_buf, " and "); (void) strcat(perm_buf, rights[2]); break; case 4: /* read */ (void) strcpy(perm_buf, rights[0]); break; case 3: /* write and execute */ (void) strcpy(perm_buf, rights[1]); (void) strcat(perm_buf, " and "); (void) strcat(perm_buf, rights[2]); break; case 2: /* write */ (void) strcpy(perm_buf, rights[1]); break; case 1: /* execute */ (void) strcpy(perm_buf, rights[2]); break; case 0: /* execute */ (void) strcpy(perm_buf, "do nothing"); break; default: (void) strcpy(perm_buf, "*** internal error ***"); break; } return(perm_buf); } /* * print privileges */ char *priv(mode_t p_perms) { unsigned short bits; bits = (p_perms>>PRIV)&07; perm_buf[0] = '\0'; switch(bits){ case 7: /* setuid, setgid, and sticky */ (void) strcpy(perm_buf, p_rights[0]); (void) strcat(perm_buf, ", "); (void) strcat(perm_buf, p_rights[1]); (void) strcat(perm_buf, ", and "); (void) strcat(perm_buf, p_rights[2]); break; case 6: /* setuid and setgid */ (void) strcpy(perm_buf, p_rights[0]); (void) strcat(perm_buf, " and "); (void) strcat(perm_buf, p_rights[1]); break; case 5: /* setuid and sticky */ (void) strcpy(perm_buf, p_rights[0]); (void) strcat(perm_buf, " and "); (void) strcat(perm_buf, p_rights[2]); break; case 4: /* setuid */ (void) strcpy(perm_buf, p_rights[0]); break; case 3: /* setgid and sticky */ (void) strcpy(perm_buf, p_rights[1]); (void) strcat(perm_buf, " and "); (void) strcat(perm_buf, p_rights[2]); break; case 2: /* setgid */ (void) strcpy(perm_buf, p_rights[1]); break; case 1: /* sticky */ (void) strcpy(perm_buf, p_rights[2]); break; case 0: (void) strcpy(perm_buf, "none"); break; default: (void) strcpy(perm_buf, "*** internal error ***"); break; } return(perm_buf); } /* * this prints the file type */ char *ftype(mode_t f_perms) { if (S_ISREG(f_perms)) return("regular file"); else if (S_ISDIR(f_perms)) return("directory"); else if (S_ISCHR(f_perms)) return("character special device"); else if (S_ISBLK(f_perms)) return("block special device"); else if (S_ISFIFO(f_perms)) return("fifo (named pipe)"); else if (S_ISLNK(f_perms)) return("symbolic link"); else if (S_ISSOCK(f_perms)) return("socket"); /* should never get here, but just in case . . . */ sprintf(perm_buf, "*** unknown type (%0o) ***", (f_perms>>12)&0xf); return(perm_buf); } /* * print time */ char p_time[1024]; char *timefmt = "%A, %B %e, %Y at %l:%M:%S%p %Z"; char *prtime(time_t tock) { struct tm ticktock; ticktock = *localtime(&tock); if (!strftime(p_time, sizeof(p_time), timefmt, &ticktock)) sprintf(p_time, "%ld", tock); return(p_time); } int do_stat(char *); int main(int argc, char *argv[]) { int i; /* * need at least one file name */ if (argc == 1){ fprintf(stderr, "Usage: %s file1 [ ... ]\n", argv[0]); (void) exit(1); } /* * do the files one at a time */ for(i = 1; i < argc; i++){ if (do_stat(argv[i]) && i+1 != argc) printf("====================\n"); } /* * all done! */ (void) exit(0); } /* * do the file */ int do_stat(char *fname) { struct stat stbuf; char *lname; ssize_t r; /* * get the file information and complain on error */ if (lstat(fname, &stbuf) < 0){ perror(fname); return(0); } /* * print file name */ printf("%s:\n", fname); /* * print file system information */ printf("\t* File system information:\n"); printf("\t Major ID of file's device: %d\n", (int) major(stbuf.st_dev)); printf("\t Minor ID of file's device: %d\n", (int) minor(stbuf.st_dev)); printf("\t Optimal file system blocksize: %ld\n", (long) stbuf.st_blksize); printf("\t File inode number %ld\n", (long) stbuf.st_ino); if (S_ISBLK(stbuf.st_mode) || S_ISCHR(stbuf.st_mode)){ printf("\t File is a device interface:\n"); printf("\t\tMajor device number (driver number): %d\n", (int) major(stbuf.st_rdev)); printf("\t\tMinor device number (driver dependent): %d\n", (int) minor(stbuf.st_rdev)); } /* * print file type, and target if a symlink */ printf("\t* File type information:\n"); printf("\t File type: %s", ftype(stbuf.st_mode)); if (S_ISLNK(stbuf.st_mode)){ printf(" ["); if ((lname = malloc(stbuf.st_size+1)) == NULL) printf("*** Ran out of memory ***"); else if ((r = readlink(fname, lname, stbuf.st_size + 1)) < 0) printf("*** Error reading link name ***"); else if (r > stbuf.st_size) printf("*** Contents changed during read ***"); else{ lname[stbuf.st_size] = '\0'; printf("%s", lname); } printf("]"); } putchar('\n'); printf("\t Number of hard links: %ld\n", (long) stbuf.st_nlink); printf("\t Number of bytes in file: %ld\n", (long) stbuf.st_size); printf("\t Number of 512 byte blocks allocated: %ld\n", (long) stbuf.st_blocks); /* * print file permission and ownership information */ printf("\t* File permission information:\n"); printf("\t User ID: %d\n", (int) stbuf.st_uid); printf("\t Group ID: %d\n", (int) stbuf.st_gid); printf("\t Permissions: %04o\n", (int) (stbuf.st_mode&07777)); printf("\t\tUser can %s\n", perm(USER, stbuf.st_mode)); printf("\t\tGroup can %s\n", perm(GROUP, stbuf.st_mode)); printf("\t\tEveryone else can %s\n", perm(OTHER, stbuf.st_mode)); printf("\t* File privileges: %s\n", priv(stbuf.st_mode)); /* * file times */ printf("\t* File time information:\n"); printf("\t Time of last access: %s\n", prtime(stbuf.st_atime)); printf("\t Time of last modification: %s\n", prtime(stbuf.st_mtime)); printf("\t Time of inode creation: %s\n", prtime(stbuf.st_ctime)); return(1); }