logo

bootstrap-initrd

Linux initrd to bootstrap from a small binary seed git clone https://hacktivis.me/git/bootstrap-initrd.git

ls-stub.c (35347B)


  1. // SPDX-License-Identifier: BSD-3-Clause
  2. /* ls 4.1 - List files. Author: Kees J. Bot
  3. * 25 Apr 1989
  4. */
  5. /*
  6. * Changes by Gunnar Ritter, Freiburg i. Br., Germany, October 2001. Taken
  7. * from the MINIX sources:
  8. */
  9. /*
  10. * Copyright (c) 1987,1997, Prentice Hall All rights reserved.
  11. *
  12. * Redistribution and use of the MINIX operating system in source and binary
  13. * forms, with or without modification, are permitted provided that the
  14. * following conditions are met:
  15. *
  16. * Redistributions of source code must retain the above copyright notice, this
  17. * list of conditions and the following disclaimer.
  18. *
  19. * Redistributions in binary form must reproduce the above copyright notice,
  20. * this list of conditions and the following disclaimer in the documentation
  21. * and/or other materials provided with the distribution.
  22. *
  23. * Neither the name of Prentice Hall nor the names of the software authors or
  24. * contributors may be used to endorse or promote products derived from this
  25. * software without specific prior written permission.
  26. *
  27. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND CONTRIBUTORS
  28. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  29. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  30. * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PRENTICE HALL OR ANY
  31. * AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  32. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
  33. * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  34. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  35. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  36. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  37. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. */
  39. /*
  40. * About the amount of bytes for heap + stack under Minix:
  41. * Ls needs a average amount of 42 bytes per unserviced directory entry, so
  42. * scanning 10 directory levels deep in an ls -R with 100 entries per directory
  43. * takes 42000 bytes of heap. So giving ls 10000 bytes is tight, 20000 is
  44. * usually enough, 40000 is pessimistic.
  45. */
  46. /* The array ifmt_c[] is used in an 'ls -l' to map the type of a file to a
  47. * letter. This is done so that ls can list any future file or device type
  48. * other than symlinks, without recompilation. (Yes it's dirty.)
  49. */
  50. static char ifmt_c[] = "-pc-d-b--nl-SD--";
  51. /* S_IFIFO
  52. * S_IFCHR
  53. * S_IFDIR
  54. * S_IFBLK
  55. * S_IFREG
  56. * S_IFNWK
  57. * S_IFLNK
  58. * S_IFSOCK
  59. * S_IFDOOR
  60. */
  61. #define ifmt(mode) ifmt_c[((mode) >> 12) & 0xF]
  62. #include <ctype.h>
  63. #include <dirent.h>
  64. #include <errno.h>
  65. #include <fcntl.h>
  66. #include <grp.h>
  67. #include <libgen.h>
  68. #include <limits.h>
  69. #include <locale.h>
  70. #include <pwd.h>
  71. #include <stddef.h>
  72. #include <stdio.h>
  73. #include <stdlib.h>
  74. #include <string.h>
  75. #include <sys/ioctl.h>
  76. #include <sys/stat.h>
  77. #include <sys/types.h>
  78. #include <termios.h>
  79. #include <time.h>
  80. #include <unistd.h>
  81. #include <wchar.h>
  82. #include <wctype.h>
  83. #if defined(__linux__) || defined(_AIX)
  84. #include <sys/sysmacros.h>
  85. #endif /* __linux__ or _AIX, since sys/sysmacros.h
  86. * adds a definition of "major". */
  87. #ifndef S_IFNAM
  88. #define S_IFNAM 0x5000 /* XENIX special named file */
  89. #endif
  90. #ifndef S_INSEM
  91. #define S_INSEM 0x1 /* XENIX semaphore subtype of IFNAM */
  92. #endif
  93. #ifndef S_INSHD
  94. #define S_INSHD 0x2 /* XENIX shared data subtype of IFNAM */
  95. #endif
  96. #ifndef S_IFDOOR
  97. #define S_IFDOOR 0xD000 /* Solaris door */
  98. #endif
  99. #ifndef S_IFNWK
  100. #define S_IFNWK 0x9000 /* HP-UX network special */
  101. #endif
  102. #if !__minix
  103. #define SUPER_ID uid /* Let -A flag be default for SUPER_ID == 0. */
  104. #else
  105. #define SUPER_ID gid
  106. #endif
  107. #if __minix
  108. #define BLOCK 1024
  109. #else
  110. #define BLOCK 512
  111. #endif
  112. /* Assume other systems have st_blocks. */
  113. #if !__minix
  114. #define ST_BLOCKS 1
  115. #endif
  116. /* Some terminals ignore more than 80 characters on a line. Dumb ones wrap
  117. * when the cursor hits the side. Nice terminals don't wrap until they have
  118. * to print the 81st character. Wether we like it or not, no column 80.
  119. */
  120. static int ncols = 79;
  121. #define NSEP 2 /* # spaces between columns. */
  122. #define MAXCOLS 150 /* Max # of files per line. */
  123. static char *arg0; /* Last component of argv[0]. */
  124. static int uid, gid; /* callers id. */
  125. static int ex = 0; /* Exit status to be. */
  126. static int istty; /* Output is on a terminal. */
  127. static int tinfostat = -1; /* terminfo is initalized */
  128. #ifdef SU3
  129. static struct visit
  130. {
  131. ino_t v_ino;
  132. dev_t v_dev;
  133. } *visited;
  134. static int vismax; /* number of members in visited */
  135. #endif /* SU3 */
  136. static enum { PER_LS = 0, PER_DIR = 1 } personality = PER_LS;
  137. static struct
  138. {
  139. const char *per_opt;
  140. } personalities[] = {
  141. /* orig: acdfgilnqrstu1ACFLMRTX */
  142. #ifdef UCB
  143. {":1RaAdClgrtucFqisfLSUXhH"}, /* PER_LS */
  144. #else /* !UCB */
  145. {"1RadCxmnlogrtucpFbqisfLSUXhH"}, /* PER_LS */
  146. #endif /* !UCB */
  147. {"1RadCxmnlogrtucpFbqiOfLSXhH"} /* PER_DIR */
  148. };
  149. /* Safer versions of malloc and realloc: */
  150. static void
  151. heaperr(void)
  152. {
  153. write(2, "out of memory\n", 14);
  154. exit(077);
  155. }
  156. /*
  157. * Deliver or die.
  158. */
  159. static void *
  160. salloc(size_t n)
  161. {
  162. void *a;
  163. if((a = malloc(n)) == NULL) heaperr();
  164. return a;
  165. }
  166. static void *
  167. srealloc(void *a, size_t n)
  168. {
  169. if((a = realloc(a, n)) == NULL) heaperr();
  170. return a;
  171. }
  172. static char flags[0477];
  173. static int
  174. present(int f)
  175. {
  176. return f == 0 || flags[f] != 0;
  177. }
  178. /*
  179. * Like perror(3), but in the style: "ls: junk: No such file or directory.
  180. */
  181. static void
  182. report(const char *f)
  183. {
  184. #ifdef UCB
  185. fprintf(stderr, "%s not found\n", f);
  186. #else /* !UCB */
  187. fprintf(stderr, "%s: %s\n", f, strerror(errno));
  188. #endif /* !UCB */
  189. ex = 1;
  190. }
  191. #ifdef UCB
  192. #define blockcount(n) (((n) & 1 ? (n) + 1 : (n)) >> 1)
  193. #else
  194. #define blockcount(n) (n)
  195. #endif
  196. /*
  197. * Two functions, uidname and gidname, translate id's to readable names.
  198. * All names are remembered to avoid searching the password file.
  199. */
  200. #define NNAMES (1 << (sizeof(int) + sizeof(char *)))
  201. enum whatmap
  202. {
  203. PASSWD,
  204. GROUP
  205. };
  206. static struct idname
  207. { /* Hash list of names. */
  208. struct idname *next;
  209. char *name;
  210. uid_t id;
  211. } *uids[NNAMES], *gids[NNAMES];
  212. /*
  213. * Return name for a given user/group id.
  214. */
  215. static char *
  216. idname(unsigned id, enum whatmap map)
  217. {
  218. struct idname *i;
  219. struct idname **ids = &(map == PASSWD ? uids : gids)[id % NNAMES];
  220. while((i = *ids) != NULL && id < i->id)
  221. ids = &i->next;
  222. if(i == NULL || id != i->id)
  223. {
  224. /* Not found, go look in the password or group map. */
  225. char *name = NULL;
  226. char noname[3 * sizeof(uid_t)];
  227. if(!present('n'))
  228. {
  229. if(map == PASSWD)
  230. {
  231. struct passwd *pw = getpwuid(id);
  232. if(pw != NULL) name = pw->pw_name;
  233. }
  234. else
  235. {
  236. struct group *gr = getgrgid(id);
  237. if(gr != NULL) name = gr->gr_name;
  238. }
  239. }
  240. if(name == NULL)
  241. {
  242. /* Can't find it, weird. Use numerical "name." */
  243. sprintf(noname, "%lu", (long)id);
  244. name = noname;
  245. }
  246. /* Add a new id-to-name cell. */
  247. i = salloc(sizeof(*i));
  248. i->id = id;
  249. i->name = salloc(strlen(name) + 1);
  250. strcpy(i->name, name);
  251. i->next = *ids;
  252. *ids = i;
  253. }
  254. return i->name;
  255. }
  256. #define uidname(uid) idname((uid), PASSWD)
  257. #define gidname(gid) idname((gid), GROUP)
  258. /*
  259. * Path name construction, addpath adds a component, delpath removes it.
  260. * The string path is used throughout the program as the file under examination.
  261. */
  262. static char *path; /* Path name constructed in path[]. */
  263. static int plen = 0, pidx = 0; /* Lenght/index for path[]. */
  264. /*
  265. * Add a component to path. (name may also be a full path at the first call)
  266. * The index where the current path ends is stored in *pdi.
  267. */
  268. static void
  269. addpath(int *didx, char *name)
  270. {
  271. if(plen == 0) path = salloc((plen = 32) * sizeof(path[0]));
  272. if(pidx == 1 && path[0] == '.') pidx = 0; /* Remove "." */
  273. *didx = pidx; /* Record point to go back to for delpath. */
  274. if(pidx > 0 && path[pidx - 1] != '/') path[pidx++] = '/';
  275. do
  276. {
  277. if(*name != '/' || pidx == 0 || path[pidx - 1] != '/')
  278. {
  279. if(pidx == plen)
  280. {
  281. path = srealloc(path, (plen *= 2) * sizeof(path[0]));
  282. }
  283. path[pidx++] = *name;
  284. }
  285. } while(*name++ != 0);
  286. --pidx; /*
  287. * Put pidx back at the null. The path[pidx++] = '/'
  288. * statement will overwrite it at the next call.
  289. */
  290. }
  291. #define delpath(didx) (path[pidx = didx] = 0) /* Remove component. */
  292. static int field = 0; /* (used to be) Fields that must be printed. */
  293. /* (now) Effects triggered by certain flags. */
  294. #define FL_INODE 0x001 /* -i */
  295. #define FL_BLOCKS 0x002 /* -s */
  296. #define FL_UNUSED 0x004
  297. #define FL_MODE 0x008 /* -lMX */
  298. #define FL_LONG 0x010 /* -l */
  299. #define FL_GROUP 0x020 /* -g */
  300. #define FL_BYTIME 0x040 /* -tuc */
  301. #define FL_ATIME 0x080 /* -u */
  302. #define FL_CTIME 0x100 /* -c */
  303. #define FL_MARK 0x200 /* -F */
  304. /*#define FL_UNUSED 0x400 */
  305. #define FL_DIR 0x800 /* -d */
  306. #define FL_OWNER 0x1000 /* -o */
  307. #define FL_STATUS 0x2000
  308. #define ENDCOL 0x001 /* last printable column in -x mode */
  309. struct file
  310. { /* A file plus stat(2) information. */
  311. off_t size;
  312. #if ST_BLOCKS
  313. blkcnt_t blocks;
  314. #endif
  315. ino_t ino;
  316. struct file *next; /* Lists are made of them. */
  317. struct file *sord; /* Saved order of list. */
  318. char *name; /* Null terminated name. */
  319. time_t mtime;
  320. time_t atime;
  321. time_t ctime;
  322. mode_t mode;
  323. int flag;
  324. uid_t uid;
  325. gid_t gid;
  326. dev_t rdev;
  327. nlink_t nlink;
  328. unsigned short namlen;
  329. };
  330. static void
  331. setstat(struct file *f, struct stat *stp)
  332. {
  333. f->ino = stp->st_ino;
  334. f->mode = stp->st_mode;
  335. f->nlink = stp->st_nlink;
  336. f->uid = stp->st_uid;
  337. f->gid = stp->st_gid;
  338. f->rdev = stp->st_rdev;
  339. f->size = stp->st_size;
  340. f->mtime = stp->st_mtime;
  341. f->atime = stp->st_atime;
  342. f->ctime = stp->st_ctime;
  343. #if ST_BLOCKS
  344. f->blocks = stp->st_blocks;
  345. #endif
  346. }
  347. #define PAST (26 * 7 * 24 * 3600L) /* Half a year ago. */
  348. /* Between PAST and FUTURE from now a time is printed, otherwise a year. */
  349. #define FUTURE (15 * 60L) /* Fifteen minutes. */
  350. /*
  351. * Transform the right time field into something readable.
  352. */
  353. static char *
  354. timestamp(struct file *f)
  355. {
  356. struct tm *tm;
  357. time_t t;
  358. static time_t now;
  359. static int drift = 0;
  360. static char date[32];
  361. t = f->mtime;
  362. if(field & FL_ATIME) t = f->atime;
  363. if(field & FL_CTIME) t = f->ctime;
  364. tm = localtime(&t);
  365. if(--drift < 0)
  366. {
  367. time(&now);
  368. drift = 50;
  369. } /* limit time() calls */
  370. if(t < now - PAST || t > now + FUTURE)
  371. {
  372. strftime(date, sizeof date - 1, "%b %e %Y", tm);
  373. }
  374. else
  375. {
  376. strftime(date, sizeof date - 1, "%b %e %H:%M", tm);
  377. }
  378. return date;
  379. }
  380. /*
  381. * Compute long or short rwx bits.
  382. */
  383. static char *
  384. permissions(struct file *f)
  385. {
  386. /*
  387. * Note that rwx[0] is a guess for the more alien file types. It is
  388. * correct for BSD4.3 and derived systems. I just don't know how
  389. * "standardized" these numbers are.
  390. */
  391. static char rwx[] = "drwxr-x--x ";
  392. char *p = rwx + 1;
  393. int mode = f->mode;
  394. rwx[0] = ifmt(f->mode);
  395. if((f->mode & S_IFMT) == S_IFNAM)
  396. {
  397. if(f->rdev == S_INSEM)
  398. rwx[0] = 's';
  399. else if(f->rdev == S_INSHD)
  400. rwx[0] = 'm';
  401. else
  402. rwx[0] = '?';
  403. }
  404. do
  405. {
  406. p[0] = (mode & S_IRUSR) ? 'r' : '-';
  407. p[1] = (mode & S_IWUSR) ? 'w' : '-';
  408. p[2] = (mode & S_IXUSR) ? 'x' : '-';
  409. mode <<= 3;
  410. } while((p += 3) <= rwx + 7);
  411. if(f->mode & S_ISUID) rwx[3] = f->mode & (S_IXUSR >> 0) ? 's' : 'S';
  412. if(f->mode & S_ISGID)
  413. rwx[6] = f->mode & (S_IXGRP >> 0) ? 's' :
  414. #ifndef UCB
  415. (f->mode & S_IFMT) != S_IFDIR ?
  416. #if defined(SUS) || defined(SU3)
  417. 'L'
  418. #else /* !SUS, !SU3 */
  419. 'l'
  420. #endif /* !SUS, !SU3 */
  421. :
  422. #endif /* !UCB */
  423. 'S';
  424. if(f->mode & S_ISVTX) rwx[9] = f->mode & (S_IXUSR >> 6) ? 't' : 'T';
  425. /*
  426. * rwx[10] would be the "optional alternate access method flag",
  427. * leave as a space for now.
  428. */
  429. return rwx;
  430. }
  431. #ifdef notdef
  432. void
  433. numeral(int i, char **pp)
  434. {
  435. char itoa[3 * sizeof(int)], *a = itoa;
  436. do
  437. *a++ = i % 10 + '0';
  438. while((i /= 10) > 0);
  439. do
  440. *(*pp)++ = *--a;
  441. while(a > itoa);
  442. }
  443. #endif
  444. static char *
  445. extension(const char *fn)
  446. {
  447. const char *ep = "";
  448. while(*fn++)
  449. if(*fn == '.') ep = &fn[1];
  450. return (char *)ep;
  451. }
  452. static int (*CMP)(struct file *f1, struct file *f2);
  453. static int (*rCMP)(struct file *f1, struct file *f2);
  454. /*
  455. * This is either a stable mergesort, or thermal noise, I'm no longer sure.
  456. * It must be called like this: if (L != NULL && L->next != NULL) mergesort(&L);
  457. */
  458. static void
  459. _mergesort(struct file **al)
  460. {
  461. /* static */ struct file *l1, **mid; /* Need not be local */
  462. struct file *l2;
  463. l1 = *(mid = &(*al)->next);
  464. do
  465. {
  466. if((l1 = l1->next) == NULL) break;
  467. mid = &(*mid)->next;
  468. } while((l1 = l1->next) != NULL);
  469. l2 = *mid;
  470. *mid = NULL;
  471. if((*al)->next != NULL) _mergesort(al);
  472. if(l2->next != NULL) _mergesort(&l2);
  473. l1 = *al;
  474. for(;;)
  475. {
  476. if((*CMP)(l1, l2) <= 0)
  477. {
  478. if((l1 = *(al = &l1->next)) == NULL)
  479. {
  480. *al = l2;
  481. break;
  482. }
  483. }
  484. else
  485. {
  486. *al = l2;
  487. l2 = *(al = &l2->next);
  488. *al = l1;
  489. if(l2 == NULL) break;
  490. }
  491. }
  492. }
  493. static int
  494. namecmp(struct file *f1, struct file *f2)
  495. {
  496. return strcoll(f1->name, f2->name);
  497. }
  498. static int
  499. extcmp(struct file *f1, struct file *f2)
  500. {
  501. return strcoll(extension(f1->name), extension(f2->name));
  502. }
  503. static int
  504. mtimecmp(struct file *f1, struct file *f2)
  505. {
  506. return f1->mtime == f2->mtime ? 0 : f1->mtime > f2->mtime ? -1 : 1;
  507. }
  508. static int
  509. atimecmp(struct file *f1, struct file *f2)
  510. {
  511. return f1->atime == f2->atime ? 0 : f1->atime > f2->atime ? -1 : 1;
  512. }
  513. static int
  514. ctimecmp(struct file *f1, struct file *f2)
  515. {
  516. return f1->ctime == f2->ctime ? 0 : f1->ctime > f2->ctime ? -1 : 1;
  517. }
  518. static int
  519. sizecmp(struct file *f1, struct file *f2)
  520. {
  521. return f1->size == f2->size ? 0 : f1->size > f2->size ? -1 : 1;
  522. }
  523. static int
  524. revcmp(struct file *f1, struct file *f2)
  525. {
  526. return (*rCMP)(f2, f1);
  527. }
  528. /*
  529. * Sort the files according to the flags.
  530. */
  531. static void
  532. sort(struct file **al)
  533. {
  534. if(present('U')) return;
  535. if(!present('f') && *al != NULL && (*al)->next != NULL)
  536. {
  537. CMP = namecmp;
  538. if(!(field & FL_BYTIME))
  539. {
  540. /* Sort on name */
  541. if(present('r'))
  542. {
  543. rCMP = CMP;
  544. CMP = revcmp;
  545. }
  546. _mergesort(al);
  547. }
  548. else
  549. {
  550. /* Sort on name first, then sort on time. */
  551. _mergesort(al);
  552. if(field & FL_CTIME)
  553. {
  554. CMP = ctimecmp;
  555. }
  556. else if(field & FL_ATIME)
  557. {
  558. CMP = atimecmp;
  559. }
  560. else
  561. {
  562. CMP = mtimecmp;
  563. }
  564. if(present('r'))
  565. {
  566. rCMP = CMP;
  567. CMP = revcmp;
  568. }
  569. _mergesort(al);
  570. }
  571. if(present('X'))
  572. {
  573. CMP = extcmp;
  574. if(present('r'))
  575. {
  576. rCMP = CMP;
  577. CMP = revcmp;
  578. }
  579. _mergesort(al);
  580. }
  581. if(present('S'))
  582. {
  583. CMP = sizecmp;
  584. if(present('r'))
  585. {
  586. rCMP = CMP;
  587. CMP = revcmp;
  588. }
  589. _mergesort(al);
  590. }
  591. }
  592. }
  593. /*
  594. * Create file structure for given name.
  595. */
  596. static struct file *
  597. newfile(char *name)
  598. {
  599. struct file *new;
  600. new = salloc(sizeof(*new));
  601. new->name = strcpy(salloc(strlen(name) + 1), name);
  602. new->namlen = 0;
  603. new->flag = 0;
  604. return new;
  605. }
  606. /*
  607. * Add file to the head of a list.
  608. */
  609. static void
  610. pushfile(struct file **flist, struct file *new)
  611. {
  612. new->next = *flist;
  613. *flist = new;
  614. }
  615. /*
  616. * Release old file structure.
  617. */
  618. static void
  619. delfile(struct file *old)
  620. {
  621. free(old->name);
  622. free(old);
  623. }
  624. /*
  625. * Pop file off top of file list.
  626. */
  627. static struct file *
  628. popfile(struct file **flist)
  629. {
  630. struct file *f;
  631. f = *flist;
  632. *flist = f->next;
  633. return f;
  634. }
  635. /*
  636. * Save the current file order.
  637. */
  638. static void
  639. savord(struct file *f)
  640. {
  641. while(f)
  642. {
  643. f->sord = f->next;
  644. f = f->next;
  645. }
  646. }
  647. /*
  648. * Restore the saved file order.
  649. */
  650. static void
  651. resord(struct file *f)
  652. {
  653. while(f)
  654. {
  655. f->next = f->sord;
  656. f = f->sord;
  657. }
  658. }
  659. /*
  660. * Return flag that would make ls list this name: -a or -A.
  661. */
  662. static int
  663. dotflag(char *name)
  664. {
  665. if(*name++ != '.') return 0;
  666. switch(*name++)
  667. {
  668. case 0:
  669. return 'a'; /* "." */
  670. case '.':
  671. if(*name == 0) return 'a'; /* ".." */
  672. default:
  673. return 'A'; /* ".*" */
  674. }
  675. }
  676. /*
  677. * Add directory entries of directory name to a file list.
  678. */
  679. static int
  680. adddir(struct file **aflist, char *name)
  681. {
  682. DIR *d;
  683. struct dirent *e;
  684. if(access(name, 0) < 0)
  685. {
  686. report(name);
  687. return 0;
  688. }
  689. if((d = opendir(name)) == NULL)
  690. {
  691. #ifdef UCB
  692. fprintf(stderr, "%s unreadable\n", name);
  693. #else
  694. fprintf(stderr, "can not access directory %s\n", name);
  695. #endif
  696. ex = 1;
  697. return 0;
  698. }
  699. while((e = readdir(d)) != NULL)
  700. {
  701. if(e->d_ino != 0 && present(dotflag(e->d_name)))
  702. {
  703. pushfile(aflist, newfile(e->d_name));
  704. aflist = &(*aflist)->next;
  705. }
  706. }
  707. closedir(d);
  708. return 1;
  709. }
  710. /*
  711. * Compute total block count for a list of files.
  712. */
  713. static off_t
  714. countblocks(struct file *flist)
  715. {
  716. off_t cb = 0;
  717. while(flist != NULL)
  718. {
  719. switch(flist->mode & S_IFMT)
  720. {
  721. case S_IFDIR:
  722. case S_IFREG:
  723. #ifdef S_IFLNK
  724. case S_IFLNK:
  725. #endif
  726. cb += flist->blocks;
  727. }
  728. flist = flist->next;
  729. }
  730. return cb;
  731. }
  732. static char *
  733. #ifdef LONGLONG
  734. hfmt(long long n, int fill)
  735. #else
  736. hfmt(long n, int fill)
  737. #endif
  738. {
  739. static char b[10];
  740. const char units[] = " KMGTPE", *up = units;
  741. int rest = 0;
  742. while(n > 1023)
  743. {
  744. rest = (n % 1024) / 128;
  745. n /= 1024;
  746. up++;
  747. }
  748. #ifdef LONGLONG
  749. if(up == units)
  750. snprintf(b, sizeof b, "%*llu", fill ? 5 : 1, n);
  751. else if(n < 10 && rest)
  752. snprintf(b, sizeof b, "%*llu.%u%c", fill ? 2 : 1, n, rest, *up);
  753. else
  754. snprintf(b, sizeof b, "%*llu%c", fill ? 4 : 1, n, *up);
  755. #else /* !LONGLONG */
  756. if(up == units)
  757. snprintf(b, sizeof b, "%*lu", fill ? 5 : 1, n);
  758. else if(n < 10 && rest)
  759. snprintf(b, sizeof b, "%*lu.%u%c", fill ? 2 : 1, n, rest, *up);
  760. else
  761. snprintf(b, sizeof b, "%*lu%c", fill ? 4 : 1, n, *up);
  762. #endif /* !LONGLONG */
  763. return b;
  764. }
  765. #define FC_NORMAL 0
  766. #define FC_BLACK 30
  767. #define FC_RED 31
  768. #define FC_GREEN 32
  769. #define FC_YELLOW 33
  770. #define FC_BLUE 34
  771. #define FC_MAGENTA 35
  772. #define FC_CYAN 36
  773. #define FC_WHITE 37
  774. /*
  775. * Display a nonprintable character.
  776. */
  777. static unsigned
  778. nonprint(register int c, int doit)
  779. {
  780. register int d;
  781. unsigned n;
  782. if(present('b'))
  783. {
  784. n = 4;
  785. if(doit)
  786. {
  787. char *nums = "01234567";
  788. putchar('\\');
  789. putchar(nums[(c & ~077) >> 6]);
  790. c &= 077;
  791. d = c & 07;
  792. if(c > d)
  793. putchar(nums[(c - d) >> 3]);
  794. else
  795. putchar(nums[0]);
  796. putchar(nums[d]);
  797. }
  798. }
  799. else
  800. {
  801. n = 1;
  802. if(doit) putchar('?');
  803. }
  804. return n;
  805. }
  806. /*
  807. * Print a name with control characters as '?' (unless -q). The terminal is
  808. * assumed to be eight bit clean.
  809. */
  810. static unsigned
  811. printname(const char *name, struct file *f, int doit)
  812. {
  813. int c, q = present('q');
  814. unsigned n = 0;
  815. if(f != NULL && doit == 0 && f->namlen != 0) return f->namlen;
  816. if(q || istty)
  817. {
  818. #ifdef MB_CUR_MAX
  819. wchar_t wc;
  820. while(
  821. #define ASCII
  822. #ifdef ASCII
  823. (*name & 0200) == 0 ? c = 1,
  824. (wc = *name) != '\0'
  825. :
  826. #endif
  827. (c = mbtowc(&wc, name, MB_CUR_MAX)) != 0)
  828. {
  829. if(c != -1)
  830. {
  831. if(iswprint(wc)
  832. #ifdef UCB
  833. || wc == '\t' || wc == '\n'
  834. #else /* !UCB */
  835. && wc != '\t'
  836. #endif /* !UCB */
  837. )
  838. {
  839. if(doit)
  840. {
  841. while(c-- > 0)
  842. putchar(*name++ & 0377);
  843. }
  844. else
  845. name += c;
  846. n += wcwidth(wc);
  847. }
  848. else
  849. {
  850. while(c-- > 0)
  851. n += nonprint(*name++ & 0377, doit);
  852. }
  853. }
  854. else
  855. n += nonprint(*name++ & 0377, doit);
  856. }
  857. #else /* !MB_CUR_MAX */
  858. while((c = (*name++ & 0377)) != '\0')
  859. {
  860. if(isprint(c)
  861. #ifdef UCB
  862. || c == '\t' || c == '\n'
  863. #else /* !UCB */
  864. && c != '\t'
  865. #endif /* !UCB */
  866. )
  867. {
  868. if(doit) putchar(c);
  869. n++;
  870. }
  871. else
  872. n += nonprint(c, doit);
  873. }
  874. #endif /* !MB_CUR_MAX */
  875. }
  876. else
  877. {
  878. while((c = (*name++ & 0377)) != '\0')
  879. {
  880. if(doit) putchar(c);
  881. n++;
  882. }
  883. }
  884. if(f) f->namlen = n;
  885. return n;
  886. }
  887. static int
  888. mark(struct file *f, int doit)
  889. {
  890. int c;
  891. if(!(field & FL_MARK)) return 0;
  892. switch(f->mode & S_IFMT)
  893. {
  894. case S_IFDIR:
  895. c = '/';
  896. break;
  897. #ifdef S_IFIFO
  898. case S_IFIFO:
  899. c = '|';
  900. break;
  901. #endif
  902. #ifdef S_IFLNK
  903. case S_IFLNK:
  904. c = '@';
  905. break;
  906. #endif
  907. #ifdef S_IFSOCK
  908. case S_IFSOCK:
  909. c = '=';
  910. break;
  911. #endif
  912. #ifdef S_IFDOOR
  913. case S_IFDOOR:
  914. c = '>';
  915. break;
  916. #endif
  917. case S_IFREG:
  918. if(f->mode & (S_IXUSR | S_IXGRP | S_IXOTH))
  919. {
  920. c = '*';
  921. break;
  922. }
  923. default:
  924. c = 0;
  925. }
  926. if(doit && c != 0) putchar(c);
  927. return c;
  928. }
  929. static int colwidth[MAXCOLS]; /* Need colwidth[i] spaces to print column i. */
  930. static int sizwidth[MAXCOLS]; /* Spaces for the size field in a -X print. */
  931. static int namwidth[MAXCOLS]; /* Name field. */
  932. /*
  933. * Set *aw to the larger of it and w. Then return it.
  934. */
  935. static int
  936. maxise(int *aw, int w)
  937. {
  938. if(w > *aw) *aw = w;
  939. return *aw;
  940. }
  941. static int nsp = 0; /* This many spaces have not been printed yet. */
  942. #define spaces(n) (nsp = (n))
  943. #define terpri() (nsp = 0, putchar('\n')) /* No trailing spaces */
  944. /*
  945. * Either compute the number of spaces needed to print file f (doit == 0) or
  946. * really print it (doit == 1).
  947. */
  948. static int
  949. print1(struct file *f, int col, int doit)
  950. {
  951. int width = 0, n;
  952. n = printname(f->name, f, 0);
  953. if(present('m'))
  954. {
  955. if(present('p') && (f->mode & S_IFMT) == S_IFDIR) width++;
  956. if(present('F')) width++;
  957. }
  958. while(nsp > 0)
  959. {
  960. putchar(' ');
  961. nsp--;
  962. } /* Fill gap between two columns */
  963. if(field & FL_INODE)
  964. {
  965. char dummy[2];
  966. if(doit)
  967. #ifdef LONGLONG
  968. printf("%*llu ", present('m') ? 1 : 5, (long long)f->ino);
  969. #else
  970. printf("%*lu ", present('m') ? 1 : 5, (long)f->ino);
  971. #endif
  972. else
  973. #ifdef LONGLONG
  974. width += snprintf(dummy, sizeof dummy, "%*llu ", present('m') ? 1 : 5, (long long)f->ino);
  975. #else
  976. width += snprintf(dummy, sizeof dummy, "%*lu ", present('m') ? 1 : 5, (long)f->ino);
  977. #endif
  978. }
  979. if(field & FL_BLOCKS)
  980. {
  981. char dummy[2];
  982. if(doit)
  983. {
  984. if(present('h'))
  985. printf("%s ", hfmt(f->blocks * 512, !present('m')));
  986. else
  987. #ifdef LONGLONG
  988. printf("%*llu ", present('m') ? 1 : 4, (long long)blockcount(f->blocks));
  989. #else
  990. printf("%*lu ", present('m') ? 1 : 4, (long)blockcount(f->blocks));
  991. #endif
  992. }
  993. else
  994. {
  995. if(present('h'))
  996. width += 6;
  997. else
  998. #ifdef LONGLONG
  999. width +=
  1000. snprintf(dummy, sizeof dummy, "%*llu ", present('m') ? 1 : 4, (long long)f->blocks);
  1001. #else
  1002. width += snprintf(dummy, sizeof dummy, "%*lu ", present('m') ? 1 : 4, (long)f->blocks);
  1003. #endif
  1004. }
  1005. }
  1006. if(field & FL_MODE)
  1007. {
  1008. if(doit)
  1009. {
  1010. printf("%s ", permissions(f));
  1011. }
  1012. else
  1013. {
  1014. width += 11;
  1015. }
  1016. }
  1017. if(field & FL_LONG)
  1018. {
  1019. if(doit)
  1020. {
  1021. printf("%2u ", (unsigned)f->nlink);
  1022. if(!(field & FL_GROUP))
  1023. {
  1024. printf("%-8s ", uidname(f->uid));
  1025. }
  1026. if(!(field & FL_OWNER))
  1027. {
  1028. printf("%-8s ", gidname(f->gid));
  1029. }
  1030. switch(f->mode & S_IFMT)
  1031. {
  1032. case S_IFBLK:
  1033. case S_IFCHR:
  1034. #ifdef S_IFMPB
  1035. case S_IFMPB:
  1036. #endif
  1037. #ifdef S_IFMPC
  1038. case S_IFMPC:
  1039. #endif
  1040. printf("%3lu,%3lu ", (long)major(f->rdev), (long)minor(f->rdev));
  1041. break;
  1042. default:
  1043. if(present('h'))
  1044. printf("%5s ", hfmt(f->size, 1));
  1045. else
  1046. #ifdef LONGLONG
  1047. printf("%7llu ", (long long)f->size);
  1048. #else
  1049. printf("%7lu ", (long)f->size);
  1050. #endif
  1051. }
  1052. printf("%s ", timestamp(f));
  1053. }
  1054. else
  1055. {
  1056. width += (field & FL_GROUP) ? 34 : 43;
  1057. }
  1058. }
  1059. if(doit)
  1060. {
  1061. printname(f->name, f, 1);
  1062. if(mark(f, 1) != 0) n++;
  1063. if(present('p') && (f->mode & S_IFMT) == S_IFDIR)
  1064. {
  1065. n++;
  1066. if(doit) putchar('/');
  1067. }
  1068. #ifdef S_IFLNK
  1069. if((field & FL_LONG) && (f->mode & S_IFMT) == S_IFLNK)
  1070. {
  1071. char *buf;
  1072. int sz, r, didx;
  1073. sz = f->size ? f->size : PATH_MAX;
  1074. buf = salloc(sz + 1);
  1075. addpath(&didx, f->name);
  1076. if((r = readlink(path, buf, sz)) < 0) r = 0;
  1077. delpath(didx);
  1078. buf[r] = 0;
  1079. printf(" -> ");
  1080. printname(buf, NULL, 1);
  1081. free(buf);
  1082. n += 4 + r;
  1083. }
  1084. #endif
  1085. if(!present('m')) spaces(namwidth[col] - n);
  1086. }
  1087. else
  1088. {
  1089. if(mark(f, 0) != 0) n++;
  1090. #ifdef S_IFLNK
  1091. if((field & FL_LONG) && (f->mode & S_IFMT) == S_IFLNK)
  1092. {
  1093. n += 4 + (int)f->size;
  1094. }
  1095. #endif
  1096. if(!present('m'))
  1097. {
  1098. width += maxise(&namwidth[col], n + NSEP);
  1099. maxise(&colwidth[col], width);
  1100. }
  1101. }
  1102. return n + width;
  1103. }
  1104. /*
  1105. * Return number of files in the list.
  1106. */
  1107. static int
  1108. countfiles(struct file *flist)
  1109. {
  1110. int n = 0;
  1111. while(flist != NULL)
  1112. {
  1113. n++;
  1114. flist = flist->next;
  1115. }
  1116. return n;
  1117. }
  1118. static struct file *filecol[MAXCOLS]; /*
  1119. * filecol[i] is list of files
  1120. * for column i.
  1121. */
  1122. static int nfiles, nlines; /* # files to print, # of lines needed. */
  1123. /*
  1124. * Chop list of files up in columns. Note that 3 columns are used for 5 files
  1125. * even though nplin may be 4, filecol[3] will simply be NULL.
  1126. */
  1127. static void
  1128. columnise(struct file **flist, struct file *fsav, int nplin)
  1129. {
  1130. struct file *f = *flist;
  1131. int i, j;
  1132. nlines = (nfiles + nplin - 1) / nplin; /* nlines needed for nfiles */
  1133. filecol[0] = f;
  1134. if(!present('x'))
  1135. {
  1136. for(i = 1; i < nplin; i++)
  1137. {
  1138. /* Give nlines files to each column. */
  1139. for(j = 0; j < nlines && f != NULL; j++)
  1140. f = f->next;
  1141. filecol[i] = f;
  1142. }
  1143. }
  1144. else
  1145. {
  1146. /*
  1147. * Ok, this is an ugly hack. We use the mechanisms for '-C'
  1148. * and thus have to change the file list order.
  1149. */
  1150. struct file *curcol[MAXCOLS];
  1151. resord(fsav);
  1152. *flist = fsav;
  1153. f = *flist;
  1154. for(i = 0; i < nplin && f; i++)
  1155. {
  1156. filecol[i] = curcol[i] = f;
  1157. f->flag &= ~ENDCOL;
  1158. f = f->next;
  1159. }
  1160. while(f != NULL)
  1161. {
  1162. for(i = 0; i < nplin && f; i++)
  1163. {
  1164. curcol[i]->next = f;
  1165. curcol[i] = f;
  1166. f->flag &= ~ENDCOL;
  1167. f = f->next;
  1168. }
  1169. }
  1170. for(i = 1; i < nplin; i++)
  1171. {
  1172. curcol[i - 1]->next = filecol[i];
  1173. curcol[i - 1]->flag |= ENDCOL;
  1174. }
  1175. curcol[nplin - 1]->next = NULL;
  1176. }
  1177. }
  1178. /*
  1179. * Try (doit == 0), or really print the list of files over nplin columns.
  1180. * Return true if it can be done in nplin columns or if nplin == 1.
  1181. */
  1182. static int
  1183. print(struct file **flist, struct file *fsav, int nplin, int doit)
  1184. {
  1185. register struct file *f;
  1186. register int i, totlen;
  1187. if(present('m'))
  1188. {
  1189. if(!doit) return 1;
  1190. totlen = 0;
  1191. for(f = *flist; f; f = f->next)
  1192. {
  1193. i = print1(f, 0, 0) + 2;
  1194. totlen += i;
  1195. if(totlen > ncols + 1)
  1196. {
  1197. putchar('\n');
  1198. totlen = i;
  1199. }
  1200. else if(f != *flist)
  1201. putchar(' ');
  1202. print1(f, 0, 1);
  1203. if(f->next) putchar(',');
  1204. }
  1205. putchar('\n');
  1206. return 1;
  1207. }
  1208. columnise(flist, fsav, nplin);
  1209. if(!doit)
  1210. {
  1211. if(nplin == 1) return 1; /* No need to try 1 column. */
  1212. for(i = 0; i < nplin; i++)
  1213. {
  1214. colwidth[i] = sizwidth[i] = namwidth[i] = 0;
  1215. }
  1216. }
  1217. while(--nlines >= 0)
  1218. {
  1219. totlen = 0;
  1220. for(i = 0; i < nplin; i++)
  1221. {
  1222. if((f = filecol[i]) != NULL)
  1223. {
  1224. if(f->flag & ENDCOL)
  1225. filecol[i] = NULL;
  1226. else
  1227. filecol[i] = f->next;
  1228. print1(f, i, doit);
  1229. }
  1230. if(!doit && nplin > 1)
  1231. {
  1232. /* See if this line is not too long. */
  1233. totlen += colwidth[i];
  1234. if(totlen > ncols + NSEP) return 0;
  1235. }
  1236. }
  1237. if(doit && !present('m')) terpri();
  1238. }
  1239. return 1;
  1240. }
  1241. enum depth
  1242. {
  1243. SURFACE,
  1244. SURFACE1,
  1245. SUBMERGED
  1246. };
  1247. enum state
  1248. {
  1249. BOTTOM,
  1250. SINKING,
  1251. FLOATING
  1252. };
  1253. /*
  1254. * Main workhorse of ls, it sorts and prints the list of files. Flags:
  1255. * depth: working with the command line / just one file / listing dir.
  1256. * state: How "recursive" do we have to be.
  1257. */
  1258. static void
  1259. listfiles(struct file *flist, enum depth depth, enum state state, int level)
  1260. {
  1261. struct file *dlist = NULL, **afl = &flist, **adl = &dlist, *fsav;
  1262. int nplin, t;
  1263. static int white = 1; /* Nothing printed yet. */
  1264. /*
  1265. * Flush everything previously printed, so new error output will
  1266. * not intermix with files listed earlier.
  1267. */
  1268. fflush(stdout);
  1269. if(field != 0 || state != BOTTOM)
  1270. { /* Need stat(2) info. */
  1271. while(*afl != NULL)
  1272. {
  1273. static struct stat st;
  1274. int didx;
  1275. #ifdef S_IFLNK
  1276. int (*status)(const char *file, struct stat *stp) =
  1277. depth == SURFACE1 && (field & FL_LONG) == 0
  1278. #ifdef SU3
  1279. && !present('F')
  1280. #endif /* SU3 */
  1281. || present('L') || present('H') && depth != SUBMERGED
  1282. ? stat
  1283. : lstat;
  1284. #else
  1285. #define status stat
  1286. #endif
  1287. /* Basic disk block size is 512 except for one niche O.S. */
  1288. addpath(&didx, (*afl)->name);
  1289. if((t = status(path, &st)) < 0
  1290. #ifdef S_IFLNK
  1291. && (status == lstat || lstat(path, &st) < 0)
  1292. #endif
  1293. )
  1294. {
  1295. if(depth != SUBMERGED || errno != ENOENT) report((*afl)->name);
  1296. #ifdef SU3
  1297. fail:
  1298. #endif /* SU3 */
  1299. delfile(popfile(afl));
  1300. }
  1301. else
  1302. {
  1303. #ifdef SU3
  1304. if(t < 0 && errno == ELOOP && (present('H') || present('L')))
  1305. {
  1306. report((*afl)->name);
  1307. goto fail;
  1308. }
  1309. if(present('L'))
  1310. {
  1311. int i;
  1312. for(i = 0; i < level; i++)
  1313. {
  1314. if(st.st_dev == visited[i].v_dev && st.st_ino == visited[i].v_ino)
  1315. {
  1316. fprintf(stderr,
  1317. "link "
  1318. "loop at %s\n",
  1319. path);
  1320. ex = 1;
  1321. goto fail;
  1322. }
  1323. }
  1324. if(level >= vismax)
  1325. {
  1326. vismax += 20;
  1327. visited = srealloc(visited, sizeof *visited * vismax);
  1328. }
  1329. visited[level].v_dev = st.st_dev;
  1330. visited[level].v_ino = st.st_ino;
  1331. }
  1332. #endif /* SU3 */
  1333. if(((field & FL_MARK) || tinfostat == 1 || present('H')) && !present('L') &&
  1334. status != lstat && (st.st_mode & S_IFMT) != S_IFDIR)
  1335. {
  1336. struct stat lst;
  1337. if(lstat(path, &lst) == 0) st = lst;
  1338. }
  1339. setstat(*afl, &st);
  1340. afl = &(*afl)->next;
  1341. }
  1342. delpath(didx);
  1343. }
  1344. }
  1345. sort(&flist);
  1346. if(depth == SUBMERGED && (field & (FL_BLOCKS | FL_LONG)))
  1347. {
  1348. printf("total ");
  1349. if(present('h'))
  1350. printf("%s\n", hfmt(countblocks(flist) * 512, 0));
  1351. else
  1352. #ifdef LONGLONG
  1353. printf("%lld\n", (long long)blockcount(countblocks(flist)));
  1354. #else
  1355. printf("%ld\n", (long)blockcount(countblocks(flist)));
  1356. #endif
  1357. }
  1358. if(state == SINKING || depth == SURFACE1)
  1359. {
  1360. /* Don't list directories themselves, list their contents later. */
  1361. afl = &flist;
  1362. while(*afl != NULL)
  1363. {
  1364. if(((*afl)->mode & S_IFMT) == S_IFDIR)
  1365. {
  1366. pushfile(adl, popfile(afl));
  1367. adl = &(*adl)->next;
  1368. }
  1369. else
  1370. {
  1371. afl = &(*afl)->next;
  1372. }
  1373. }
  1374. }
  1375. if((nfiles = countfiles(flist)) > 0)
  1376. {
  1377. /* Print files in how many columns? */
  1378. nplin = !present('C') && !present('x') ? 1 : nfiles < MAXCOLS ? nfiles : MAXCOLS;
  1379. fsav = flist;
  1380. if(present('x')) savord(flist);
  1381. while(!print(&flist, fsav, nplin, 0))
  1382. nplin--; /* Try first */
  1383. print(&flist, fsav, nplin, 1); /* Then do it! */
  1384. white = 0;
  1385. }
  1386. while(flist != NULL)
  1387. { /* Destroy file list */
  1388. if(state == FLOATING && (flist->mode & S_IFMT) == S_IFDIR)
  1389. {
  1390. /* But keep these directories for ls -R. */
  1391. pushfile(adl, popfile(&flist));
  1392. adl = &(*adl)->next;
  1393. }
  1394. else
  1395. {
  1396. delfile(popfile(&flist));
  1397. }
  1398. }
  1399. while(dlist != NULL)
  1400. { /* List directories */
  1401. if(dotflag(dlist->name) != 'a' || depth != SUBMERGED)
  1402. {
  1403. int didx;
  1404. addpath(&didx, dlist->name);
  1405. flist = NULL;
  1406. if(adddir(&flist, path))
  1407. {
  1408. if(depth != SURFACE1)
  1409. {
  1410. if(!white) putchar('\n');
  1411. white = 0;
  1412. }
  1413. if(depth != SURFACE1 || present('R')) printf("%s:\n", path);
  1414. listfiles(flist, SUBMERGED, state == FLOATING ? FLOATING : BOTTOM, level + 1);
  1415. }
  1416. delpath(didx);
  1417. }
  1418. delfile(popfile(&dlist));
  1419. }
  1420. }
  1421. #ifndef UCB
  1422. static void
  1423. usage(void)
  1424. {
  1425. if(personality == PER_LS) fprintf(stderr, "usage: %s -1RadCxmnlogrtucpFbqisfL [files]\n", arg0);
  1426. exit(2);
  1427. }
  1428. #else /* UCB */
  1429. #define usage()
  1430. #endif /* UCB */
  1431. int
  1432. main(int argc, char **argv)
  1433. {
  1434. struct file *flist = NULL, **aflist = &flist;
  1435. enum depth depth;
  1436. struct winsize ws;
  1437. int i;
  1438. char *cp;
  1439. setlocale(LC_ALL, "");
  1440. uid = geteuid();
  1441. gid = getegid();
  1442. arg0 = basename(argv[0]);
  1443. if(strcmp(arg0, "dir") == 0)
  1444. {
  1445. flags['s'] = flags['U'] = 1;
  1446. personality = PER_DIR;
  1447. }
  1448. else if(strcmp(arg0, "lc") == 0)
  1449. {
  1450. flags['C'] = 1;
  1451. istty = 1;
  1452. }
  1453. if(istty || isatty(1))
  1454. {
  1455. istty = 1;
  1456. field |= FL_STATUS;
  1457. }
  1458. while((i = getopt(argc, argv, personalities[personality].per_opt)) != EOF)
  1459. {
  1460. switch(i)
  1461. {
  1462. case '?':
  1463. usage();
  1464. break;
  1465. case 'O':
  1466. flags['U'] = 0;
  1467. break;
  1468. case '1':
  1469. flags[i] = 1;
  1470. flags['C'] = 0;
  1471. break;
  1472. case 'L':
  1473. flags[i] = 1;
  1474. flags['H'] = 0;
  1475. break;
  1476. case 'H':
  1477. flags[i] = 1;
  1478. flags['L'] = 0;
  1479. break;
  1480. #if defined(SUS) || defined(SU3)
  1481. case 'C':
  1482. flags[i] = 1;
  1483. flags['l'] = flags['m'] = flags['x'] = flags['o'] = flags['g'] = flags['n'] = flags['1'] = 0;
  1484. break;
  1485. case 'm':
  1486. flags[i] = 1;
  1487. flags['l'] = flags['C'] = flags['x'] = flags['o'] = flags['g'] = flags['n'] = flags['1'] = 0;
  1488. break;
  1489. case 'l':
  1490. flags[i] = 1;
  1491. flags['m'] = flags['C'] = flags['x'] = flags['o'] = flags['g'] = 0;
  1492. break;
  1493. case 'x':
  1494. flags[i] = 1;
  1495. flags['m'] = flags['C'] = flags['l'] = flags['o'] = flags['g'] = flags['n'] = flags['1'] = 0;
  1496. break;
  1497. case 'g':
  1498. flags[i] = 1;
  1499. flags['m'] = flags['C'] = flags['l'] = flags['x'] = flags['o'] = 0;
  1500. break;
  1501. case 'o':
  1502. flags[i] = 1;
  1503. flags['m'] = flags['C'] = flags['l'] = flags['x'] = flags['g'] = 0;
  1504. break;
  1505. case 'n':
  1506. flags[i] = 1;
  1507. flags['m'] = flags['C'] = flags['x'] = 0;
  1508. break;
  1509. #endif /* !SUS, !SU3 */
  1510. default:
  1511. flags[i] = 1;
  1512. }
  1513. }
  1514. #ifdef UCB
  1515. if(present('l'))
  1516. {
  1517. if(present('g'))
  1518. flags['g'] = 0;
  1519. else
  1520. flags['o'] = 1;
  1521. }
  1522. else if(present('g'))
  1523. flags['g'] = 0;
  1524. #endif
  1525. #ifdef UCB
  1526. if(SUPER_ID == 0 || present('a')) flags['A'] = 1;
  1527. #else /* !UCB */
  1528. if(present('a')) flags['A'] = 1;
  1529. #endif /* !UCB */
  1530. if(present('i')) field |= FL_INODE;
  1531. if(present('s')) field |= FL_BLOCKS;
  1532. if(present('t')) field |= FL_BYTIME;
  1533. if(present('u')) field |= FL_ATIME;
  1534. if(present('c')) field |= FL_CTIME;
  1535. if(present('l') || present('n') || present('g') || present('o'))
  1536. {
  1537. field = field | FL_MODE | FL_LONG;
  1538. flags['m'] = flags['C'] = flags['x'] = 0;
  1539. }
  1540. if(present('g')) field = field | FL_MODE | FL_LONG | FL_GROUP;
  1541. if(present('o')) field = field | FL_MODE | FL_LONG | FL_OWNER;
  1542. if(present('F')) field |= FL_MARK;
  1543. if(present('d')) field |= FL_DIR;
  1544. if(present('f'))
  1545. {
  1546. field &= ~(FL_LONG | FL_BYTIME | FL_BLOCKS | FL_MODE | FL_MARK | FL_DIR);
  1547. flags['o'] = flags['g'] = flags['l'] = flags['t'] = flags['s'] = flags['r'] = flags['d'] =
  1548. flags['F'] = flags['R'] = flags['p'] = 0;
  1549. flags['a'] = flags['A'] = 1;
  1550. field |= FL_STATUS;
  1551. }
  1552. if(!present('1') && !present('C') && !present('l') && !present('o') && !present('g') &&
  1553. !present('m') && (istty || present('x')))
  1554. flags['C'] = 1;
  1555. if(istty) flags['q'] = 1;
  1556. if((cp = getenv("COLUMNS")) != NULL)
  1557. {
  1558. ncols = atoi(cp);
  1559. }
  1560. else if((present('C') || present('x') || present('m')) && istty)
  1561. {
  1562. if(ioctl(1, TIOCGWINSZ, &ws) == 0 && ws.ws_col > 0) ncols = ws.ws_col - 1;
  1563. }
  1564. depth = SURFACE;
  1565. if(optind == argc)
  1566. {
  1567. if(!(field & FL_DIR)) depth = SURFACE1;
  1568. pushfile(aflist, newfile("."));
  1569. }
  1570. else
  1571. {
  1572. if(optind + 1 == argc && !(field & FL_DIR)) depth = SURFACE1;
  1573. while(optind < argc)
  1574. {
  1575. if(present('f'))
  1576. {
  1577. struct stat st;
  1578. if(stat(argv[optind], &st) == 0 && (st.st_mode & S_IFMT) != S_IFDIR)
  1579. {
  1580. #ifdef UCB
  1581. fprintf(stderr, "%s unreadable\n", argv[optind]);
  1582. #else
  1583. fprintf(stderr, "%s: Not a directory\n", argv[optind]);
  1584. #endif
  1585. ex = 1;
  1586. optind++;
  1587. continue;
  1588. }
  1589. }
  1590. pushfile(aflist, newfile(argv[optind++]));
  1591. aflist = &(*aflist)->next;
  1592. }
  1593. }
  1594. listfiles(flist, depth, (field & FL_DIR) ? BOTTOM : present('R') ? FLOATING : SINKING, 0);
  1595. return ex;
  1596. }