1 /* $OpenBSD: print.c,v 1.15 2000/01/06 21:32:40 espie Exp $ */ 2 /* $NetBSD: print.c,v 1.15 1996/12/11 03:25:39 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 1989, 1993, 1994 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Michael Fischbein. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 */ 39 40 #ifndef lint 41 #if 0 42 static char sccsid[] = "@(#)print.c 8.5 (Berkeley) 7/28/94"; 43 #else 44 static char rcsid[] = "$OpenBSD: print.c,v 1.15 2000/01/06 21:32:40 espie Exp $"; 45 #endif 46 #endif /* not lint */ 47 48 #include <sys/param.h> 49 #include <sys/stat.h> 50 51 #include <err.h> 52 #include <errno.h> 53 #include <fts.h> 54 #include <grp.h> 55 #include <pwd.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <time.h> 60 #include <tzfile.h> 61 #include <unistd.h> 62 #include <utmp.h> 63 64 #include "ls.h" 65 #include "extern.h" 66 67 static int printaname __P((FTSENT *, u_long, u_long)); 68 static void printlink __P((FTSENT *)); 69 static void printtime __P((time_t)); 70 static int printtype __P((u_int)); 71 static int compute_columns __P((DISPLAY *, int *)); 72 73 #define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) 74 75 void 76 printscol(dp) 77 DISPLAY *dp; 78 { 79 FTSENT *p; 80 81 for (p = dp->list; p; p = p->fts_link) { 82 if (IS_NOPRINT(p)) 83 continue; 84 (void)printaname(p, dp->s_inode, dp->s_block); 85 (void)putchar('\n'); 86 } 87 } 88 89 void 90 printlong(dp) 91 DISPLAY *dp; 92 { 93 struct stat *sp; 94 FTSENT *p; 95 NAMES *np; 96 char buf[20]; 97 98 if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 99 (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 100 101 for (p = dp->list; p; p = p->fts_link) { 102 if (IS_NOPRINT(p)) 103 continue; 104 sp = p->fts_statp; 105 if (f_inode) 106 (void)printf("%*u ", dp->s_inode, sp->st_ino); 107 if (f_size) 108 (void)printf("%*qd ", 109 dp->s_block, howmany(sp->st_blocks, blocksize)); 110 (void)strmode(sp->st_mode, buf); 111 np = p->fts_pointer; 112 (void)printf("%s %*u %-*s %-*s ", buf, dp->s_nlink, 113 sp->st_nlink, dp->s_user, np->user, dp->s_group, 114 np->group); 115 if (f_flags) 116 (void)printf("%-*s ", dp->s_flags, np->flags); 117 if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) 118 (void)printf("%3d, %3d ", 119 major(sp->st_rdev), minor(sp->st_rdev)); 120 else if (dp->bcfile) 121 (void)printf("%*s%*qd ", 122 8 - dp->s_size, "", dp->s_size, sp->st_size); 123 else 124 (void)printf("%*qd ", dp->s_size, sp->st_size); 125 if (f_accesstime) 126 printtime(sp->st_atime); 127 else if (f_statustime) 128 printtime(sp->st_ctime); 129 else 130 printtime(sp->st_mtime); 131 (void)putname(p->fts_name); 132 if (f_type || (f_typedir && S_ISDIR(sp->st_mode))) 133 (void)printtype(sp->st_mode); 134 if (S_ISLNK(sp->st_mode)) 135 printlink(p); 136 (void)putchar('\n'); 137 } 138 } 139 140 static int 141 compute_columns(dp, pnum) 142 DISPLAY *dp; 143 int *pnum; 144 { 145 int colwidth; 146 extern int termwidth; 147 int mywidth; 148 149 colwidth = dp->maxlen; 150 if (f_inode) 151 colwidth += dp->s_inode + 1; 152 if (f_size) 153 colwidth += dp->s_block + 1; 154 if (f_type || f_typedir) 155 colwidth += 1; 156 157 colwidth += 1; 158 mywidth = termwidth + 1; /* no extra space for last column */ 159 160 if (mywidth < 2 * colwidth) { 161 printscol(dp); 162 return (0); 163 } 164 165 *pnum = mywidth / colwidth; 166 return (mywidth / *pnum); /* spread out if possible */ 167 } 168 169 void 170 printcol(dp) 171 DISPLAY *dp; 172 { 173 static FTSENT **array; 174 static int lastentries = -1; 175 FTSENT *p; 176 int base, chcnt, col, colwidth, num; 177 int numcols, numrows, row; 178 179 if ( (colwidth = compute_columns(dp, &numcols)) == 0) 180 return; 181 /* 182 * Have to do random access in the linked list -- build a table 183 * of pointers. 184 */ 185 if (dp->entries > lastentries) { 186 FTSENT **a; 187 188 if ((a = 189 realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) { 190 warn(NULL); 191 printscol(dp); 192 return; 193 } 194 lastentries = dp->entries; 195 array = a; 196 } 197 for (p = dp->list, num = 0; p; p = p->fts_link) 198 if (p->fts_number != NO_PRINT) 199 array[num++] = p; 200 201 numrows = num / numcols; 202 if (num % numcols) 203 ++numrows; 204 205 if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 206 (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 207 for (row = 0; row < numrows; ++row) { 208 for (base = row, col = 0;;) { 209 chcnt = printaname(array[base], dp->s_inode, dp->s_block); 210 if ((base += numrows) >= num) 211 break; 212 if (++col == numcols) 213 break; 214 while (chcnt++ < colwidth) 215 putchar(' '); 216 } 217 (void)putchar('\n'); 218 } 219 } 220 221 /* 222 * print [inode] [size] name 223 * return # of characters printed, no trailing characters. 224 */ 225 static int 226 printaname(p, inodefield, sizefield) 227 FTSENT *p; 228 u_long sizefield, inodefield; 229 { 230 struct stat *sp; 231 int chcnt; 232 233 sp = p->fts_statp; 234 chcnt = 0; 235 if (f_inode) 236 chcnt += printf("%*u ", (int)inodefield, sp->st_ino); 237 if (f_size) 238 chcnt += printf("%*qd ", 239 (int)sizefield, howmany(sp->st_blocks, blocksize)); 240 chcnt += putname(p->fts_name); 241 if (f_type || (f_typedir && S_ISDIR(sp->st_mode))) 242 chcnt += printtype(sp->st_mode); 243 return (chcnt); 244 } 245 246 static void 247 printtime(ftime) 248 time_t ftime; 249 { 250 int i; 251 char *longstring; 252 253 longstring = ctime(&ftime); 254 for (i = 4; i < 11; ++i) 255 (void)putchar(longstring[i]); 256 257 #define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY) 258 if (f_sectime) 259 for (i = 11; i < 24; i++) 260 (void)putchar(longstring[i]); 261 else if (ftime + SIXMONTHS > time(NULL)) 262 for (i = 11; i < 16; ++i) 263 (void)putchar(longstring[i]); 264 else { 265 (void)putchar(' '); 266 for (i = 20; i < 24; ++i) 267 (void)putchar(longstring[i]); 268 } 269 (void)putchar(' '); 270 } 271 272 void 273 printacol(dp) 274 DISPLAY *dp; 275 { 276 FTSENT *p; 277 int chcnt, col, colwidth; 278 int numcols; 279 280 if ( (colwidth = compute_columns(dp, &numcols)) == 0) 281 return; 282 283 if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 284 (void)printf("total %llu\n", 285 (long long)(howmany(dp->btotal, blocksize))); 286 col = 0; 287 for (p = dp->list; p; p = p->fts_link) { 288 if (IS_NOPRINT(p)) 289 continue; 290 if (col >= numcols) { 291 col = 0; 292 (void)putchar('\n'); 293 } 294 chcnt = printaname(p, dp->s_inode, dp->s_block); 295 col++; 296 if (col < numcols) 297 while (chcnt++ < colwidth) 298 (void)putchar(' '); 299 } 300 (void)putchar('\n'); 301 } 302 303 void 304 printstream(dp) 305 DISPLAY *dp; 306 { 307 extern int termwidth; 308 FTSENT *p; 309 int col; 310 int extwidth; 311 312 extwidth = 0; 313 if (f_inode) 314 extwidth += dp->s_inode + 1; 315 if (f_size) 316 extwidth += dp->s_block + 1; 317 if (f_type) 318 extwidth += 1; 319 320 for (col = 0, p = dp->list; p != NULL; p = p->fts_link) { 321 if (IS_NOPRINT(p)) 322 continue; 323 if (col > 0) { 324 (void)putchar(','), col++; 325 if (col + 1 + extwidth + p->fts_namelen >= termwidth) 326 (void)putchar('\n'), col = 0; 327 else 328 (void)putchar(' '), col++; 329 } 330 col += printaname(p, dp->s_inode, dp->s_block); 331 } 332 (void)putchar('\n'); 333 } 334 335 static int 336 printtype(mode) 337 u_int mode; 338 { 339 switch (mode & S_IFMT) { 340 case S_IFDIR: 341 (void)putchar('/'); 342 return (1); 343 case S_IFIFO: 344 (void)putchar('|'); 345 return (1); 346 case S_IFLNK: 347 (void)putchar('@'); 348 return (1); 349 case S_IFSOCK: 350 (void)putchar('='); 351 return (1); 352 case S_IFWHT: 353 (void)putchar('%'); 354 return (1); 355 } 356 if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 357 (void)putchar('*'); 358 return (1); 359 } 360 return (0); 361 } 362 363 static void 364 printlink(p) 365 FTSENT *p; 366 { 367 int lnklen; 368 char name[MAXPATHLEN], path[MAXPATHLEN]; 369 370 if (p->fts_level == FTS_ROOTLEVEL) 371 (void)snprintf(name, sizeof(name), "%s", p->fts_name); 372 else 373 (void)snprintf(name, sizeof(name), 374 "%s/%s", p->fts_parent->fts_accpath, p->fts_name); 375 if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { 376 (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno)); 377 return; 378 } 379 path[lnklen] = '\0'; 380 (void)printf(" -> "); 381 (void)putname(path); 382 } 383