#include #include #include #include #include #include #include #include #if defined(sgi) || defined(sun) #include #endif #include #ifdef sun #ifdef __svr4__ #define SOLARIS2 #else #define SOLARIS1 #endif #endif #ifdef SOLARIS2 #define HAS_STATVFS #endif #ifdef sgi #define HAS_ST_FSTYPE #endif #ifdef HAS_STATVFS #include #endif int opt_L = 0, opt_i = 0, opt_d = 0, opt_r = 0, opt_l = 0, opt_s = 0, opt_p = 0, opt_k = 0, opt_u = 0, opt_g = 0, opt_c = 0, opt_a = 0, opt_m = 0, opt_t = 0, opt_q = 0, opt_f = -1; int opt_fstype = 0; time_t now; void sep(void); void sino(struct stat* s) { if(!opt_q) printf("inode "); printf("%d", s->st_ino); } void sdev(struct stat* s) { if(!opt_q) printf("dev "); printf("%d", s->st_dev); } void srdev(struct stat* s) { if(!opt_q) printf("rdev "); printf("%d,%d", major(s->st_rdev), minor(s->st_rdev)); } void snlink(struct stat* s) { if(!opt_q) printf("links "); printf("%d", s->st_nlink); } void ssize(struct stat* s) { if(!opt_q) printf("size "); printf("%d", s->st_size); } void smode(struct stat* s) { int i; if(opt_q) { printf("%u", s->st_mode); return; } printf("mode is %04o/", s->st_mode & 07777); /* sticky bit */ #ifndef S_ISTXT #if defined(S_ISVTX) #define S_ISTXT S_ISVTX #else #define S_ISTXT 0001000 #endif #endif if(s->st_mode & (S_ISUID|S_ISGID|S_ISTXT)) { if(s->st_mode & S_ISUID) putchar('u'); else putchar('-'); if(s->st_mode & S_ISGID) putchar('g'); else putchar('-'); if(s->st_mode & S_ISTXT) putchar('t'); else putchar('-'); } for(i = 8; i >= 0; i--) if(s->st_mode & (1u << i)) putchar("rwxrwxrwx"[8-i]); else putchar('-'); } void skind(struct stat* s) { if(S_ISDIR(s->st_mode)) printf("directory"); else if(S_ISCHR(s->st_mode)) printf("char_spec"); else if(S_ISBLK(s->st_mode)) printf("block_spec"); else if(S_ISREG(s->st_mode)) printf("regular"); else if(s->st_mode & S_IFIFO) printf("fifo"); else if((s->st_mode & S_IFSOCK) == S_IFSOCK) printf("socket"); #ifdef S_IFLNK else if((s->st_mode & S_IFLNK) == S_IFLNK) printf("link"); #endif else printf("UNKNOWN"); } void suid(struct stat* s) { struct passwd* pw; if(opt_q) { printf("%d", s->st_uid); return; } printf("uid %d", s->st_uid); if((pw = getpwuid(s->st_uid)) != NULL) printf(" (%s)", pw->pw_name); } void sgid(struct stat* s) { struct group* gr; if(opt_q) { printf("%d", s->st_gid); return; } printf("gid %d", s->st_gid); if((gr = getgrgid(s->st_gid)) != NULL) printf(" (%s)", gr->gr_name); } char* get_time(time_t t) { static char buff[BUFSIZ]; char* p; long diff = now - t; sprintf(buff, "%s%u", ctime(&t), t); if((p = strchr(buff, '\n')) != NULL) *p = ' '; p += strlen(p); sprintf(p, " (%05d.", diff / (60*60*24)); if(diff < 0) diff = -diff; p += strlen(p); diff %= 60*60*24; sprintf(p, "%02d:%02d:%02d)", diff / (60*60), (diff / 60) % 60, diff % 60); return buff; } void sfstype(struct stat* s, char *path) { #if defined(HAS_ST_FSTYPE) || defined(HAS_ST_FSTYPE) char *fstag; char *fstype; #if defined(HAS_ST_FSTYPE) fstag = "st_fstype"; fstype = s->st_fstype; #elif defined(HAS_STATVFS) struct statvfs vfs; fstag = "vfstype"; fstype = NULL; if(path == NULL) { if(fstatvfs(opt_f, &vfs) < 0) goto print; } else { if(statvfs(path, &vfs) < 0) goto print; } fstype = vfs.f_basetype; print: #endif sep(); if(!opt_q) printf("%s: ", fstag); printf("%s", fstype); #endif } void sctime(struct stat* s) { if(opt_q) printf("%u", s->st_ctime); else printf("change time - %s", get_time(s->st_ctime)); } void satime(struct stat* s) { if(opt_q) printf("%u", s->st_atime); else printf("access time - %s", get_time(s->st_atime)); } void smtime(struct stat* s) { if(opt_q) printf("%u", s->st_mtime); else printf("modify time - %s", get_time(s->st_mtime)); } void usage(void) { fputs("Usage: stat [-idrlspkugcamtqL] [-f fdesc] files ...\n", stderr); fputs("\tinode, dev, rdev, links, size, perm, kind, user, grp\n", stderr); fputs("\tctime, atime, mtime, t = all times, q = quiet, L = lstat\n", stderr); fputs("\tdefault is everything\n", stderr); fputs("\t-f option takes file descriptor instead of filenames\n", stderr); exit(1); } int col = 0; int col_max = 3; void sep(void) { if(opt_q) { if(col > 0) putchar('\n'); col++; } else { if(col >= col_max) { putchar('\n'); putchar('\t'); col = 0; } else { col++; putchar(';'); putchar(' '); } } } void print_stat(struct stat* s, char *path) { col_max = 3; if(opt_q) col = 0; else col = col_max; if(opt_i) { sep(); sino(s); } if(opt_d) { sep(); sdev(s); } if(opt_r) { sep(); srdev(s); } if(opt_l) { sep(); snlink(s); } if(opt_s) { sep(); ssize(s); } if(opt_p) { sep(); smode(s); } if(opt_k) { sep(); skind(s); } col_max = 2; if(opt_u) { sep(); suid(s); } if(opt_g) { sep(); sgid(s); } if(!opt_q) col = col_max = 0; if(opt_fstype) { sfstype(s, path); } if(opt_c) { sep(); sctime(s); } if(opt_a) { sep(); satime(s); } if(opt_m) { sep(); smtime(s); } putchar('\n'); } int main(int argc, char** argv) { int i, ch, opt; opt = 0; while((ch = getopt(argc, argv, "Lidrlspkugcamtqf:")) != -1) { switch(ch) { case 'L': opt_L = 1; break; case 'i': opt = opt_i = 1; break; case 'd': opt = opt_d = 1; break; case 'r': opt = opt_r = 1; break; case 'l': opt = opt_l = 1; break; case 's': opt = opt_s = 1; break; case 'p': opt = opt_p = 1; break; case 'k': opt = opt_k = 1; break; case 'u': opt = opt_u = 1; break; case 'g': opt = opt_g = 1; break; case 'c': opt = opt_c = 1; break; case 'a': opt = opt_a = 1; break; case 'm': opt = opt_m = 1; break; case 't': opt = opt_t = 1; break; case 'q': opt_q = 1; break; case 'f': opt_f = atoi(optarg); break; } } if(opt == 0) { opt_i = opt_d = opt_r = opt_l = opt_s = opt_p = opt_k = opt_u = opt_g = opt_c = opt_a = opt_m = opt_t = opt_fstype = 1; } now = time(NULL); if(opt_f >= 0) { struct stat s; if(fstat(opt_f, &s) < 0) { perror("fstat"); return 1; } if(!opt_q) printf("file descriptor %d:", opt_f); print_stat(&s, NULL); return 0; } if(optind == argc) usage(); if(strcmp(argv[optind], "-") == 0) optind++; else if(argv[optind][0] == '-') usage(); if(opt_t) opt_c = opt_a = opt_m = 1; for(i = optind; i < argc; i++) { char* file; struct stat s; file = argv[i]; if(opt_L) { if(lstat(file, &s) < 0) { perror(file); continue; } } else { if(stat(file, &s) < 0) { perror(file); continue; } } if(!opt_q) printf("%s:", file); print_stat(&s, file); } return 0; }