/* by Mark A. Sheldon, February 2005 */ /* Usage: lsdir [dirname] Prints the files in the specified directory or "." if no dirname is given. Much of this code is taken from or inspired by the code in Marc Rochkind, Advanced Unix Programming, 2nd edition, Chapter 3. */ #include #include #include #include #include #include #include #include #include /* Macros for extracting file type and mode from the mode field in a stat structure */ #define TYPE(b) ((statp->st_mode & (S_IFMT)) == (b)) #define MODE(b) ((statp->st_mode & (b)) == (b)) void display_entry(char *name) { struct stat stat_buf; struct stat *statp = &stat_buf; struct passwd *passwdp; struct group *groupp; time_t now; char mtimebuf[26], *format; /* man page says ctime, etc. have max size of 26 */ double diff; char *link_target; ssize_t n; if (lstat(name, statp) == -1) { perror(name); return; } /* Mode bits */ printf("%c%c%c%c%c%c%c%c%c%c", TYPE(S_IFBLK) ? 'b' /* First char is file type */ : TYPE(S_IFCHR)? 'c' : TYPE(S_IFDIR)? 'd' : TYPE(S_IFIFO)? 'p' : TYPE(S_IFREG)? '-' : TYPE(S_IFLNK)? 'l' : TYPE(S_IFSOCK)? 's' : '?', MODE(S_IRUSR)? 'r' : '-', /* User permissions */ MODE(S_IWUSR)? 'w' : '-', MODE(S_ISUID)? (MODE(S_IXUSR)? 's' : 'S') : MODE(S_IXUSR)? 'x' : '-', MODE(S_IRGRP)? 'r' : '-', /* Group permissions */ MODE(S_IWGRP)? 'w' : '-', MODE(S_ISGID)? (MODE(S_IXGRP)? 's' : 'S') : MODE(S_IXGRP)? 'x' : '-', MODE(S_IROTH)? 'r' : '-', /* Other permissions */ MODE(S_IWOTH)? 'w' : '-', (MODE(S_IFDIR) && MODE(S_ISVTX))? (MODE(S_IXOTH)? 't' : 'T') : MODE(S_IXOTH)? 'x' : '-' ); /* number of links */ printf("%5ld", (long) statp->st_nlink); /* Look up and display owner's user name, print UID if unknown */ passwdp = getpwuid(statp->st_uid); if (passwdp) printf(" %-8s", passwdp->pw_name); else printf(" %-8ld", (long)statp->st_uid); /* Look up and display group name, print GID if unknown */ groupp = getgrgid(statp->st_gid); if (groupp) printf(" %-8s", groupp->gr_name); else printf(" %-8ld", (long)statp->st_gid); /* File size. For device files, major and minor number (assuming each gets 8 bits) */ switch (statp->st_mode & S_IFMT) { case S_IFCHR: case S_IFBLK: printf("%4u,%4u", (unsigned) (statp->st_rdev >> 8), (unsigned) (statp->st_rdev & 0xFF)); break; default: printf("%9lu", (unsigned long) statp->st_size); } /* File modification time First draft was this, but it didn't really do the ls -l thing: printf(" %s", (mtime = ctime(&(statp->st_mtime))) ? mtime : "??? ?? ????"); */ if (time(&now) == -1) printf ("??? ?? ????"); else { diff = difftime(now, statp->st_mtime); if (diff < 0 || diff > 60*60*24*182.5) /* ~6 months */ format = "%b %e %Y"; else format = "%b %e %H:%M"; strftime(mtimebuf, sizeof(mtimebuf), format, localtime(&statp->st_mtime)); printf(" %s", mtimebuf); } /* File name with annotation if the file is a link */ if (!S_ISLNK(statp->st_mode)) { printf(" %s\n", name); return; } link_target = (char *)malloc(statp->st_size + 1); if ( (link_target != NULL) && ((n = readlink(name, link_target, statp->st_size)) != -1) ) { link_target[n] = '\0'; printf(" %s -> %s", name, link_target); } else printf(" %s -> [can't read link]", name); free(link_target); putchar('\n'); } /* display_entry */ void lsdir(char *path) { DIR *dirp; struct dirent *entry; dirp = opendir(path); if (!dirp) { perror("lsdir: Cannot open directory"); exit(EINVAL); } /* Reset errno on each iteration to detect readdir() errors */ while (errno = 0, entry = readdir(dirp)) display_entry(entry->d_name); if (errno) perror("lsdir: Error reading directory"); /* Since we're already done, is there really a reason to check for failure on close? */ if (closedir(dirp) == -1) perror("lsdir: Error closing directory"); return; } /* lsdir */ int main(int argc, char* argv[]) { char *dirname; if (argc > 2) { fprintf(stderr, "Usage: %s [dirname]\n", argv[0]); exit(EINVAL); } if (argc == 2) chdir(argv[1]); lsdir("."); return 0; } /* main() */