#include void dprint(int fd, char *par, int left, int rec) { printf("%s/:\n", par); char *pend = par + strlen(par); snprintf(pend, left, "/"); left--; pend = par + strlen(par); DIR *dir = fdopendir(fd); if (!dir) err(-1, "fdopendir"); struct dirent des, *de; int ret; while (1) { ret = readdir_r(dir, &des, &de); if (ret) errx(-1, "readdir_r %s", strerror(ret)); if (!de) break; int used = snprintf(pend, left, "%s", de->d_name); if (used >= left) errx(-1, "long filenames!"); char *fn = par; struct stat st; if (stat(fn, &st)) err(-1, "stat"); char spec; if (S_ISDIR(st.st_mode)) spec = 'd'; else if (S_ISSOCK(st.st_mode)) spec = 's'; else spec = '-'; printf("%crwxr-xr-x %ld %s\n", spec, (long)st.st_size, de->d_name); } if (!rec) { if (closedir(dir) == -1) err(-1, "closedir"); return; } // recursive list *pend = 0; rewinddir(dir); while (1) { ret = readdir_r(dir, &des, &de); if (ret) errx(-1, "readdir_r %s", strerror(ret)); if (!de) break; char *tn = de->d_name; if (strncmp(tn, "..", 3) == 0 || strncmp(tn, ".", 2) == 0) continue; snprintf(pend, left, "%s", tn); char *fn = par; struct stat st; if (stat(fn, &st)) err(-1, "stat"); if (S_ISDIR(st.st_mode)) { int tfd = open(fn, O_RDONLY | O_DIRECTORY, 0); if (tfd < 0) err(-1, "rec open"); dprint(tfd, par, left - strlen(pend), 1); // dprint closes tfd } } if (closedir(dir) == -1) err(-1, "closedir"); } __attribute__((noreturn)) void usage(void) { fprintf(stderr, "%s [-R]\n" "-R recurse subdirectories\n" "\n", "ls"); exit(-1); } int main(int argc, char **argv) { int rec = 0; int ch; while ((ch = getopt(argc, argv, "R")) != -1) { switch (ch) { case 'R': rec = 1; break; default: usage(); break; } } char *start; int rem = argc - optind; if (rem == 0) start = "."; else if (rem == 1) start = argv[optind]; else usage(); int fd; if ((fd = open(start, O_RDONLY | O_DIRECTORY, 0)) == -1) err(-1, "open %s", start); char pbuf[256]; strncpy(pbuf, start, sizeof(pbuf)); dprint(fd, pbuf, sizeof(pbuf) - strlen(pbuf), rec); close(fd); return 0; }