xref: /original-bsd/bin/ls/print.c (revision a9a02843)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * 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 are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the University of California, Berkeley.  The name of the
14  * University may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  */
20 
21 #ifndef lint
22 static char sccsid[] = "@(#)print.c	5.14 (Berkeley) 06/28/89";
23 #endif /* not lint */
24 
25 #include <sys/param.h>
26 #include <sys/stat.h>
27 #include <stdio.h>
28 #include <grp.h>
29 #include <pwd.h>
30 #include <utmp.h>
31 #include <tzfile.h>
32 #include "ls.h"
33 
34 printscol(stats, num)
35 	register LS *stats;
36 	register int num;
37 {
38 	for (; num--; ++stats) {
39 		(void)printaname(stats);
40 		(void)putchar('\n');
41 	}
42 }
43 
44 printlong(stats, num)
45 	LS *stats;
46 	register int num;
47 {
48 	if (f_total)
49 		(void)printf("total %lu\n", stats[0].lstat.st_btotal);
50 	for (; num--; ++stats) {
51 		if (f_inode)
52 			(void)printf("%6lu ", stats->lstat.st_ino);
53 		if (f_size)
54 			(void)printf("%4ld ", stats->lstat.st_blocks);
55 		printperms(stats->lstat.st_mode);
56 		(void)printf("%3d ", stats->lstat.st_nlink);
57 		printowner(stats->lstat.st_uid);
58 		if (f_group)
59 			printgrp(stats->lstat.st_gid);
60 		if (S_ISCHR(stats->lstat.st_mode) ||
61 		    S_ISBLK(stats->lstat.st_mode))
62 			(void)printf("%3d,%4d ", major(stats->lstat.st_rdev),
63 			    minor(stats->lstat.st_rdev));
64 		else
65 			(void)printf("%8ld ", stats->lstat.st_size);
66 		if (f_accesstime)
67 			printtime(stats->lstat.st_atime);
68 		else if (f_statustime)
69 			printtime(stats->lstat.st_ctime);
70 		else
71 			printtime(stats->lstat.st_mtime);
72 		(void)printf("%s", stats->name);
73 		if (f_type)
74 			(void)printtype(stats->lstat.st_mode);
75 		if (S_ISLNK(stats->lstat.st_mode))
76 			printlink(stats->name);
77 		(void)putchar('\n');
78 	}
79 }
80 
81 #define	TAB	8
82 
83 printcol(stats, num)
84 	LS *stats;
85 	int num;
86 {
87 	extern int termwidth;
88 	register int base, chcnt, cnt, col, colwidth;
89 	int endcol, numcols, numrows, row;
90 
91 	colwidth = stats[0].lstat.st_maxlen;
92 	if (f_inode)
93 		colwidth += 6;
94 	if (f_size)
95 		colwidth += 5;
96 	if (f_type)
97 		colwidth += 1;
98 	colwidth = (colwidth + TAB) & ~(TAB - 1);
99 
100 	numcols = termwidth / colwidth;
101 	numrows = num / numcols;
102 	if (num % numcols)
103 		++numrows;
104 
105 	if (f_size && f_total)
106 		(void)printf("total %lu\n", stats[0].lstat.st_btotal);
107 	for (row = 0; row < numrows; ++row) {
108 		endcol = colwidth;
109 		for (base = row, chcnt = col = 0; col < numcols; ++col) {
110 			chcnt += printaname(stats + base);
111 			if ((base += numrows) >= num)
112 				break;
113 			while ((cnt = (chcnt + TAB & ~(TAB - 1))) <= endcol) {
114 				(void)putchar('\t');
115 				chcnt = cnt;
116 			}
117 			endcol += colwidth;
118 		}
119 		putchar('\n');
120 	}
121 }
122 
123 /*
124  * print [inode] [size] name
125  * return # of characters printed, no trailing characters
126  */
127 printaname(lp)
128 	LS *lp;
129 {
130 	int chcnt;
131 
132 	chcnt = 0;
133 	if (f_inode)
134 		chcnt += printf("%5lu ", lp->lstat.st_ino);
135 	if (f_size)
136 		chcnt += printf("%4ld ", lp->lstat.st_blocks);
137 	chcnt += printf("%s", lp->name);
138 	if (f_type)
139 		chcnt += printtype(lp->lstat.st_mode);
140 	return(chcnt);
141 }
142 
143 #define	NCACHE	64		/* power of 2 */
144 #define	LSMASK	NCACHE - 1	/* bits to store with */
145 printowner(uid)
146 	uid_t uid;
147 {
148 	static struct ncache {
149 		uid_t	uid;
150 		char	name[UT_NAMESIZE];
151 	} c_uid[NCACHE];
152 	register struct passwd *pw;
153 	register struct ncache *cp;
154 
155 	cp = c_uid + (uid & LSMASK);
156 	if (cp->uid != uid || !*cp->name) {
157 		/* if can't find owner, print out number instead */
158 		if (!(pw = getpwuid(uid))) {
159 			(void)printf("%-*u ", UT_NAMESIZE, uid);
160 			return;
161 		}
162 		cp->uid = uid;
163 		(void)strncpy(cp->name, pw->pw_name, UT_NAMESIZE);
164 	}
165 	(void)printf("%-*.*s ", UT_NAMESIZE, UT_NAMESIZE, cp->name);
166 }
167 
168 printgrp(gid)
169 	gid_t gid;
170 {
171 	static struct ncache {
172 		gid_t	gid;
173 		char	name[UT_NAMESIZE];
174 	} c_gid[NCACHE];
175 	register struct group *gr;
176 	register struct ncache *cp;
177 
178 	cp = c_gid + (gid & LSMASK);
179 	if (cp->gid != gid || !*cp->name) {
180 		/* can't find group, print out number instead */
181 		if (!(gr = getgrgid(gid))) {
182 			(void)printf("%-*u ", UT_NAMESIZE, gid);
183 			return;
184 		}
185 		cp->gid = gid;
186 		(void)strncpy(cp->name, gr->gr_name, UT_NAMESIZE);
187 	}
188 	(void)printf("%-*.*s ", UT_NAMESIZE, UT_NAMESIZE, cp->name);
189 }
190 
191 printtime(ftime)
192 	time_t ftime;
193 {
194 	int i;
195 	char *longstring, *ctime();
196 	time_t time();
197 
198 	longstring = ctime((long *)&ftime);
199 	for (i = 4; i < 11; ++i)
200 		(void)putchar(longstring[i]);
201 
202 #define	SIXMONTHS	((DAYSPERNYEAR / 2) * SECSPERDAY)
203 	if (ftime + SIXMONTHS > time((time_t *)NULL))
204 		for (i = 11; i < 16; ++i)
205 			(void)putchar(longstring[i]);
206 	else {
207 		(void)putchar(' ');
208 		for (i = 20; i < 24; ++i)
209 			(void)putchar(longstring[i]);
210 	}
211 	(void)putchar(' ');
212 }
213 
214 /*
215  * do the permissions printing, passed the mode
216  */
217 printperms(mode)
218 	mode_t mode;
219 {
220 	 /* print type */
221 	switch (mode & S_IFMT) {
222 	case S_IFDIR:			/* directory */
223 		(void)putchar('d');
224 		break;
225 	case S_IFCHR:			/* character special */
226 		(void)putchar('c');
227 		break;
228 	case S_IFBLK:			/* block special */
229 		(void)putchar('b');
230 		break;
231 	case S_IFREG:			/* regular */
232 		(void)putchar('-');
233 		break;
234 	case S_IFLNK:			/* symbolic link */
235 		(void)putchar('l');
236 		break;
237 	case S_IFSOCK:			/* socket */
238 		(void)putchar('s');
239 		break;
240 #ifdef S_IFIFO
241 	case S_IFIFO:			/* fifo */
242 		(void)putchar('p');
243 		break;
244 #endif
245 	default:			/* unknown */
246 		(void)putchar('?');
247 		break;
248 	}
249 	/* usr */
250 	if (mode & S_IRUSR)
251 		(void)putchar('r');
252 	else
253 		(void)putchar('-');
254 	if (mode & S_IWUSR)
255 		(void)putchar('w');
256 	else
257 		(void)putchar('-');
258 	switch (mode & (S_IXUSR | S_ISUID)) {
259 	case 0:
260 		(void)putchar('-');
261 		break;
262 	case S_IXUSR:
263 		(void)putchar('x');
264 		break;
265 	case S_ISUID:
266 		(void)putchar('S');
267 		break;
268 	case S_IXUSR | S_ISUID:
269 		(void)putchar('s');
270 		break;
271 	}
272 	/* group */
273 	if (mode & S_IRGRP)
274 		(void)putchar('r');
275 	else
276 		(void)putchar('-');
277 	if (mode & S_IWGRP)
278 		(void)putchar('w');
279 	else
280 		(void)putchar('-');
281 	switch (mode & (S_IXGRP | S_ISGID)) {
282 	case 0:
283 		(void)putchar('-');
284 		break;
285 	case S_IXGRP:
286 		(void)putchar('x');
287 		break;
288 	case S_ISGID:
289 		(void)putchar('S');
290 		break;
291 	case S_IXGRP | S_ISGID:
292 		(void)putchar('s');
293 		break;
294 	}
295 	/* other */
296 	if (mode & S_IROTH)
297 		(void)putchar('r');
298 	else
299 		(void)putchar('-');
300 	if (mode & S_IWOTH)
301 		(void)putchar('w');
302 	else
303 		(void)putchar('-');
304 	switch (mode & (S_IXOTH | S_ISVTX)) {
305 	case 0:
306 		(void)putchar('-');
307 		break;
308 	case S_IXOTH:
309 		(void)putchar('x');
310 		break;
311 	case S_ISVTX:
312 		(void)putchar('T');
313 		break;
314 	case S_IXOTH | S_ISVTX:
315 		(void)putchar('t');
316 		break;
317 	}
318 }
319 
320 printtype(mode)
321 	mode_t mode;
322 {
323 	switch(mode & S_IFMT) {
324 	case S_IFDIR:
325 		(void)putchar('/');
326 		return(1);
327 	case S_IFLNK:
328 		(void)putchar('@');
329 		return(1);
330 	case S_IFSOCK:
331 		(void)putchar('=');
332 		return(1);
333 	}
334 	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
335 		(void)putchar('*');
336 		return(1);
337 	}
338 	return(0);
339 }
340 
341 printlink(name)
342 	char *name;
343 {
344 	int lnklen;
345 	char path[MAXPATHLEN + 1], *strerror();
346 
347 	if ((lnklen = readlink(name, path, MAXPATHLEN)) == -1) {
348 		(void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
349 		return;
350 	}
351 	path[lnklen] = '\0';
352 	(void)printf(" -> %s", path);
353 }
354