ls -l
outputThe program ls2
displays information about files in the standard
ls -l
format. The main
program
uses a command argument for the directory name (or ".") as the default and calls the routine
do_ls
, which scans the directory and calls dostat
to output the file information via a call to
show_file_info
. This routine prints out the information from struct stat
, using mode_to_letters
to generate a string describing the file permissions (in the style of ls
), uid_to_name
to look up the user name and
gid_to_name
to look up the group name.
> ./ls2 -rwxr-xr-x 1 loomis users 9649 Sep 27 12:06 ls2 -rwxr-xr-x 1 loomis users 153 Sep 23 17:34 Makefile -rwxr-xr-x 1 loomis users 3604 Sep 27 08:52 ls2.c -rwxr-xr-x 1 loomis users 1450 Sep 27 12:08 printdir.c~ drwxr-xr-x 3 loomis users 72 Sep 27 12:04 subDir1 -rwxr-xr-x 1 loomis users 8465 Sep 27 12:12 printdir -rwxr-xr-x 1 loomis users 55 Sep 27 12:02 prog.sh~ -rw-r--r-- 1 loomis users 0 Sep 27 12:51 prog.txt -rwxr-xr-x 1 loomis users 1471 Sep 27 12:12 printdir.c -rwxr-xr-x 1 loomis users 54 Sep 27 12:08 prog.sh > ls -l total 48 -rwxr-xr-x 1 loomis users 9649 2006-09-27 12:06 ls2 -rwxr-xr-x 1 loomis users 3604 2006-09-27 08:52 ls2.c -rwxr-xr-x 1 loomis users 153 2006-09-23 17:34 Makefile -rwxr-xr-x 1 loomis users 8465 2006-09-27 12:12 printdir -rwxr-xr-x 1 loomis users 1471 2006-09-27 12:12 printdir.c -rwxr-xr-x 1 loomis users 1450 2006-09-27 12:08 printdir.c~ -rwxr-xr-x 1 loomis users 54 2006-09-27 12:08 prog.sh -rwxr-xr-x 1 loomis users 55 2006-09-27 12:02 prog.sh~ -rw-r--r-- 1 loomis users 0 2006-09-27 12:51 prog.txt drwxr-xr-x 3 loomis users 72 2006-09-27 12:04 subDir1
The real version of ls
prints a total line at the top.
What does that mean? Furthermore, our version does not sort filenames and assumes the arguments must be directories. Unlike ls
without the -a
option, our code always shows hidden files.
Finally, there is a more serious bug: it does not list the information about files in other directories correctly:
$ls /usr bin i586-suse-linux lib sbin src X11 games include local share tmp X11R6 $./ls2 /usr /usr: X11: No such file or directory bin: No such file or directory lib: No such file or directory src: No such file or directory tmp: No such file or directory sbin: No such file or directory X11R6: No such file or directory games: No such file or directory local: No such file or directory share: No such file or directory i586-suse-linux: No such file or directory include: No such file or directory
Correcting this bug is left as an exercise.
Bruce Molay, Understanding Unix/Linux Programming, Pearson Prentice-Hall, 2003. ISBN 0-13-008396-8. Chapter 3, p 91-95
ls2.c
/* ls2.c * purpose list contents of directory or directories * action if no args, use . else list files in args * note uses stat and pwd.h and grp.h * BUG: try ls2 /tmp * * Molay, chapter 3, p 91-95 */ #include <stdio.h> #include <sys/types.h> #include <dirent.h> #include <sys/stat.h> #include <string.h> void do_ls(char[]); void dostat(char *); void show_file_info( char *, struct stat *); void mode_to_letters( int , char [] ); char *uid_to_name( uid_t ); char *gid_to_name( gid_t ); int main(int ac, char *av[]) { if ( ac == 1 ) do_ls( "." ); else while ( --ac ){ printf("%s:\n", *++av ); do_ls( *av ); } return 0; } void do_ls( char dirname[] ) /* * list files in directory called dirname */ { DIR *dir_ptr; /* the directory */ struct dirent *direntp; /* each entry */ if ( ( dir_ptr = opendir( dirname ) ) == NULL ) fprintf(stderr,"ls2: cannot open %s\n", dirname); else { while ( ( direntp = readdir( dir_ptr ) ) != NULL ) { if (strcmp(direntp->d_name,".")==0 || strcmp(direntp->d_name,"..")==0) continue; dostat( direntp->d_name ); } closedir(dir_ptr); } } void dostat( char *filename ) { struct stat info; if ( stat(filename, &info) == -1 ) /* cannot stat */ perror( filename ); /* say why */ else /* else show info */ show_file_info( filename, &info ); } void show_file_info( char *filename, struct stat *info_p ) /* * display the info about 'filename'. The info is stored in struct at *info_p */ { char *uid_to_name(), *ctime(), *gid_to_name(), *filemode(); void mode_to_letters(); char modestr[11]; mode_to_letters( info_p->st_mode, modestr ); printf( "%s" , modestr ); printf( "%4d " , (int) info_p->st_nlink); printf( "%-8s " , uid_to_name(info_p->st_uid) ); printf( "%-8s " , gid_to_name(info_p->st_gid) ); printf( "%8ld " , (long)info_p->st_size); printf( "%.12s ", 4+ctime(&info_p->st_mtime)); printf( "%s\n" , filename ); } /* * utility functions */ /* * This function takes a mode value and a char array * and puts into the char array the file type and the * nine letters that correspond to the bits in mode. * NOTE: It does not code setuid, setgid, and sticky * codes */ void mode_to_letters( int mode, char str[] ) { strcpy( str, "----------" ); /* default=no perms */ if ( S_ISDIR(mode) ) str[0] = 'd'; /* directory? */ if ( S_ISCHR(mode) ) str[0] = 'c'; /* char devices */ if ( S_ISBLK(mode) ) str[0] = 'b'; /* block device */ if ( mode & S_IRUSR ) str[1] = 'r'; /* 3 bits for user */ if ( mode & S_IWUSR ) str[2] = 'w'; if ( mode & S_IXUSR ) str[3] = 'x'; if ( mode & S_IRGRP ) str[4] = 'r'; /* 3 bits for group */ if ( mode & S_IWGRP ) str[5] = 'w'; if ( mode & S_IXGRP ) str[6] = 'x'; if ( mode & S_IROTH ) str[7] = 'r'; /* 3 bits for other */ if ( mode & S_IWOTH ) str[8] = 'w'; if ( mode & S_IXOTH ) str[9] = 'x'; } #include <pwd.h> char *uid_to_name( uid_t uid ) /* * returns pointer to username associated with uid, uses getpw() */ { struct passwd *getpwuid(), *pw_ptr; static char numstr[10]; if ( ( pw_ptr = getpwuid( uid ) ) == NULL ){ sprintf(numstr,"%d", uid); return numstr; } else return pw_ptr->pw_name ; } #include <grp.h> char *gid_to_name( gid_t gid ) /* * returns pointer to group number gid. used getgrgid(3) */ { struct group *getgrgid(), *grp_ptr; static char numstr[10]; if ( ( grp_ptr = getgrgid(gid) ) == NULL ){ sprintf(numstr,"%d", gid); return numstr; } else return grp_ptr->gr_name; }
Maintained by John Loomis, last updated 27 September 2006