rev |
line source |
nuclear@0
|
1 /*! gcc -pedantic -Wall -g -o ls ls.c */
|
nuclear@0
|
2 #include <stdio.h>
|
nuclear@0
|
3 #include <stdlib.h>
|
nuclear@0
|
4 #include <string.h>
|
nuclear@0
|
5 #include <errno.h>
|
nuclear@0
|
6 #include <time.h>
|
nuclear@0
|
7 #include <unistd.h>
|
nuclear@0
|
8 #include <fcntl.h>
|
nuclear@0
|
9 #include <dirent.h>
|
nuclear@0
|
10 #include <pwd.h>
|
nuclear@0
|
11 #include <grp.h>
|
nuclear@0
|
12 #include <sys/types.h>
|
nuclear@0
|
13 #include <sys/stat.h>
|
nuclear@0
|
14
|
nuclear@0
|
15 enum {SORT_NONE, SORT_NAME};
|
nuclear@0
|
16
|
nuclear@0
|
17 enum {
|
nuclear@0
|
18 OPT_LONG = 1,
|
nuclear@0
|
19 OPT_ALL = 2,
|
nuclear@0
|
20 OPT_DIR = 4,
|
nuclear@0
|
21 OPT_CLASS = 8,
|
nuclear@0
|
22 OPT_HUMAN = 16,
|
nuclear@0
|
23 OPT_INODES = 32
|
nuclear@0
|
24 };
|
nuclear@0
|
25
|
nuclear@0
|
26 int proc_opt(char opt);
|
nuclear@0
|
27 int ls_dir(char *dir);
|
nuclear@0
|
28
|
nuclear@0
|
29 unsigned int flags = 0;
|
nuclear@0
|
30 int sort_by = SORT_NAME;
|
nuclear@0
|
31 int term_col = 80; /* TODO: detect columns */
|
nuclear@0
|
32
|
nuclear@0
|
33 int main(int argc, char **argv)
|
nuclear@0
|
34 {
|
nuclear@0
|
35 int i, did_one = 0;
|
nuclear@0
|
36
|
nuclear@0
|
37 for(i=1; i<argc; i++) {
|
nuclear@0
|
38 if(argv[i][0] == '-') {
|
nuclear@0
|
39 char *ptr = argv[i] + 1;
|
nuclear@0
|
40 while(ptr && *ptr) {
|
nuclear@0
|
41 if(proc_opt(*ptr++) == -1) {
|
nuclear@0
|
42 fprintf(stderr, "%s: invalid option -- %c\n", argv[0], *(ptr - 1));
|
nuclear@0
|
43 return 1;
|
nuclear@0
|
44 }
|
nuclear@0
|
45 }
|
nuclear@0
|
46 } else {
|
nuclear@0
|
47 printf("%s:\n", argv[i]);
|
nuclear@0
|
48 if(ls_dir(argv[i]) == -1) {
|
nuclear@0
|
49 fprintf(stderr, "%s: %s: %s\n", argv[0], argv[i], strerror(errno));
|
nuclear@0
|
50 }
|
nuclear@0
|
51 did_one = 1;
|
nuclear@0
|
52 }
|
nuclear@0
|
53 }
|
nuclear@0
|
54
|
nuclear@0
|
55 if(!did_one) {
|
nuclear@0
|
56 ls_dir(".");
|
nuclear@0
|
57 }
|
nuclear@0
|
58
|
nuclear@0
|
59 return 0;
|
nuclear@0
|
60 }
|
nuclear@0
|
61
|
nuclear@0
|
62 int proc_opt(char opt)
|
nuclear@0
|
63 {
|
nuclear@0
|
64 switch(opt) {
|
nuclear@0
|
65 case 'a':
|
nuclear@0
|
66 flags |= OPT_ALL;
|
nuclear@0
|
67 break;
|
nuclear@0
|
68
|
nuclear@0
|
69 case 'l':
|
nuclear@0
|
70 flags |= OPT_LONG;
|
nuclear@0
|
71 break;
|
nuclear@0
|
72
|
nuclear@0
|
73 case 'F':
|
nuclear@0
|
74 flags |= OPT_CLASS;
|
nuclear@0
|
75 break;
|
nuclear@0
|
76
|
nuclear@0
|
77 case 'h':
|
nuclear@0
|
78 flags |= OPT_HUMAN;
|
nuclear@0
|
79 break;
|
nuclear@0
|
80
|
nuclear@0
|
81 case 'i':
|
nuclear@0
|
82 flags |= OPT_INODES;
|
nuclear@0
|
83 break;
|
nuclear@0
|
84
|
nuclear@0
|
85 default:
|
nuclear@0
|
86 return -1;
|
nuclear@0
|
87 }
|
nuclear@0
|
88 return 0;
|
nuclear@0
|
89 }
|
nuclear@0
|
90
|
nuclear@0
|
91 struct entry {
|
nuclear@0
|
92 char *name;
|
nuclear@0
|
93 struct stat st;
|
nuclear@0
|
94 struct entry *next;
|
nuclear@0
|
95 };
|
nuclear@0
|
96
|
nuclear@0
|
97 int print_entry(struct entry *ent)
|
nuclear@0
|
98 {
|
nuclear@0
|
99 int len = strlen(ent->name);
|
nuclear@0
|
100
|
nuclear@0
|
101 if(flags & OPT_LONG) {
|
nuclear@0
|
102 int i;
|
nuclear@0
|
103 struct passwd *pwd;
|
nuclear@0
|
104 struct group *grp;
|
nuclear@0
|
105 char tmbuf[128];
|
nuclear@0
|
106
|
nuclear@0
|
107 switch(ent->st.st_mode & S_IFMT) {
|
nuclear@0
|
108 case S_IFSOCK:
|
nuclear@0
|
109 putchar('s');
|
nuclear@0
|
110 break;
|
nuclear@0
|
111 case S_IFLNK:
|
nuclear@0
|
112 putchar('l');
|
nuclear@0
|
113 break;
|
nuclear@0
|
114 case S_IFBLK:
|
nuclear@0
|
115 putchar('b');
|
nuclear@0
|
116 break;
|
nuclear@0
|
117 case S_IFDIR:
|
nuclear@0
|
118 putchar('d');
|
nuclear@0
|
119 break;
|
nuclear@0
|
120 case S_IFCHR:
|
nuclear@0
|
121 putchar('c');
|
nuclear@0
|
122 break;
|
nuclear@0
|
123 case S_IFIFO:
|
nuclear@0
|
124 putchar('f');
|
nuclear@0
|
125 break;
|
nuclear@0
|
126 default:
|
nuclear@0
|
127 putchar('-');
|
nuclear@0
|
128 }
|
nuclear@0
|
129
|
nuclear@0
|
130 for(i=0; i<3; i++) {
|
nuclear@0
|
131 int s = (2 - i) * 3;
|
nuclear@0
|
132 unsigned int val = (ent->st.st_mode >> s) & 7;
|
nuclear@0
|
133
|
nuclear@0
|
134 putchar(val & 4 ? 'r' : '-');
|
nuclear@0
|
135 putchar(val & 2 ? 'w' : '-');
|
nuclear@0
|
136 putchar(val & 1 ? 'x' : '-');
|
nuclear@0
|
137 }
|
nuclear@0
|
138 printf(" %3d ", (int)ent->st.st_nlink);
|
nuclear@0
|
139
|
nuclear@0
|
140 if(!(pwd = getpwuid(ent->st.st_uid))) {
|
nuclear@0
|
141 printf("%d ", ent->st.st_uid);
|
nuclear@0
|
142 } else {
|
nuclear@0
|
143 printf("%s ", pwd->pw_name);
|
nuclear@0
|
144 }
|
nuclear@0
|
145 if(!(grp = getgrgid(ent->st.st_gid))) {
|
nuclear@0
|
146 printf("%d ", ent->st.st_gid);
|
nuclear@0
|
147 } else {
|
nuclear@0
|
148 printf("%s ", grp->gr_name);
|
nuclear@0
|
149 }
|
nuclear@0
|
150
|
nuclear@0
|
151 sprintf(tmbuf, "%s", ctime(&ent->st.st_mtime));
|
nuclear@0
|
152 tmbuf[strlen(tmbuf) - 1] = 0;
|
nuclear@0
|
153
|
nuclear@0
|
154 printf("%6ld %s ", (long)ent->st.st_size, tmbuf);
|
nuclear@0
|
155 }
|
nuclear@0
|
156
|
nuclear@0
|
157 fputs(ent->name, stdout);
|
nuclear@0
|
158
|
nuclear@0
|
159 if(flags & OPT_CLASS) {
|
nuclear@0
|
160 if(S_ISDIR(ent->st.st_mode)) {
|
nuclear@0
|
161 putchar('/');
|
nuclear@0
|
162 len++;
|
nuclear@0
|
163 } else if(ent->st.st_mode & S_IXUSR) {
|
nuclear@0
|
164 putchar('*');
|
nuclear@0
|
165 len++;
|
nuclear@0
|
166 }
|
nuclear@0
|
167 }
|
nuclear@0
|
168
|
nuclear@0
|
169 return len;
|
nuclear@0
|
170 }
|
nuclear@0
|
171
|
nuclear@0
|
172 void print_list(struct entry *arr, int count)
|
nuclear@0
|
173 {
|
nuclear@0
|
174 int i, j, ncol, longest = 0;
|
nuclear@0
|
175
|
nuclear@0
|
176 for(i=0; i<count; i++) {
|
nuclear@0
|
177 int len = strlen(arr[i].name) + 2;
|
nuclear@0
|
178 if(len > longest) {
|
nuclear@0
|
179 longest = len;
|
nuclear@0
|
180 }
|
nuclear@0
|
181 }
|
nuclear@0
|
182
|
nuclear@0
|
183 if(isatty(1) && !(flags & OPT_LONG)) {
|
nuclear@0
|
184 ncol = term_col / longest;
|
nuclear@0
|
185 if(!ncol) ncol = 1;
|
nuclear@0
|
186 } else {
|
nuclear@0
|
187 ncol = 1;
|
nuclear@0
|
188 }
|
nuclear@0
|
189
|
nuclear@0
|
190 for(i=0; i<count; i++) {
|
nuclear@0
|
191 int len;
|
nuclear@0
|
192
|
nuclear@0
|
193 len = print_entry(&arr[i]);
|
nuclear@0
|
194
|
nuclear@0
|
195 if(i < count - 1 && (i % ncol) == ncol - 1) {
|
nuclear@0
|
196 putchar('\n');
|
nuclear@0
|
197 } else {
|
nuclear@0
|
198 for(j=0; j<longest - len; j++) {
|
nuclear@0
|
199 putchar(' ');
|
nuclear@0
|
200 }
|
nuclear@0
|
201 }
|
nuclear@0
|
202 }
|
nuclear@0
|
203 putchar('\n');
|
nuclear@0
|
204 }
|
nuclear@0
|
205
|
nuclear@0
|
206 int cmp_func(const void *e1, const void *e2)
|
nuclear@0
|
207 {
|
nuclear@0
|
208 const struct entry *ent1, *ent2;
|
nuclear@0
|
209 const char *n1, *n2;
|
nuclear@0
|
210
|
nuclear@0
|
211 ent1 = e1;
|
nuclear@0
|
212 ent2 = e2;
|
nuclear@0
|
213
|
nuclear@0
|
214 switch(sort_by) {
|
nuclear@0
|
215 case SORT_NAME:
|
nuclear@0
|
216 default:
|
nuclear@0
|
217 n1 = ent1->name;
|
nuclear@0
|
218 n2 = ent2->name;
|
nuclear@0
|
219 }
|
nuclear@0
|
220 return strcmp(n1, n2);
|
nuclear@0
|
221 }
|
nuclear@0
|
222
|
nuclear@0
|
223 int ls_dir(char *dname)
|
nuclear@0
|
224 {
|
nuclear@0
|
225 int i, cwd_fd = -1, saved_err, ent_count = 0;
|
nuclear@0
|
226 DIR *dir = 0;
|
nuclear@0
|
227 struct dirent *ent = 0;
|
nuclear@0
|
228 struct entry *earr = 0, *elist = 0, *enode = 0;
|
nuclear@0
|
229
|
nuclear@0
|
230
|
nuclear@0
|
231 if(strcmp(dname, ".") != 0) {
|
nuclear@0
|
232 if((cwd_fd = open(".", O_RDONLY)) == -1) {
|
nuclear@0
|
233 goto err;
|
nuclear@0
|
234 }
|
nuclear@0
|
235 chdir(dname);
|
nuclear@0
|
236 }
|
nuclear@0
|
237
|
nuclear@0
|
238 if(!(dir = opendir("."))) {
|
nuclear@0
|
239 goto err;
|
nuclear@0
|
240 }
|
nuclear@0
|
241
|
nuclear@0
|
242 if(!(elist = malloc(sizeof *elist))) {
|
nuclear@0
|
243 goto err;
|
nuclear@0
|
244 }
|
nuclear@0
|
245 elist->name = 0;
|
nuclear@0
|
246 elist->next = 0;
|
nuclear@0
|
247
|
nuclear@0
|
248 while((ent = readdir(dir))) {
|
nuclear@0
|
249 struct stat st;
|
nuclear@0
|
250
|
nuclear@0
|
251 if(ent->d_name[0] == '.' && !(flags & OPT_ALL)) {
|
nuclear@0
|
252 continue;
|
nuclear@0
|
253 }
|
nuclear@0
|
254
|
nuclear@0
|
255 if(lstat(ent->d_name, &st) == -1) {
|
nuclear@0
|
256 goto err;
|
nuclear@0
|
257 }
|
nuclear@0
|
258
|
nuclear@0
|
259 if(!(enode = malloc(sizeof *enode))) {
|
nuclear@0
|
260 goto err;
|
nuclear@0
|
261 }
|
nuclear@0
|
262 if(!(enode->name = malloc(strlen(ent->d_name) + 1))) {
|
nuclear@0
|
263 goto err;
|
nuclear@0
|
264 }
|
nuclear@0
|
265 strcpy(enode->name, ent->d_name);
|
nuclear@0
|
266 memcpy(&enode->st, &st, sizeof st);
|
nuclear@0
|
267
|
nuclear@0
|
268 enode->next = elist->next;
|
nuclear@0
|
269 elist->next = enode;
|
nuclear@0
|
270 ent_count++;
|
nuclear@0
|
271 }
|
nuclear@0
|
272 closedir(dir);
|
nuclear@0
|
273 dir = 0;
|
nuclear@0
|
274
|
nuclear@0
|
275 /* change the list into an array, don't feel like writing list mergesorts */
|
nuclear@0
|
276 if(!(earr = malloc(ent_count * sizeof *earr))) {
|
nuclear@0
|
277 goto err;
|
nuclear@0
|
278 }
|
nuclear@0
|
279
|
nuclear@0
|
280 i = 0;
|
nuclear@0
|
281 enode = elist->next;
|
nuclear@0
|
282 while(enode) {
|
nuclear@0
|
283 earr[i].name = enode->name;
|
nuclear@0
|
284 earr[i++].st = enode->st;
|
nuclear@0
|
285 enode = enode->next;
|
nuclear@0
|
286 }
|
nuclear@0
|
287 if(sort_by != SORT_NONE) {
|
nuclear@0
|
288 qsort(earr, ent_count, sizeof *earr, cmp_func);
|
nuclear@0
|
289 }
|
nuclear@0
|
290
|
nuclear@0
|
291 print_list(earr, ent_count);
|
nuclear@0
|
292
|
nuclear@0
|
293 if(cwd_fd != -1) {
|
nuclear@0
|
294 fchdir(cwd_fd);
|
nuclear@0
|
295 }
|
nuclear@0
|
296 return 0;
|
nuclear@0
|
297
|
nuclear@0
|
298 err:
|
nuclear@0
|
299 saved_err = errno;
|
nuclear@0
|
300 free(earr);
|
nuclear@0
|
301 /*free_entry_list(elist);*/
|
nuclear@0
|
302 free(enode->name);
|
nuclear@0
|
303 free(enode);
|
nuclear@0
|
304 if(dir) {
|
nuclear@0
|
305 closedir(dir);
|
nuclear@0
|
306 }
|
nuclear@0
|
307 if(cwd_fd != -1) {
|
nuclear@0
|
308 fchdir(cwd_fd);
|
nuclear@0
|
309 close(cwd_fd);
|
nuclear@0
|
310 }
|
nuclear@0
|
311 errno = saved_err;
|
nuclear@0
|
312 return -1;
|
nuclear@0
|
313 }
|