00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #define WANT_LSDIR_FIXEDx
00022 #define AUPLS_FULL
00023
00024 #include "defs.h"
00025 #include <dirent.h>
00026 #include <pwd.h>
00027 #include <grp.h>
00028
00029 #define USAGE "Usage: aupls [-Rd] [dir]\n"
00030
00031 static long total_entries = 0, total_dirs = 0;
00032
00033 typedef enum {SHOW_PATH, SHOW_INFO} SHOW_OP;
00034
00035 struct traverse_info {
00036 bool ti_recursive;
00037 char *ti_name;
00038 struct stat ti_stat;
00039 bool (*ti_fcn)(struct traverse_info *, SHOW_OP);
00040 };
00041
00042 #define TYPE(b) ((statp->st_mode & (S_IFMT)) == (b))
00043 #define MODE(b) ((statp->st_mode & (b)) == (b))
00044
00045 static void print_mode(const struct stat *statp)
00046 {
00047 if (TYPE(S_IFBLK))
00048 putchar('b');
00049 else if (TYPE(S_IFCHR))
00050 putchar('c');
00051 else if (TYPE(S_IFDIR))
00052 putchar('d');
00053 else if (TYPE(S_IFIFO))
00054 putchar('p');
00055 else if (TYPE(S_IFREG))
00056 putchar('-');
00057 else if (TYPE(S_IFLNK))
00058 putchar('l');
00059 else if (TYPE(S_IFSOCK))
00060 putchar('s');
00061 else
00062 putchar('?');
00063 putchar(MODE(S_IRUSR) ? 'r' : '-');
00064 putchar(MODE(S_IWUSR) ? 'w' : '-');
00065 if (MODE(S_ISUID)) {
00066 if (MODE(S_IXUSR))
00067 putchar('s');
00068 else
00069 putchar('S');
00070 }
00071 else if (MODE(S_IXUSR))
00072 putchar('x');
00073 else
00074 putchar('-');
00075 putchar(MODE(S_IRGRP) ? 'r' : '-');
00076 putchar(MODE(S_IWGRP) ? 'w' : '-');
00077 if (MODE(S_ISGID)) {
00078 if (MODE(S_IXGRP))
00079 putchar('s');
00080 else
00081 putchar('S');
00082 }
00083 else if (MODE(S_IXGRP))
00084 putchar('x');
00085 else
00086 putchar('-');
00087 putchar(MODE(S_IROTH) ? 'r' : '-');
00088 putchar(MODE(S_IWOTH) ? 'w' : '-');
00089 if (MODE(S_IFDIR) && MODE(S_ISVTX)) {
00090 if (MODE(S_IXOTH))
00091 putchar('t');
00092 else
00093 putchar('T');
00094 }
00095 else if (MODE(S_IXOTH))
00096 putchar('x');
00097 else
00098 putchar('-');
00099 }
00100
00101
00102 #undef TYPE
00103 #undef MODE
00104
00105
00106 static void print_numlinks(const struct stat *statp)
00107 {
00108 printf("%5ld", (long)statp->st_nlink);
00109 }
00110
00111 static void print_owner(const struct stat *statp)
00112 {
00113 struct passwd *pwd = getpwuid(statp->st_uid);
00114
00115 if (pwd == NULL)
00116 printf(" %-8ld", (long)statp->st_uid);
00117 else
00118 printf(" %-8s", pwd->pw_name);
00119 }
00120
00121 static void print_group(const struct stat *statp)
00122 {
00123 struct group *grp = getgrgid(statp->st_gid);
00124
00125 if (grp == NULL)
00126 printf(" %-8ld", (long)statp->st_gid);
00127 else
00128 printf(" %-8s", grp->gr_name);
00129 }
00130
00131 static void print_size(const struct stat *statp)
00132 {
00133 switch (statp->st_mode & S_IFMT) {
00134 case S_IFCHR:
00135 case S_IFBLK:
00136 printf("%4u,%4u", (unsigned)(statp->st_rdev >> 8),
00137 (unsigned)(statp->st_rdev & 0xFF));
00138 break;
00139 default:
00140 printf("%9lu", (unsigned long)statp->st_size);
00141 }
00142 }
00143
00144 static void print_date(const struct stat *statp)
00145 {
00146 time_t now;
00147 double diff;
00148 char buf[100], *fmt;
00149
00150 if (time(&now) == -1) {
00151 printf(" ????????????");
00152 return;
00153 }
00154 diff = difftime(now, statp->st_mtime);
00155 if (diff < 0 || diff > 60 * 60 * 24 * 182.5)
00156 fmt = "%b %e %Y";
00157 else
00158 fmt = "%b %e %H:%M";
00159 strftime(buf, sizeof(buf), fmt, localtime(&statp->st_mtime));
00160 printf(" %s", buf);
00161 }
00162
00163
00164
00165
00166
00167 static long get_max_pathname(const char *path)
00168 {
00169 long max_path;
00170
00171 errno = 0;
00172 max_path = pathconf(path, _PC_PATH_MAX);
00173 if (max_path == -1) {
00174 if (errno == 0 || errno == EINVAL)
00175 max_path = 4096;
00176 else
00177 EC_FAIL
00178 }
00179 return max_path + 1;
00180
00181 EC_CLEANUP_BGN
00182 return -1;
00183 EC_CLEANUP_END
00184 }
00185
00186
00187 static void print_name(const struct stat *statp, const char *name)
00188 {
00189 if (S_ISLNK(statp->st_mode)) {
00190 char *contents = malloc(statp->st_size + 1);
00191 ssize_t n;
00192
00193 if (contents != NULL && (n = readlink(name, contents,
00194 statp->st_size)) != -1) {
00195 contents[n] = '\0';
00196 printf(" %s -> %s", name, contents);
00197 }
00198 else
00199 printf(" %s -> [can't read link]", name);
00200 free(contents);
00201 }
00202 else
00203 printf(" %s", name);
00204 }
00205
00206 static void ls_long(const struct stat *statp, const char *name)
00207 {
00208 print_mode(statp);
00209 print_numlinks(statp);
00210 print_owner(statp);
00211 print_group(statp);
00212 print_size(statp);
00213 print_date(statp);
00214 print_name(statp, name);
00215 putchar('\n');
00216 }
00217
00218 #ifdef WANT_LSLONG
00219
00220 int main(int argc, char *argv[])
00221 {
00222 int i;
00223 struct stat statbuf;
00224
00225 for (i = 1; i < argc; i++) {
00226 ec_neg1( lstat(argv[i], &statbuf) )
00227 ls_long(&statbuf, argv[i]);
00228 }
00229 exit(EXIT_SUCCESS);
00230
00231 EC_CLEANUP_BGN
00232 exit(EXIT_FAILURE);
00233 EC_CLEANUP_END
00234 }
00235
00236 #endif
00237
00238 static char *get_cwd(bool cleanup)
00239 {
00240 static char *cwd = NULL;
00241 static long max_path;
00242
00243 if (cleanup) {
00244 free(cwd);
00245 cwd = NULL;
00246 }
00247 else {
00248 if (cwd == NULL) {
00249 ec_neg1( max_path = get_max_pathname(".") )
00250 ec_null( cwd = malloc((size_t)max_path) )
00251 }
00252 ec_null( getcwd(cwd, max_path) )
00253 return cwd;
00254 }
00255 return NULL;
00256
00257 EC_CLEANUP_BGN
00258 return NULL;
00259 EC_CLEANUP_END
00260 }
00261
00262 static bool print_cwd(bool cleanup)
00263 {
00264 char *cwd;
00265
00266 if (cleanup)
00267 (void)get_cwd(true);
00268 else {
00269 ec_null( cwd = get_cwd(false) )
00270 printf("\n%s:\n", cwd);
00271 }
00272 return true;
00273
00274 EC_CLEANUP_BGN
00275 return false;
00276 EC_CLEANUP_END
00277 }
00278
00279 static bool show_stat(struct traverse_info *p, SHOW_OP op)
00280 {
00281 switch (op) {
00282 case SHOW_PATH:
00283 ec_false( print_cwd(false) )
00284 break;
00285 case SHOW_INFO:
00286 ls_long(&p->ti_stat, p->ti_name);
00287 }
00288 return true;
00289
00290 EC_CLEANUP_BGN
00291 return false;
00292 EC_CLEANUP_END
00293 }
00294
00295 static bool check_parent(int dirfd, const char *name)
00296 {
00297 struct stat statbuf1, statbuf2;
00298
00299 if (name[0] != '/') {
00300 ec_neg1( fstat(dirfd, &statbuf1) )
00301 ec_neg1( lstat("..", &statbuf2) )
00302 if (statbuf1.st_dev != statbuf2.st_dev ||
00303 statbuf1.st_ino != statbuf2.st_ino) {
00304 print_cwd(false);
00305 fprintf(stderr, "Doubly-linked directory encountered (%s).\n",
00306 name);
00307 errno = 0;
00308 EC_FAIL
00309 }
00310 }
00311 return true;
00312
00313 EC_CLEANUP_BGN
00314 return false;
00315 EC_CLEANUP_END
00316 }
00317
00318
00319 static bool do_entry(struct traverse_info *p, bool stat_only);
00320
00321
00322 static bool do_dir(struct traverse_info *p)
00323 {
00324 DIR *sp = NULL;
00325 struct dirent *dp;
00326 int dirfd = -1;
00327 bool result = false;
00328
00329
00330
00331
00332
00333
00334 ec_neg1( dirfd = open(".", O_RDONLY) )
00335
00336
00337
00338
00339
00340
00341
00342
00343 if (strcmp(p->ti_name, "dev") == 0 || strncmp(p->ti_name, "/dev", 4) == 0) {
00344 printf("Skipping directory \"dev\" (even if it's not /dev).\n");
00345 result = true;
00346 EC_CLEANUP
00347 }
00348
00349 if ((sp = opendir(p->ti_name)) == NULL || chdir(p->ti_name) == -1) {
00350 if (errno == EACCES) {
00351 fprintf(stderr, "%s: Permission denied.\n", p->ti_name);
00352 result = true;
00353 EC_CLEANUP
00354 }
00355
00356 else {
00357 syserr_print("do_dir()");
00358 result = true;
00359 EC_CLEANUP
00360 }
00361
00362 }
00363
00364
00365
00366
00367 if (strcmp(p->ti_name, ".") != 0)
00368 ec_false( check_parent(dirfd, p->ti_name) )
00369
00370 if (p->ti_recursive)
00371 ec_false( (p->ti_fcn)(p, SHOW_PATH) )
00372 while (errno = 0, ((dp = readdir(sp)) != NULL)) {
00373 if (strcmp(dp->d_name, ".") == 0 ||
00374 strcmp(dp->d_name, "..") == 0)
00375 continue;
00376 p->ti_name = dp->d_name;
00377 ec_false( do_entry(p, true) )
00378 }
00379 if (errno != 0)
00380 syserr_print("Reading directory (Pass 1)");
00381 if (p->ti_recursive) {
00382 rewinddir(sp);
00383 while (errno = 0, ((dp = readdir(sp)) != NULL)) {
00384 if (strcmp(dp->d_name, ".") == 0 ||
00385 strcmp(dp->d_name, "..") == 0)
00386 continue;
00387 p->ti_name = dp->d_name;
00388 ec_false( do_entry(p, false) )
00389 }
00390 if (errno != 0)
00391 syserr_print("Reading directory (Pass 2)");
00392 }
00393 result = true;
00394 EC_CLEANUP
00395
00396 EC_CLEANUP_BGN
00397 if (dirfd != -1) {
00398 (void)fchdir(dirfd);
00399 (void)close(dirfd);
00400 }
00401 if (sp != NULL)
00402 (void)closedir(sp);
00403 return result;
00404 EC_CLEANUP_END
00405 }
00406
00407 static bool do_entry(struct traverse_info *p, bool stat_only)
00408 {
00409 bool is_dir;
00410
00411 ec_neg1( lstat(p->ti_name, &p->ti_stat) )
00412 is_dir = S_ISDIR(p->ti_stat.st_mode);
00413 if (stat_only) {
00414 total_entries++;
00415 if (is_dir)
00416 total_dirs++;
00417 ec_false( (p->ti_fcn)(p, SHOW_INFO) )
00418 }
00419 else if (is_dir)
00420 ec_false( do_dir(p) )
00421 return true;
00422
00423 EC_CLEANUP_BGN
00424 return false;
00425 EC_CLEANUP_END
00426 }
00427
00428 #ifdef WANT_LSDIR_BUGGY
00429
00430 int main(int argc, char *argv[])
00431 {
00432 bool ok = false;
00433 int i;
00434 DIR *dir = NULL;
00435 struct dirent *entry;
00436 struct stat statbuf;
00437
00438 for (i = 1; i < argc; i++) {
00439 ec_neg1( lstat(argv[i], &statbuf) )
00440 if (!S_ISDIR(statbuf.st_mode)) {
00441 ls_long(&statbuf, argv[i]);
00442 ok = true;
00443 EC_CLEANUP
00444 }
00445 ec_null( dir = opendir(argv[i]) )
00446 while (errno = 0, ((entry = readdir(dir)) != NULL)) {
00447 ec_neg1( lstat(entry->d_name, &statbuf) )
00448 ls_long(&statbuf, entry->d_name);
00449 }
00450 ec_nzero( errno )
00451 }
00452 ok = true;
00453 EC_CLEANUP
00454
00455 EC_CLEANUP_BGN
00456 if (dir != NULL)
00457 (void)closedir(dir);
00458 exit(ok ? EXIT_SUCCESS : EXIT_FAILURE);
00459 EC_CLEANUP_END
00460 }
00461
00462 #endif
00463 #ifdef WANT_LSDIR_FIXED
00464 int main(int argc, char *argv[])
00465 {
00466 bool ok = false;
00467 int i, fd;
00468 DIR *dir = NULL;
00469 struct dirent *entry;
00470 struct stat statbuf;
00471
00472 for (i = 1; i < argc; i++) {
00473 ec_neg1( lstat(argv[i], &statbuf) )
00474 if (!S_ISDIR(statbuf.st_mode)) {
00475 ls_long(&statbuf, argv[i]);
00476 ok = true;
00477 EC_CLEANUP
00478 }
00479
00480 ec_null( dir = opendir(argv[i]) )
00481 ec_neg1( fd = open(".", O_RDONLY) )
00482 ec_neg1( chdir(argv[i]) )
00483 while (errno = 0, ((entry = readdir(dir)) != NULL)) {
00484 ec_neg1( lstat(entry->d_name, &statbuf) )
00485 ls_long(&statbuf, entry->d_name);
00486 }
00487 ec_nzero( errno )
00488 ec_neg1( fchdir(fd) )
00489
00490 }
00491 ok = true;
00492 EC_CLEANUP
00493
00494 EC_CLEANUP_BGN
00495 if (dir != NULL)
00496 (void)closedir(dir);
00497 exit(ok ? EXIT_SUCCESS : EXIT_FAILURE);
00498 EC_CLEANUP_END
00499 }
00500 #endif
00501 #ifdef WANT_LSDIR_ALTERNATIVE
00502 int main(int argc, char *argv[])
00503 {
00504 bool ok = false;
00505 int i, fd, lstat_result, errno_save;
00506 DIR *dir = NULL;
00507 struct dirent *entry;
00508 struct stat statbuf;
00509
00510 for (i = 1; i < argc; i++) {
00511 ec_neg1( lstat(argv[i], &statbuf) )
00512 if (!S_ISDIR(statbuf.st_mode)) {
00513 ls_long(&statbuf, argv[i]);
00514 ok = true;
00515 EC_CLEANUP
00516 }
00517
00518 ec_null( dir = opendir(argv[i]) )
00519 ec_neg1( fd = open(".", O_RDONLY) )
00520 ec_neg1( chdir(argv[i]) )
00521 while (errno = 0, ((entry = readdir(dir)) != NULL)) {
00522 if ((lstat_result = lstat(entry->d_name, &statbuf)) == -1)
00523 break;
00524 ls_long(&statbuf, entry->d_name);
00525 }
00526 errno_save = errno;
00527 ec_neg1( fchdir(fd) )
00528 errno = errno_save;
00529 ec_neg1( lstat_result )
00530 ec_nzero( errno )
00531
00532 }
00533 ok = true;
00534 EC_CLEANUP
00535
00536 EC_CLEANUP_BGN
00537 if (dir != NULL)
00538 (void)closedir(dir);
00539 exit(ok ? EXIT_SUCCESS : EXIT_FAILURE);
00540 EC_CLEANUP_END
00541 }
00542 #endif
00543
00544 static bool ls_one(const char *name)
00545 {
00546 struct stat statbuf;
00547
00548 ec_neg1( lstat(name, &statbuf) )
00549 ls_long(&statbuf, name);
00550 return true;
00551
00552 EC_CLEANUP_BGN
00553 return false;
00554 EC_CLEANUP_END
00555 }
00556
00557 static char *big_cwd = NULL;
00558 static char big_name[FILENAME_MAX + 1];
00559 static off_t big_size = 0;
00560
00561 static bool biggest(struct traverse_info *p, SHOW_OP op)
00562 {
00563 char *cwd;
00564
00565 if (p->ti_stat.st_size > big_size && S_ISREG(p->ti_stat.st_mode)) {
00566 ec_null( cwd = get_cwd(false) )
00567 free(big_cwd);
00568 ec_null( big_cwd = malloc(strlen(cwd) + 1) )
00569 strcpy(big_cwd, cwd);
00570 strncpy(big_name, p->ti_name, sizeof(big_name));
00571 big_name[sizeof(big_name) - 1] = '\0';
00572 big_size = p->ti_stat.st_size;
00573 }
00574 return true;
00575
00576 EC_CLEANUP_BGN
00577 return false;
00578 EC_CLEANUP_END
00579 }
00580
00581 static void biggest_file(void)
00582 {
00583 struct traverse_info ti = {0};
00584
00585 ti.ti_fcn = biggest;
00586 ti.ti_recursive = true;
00587 ti.ti_name = "/";
00588 ec_false( do_entry(&ti, false) )
00589 printf("Biggest file:\n%s\n%s\n%lu\n", big_cwd, big_name,
00590 (unsigned long)big_size);
00591 return;
00592
00593 EC_CLEANUP_BGN
00594 EC_FLUSH("biggest_file");
00595 EC_CLEANUP_END
00596 }
00597
00598 static bool runtest(char testtype, const char *name)
00599 {
00600 struct stat statbuf;
00601
00602 ec_neg1( lstat(name, &statbuf) )
00603 switch (testtype) {
00604 case 'a':
00605 printf("get_max_pathname = %ld\n", get_max_pathname("."));
00606 printf("get_max_pathname = %ld\n", get_max_pathname("/aup"));
00607
00608 printf("get_max_pathname = %ld\n", get_max_pathname("/dev/fd"));
00609 break;
00610 case 'b':
00611 biggest_file();
00612 break;
00613 case 'y':
00614 ec_false( ls_one(name) )
00615 break;
00616 case 'c':
00617 {
00618
00619 char *cwd;
00620
00621 ec_null( cwd = get_cwd(false) )
00622 printf("%s\n", cwd);
00623 (void) get_cwd(true);
00624
00625 ec_null( cwd = get_cwd(false) )
00626 printf("%s\n", cwd);
00627 (void) get_cwd(true);
00628 ec_null( cwd = get_cwd(false) )
00629 printf("%s\n", cwd);
00630 (void) get_cwd(true);
00631 ec_null( cwd = get_cwd(false) )
00632 printf("%s\n", cwd);
00633 (void) get_cwd(true);
00634 }
00635 break;
00636 case 'M':
00637 {
00638
00639 struct stat statbuf;
00640
00641 ec_neg1( lstat("fifo", &statbuf) )
00642 print_mode(&statbuf);
00643 putchar('\n');
00644 ec_neg1( system("ls -l fifo") )
00645
00646 }
00647 break;
00648 case 'm':
00649 print_mode(&statbuf);
00650 break;
00651 case 'l':
00652 print_numlinks(&statbuf);
00653 break;
00654 case 'o':
00655 print_owner(&statbuf);
00656 break;
00657 case 'g':
00658 print_group(&statbuf);
00659 break;
00660 case 's':
00661 print_size(&statbuf);
00662 break;
00663 case 'd':
00664 print_date(&statbuf);
00665 break;
00666 case 'n':
00667 print_name(&statbuf, name);
00668 break;
00669 default:
00670 fprintf(stderr, "Unknown test letter: %c\n", testtype);
00671 errno = 0;
00672 EC_FAIL
00673 }
00674 printf("\n");
00675 return true;
00676
00677 EC_CLEANUP_BGN
00678 return false;
00679 EC_CLEANUP_END
00680 }
00681 #ifdef AUPLS_FULL
00682
00683 int main(int argc, char *argv[])
00684 {
00685 struct traverse_info ti = {0};
00686 int c, status = EXIT_FAILURE;
00687 bool stat_only = false;
00688
00689 char testtype = '\0';
00690
00691
00692 ti.ti_fcn = show_stat;
00693 while ((c = getopt(argc, argv, "dRt:")) != -1)
00694 switch(c) {
00695 case 'd':
00696 stat_only = true;
00697 break;
00698 case 'R':
00699 ti.ti_recursive = true;
00700 break;
00701
00702 case 't':
00703 testtype = *optarg;
00704 break;
00705
00706 default:
00707 fprintf(stderr, USAGE);
00708 EC_CLEANUP
00709 }
00710 switch (argc - optind) {
00711 case 0:
00712 ti.ti_name = ".";
00713 break;
00714 case 1:
00715 ti.ti_name = argv[optind];
00716 break;
00717 default:
00718 fprintf(stderr, USAGE);
00719 EC_CLEANUP
00720 }
00721
00722 if (testtype != '\0')
00723 ec_false( runtest(testtype, ti.ti_name) )
00724 else {
00725
00726 ec_false( do_entry(&ti, stat_only) )
00727 printf("\nTotal entries: %ld; directories = %ld\n", total_entries,
00728 total_dirs);
00729
00730 }
00731
00732 status = EXIT_SUCCESS;
00733 EC_CLEANUP
00734
00735 EC_CLEANUP_BGN
00736 print_cwd(true);
00737 exit(status);
00738 EC_CLEANUP_END
00739 }
00740
00741 #endif