00001 /* 00002 ls command 00003 AUP2, Sec. 3.5, 3.6.5 00004 00005 Copyright 2003 by Marc J. Rochkind. All rights reserved. 00006 May be copied only for purposes and under conditions described 00007 on the Web page www.basepath.com/aup/copyright.htm. 00008 00009 The Example Files are provided "as is," without any warranty; 00010 without even the implied warranty of merchantability or fitness 00011 for a particular purpose. The author and his publisher are not 00012 responsible for any damages, direct or incidental, resulting 00013 from the use or non-use of these Example Files. 00014 00015 The Example Files may contain defects, and some contain deliberate 00016 coding mistakes that were included for educational reasons. 00017 You are responsible for determining if and how the Example Files 00018 are to be used. 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 /*[aupls-top1]*/ 00029 #define USAGE "Usage: aupls [-Rd] [dir]\n" 00030 00031 static long total_entries = 0, total_dirs = 0; 00032 /*[aupls-top2]*/ 00033 typedef enum {SHOW_PATH, SHOW_INFO} SHOW_OP; 00034 00035 struct traverse_info { 00036 bool ti_recursive; /* -R option? */ 00037 char *ti_name; /* current entry */ 00038 struct stat ti_stat; /* stat for ti_name */ 00039 bool (*ti_fcn)(struct traverse_info *, SHOW_OP); /* callback fcn */ 00040 }; 00041 /*[print_mode]*/ 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)) /* sic */ 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 /*[print_numlinks]*/ 00106 static void print_numlinks(const struct stat *statp) 00107 { 00108 printf("%5ld", (long)statp->st_nlink); 00109 } 00110 /*[print_owner]*/ 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 /*[print_group]*/ 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 /*[print_size]*/ 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 /*[print_date]*/ 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) /* roughly 6 months */ 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 In code below, the "not supposed to happen" test modified to include EINVAL, which Darwin 00164 returned for paths like /dev and /dev/fd. 00165 */ 00166 /*[get_max_pathname]*/ 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) /* not supposed to happen */ 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 /*[print_name]*/ 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'; /* can't assume NUL-terminated */ 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 /*[ls_long-a]*/ 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 /*[ls_long-b]*/ 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 /*[get_cwd]*/ 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 /*[aupls-print_cwd]*/ 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 /*[aupls-show_stat]*/ 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 /*[aupls-check_parent]*/ 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 /*[aupls-do_dir1]*/ 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 Entry could be changed from directory to symlink between 00331 lstat() and here, in which case opendir would follow it, 00332 possibly resulting in double-visiting or even a loop. 00333 */ 00334 ec_neg1( dirfd = open(".", O_RDONLY) ) 00335 /* 00336 [Not in book.] 00337 On Darwin, fails on directory /dev/fd. Problem is that it thinks that some of 00338 the file descriptors there are directories, and opendir fails on them with a bus 00339 error. Skipping the entire /dev directory is a good idea. The shortcut is to skip 00340 directories whose name is "dev", which isn't really correct, because they may not 00341 be at the root. Fix is left to the reader... 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 /* [End of stuff not in book.] */ 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 /* Book showed just EC_FAIL here. Change so we can keep going. */ 00356 else { 00357 syserr_print("do_dir()"); 00358 result = true; /* repeat of above, but want to keep book's logic */ 00359 EC_CLEANUP 00360 } 00361 /* EC_FAIL -- don't want this line anymore */ 00362 } 00363 /*[]*/ 00364 /* 00365 Following is a good idea, but left out of book for space reasons. 00366 */ 00367 if (strcmp(p->ti_name, ".") != 0) 00368 ec_false( check_parent(dirfd, p->ti_name) ) 00369 /*[aupls-do_dir2]*/ 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 /*[aupls-do_entry]*/ 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/* || !is_dir*/) { /* Bug fix: 24-March-2004 */ 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 /*[ls_dir]*/ 00430 int main(int argc, char *argv[]) /* has a bug */ 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 /* WANT_LSDIR_BUGGY */ 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 /*[ls_dir_fixed]*/ 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 /* WANT_LSDIR_FIXED */ 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 /*[ls_dir_fixed2]*/ 00518 ec_null( dir = opendir(argv[i]) ) 00519 ec_neg1( fd = open(".", O_RDONLY) ) 00520 ec_neg1( chdir(argv[i]) ) /* no jumps allowed until fchdir! */ 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 /* WANT_LSDIR_ALTERNATIVE */ 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 /* Following line failed on DARWIN */ 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 /*[test_get_cwd]*/ 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 /*[test_print_mode]*/ 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 /*[aupls-main1]*/ 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 /*[aupls-main2]*/ 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 /*[aupls-main3]*/ 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 /*[aupls-main4]*/ 00726 ec_false( do_entry(&ti, stat_only) ) 00727 printf("\nTotal entries: %ld; directories = %ld\n", total_entries, 00728 total_dirs); 00729 /*[]*/ 00730 } 00731 /*[aupls-main5]*/ 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