*** empty log message ***
[findutils.git] / lib / listfile.c
blob5aefd105194197bfd5fa1ba6224fd97cbec90ceb
1 /* listfile.c -- display a long listing of a file
2 Copyright (C) 1991, 1993, 2000 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18 #if HAVE_CONFIG_H
19 # include <config.h>
20 #endif
22 #ifndef __GNUC__
23 # if HAVE_ALLOCA_H
24 # include <alloca.h>
25 # else
26 # ifdef _AIX
27 # pragma alloca
28 # else
29 # ifdef _WIN32
30 # include <malloc.h>
31 # include <io.h>
32 # else
33 # ifndef alloca
34 char *alloca ();
35 # endif
36 # endif
37 # endif
38 # endif
39 #endif
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <stdio.h>
44 #include <pwd.h>
45 #include <grp.h>
46 #include <time.h>
47 #include <errno.h>
48 #include "human.h"
49 #include "pathmax.h"
51 #if HAVE_STRING_H || STDC_HEADERS
52 #include <string.h>
53 #else
54 #include <strings.h>
55 #endif
57 #if STDC_HEADERS
58 # include <stdlib.h>
59 #else
60 char *getenv ();
61 extern int errno;
62 #endif
64 /* Since major is a function on SVR4, we can't use `ifndef major'. */
65 #ifdef MAJOR_IN_MKDEV
66 #include <sys/mkdev.h>
67 #define HAVE_MAJOR
68 #endif
69 #ifdef MAJOR_IN_SYSMACROS
70 #include <sys/sysmacros.h>
71 #define HAVE_MAJOR
72 #endif
74 #ifdef STAT_MACROS_BROKEN
75 #undef S_ISCHR
76 #undef S_ISBLK
77 #undef S_ISLNK
78 #endif
80 #ifndef S_ISCHR
81 #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
82 #endif
83 #ifndef S_ISBLK
84 #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
85 #endif
86 #if defined(S_IFLNK) && !defined(S_ISLNK)
87 #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
88 #endif
90 #if defined(S_ISLNK)
91 int readlink ();
92 #endif
94 /* Get or fake the disk device blocksize.
95 Usually defined by sys/param.h (if at all). */
96 #ifndef DEV_BSIZE
97 # ifdef BSIZE
98 # define DEV_BSIZE BSIZE
99 # else /* !BSIZE */
100 # define DEV_BSIZE 4096
101 # endif /* !BSIZE */
102 #endif /* !DEV_BSIZE */
104 /* Extract or fake data from a `struct stat'.
105 ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
106 ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
107 ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
108 #ifndef HAVE_STRUCT_STAT_ST_BLOCKS
109 # define ST_BLKSIZE(statbuf) DEV_BSIZE
110 # if defined(_POSIX_SOURCE) || !defined(BSIZE) /* fileblocks.c uses BSIZE. */
111 # define ST_NBLOCKS(statbuf) \
112 (S_ISREG ((statbuf).st_mode) \
113 || S_ISDIR ((statbuf).st_mode) \
114 ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0)
115 # else /* !_POSIX_SOURCE && BSIZE */
116 # define ST_NBLOCKS(statbuf) \
117 (S_ISREG ((statbuf).st_mode) \
118 || S_ISDIR ((statbuf).st_mode) \
119 ? st_blocks ((statbuf).st_size) : 0)
120 # endif /* !_POSIX_SOURCE && BSIZE */
121 #else /* HAVE_STRUCT_STAT_ST_BLOCKS */
122 /* Some systems, like Sequents, return st_blksize of 0 on pipes. */
123 # define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
124 ? (statbuf).st_blksize : DEV_BSIZE)
125 # if defined(hpux) || defined(__hpux__) || defined(__hpux)
126 /* HP-UX counts st_blocks in 1024-byte units.
127 This loses when mixing HP-UX and BSD filesystems with NFS. */
128 # define ST_NBLOCKSIZE 1024
129 # else /* !hpux */
130 # if defined(_AIX) && defined(_I386)
131 /* AIX PS/2 counts st_blocks in 4K units. */
132 # define ST_NBLOCKSIZE (4 * 1024)
133 # else /* not AIX PS/2 */
134 # if defined(_CRAY)
135 # define ST_NBLOCKS(statbuf) \
136 (S_ISREG ((statbuf).st_mode) \
137 || S_ISDIR ((statbuf).st_mode) \
138 ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
139 # endif /* _CRAY */
140 # endif /* not AIX PS/2 */
141 # endif /* !hpux */
142 #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
144 #ifndef ST_NBLOCKS
145 # define ST_NBLOCKS(statbuf) \
146 (S_ISREG ((statbuf).st_mode) \
147 || S_ISDIR ((statbuf).st_mode) \
148 ? (statbuf).st_blocks : 0)
149 #endif
151 #ifndef ST_NBLOCKSIZE
152 # define ST_NBLOCKSIZE 512
153 #endif
155 #ifndef _POSIX_VERSION
156 struct passwd *getpwuid ();
157 struct group *getgrgid ();
158 #endif
160 #ifdef major /* Might be defined in sys/types.h. */
161 #define HAVE_MAJOR
162 #endif
163 #ifndef HAVE_MAJOR
164 #define major(dev) (((dev) >> 8) & 0xff)
165 #define minor(dev) ((dev) & 0xff)
166 #endif
167 #undef HAVE_MAJOR
169 char *xmalloc ();
170 void error ();
171 void mode_string ();
173 char *get_link_name ();
174 char *getgroup ();
175 char *getuser ();
176 void print_name_with_quoting ();
178 /* NAME is the name to print.
179 RELNAME is the path to access it from the current directory.
180 STATP is the results of stat or lstat on it.
181 Use CURRENT_TIME to decide whether to print yyyy or hh:mm.
182 Use OUTPUT_BLOCK_SIZE to determine how to print file block counts
183 and sizes.
184 STREAM is the stdio stream to print on. */
186 void
187 list_file (name, relname, statp, current_time, output_block_size, stream)
188 char *name;
189 char *relname;
190 struct stat *statp;
191 time_t current_time;
192 int output_block_size;
193 FILE *stream;
195 char modebuf[11];
196 struct tm const *when_local;
197 char const *user_name;
198 char const *group_name;
199 char hbuf[LONGEST_HUMAN_READABLE + 1];
201 #if HAVE_ST_DM_MODE
202 /* Cray DMF: look at the file's migrated, not real, status */
203 mode_string (statp->st_dm_mode, modebuf);
204 #else
205 mode_string (statp->st_mode, modebuf);
206 #endif
207 modebuf[10] = '\0';
209 fprintf (stream, "%6s ",
210 human_readable ((uintmax_t) statp->st_ino, hbuf, 1, 1));
212 fprintf (stream, "%4s ",
213 human_readable ((uintmax_t) ST_NBLOCKS (*statp), hbuf,
214 ST_NBLOCKSIZE, output_block_size));
216 /* The space between the mode and the number of links is the POSIX
217 "optional alternate access method flag". */
218 fprintf (stream, "%s %3lu ", modebuf, (unsigned long) statp->st_nlink);
220 user_name = getuser (statp->st_uid);
221 if (user_name)
222 fprintf (stream, "%-8.8s ", user_name);
223 else
224 fprintf (stream, "%-8lu ", (unsigned long) statp->st_uid);
226 group_name = getgroup (statp->st_gid);
227 if (group_name)
228 fprintf (stream, "%-8.8s ", group_name);
229 else
230 fprintf (stream, "%-8lu ", (unsigned long) statp->st_gid);
232 if (S_ISCHR (statp->st_mode) || S_ISBLK (statp->st_mode))
233 #ifdef HAVE_ST_RDEV
234 fprintf (stream, "%3lu, %3lu ",
235 (unsigned long) major (statp->st_rdev),
236 (unsigned long) minor (statp->st_rdev));
237 #else
238 fprintf (stream, " ");
239 #endif
240 else
241 fprintf (stream, "%8s ",
242 human_readable ((uintmax_t) statp->st_size, hbuf, 1,
243 output_block_size < 0 ? output_block_size : 1));
245 if ((when_local = localtime (&statp->st_mtime)))
247 char init_bigbuf[256];
248 char *buf = init_bigbuf;
249 size_t bufsize = sizeof init_bigbuf;
251 /* Use strftime rather than ctime, because the former can produce
252 locale-dependent names for the month (%b).
254 Output the year if the file is fairly old or in the future.
255 POSIX says the cutoff is 6 months old;
256 approximate this by 6*30 days.
257 Allow a 1 hour slop factor for what is considered "the future",
258 to allow for NFS server/client clock disagreement. */
259 char const *fmt =
260 ((current_time - 6 * 30 * 24 * 60 * 60 <= statp->st_mtime
261 && statp->st_mtime <= current_time + 60 * 60)
262 ? "%b %e %H:%M"
263 : "%b %e %Y");
265 while (!strftime (buf, bufsize, fmt, when_local))
266 buf = (char *) alloca (bufsize *= 2);
268 fprintf (stream, "%s ", buf);
270 else
272 /* The time cannot be represented as a local time;
273 print it as a huge integer number of seconds. */
274 int width = 12;
276 if (statp->st_mtime < 0)
278 char const *num = human_readable (- (uintmax_t) statp->st_mtime,
279 hbuf, 1, 1);
280 int sign_width = width - strlen (num);
281 fprintf (stream, "%*s%s ",
282 sign_width < 0 ? 0 : sign_width, "-", num);
284 else
285 fprintf (stream, "%*s ", width,
286 human_readable ((uintmax_t) statp->st_mtime, hbuf, 1, 1));
289 print_name_with_quoting (name, stream);
291 #ifdef S_ISLNK
292 if (S_ISLNK (statp->st_mode))
294 char *linkname = get_link_name (name, relname);
296 if (linkname)
298 fputs (" -> ", stream);
299 print_name_with_quoting (linkname, stream);
300 free (linkname);
303 #endif
304 putc ('\n', stream);
307 void
308 print_name_with_quoting (p, stream)
309 register char *p;
310 FILE *stream;
312 register unsigned char c;
314 while ((c = *p++) != '\0')
316 switch (c)
318 case '\\':
319 fprintf (stream, "\\\\");
320 break;
322 case '\n':
323 fprintf (stream, "\\n");
324 break;
326 case '\b':
327 fprintf (stream, "\\b");
328 break;
330 case '\r':
331 fprintf (stream, "\\r");
332 break;
334 case '\t':
335 fprintf (stream, "\\t");
336 break;
338 case '\f':
339 fprintf (stream, "\\f");
340 break;
342 case ' ':
343 fprintf (stream, "\\ ");
344 break;
346 case '"':
347 fprintf (stream, "\\\"");
348 break;
350 default:
351 if (c > 040 && c < 0177)
352 putc (c, stream);
353 else
354 fprintf (stream, "\\%03o", (unsigned int) c);
359 #ifdef S_ISLNK
360 char *
361 get_link_name (name, relname)
362 char *name;
363 char *relname;
365 register char *linkname;
366 register int linklen;
368 /* st_size is wrong for symlinks on AIX, and on
369 mount points with some automounters.
370 So allocate a pessimistic PATH_MAX + 1 bytes. */
371 #define LINK_BUF PATH_MAX
372 linkname = (char *) xmalloc (LINK_BUF + 1);
373 linklen = readlink (relname, linkname, LINK_BUF);
374 if (linklen < 0)
376 error (0, errno, "%s", name);
377 free (linkname);
378 return 0;
380 linkname[linklen] = '\0';
381 return linkname;
383 #endif