1 /*
2 * Copyright (c) 1989, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Michael Fischbein.
7 *
8 * %sccs.include.redist.c%
9 */
10
11 #ifndef lint
12 static char sccsid[] = "@(#)print.c 8.5 (Berkeley) 07/28/94";
13 #endif /* not lint */
14
15 #include <sys/param.h>
16 #include <sys/stat.h>
17
18 #include <err.h>
19 #include <errno.h>
20 #include <fts.h>
21 #include <grp.h>
22 #include <pwd.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27 #include <tzfile.h>
28 #include <unistd.h>
29 #include <utmp.h>
30
31 #include "ls.h"
32 #include "extern.h"
33
34 static int printaname __P((FTSENT *, u_long, u_long));
35 static void printlink __P((FTSENT *));
36 static void printtime __P((time_t));
37 static int printtype __P((u_int));
38
39 #define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT)
40
41 void
printscol(dp)42 printscol(dp)
43 DISPLAY *dp;
44 {
45 FTSENT *p;
46
47 for (p = dp->list; p; p = p->fts_link) {
48 if (IS_NOPRINT(p))
49 continue;
50 (void)printaname(p, dp->s_inode, dp->s_block);
51 (void)putchar('\n');
52 }
53 }
54
55 void
printlong(dp)56 printlong(dp)
57 DISPLAY *dp;
58 {
59 struct stat *sp;
60 FTSENT *p;
61 NAMES *np;
62 char buf[20];
63
64 if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
65 (void)printf("total %lu\n", howmany(dp->btotal, blocksize));
66
67 for (p = dp->list; p; p = p->fts_link) {
68 if (IS_NOPRINT(p))
69 continue;
70 sp = p->fts_statp;
71 if (f_inode)
72 (void)printf("%*lu ", dp->s_inode, sp->st_ino);
73 if (f_size)
74 (void)printf("%*qd ",
75 dp->s_block, howmany(sp->st_blocks, blocksize));
76 (void)strmode(sp->st_mode, buf);
77 np = p->fts_pointer;
78 (void)printf("%s %*u %-*s %-*s ", buf, dp->s_nlink,
79 sp->st_nlink, dp->s_user, np->user, dp->s_group,
80 np->group);
81 if (f_flags)
82 (void)printf("%-*s ", dp->s_flags, np->flags);
83 if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
84 (void)printf("%3d, %3d ",
85 major(sp->st_rdev), minor(sp->st_rdev));
86 else if (dp->bcfile)
87 (void)printf("%*s%*qd ",
88 8 - dp->s_size, "", dp->s_size, sp->st_size);
89 else
90 (void)printf("%*qd ", dp->s_size, sp->st_size);
91 if (f_accesstime)
92 printtime(sp->st_atime);
93 else if (f_statustime)
94 printtime(sp->st_ctime);
95 else
96 printtime(sp->st_mtime);
97 (void)printf("%s", p->fts_name);
98 if (f_type)
99 (void)printtype(sp->st_mode);
100 if (S_ISLNK(sp->st_mode))
101 printlink(p);
102 (void)putchar('\n');
103 }
104 }
105
106 #define TAB 8
107
108 void
printcol(dp)109 printcol(dp)
110 DISPLAY *dp;
111 {
112 extern int termwidth;
113 static FTSENT **array;
114 static int lastentries = -1;
115 FTSENT *p;
116 int base, chcnt, cnt, col, colwidth, num;
117 int endcol, numcols, numrows, row;
118
119 /*
120 * Have to do random access in the linked list -- build a table
121 * of pointers.
122 */
123 if (dp->entries > lastentries) {
124 lastentries = dp->entries;
125 if ((array =
126 realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
127 warn(NULL);
128 printscol(dp);
129 }
130 }
131 for (p = dp->list, num = 0; p; p = p->fts_link)
132 if (p->fts_number != NO_PRINT)
133 array[num++] = p;
134
135 colwidth = dp->maxlen;
136 if (f_inode)
137 colwidth += dp->s_inode + 1;
138 if (f_size)
139 colwidth += dp->s_block + 1;
140 if (f_type)
141 colwidth += 1;
142
143 colwidth = (colwidth + TAB) & ~(TAB - 1);
144 if (termwidth < 2 * colwidth) {
145 printscol(dp);
146 return;
147 }
148
149 numcols = termwidth / colwidth;
150 numrows = num / numcols;
151 if (num % numcols)
152 ++numrows;
153
154 if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
155 (void)printf("total %lu\n", howmany(dp->btotal, blocksize));
156 for (row = 0; row < numrows; ++row) {
157 endcol = colwidth;
158 for (base = row, chcnt = col = 0; col < numcols; ++col) {
159 chcnt += printaname(array[base], dp->s_inode,
160 dp->s_block);
161 if ((base += numrows) >= num)
162 break;
163 while ((cnt = (chcnt + TAB & ~(TAB - 1))) <= endcol) {
164 (void)putchar('\t');
165 chcnt = cnt;
166 }
167 endcol += colwidth;
168 }
169 (void)putchar('\n');
170 }
171 }
172
173 /*
174 * print [inode] [size] name
175 * return # of characters printed, no trailing characters.
176 */
177 static int
printaname(p,inodefield,sizefield)178 printaname(p, inodefield, sizefield)
179 FTSENT *p;
180 u_long sizefield, inodefield;
181 {
182 struct stat *sp;
183 int chcnt;
184
185 sp = p->fts_statp;
186 chcnt = 0;
187 if (f_inode)
188 chcnt += printf("%*lu ", (int)inodefield, sp->st_ino);
189 if (f_size)
190 chcnt += printf("%*qd ",
191 (int)sizefield, howmany(sp->st_blocks, blocksize));
192 chcnt += printf("%s", p->fts_name);
193 if (f_type)
194 chcnt += printtype(sp->st_mode);
195 return (chcnt);
196 }
197
198 static void
printtime(ftime)199 printtime(ftime)
200 time_t ftime;
201 {
202 int i;
203 char *longstring;
204
205 longstring = ctime(&ftime);
206 for (i = 4; i < 11; ++i)
207 (void)putchar(longstring[i]);
208
209 #define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY)
210 if (f_sectime)
211 for (i = 11; i < 24; i++)
212 (void)putchar(longstring[i]);
213 else if (ftime + SIXMONTHS > time(NULL))
214 for (i = 11; i < 16; ++i)
215 (void)putchar(longstring[i]);
216 else {
217 (void)putchar(' ');
218 for (i = 20; i < 24; ++i)
219 (void)putchar(longstring[i]);
220 }
221 (void)putchar(' ');
222 }
223
224 static int
printtype(mode)225 printtype(mode)
226 u_int mode;
227 {
228 switch (mode & S_IFMT) {
229 case S_IFDIR:
230 (void)putchar('/');
231 return (1);
232 case S_IFIFO:
233 (void)putchar('|');
234 return (1);
235 case S_IFLNK:
236 (void)putchar('@');
237 return (1);
238 case S_IFSOCK:
239 (void)putchar('=');
240 return (1);
241 case S_IFWHT:
242 (void)putchar('%');
243 return (1);
244 }
245 if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
246 (void)putchar('*');
247 return (1);
248 }
249 return (0);
250 }
251
252 static void
printlink(p)253 printlink(p)
254 FTSENT *p;
255 {
256 int lnklen;
257 char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1];
258
259 if (p->fts_level == FTS_ROOTLEVEL)
260 (void)snprintf(name, sizeof(name), "%s", p->fts_name);
261 else
262 (void)snprintf(name, sizeof(name),
263 "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
264 if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
265 (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
266 return;
267 }
268 path[lnklen] = '\0';
269 (void)printf(" -> %s", path);
270 }
271