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