ls.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /* SPDX-License-Identifier: BSD-3-Clause */
  2. /*
  3. * Copyright (C) 2022, 2023 Ferass El Hafidi <vitali64pmemail@protonmail.com>
  4. * Copyright (C) 2022 Leah Rowe <leah@libreboot.org>
  5. */
  6. #include <unistd.h>
  7. #include <string.h>
  8. #include <dirent.h>
  9. #include <fcntl.h>
  10. #include <stdio.h>
  11. #include <errno.h>
  12. #include <stdlib.h>
  13. #include <sys/stat.h>
  14. #include <sys/types.h>
  15. #include <pwd.h>
  16. #include <grp.h>
  17. #include <time.h>
  18. #include <sys/ioctl.h>
  19. #define REQ_PRINT_USAGE /* Require print_usage() from ../common/common.h */
  20. #define REQ_ERRPRINT /* Require errprint() from ../common/common.h */
  21. #define DESCRIPTION "Print <directory>'s contents to standard output.\
  22. If no directory is specified, print the current directory's contents."
  23. #define OPERANDS "[-1aACimlpgno] [directory]"
  24. #include "../common/common.h"
  25. char *argv0;
  26. char param[256];
  27. int ls(char *path);
  28. void printUsage(char *params);
  29. int main(int argc, char *argv[]) {
  30. int status = 0;
  31. int success = 0;
  32. int argument, i;
  33. argv0 = strdup(argv[0]);
  34. for (i=0; i<256; i++) {
  35. param[i]=0;
  36. }
  37. while ((argument = getopt(argc, argv, OPERANDS)) != -1) {
  38. if (argument == '?') {
  39. print_usage(argv[0], DESCRIPTION, OPERANDS, VERSION);
  40. return 1;
  41. }
  42. param[argument] = argument;
  43. if (argument=='C') {
  44. param['1'] = 0;
  45. param['m'] = 0;
  46. }
  47. else if (argument=='1' || argument=='g' || argument=='n') {
  48. param['m'] = 0;
  49. param['C'] = 0;
  50. }
  51. else if (argument=='m') {
  52. param['1'] = 0;
  53. param['C'] = 0;
  54. }
  55. if (argument=='o' || argument=='n' || argument=='g') {
  56. param['l'] = 'l';
  57. }
  58. } argc -= optind; argv += optind;
  59. if (status) {
  60. if(!param['1']) printf("\n");
  61. return status;
  62. }
  63. if (!param['C'] && !param['m'] && !param['1'])
  64. param['1'] = '1';
  65. if (param['l'] || param['g']) {
  66. param['m'] = 0;
  67. param['C'] = 0;
  68. param['1'] = '1';
  69. }
  70. for (i = 0; i < argc; i++) {
  71. if ((success |= (argv[i][0] != '-' ? 1 : 0))) {
  72. if (!strcmp(argv[i],".")) status |= ls("./");
  73. else status |= ls(argv[i]);
  74. }
  75. }
  76. i = success ? status : ls("./");
  77. if (!param['1'])
  78. printf("\n");
  79. return i;
  80. }
  81. int ls(char *path) {
  82. int file, dotname, cwdname, prevdir, dot;
  83. long unsigned int cols_used;
  84. DIR *directory;
  85. struct stat file_status;
  86. struct dirent *dirtree;
  87. struct winsize columns;
  88. char *name, file_moddate[256];
  89. char file_modes[] = "----------";
  90. directory = opendir(path);
  91. if (param['C']) {
  92. ioctl(STDOUT_FILENO, TIOCGWINSZ, &columns);
  93. cols_used = 0;
  94. }
  95. if (directory == NULL) {
  96. file = open(path, O_RDONLY);
  97. if (file == -1) return errprint(argv0, path, errno);
  98. printf("%s\n", path);
  99. if (close(file) == -1)
  100. return errprint(argv0, path, errno);
  101. }
  102. while ((dirtree = readdir(directory)) != NULL) {
  103. name = dirtree->d_name;
  104. cwdname = strcmp(name, ".") ? 0 : 1;
  105. prevdir = strcmp(name, "..") ? 0 : 1;
  106. dotname = (name[0]=='.' && !cwdname && !prevdir) ? 1 : 0;
  107. dot = dotname | prevdir | cwdname;
  108. if (dot && !param['a'] && !param['A']) continue;
  109. if ((cwdname || prevdir) && param['A']) continue;
  110. if (param['i']) printf("%lu ", dirtree->d_ino);
  111. if (param['l']) {
  112. char *fullpath = malloc(strlen(path) + strlen(name) + 2);
  113. if (fullpath) {
  114. strcpy(fullpath, path);
  115. if (path[strlen(path) - 1] != '/') strcat(fullpath, "/");
  116. strcat(fullpath, name);
  117. }
  118. lstat(fullpath, &file_status);
  119. /* File modes */
  120. /* File type */
  121. {
  122. if (S_ISBLK(file_status.st_mode)) file_modes[0] = 'b';
  123. else if (S_ISCHR(file_status.st_mode)) file_modes[0] = 'c';
  124. else if (S_ISDIR(file_status.st_mode)) file_modes[0] = 'd';
  125. else if (S_ISFIFO(file_status.st_mode)) file_modes[0] = 'p';
  126. else if (S_ISREG(file_status.st_mode)) file_modes[0] = '-';
  127. else if (S_ISLNK(file_status.st_mode)) file_modes[0] = 'l';
  128. else file_modes[0] = 's';
  129. }
  130. /* User */
  131. {
  132. if (file_status.st_mode & S_IRUSR) file_modes[1] = 'r';
  133. if (file_status.st_mode & S_IWUSR) file_modes[2] = 'w';
  134. if (file_status.st_mode & S_IXUSR) file_modes[3] = 'x';
  135. }
  136. /* Group */
  137. {
  138. if (file_status.st_mode & S_IRGRP) file_modes[4] = 'r';
  139. if (file_status.st_mode & S_IWGRP) file_modes[5] = 'w';
  140. if (file_status.st_mode & S_IXGRP) file_modes[6] = 'x';
  141. }
  142. /* Others */
  143. {
  144. if (file_status.st_mode & S_IROTH) file_modes[7] = 'r';
  145. if (file_status.st_mode & S_IWOTH) file_modes[8] = 'w';
  146. if (file_status.st_mode & S_IXOTH) file_modes[9] = 'x';
  147. }
  148. printf("%s ", file_modes);
  149. /* Number of links */
  150. printf("%lu ", (long unsigned int)file_status.st_nlink);
  151. /* Owner name/uid */
  152. if (!param['g'])
  153. /* This recursiveness is needed for whatever reason,
  154. * else it doesn't work...
  155. */
  156. if (!param['n'])
  157. printf("%s ", getpwuid(file_status.st_uid)->pw_name);
  158. if (param['n']) printf("%u ", file_status.st_uid);
  159. /* Group name/gid */
  160. if (!param['o'])
  161. if (!param['n']) printf("%s ", getgrgid(file_status.st_gid)->gr_name);
  162. if (param['n']) printf("%u ", file_status.st_gid);
  163. /* Size of file */
  164. printf("%lu ", file_status.st_size);
  165. /* Date and time */
  166. int strftime_status = strftime(file_moddate, sizeof(file_moddate),
  167. "%b %e %H:%MM", localtime(&file_status.st_mtime));
  168. /* It should be st_mtim right? */
  169. file_moddate[strlen(file_moddate) - 1] = 0; /* Remove newline */
  170. printf("%s ", strftime_status ? file_moddate : "<strftime() returned 0>");
  171. free(fullpath);
  172. }
  173. printf("%s", name);
  174. if (param['p']) {
  175. char *fullpath = malloc(strlen(path) + strlen(name) + 2);
  176. if (fullpath) {
  177. strcpy(fullpath, path);
  178. if (path[strlen(path) - 1] != '/') strcat(fullpath, "/");
  179. strcat(fullpath, name);
  180. }
  181. stat(fullpath, &file_status);
  182. if (S_ISDIR(file_status.st_mode)) printf("/");
  183. free(fullpath);
  184. }
  185. if (param['C']) {
  186. if (cols_used < (long unsigned int)((columns.ws_col) / 12)) {
  187. for (long unsigned int i = strlen(name); i < 11; i++) printf(" ");
  188. cols_used++;
  189. }
  190. if (cols_used == (long unsigned int)((columns.ws_col) / 12)) {
  191. printf("\n");
  192. cols_used = 0;
  193. }
  194. }
  195. else if (param['1'])
  196. printf("\n");
  197. else if (param['m'])
  198. printf(", ");
  199. }
  200. closedir(directory);
  201. return errprint(argv0, path, errno);
  202. }