- 完善ls练习一的功能:
- 排序,使用qsort
- 分栏,计算宽度和行数
- 文件“.”的显示需要由-a选项来选择
- 详细信息的显示,-l选项
- 将stat结构体中的st_mode——16位二进制数转换成10位的字符串
- 15-12:type
- 11:suid
- 10:sgid
- 9:sticky
- 8-6:user
- 5-3:group
- 2-0:other
- /etc/passwd文件中包含了用户信息,每行对应一个用户,不同的属性按照分号‘:’隔开。
- 该文件并未包含所有的用户,在某些网络计算系统中,用户需要登录到任何一台主机上,会有NIS统一地进行身份验证,本地保存的只是一个用户子集。
- getpwuid系统调用具有较好的可移植性,会从NIS中查找如果在本地找不到的话
- /etc/group包含了组信息,字段分别为1,组名;2,组密码;3,组ID;4,组成员列表
- 一个用户可以属于多个组的
- getgrgid可以用来访问组列表,移植性同上getpwuid
1 #include <stdio.h> 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include <dirent.h> 5 #include <pwd.h> 6 #include <grp.h> 7 #include <string.h> 8 #include <time.h> 9 10 void do_ls(char[]); 11 void show_file_info(char * filename , struct stat * statbufp ); 12 void mode2letter(int mode , char str[]); 13 void print_uid2name(uid_t uid ); 14 void print_gid2name(gid_t gid ); 15 16 int main(int ac , char * av[]) 17 { 18 if(ac == 1 ) 19 { 20 do_ls("."); 21 } 22 else 23 { 24 while( -- ac ) 25 { 26 printf("%s: ", * (++ av) ); 27 do_ls(*av); 28 } 29 } 30 return 0 ; 31 } 32 33 void do_ls(char dirname[]) 34 { 35 DIR * dir_ptr ; 36 struct dirent * direntp ; 37 struct stat statbuf ; 38 39 if( ( dir_ptr = opendir(dirname) )== NULL ) 40 { 41 fprintf(stderr, "ls1 can not open %s ", dirname ); 42 } 43 else 44 { 45 while( ( direntp = readdir(dir_ptr ) ) != NULL ) 46 { 47 if( stat(direntp -> d_name , &statbuf) == -1 ) 48 { 49 perror(direntp -> d_name ); 50 } 51 else 52 { 53 show_file_info( direntp -> d_name , &statbuf); 54 } 55 } 56 } 57 58 closedir(dir_ptr); 59 } 60 61 void show_file_info( char * filename, struct stat * statbufp ) 62 { 63 char modestr[11]; // include ' ' so 10 + 1 = 11 64 65 mode2letter(statbufp -> st_mode , modestr) ; 66 printf("%s", modestr ); 67 68 printf("%4d", (int)statbufp -> st_nlink ) ; 69 print_uid2name( statbufp -> st_uid ) ; 70 print_gid2name( statbufp -> st_gid ) ; 71 printf("%8ld", (long) (statbufp -> st_size) ); 72 printf(" %12.12s", (char*)(4 + ctime(&(statbufp -> st_mtime)) )); 73 printf(" %s ",filename ); 74 } 75 76 void mode2letter(int mode , char str[]) 77 { 78 strcpy(str , "----------"); 79 80 if( S_ISDIR( mode )) 81 str[0] = 'd' ; 82 else if( S_ISCHR( mode )) 83 str[0] = 'c' ; // else for efficience 84 else if( S_ISBLK( mode )) 85 str[0] = 'b' ; 86 87 if( mode & S_IRUSR ) 88 str[1] = 'r' ; 89 if( mode & S_IWUSR ) 90 str[2] = 'w' ; 91 if(mode & S_IXUSR ) 92 str[3] = 'x' ; 93 94 if( mode & S_IRGRP ) 95 str[4] = 'r' ; 96 if( mode & S_IWGRP ) 97 str[5] = 'w' ; 98 if( mode & S_IXGRP ) 99 str[6] = 'x' ; 100 101 if( mode & S_IROTH ) 102 str[7] = 'r' ; 103 if( mode & S_IWOTH ) 104 str[8] = 'w' ; 105 if( mode & S_IXOTH ) 106 str[9] = 'x' ; 107 } 108 109 void print_uid2name( uid_t uid ) 110 { 111 struct passwd * passwdbufp ; 112 113 if(( passwdbufp = getpwuid(uid)) != (struct passwd *)NULL ) // Except for error 114 { 115 printf( "%-8s" , passwdbufp -> pw_name ) ; 116 } 117 else 118 { 119 printf( "%8d" , uid) ; 120 } 121 122 } 123 124 void print_gid2name(gid_t gid) 125 { 126 struct group * grp_ptr ; 127 if(( grp_ptr = getgrgid(gid)) != (struct group * )NULL ) 128 { 129 printf("%-8s" , grp_ptr -> gr_name ) ; 130 } 131 else 132 { 133 printf("%8d" , gid ) ; 134 } 135 }
ls2.c完成了 ls -l 的功能。但是有几点不足之处:
- 不显示总数,这个容易解决
- 未排序
- 不支持参数-a
- 假设参数只是目录名
- 不能显示指定目录的信息
以上代码在OpenSuse Leap42.1上测试通过,参考原书《Unix/Linux编程实践教程》,但是含有个人修改部分,不影响功能。