Deleted Added
sdiff udiff text old ( 88584 ) new ( 88586 )
full compact
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 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38#if 0
39static char sccsid[] = "@(#)print.c 8.4 (Berkeley) 4/17/94";
40#else
41static const char rcsid[] =
42 "$FreeBSD: head/bin/ls/print.c 88584 2001-12-28 18:20:23Z joe $";
43#endif
44#endif /* not lint */
45
46#include <sys/param.h>
47#include <sys/stat.h>
48
49#include <err.h>
50#include <errno.h>
51#include <fts.h>
52#include <grp.h>
53#include <langinfo.h>
54#include <pwd.h>
55#include <stdio.h>
56#include <stdlib.h>
57#include <string.h>
58#include <time.h>
59#include <unistd.h>
60#ifdef COLORLS
61#include <ctype.h>
62#include <termcap.h>
63#include <signal.h>
64#endif
65
66#include "ls.h"
67#include "extern.h"
68
69static int printaname __P((FTSENT *, u_long, u_long));
70static void printlink __P((FTSENT *));
71static void printtime __P((time_t));
72static int printtype __P((u_int));
73#ifdef COLORLS
74static void endcolor __P((int));
75static int colortype __P((mode_t));
76#endif
77
78#define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT)
79
80#ifdef COLORLS
81/* Most of these are taken from <sys/stat.h> */
82typedef enum Colors {
83 C_DIR, /* directory */
84 C_LNK, /* symbolic link */
85 C_SOCK, /* socket */
86 C_FIFO, /* pipe */
87 C_EXEC, /* executable */
88 C_BLK, /* block special */
89 C_CHR, /* character special */
90 C_SUID, /* setuid executable */
91 C_SGID, /* setgid executable */
92 C_WSDIR, /* directory writeble to others, with sticky bit */
93 C_WDIR, /* directory writeble to others, without sticky bit */
94 C_NUMCOLORS /* just a place-holder */
95} Colors ;
96
97char *defcolors = "exfxcxdxbxegedabagacad";
98
99/* colors for file types */
100static struct {
101 int num[2];
102 int bold;
103} colors[C_NUMCOLORS];
104
105#endif
106
107void
108printscol(dp)
109 DISPLAY *dp;
110{
111 FTSENT *p;
112
113 for (p = dp->list; p; p = p->fts_link) {
114 if (IS_NOPRINT(p))
115 continue;
116 (void)printaname(p, dp->s_inode, dp->s_block);
117 (void)putchar('\n');
118 }
119}
120
121/*
122 * print name in current style
123 */
124static int
125printname(name)
126 const char *name;
127{
128 if (f_octal || f_octal_escape)
129 return prn_octal(name);
130 else if (f_nonprint)
131 return prn_printable(name);
132 else
133 return printf("%s", name);
134}
135
136void
137printlong(dp)
138 DISPLAY *dp;
139{
140 struct stat *sp;
141 FTSENT *p;
142 NAMES *np;
143 char buf[20];
144#ifdef COLORLS
145 int color_printed = 0;
146#endif
147
148 if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
149 (void)printf("total %lu\n", howmany(dp->btotal, blocksize));
150
151 for (p = dp->list; p; p = p->fts_link) {
152 if (IS_NOPRINT(p))
153 continue;
154 sp = p->fts_statp;
155 if (f_inode)
156 (void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino);
157 if (f_size)
158 (void)printf("%*qd ",
159 dp->s_block, howmany(sp->st_blocks, blocksize));
160 (void)strmode(sp->st_mode, buf);
161 np = p->fts_pointer;
162 (void)printf("%s %*u %-*s %-*s ", buf, dp->s_nlink,
163 sp->st_nlink, dp->s_user, np->user, dp->s_group,
164 np->group);
165 if (f_flags)
166 (void)printf("%-*s ", dp->s_flags, np->flags);
167 if (f_lomac)
168 (void)printf("%-*s ", dp->s_lattr, np->lattr);
169 if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
170 if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0)
171 (void)printf("%3d, 0x%08x ",
172 major(sp->st_rdev),
173 (u_int)minor(sp->st_rdev));
174 else
175 (void)printf("%3d, %3d ",
176 major(sp->st_rdev), minor(sp->st_rdev));
177 else if (dp->bcfile)
178 (void)printf("%*s%*qd ",
179 8 - dp->s_size, "", dp->s_size, sp->st_size);
180 else
181 (void)printf("%*qd ", dp->s_size, sp->st_size);
182 if (f_accesstime)
183 printtime(sp->st_atime);
184 else if (f_statustime)
185 printtime(sp->st_ctime);
186 else
187 printtime(sp->st_mtime);
188#ifdef COLORLS
189 if (f_color)
190 color_printed = colortype(sp->st_mode);
191#endif
192 (void)printname(p->fts_name);
193#ifdef COLORLS
194 if (f_color && color_printed)
195 endcolor(0);
196#endif
197 if (f_type)
198 (void)printtype(sp->st_mode);
199 if (S_ISLNK(sp->st_mode))
200 printlink(p);
201 (void)putchar('\n');
202 }
203}
204
205void
206printcol(dp)
207 DISPLAY *dp;
208{
209 extern int termwidth;
210 static FTSENT **array;
211 static int lastentries = -1;
212 FTSENT *p;
213 int base, chcnt, cnt, col, colwidth, num;
214 int endcol, numcols, numrows, row;
215 int tabwidth;
216
217 if (f_notabs)
218 tabwidth = 1;
219 else
220 tabwidth = 8;
221
222 /*
223 * Have to do random access in the linked list -- build a table
224 * of pointers.
225 */
226 if (dp->entries > lastentries) {
227 lastentries = dp->entries;
228 if ((array =
229 realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
230 warn(NULL);
231 printscol(dp);
232 }
233 }
234 for (p = dp->list, num = 0; p; p = p->fts_link)
235 if (p->fts_number != NO_PRINT)
236 array[num++] = p;
237
238 colwidth = dp->maxlen;
239 if (f_inode)
240 colwidth += dp->s_inode + 1;
241 if (f_size)
242 colwidth += dp->s_block + 1;
243 if (f_type)
244 colwidth += 1;
245
246 colwidth = (colwidth + tabwidth) & ~(tabwidth - 1);
247 if (termwidth < 2 * colwidth) {
248 printscol(dp);
249 return;
250 }
251
252 numcols = termwidth / colwidth;
253 numrows = num / numcols;
254 if (num % numcols)
255 ++numrows;
256
257 if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
258 (void)printf("total %lu\n", howmany(dp->btotal, blocksize));
259 for (row = 0; row < numrows; ++row) {
260 endcol = colwidth;
261 for (base = row, chcnt = col = 0; col < numcols; ++col) {
262 chcnt += printaname(array[base], dp->s_inode,
263 dp->s_block);
264 if ((base += numrows) >= num)
265 break;
266 while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1)))
267 <= endcol){
268 (void)putchar(f_notabs ? ' ' : '\t');
269 chcnt = cnt;
270 }
271 endcol += colwidth;
272 }
273 (void)putchar('\n');
274 }
275}
276
277/*
278 * print [inode] [size] name
279 * return # of characters printed, no trailing characters.
280 */
281static int
282printaname(p, inodefield, sizefield)
283 FTSENT *p;
284 u_long sizefield, inodefield;
285{
286 struct stat *sp;
287 int chcnt;
288#ifdef COLORLS
289 int color_printed = 0;
290#endif
291
292 sp = p->fts_statp;
293 chcnt = 0;
294 if (f_inode)
295 chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino);
296 if (f_size)
297 chcnt += printf("%*qd ",
298 (int)sizefield, howmany(sp->st_blocks, blocksize));
299#ifdef COLORLS
300 if (f_color)
301 color_printed = colortype(sp->st_mode);
302#endif
303 chcnt += printname(p->fts_name);
304#ifdef COLORLS
305 if (f_color && color_printed)
306 endcolor(0);
307#endif
308 if (f_type)
309 chcnt += printtype(sp->st_mode);
310 return (chcnt);
311}
312
313static void
314printtime(ftime)
315 time_t ftime;
316{
317 char longstring[80];
318 static time_t now;
319 const char *format;
320 static int d_first = -1;
321
322 if (d_first < 0)
323 d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
324 if (now == 0)
325 now = time(NULL);
326
327#define SIXMONTHS ((365 / 2) * 86400)
328 if (f_sectime)
329 /* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */
330 format = d_first ? "%e %b %T %Y " : "%b %e %T %Y ";
331 else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS)
332 /* mmm dd hh:mm || dd mmm hh:mm */
333 format = d_first ? "%e %b %R " : "%b %e %R ";
334 else
335 /* mmm dd yyyy || dd mmm yyyy */
336 format = d_first ? "%e %b %Y " : "%b %e %Y ";
337 strftime(longstring, sizeof(longstring), format, localtime(&ftime));
338 fputs(longstring, stdout);
339}
340
341static int
342printtype(mode)
343 u_int mode;
344{
345 switch (mode & S_IFMT) {
346 case S_IFDIR:
347 (void)putchar('/');
348 return (1);
349 case S_IFIFO:
350 (void)putchar('|');
351 return (1);
352 case S_IFLNK:
353 (void)putchar('@');
354 return (1);
355 case S_IFSOCK:
356 (void)putchar('=');
357 return (1);
358 case S_IFWHT:
359 (void)putchar('%');
360 return (1);
361 }
362 if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
363 (void)putchar('*');
364 return (1);
365 }
366 return (0);
367}
368
369#ifdef COLORLS
370static int
371putch(c)
372 int c;
373{
374 (void) putchar(c);
375 return 0;
376}
377
378static int
379writech(c)
380 int c;
381{
382 char tmp = c;
383
384 (void) write(STDOUT_FILENO, &tmp, 1);
385 return 0;
386}
387
388static void
389printcolor(c)
390 Colors c;
391{
392 char *ansiseq;
393
394 if (colors[c].bold)
395 tputs(enter_bold, 1, putch);
396
397 if (colors[c].num[0] != -1) {
398 ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]);
399 if (ansiseq)
400 tputs(ansiseq, 1, putch);
401 }
402
403 if (colors[c].num[1] != -1) {
404 ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]);
405 if (ansiseq)
406 tputs(ansiseq, 1, putch);
407 }
408}
409
410static void
411endcolor(sig)
412 int sig;
413{
414 tputs(ansi_coloff, 1, sig ? writech : putch);
415 tputs(attrs_off, 1, sig ? writech : putch);
416}
417
418static int
419colortype(mode)
420 mode_t mode;
421{
422 switch(mode & S_IFMT) {
423 case S_IFDIR:
424 if (mode & S_IWOTH)
425 if (mode & S_ISTXT)
426 printcolor(C_WSDIR);
427 else
428 printcolor(C_WDIR);
429 else
430 printcolor(C_DIR);
431 return(1);
432 case S_IFLNK:
433 printcolor(C_LNK);
434 return(1);
435 case S_IFSOCK:
436 printcolor(C_SOCK);
437 return(1);
438 case S_IFIFO:
439 printcolor(C_FIFO);
440 return(1);
441 case S_IFBLK:
442 printcolor(C_BLK);
443 return(1);
444 case S_IFCHR:
445 printcolor(C_CHR);
446 return(1);
447 }
448 if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
449 if (mode & S_ISUID)
450 printcolor(C_SUID);
451 else if (mode & S_ISGID)
452 printcolor(C_SGID);
453 else
454 printcolor(C_EXEC);
455 return(1);
456 }
457 return(0);
458}
459
460void
461parsecolors(cs)
462char *cs;
463{
464 int i, j, len;
465 char c[2];
466 short legacy_warn = 0;
467
468 if (cs == NULL) cs = ""; /* LSCOLORS not set */
469 len = strlen(cs);
470 for (i = 0 ; i < C_NUMCOLORS ; i++) {
471 colors[i].bold = 0;
472
473 if (len <= 2*i) {
474 c[0] = defcolors[2*i];
475 c[1] = defcolors[2*i+1];
476 }
477 else {
478 c[0] = cs[2*i];
479 c[1] = cs[2*i+1];
480 }
481 for (j = 0 ; j < 2 ; j++) {
482 /* Legacy colours used 0-7 */
483 if (c[j] >= '0' && c[j] <= '7') {
484 colors[i].num[j] = c[j] - '0';
485 if (!legacy_warn) {
486 fprintf(stderr,
487 "warn: colors are now defined "
488 "using a-h instead of 0-9. "
489 "see manual page.\n");
490 }
491 legacy_warn = 1;
492 } else if (c[j] >= 'a' && c[j] <= 'h')
493 colors[i].num[j] = c[j] - 'a';
494 else if (c[j] >= 'A' && c[j] <= 'H') {
495 colors[i].num[j] = c[j] - 'A';
496 colors[i].bold = 1;
497 } else if (tolower((unsigned char)c[j] == 'x'))
498 colors[i].num[j] = -1;
499 else {
500 fprintf(stderr,
501 "error: invalid character '%c' in LSCOLORS"
502 " env var\n", c[j]);
503 colors[i].num[j] = -1;
504 }
505 }
506 }
507}
508
509void
510colorquit(sig)
511 int sig;
512{
513 endcolor(sig);
514
515 (void) signal(sig, SIG_DFL);
516 (void) kill(getpid(), sig);
517}
518#endif /*COLORLS*/
519
520static void
521printlink(p)
522 FTSENT *p;
523{
524 int lnklen;
525 char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1];
526
527 if (p->fts_level == FTS_ROOTLEVEL)
528 (void)snprintf(name, sizeof(name), "%s", p->fts_name);
529 else
530 (void)snprintf(name, sizeof(name),
531 "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
532 if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
533 (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
534 return;
535 }
536 path[lnklen] = '\0';
537 (void)printf(" -> ");
538 printname(path);
539}