1 /* $NetBSD: print.c,v 1.55 2014/05/10 09:39:18 martin Exp $ */
4 * Copyright (c) 1989, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/cdefs.h>
38 static char sccsid
[] = "@(#)print.c 8.5 (Berkeley) 7/28/94";
40 __RCSID("$NetBSD: print.c,v 1.55 2014/05/10 09:39:18 martin Exp $");
44 #include <sys/param.h>
66 static int printaname(FTSENT
*, int, int);
67 static void printlink(FTSENT
*);
68 static void printtime(time_t);
69 static void printtotal(DISPLAY
*dp
);
70 static int printtype(u_int
);
74 #define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT)
77 safe_printpath(const FTSENT
*p
) {
81 chcnt
= safe_print(p
->fts_path
);
82 chcnt
+= safe_print("/");
85 return chcnt
+ safe_print(p
->fts_name
);
89 printescapedpath(const FTSENT
*p
) {
93 chcnt
= printescaped(p
->fts_path
);
94 chcnt
+= printescaped("/");
98 return chcnt
+ printescaped(p
->fts_name
);
102 printpath(const FTSENT
*p
) {
104 return printf("%s/%s", p
->fts_path
, p
->fts_name
);
106 return printf("%s", p
->fts_name
);
110 printscol(DISPLAY
*dp
)
114 for (p
= dp
->list
; p
; p
= p
->fts_link
) {
117 (void)printaname(p
, dp
->s_inode
, dp
->s_block
);
123 printlong(DISPLAY
*dp
)
128 char buf
[20], szbuf
[5];
133 printtotal(dp
); /* "total: %u\n" */
135 for (p
= dp
->list
; p
; p
= p
->fts_link
) {
140 (void)printf("%*"PRIu64
" ", dp
->s_inode
, sp
->st_ino
);
143 if ((humanize_number(szbuf
, sizeof(szbuf
),
144 sp
->st_blocks
* S_BLKSIZE
,
146 (HN_DECIMAL
| HN_B
| HN_NOSPACE
))) == -1)
147 err(1, "humanize_number");
148 (void)printf("%*s ", dp
->s_block
, szbuf
);
150 (void)printf(f_commas
? "%'*llu " : "%*llu ",
152 (unsigned long long)howmany(sp
->st_blocks
,
156 (void)strmode(sp
->st_mode
, buf
);
158 (void)printf("%s %*lu ", buf
, dp
->s_nlink
,
159 (unsigned long)sp
->st_nlink
);
161 (void)printf("%-*s ", dp
->s_user
, np
->user
);
162 (void)printf("%-*s ", dp
->s_group
, np
->group
);
164 (void)printf("%-*s ", dp
->s_flags
, np
->flags
);
165 if (S_ISCHR(sp
->st_mode
) || S_ISBLK(sp
->st_mode
))
166 (void)printf("%*lld, %*lld ",
167 dp
->s_major
, (long long)major(sp
->st_rdev
),
168 dp
->s_minor
, (long long)minor(sp
->st_rdev
));
171 if ((humanize_number(szbuf
, sizeof(szbuf
),
172 sp
->st_size
, "", HN_AUTOSCALE
,
173 (HN_DECIMAL
| HN_B
| HN_NOSPACE
))) == -1)
174 err(1, "humanize_number");
175 (void)printf("%*s ", dp
->s_size
, szbuf
);
177 (void)printf(f_commas
? "%'*llu " : "%*llu ",
178 dp
->s_size
, (unsigned long long)
182 printtime(sp
->st_atime
);
183 else if (f_statustime
)
184 printtime(sp
->st_ctime
);
186 printtime(sp
->st_mtime
);
187 if (f_octal
|| f_octal_escape
)
188 (void)safe_printpath(p
);
190 (void)printescapedpath(p
);
194 if (f_type
|| (f_typedir
&& S_ISDIR(sp
->st_mode
)))
195 (void)printtype(sp
->st_mode
);
196 if (S_ISLNK(sp
->st_mode
))
203 printcol(DISPLAY
*dp
)
205 static FTSENT
**array
;
206 static int lastentries
= -1;
208 int base
, chcnt
, col
, colwidth
, num
;
209 int numcols
, numrows
, row
;
211 colwidth
= dp
->maxlen
;
213 colwidth
+= dp
->s_inode
+ 1;
216 colwidth
+= dp
->s_size
+ 1;
218 colwidth
+= dp
->s_block
+ 1;
220 if (f_type
|| f_typedir
)
225 if (termwidth
< 2 * colwidth
) {
231 * Have to do random access in the linked list -- build a table
234 if (dp
->entries
> lastentries
) {
237 newarray
= realloc(array
, dp
->entries
* sizeof(FTSENT
*));
238 if (newarray
== NULL
) {
243 lastentries
= dp
->entries
;
246 for (p
= dp
->list
, num
= 0; p
; p
= p
->fts_link
)
247 if (p
->fts_number
!= NO_PRINT
)
250 numcols
= termwidth
/ colwidth
;
251 colwidth
= termwidth
/ numcols
; /* spread out if possible */
252 numrows
= num
/ numcols
;
256 printtotal(dp
); /* "total: %u\n" */
258 for (row
= 0; row
< numrows
; ++row
) {
259 for (base
= row
, chcnt
= col
= 0; col
< numcols
; ++col
) {
260 chcnt
= printaname(array
[base
], dp
->s_inode
,
261 f_humanize
? dp
->s_size
: dp
->s_block
);
262 if ((base
+= numrows
) >= num
)
264 while (chcnt
++ < colwidth
)
272 printacol(DISPLAY
*dp
)
275 int chcnt
, col
, colwidth
;
278 colwidth
= dp
->maxlen
;
280 colwidth
+= dp
->s_inode
+ 1;
283 colwidth
+= dp
->s_size
+ 1;
285 colwidth
+= dp
->s_block
+ 1;
287 if (f_type
|| f_typedir
)
292 if (termwidth
< 2 * colwidth
) {
297 numcols
= termwidth
/ colwidth
;
298 colwidth
= termwidth
/ numcols
; /* spread out if possible */
300 printtotal(dp
); /* "total: %u\n" */
303 for (p
= dp
->list
; p
; p
= p
->fts_link
) {
306 if (col
>= numcols
) {
310 chcnt
= printaname(p
, dp
->s_inode
,
311 f_humanize
? dp
->s_size
: dp
->s_block
);
312 while (chcnt
++ < colwidth
)
320 printstream(DISPLAY
*dp
)
328 extwidth
+= dp
->s_inode
+ 1;
331 extwidth
+= dp
->s_size
+ 1;
333 extwidth
+= dp
->s_block
+ 1;
338 for (col
= 0, p
= dp
->list
; p
!= NULL
; p
= p
->fts_link
) {
342 (void)putchar(','), col
++;
343 if (col
+ 1 + extwidth
+ (int)p
->fts_namelen
>= termwidth
)
344 (void)putchar('\n'), col
= 0;
346 (void)putchar(' '), col
++;
348 col
+= printaname(p
, dp
->s_inode
,
349 f_humanize
? dp
->s_size
: dp
->s_block
);
355 * print [inode] [size] name
356 * return # of characters printed, no trailing characters.
359 printaname(FTSENT
*p
, int inodefield
, int sizefield
)
368 chcnt
+= printf("%*"PRIu64
" ", inodefield
, sp
->st_ino
);
371 if ((humanize_number(szbuf
, sizeof(szbuf
), sp
->st_size
,
373 (HN_DECIMAL
| HN_B
| HN_NOSPACE
))) == -1)
374 err(1, "humanize_number");
375 chcnt
+= printf("%*s ", sizefield
, szbuf
);
377 chcnt
+= printf(f_commas
? "%'*llu " : "%*llu ",
378 sizefield
, (unsigned long long)
379 howmany(sp
->st_blocks
, blocksize
));
382 if (f_octal
|| f_octal_escape
)
383 chcnt
+= safe_printpath(p
);
385 chcnt
+= printescapedpath(p
);
387 chcnt
+= printpath(p
);
388 if (f_type
|| (f_typedir
&& S_ISDIR(sp
->st_mode
)))
389 chcnt
+= printtype(sp
->st_mode
);
394 printtime(time_t ftime
)
397 const char *longstring
;
399 if ((longstring
= ctime(&ftime
)) == NULL
) {
400 /* 012345678901234567890123 */
401 longstring
= "????????????????????????";
403 for (i
= 4; i
< 11; ++i
)
404 (void)putchar(longstring
[i
]);
406 #define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY)
408 for (i
= 11; i
< 24; i
++)
409 (void)putchar(longstring
[i
]);
410 else if (ftime
+ SIXMONTHS
> now
&& ftime
- SIXMONTHS
< now
)
411 for (i
= 11; i
< 16; ++i
)
412 (void)putchar(longstring
[i
]);
415 for (i
= 20; i
< 24; ++i
)
416 (void)putchar(longstring
[i
]);
422 * Display total used disk space in the form "total: %u\n".
423 * Note: POSIX (IEEE Std 1003.1-2001) says this should be always in 512 blocks,
424 * but we humanise it with -h, or separate it with commas with -M, and use 1024
428 printtotal(DISPLAY
*dp
)
432 if (dp
->list
->fts_level
!= FTS_ROOTLEVEL
&& (f_longform
|| f_size
)) {
434 if ((humanize_number(szbuf
, sizeof(szbuf
), (int64_t)dp
->stotal
,
436 (HN_DECIMAL
| HN_B
| HN_NOSPACE
))) == -1)
437 err(1, "humanize_number");
438 (void)printf("total %s\n", szbuf
);
440 (void)printf(f_commas
? "total %'llu\n" :
441 "total %llu\n", (unsigned long long)
442 howmany(dp
->btotal
, blocksize
));
448 printtype(u_int mode
)
450 switch (mode
& S_IFMT
) {
467 if (mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) {
478 char name
[MAXPATHLEN
+ 1], path
[MAXPATHLEN
+ 1];
480 if (p
->fts_level
== FTS_ROOTLEVEL
)
481 (void)snprintf(name
, sizeof(name
), "%s", p
->fts_name
);
483 (void)snprintf(name
, sizeof(name
),
484 "%s/%s", p
->fts_parent
->fts_accpath
, p
->fts_name
);
485 if ((lnklen
= readlink(name
, path
, sizeof(path
) - 1)) == -1) {
486 (void)fprintf(stderr
, "\nls: %s: %s\n", name
, strerror(errno
));
490 (void)printf(" -> ");
491 if (f_octal
|| f_octal_escape
)
492 (void)safe_print(path
);
494 (void)printescaped(path
);
496 (void)printf("%s", path
);