cvsimport
[findutils.git] / lib / listfile.c
blobd53f905311a23209830e36fc81d6c55fb0a36f21
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
17 USA.
20 #if HAVE_CONFIG_H
21 # include <config.h>
22 #endif
24 #ifndef __GNUC__
25 # if HAVE_ALLOCA_H
26 # include <alloca.h>
27 # else
28 # ifdef _AIX
29 # pragma alloca
30 # else
31 # ifdef _WIN32
32 # include <malloc.h>
33 # include <io.h>
34 # else
35 # ifndef alloca
36 char *alloca ();
37 # endif
38 # endif
39 # endif
40 # endif
41 #endif
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <stdio.h>
46 #include <pwd.h>
47 #include <grp.h>
48 #include <time.h>
49 #include <errno.h>
50 #include <fcntl.h>
51 #include <openat.h>
52 #include "human.h"
53 #include "xalloc.h"
54 #include "pathmax.h"
55 #include "error.h"
56 #include "filemode.h"
58 #include "listfile.h"
60 #if HAVE_STRING_H || STDC_HEADERS
61 #include <string.h>
62 #else
63 #include <strings.h>
64 #endif
67 /* The presence of unistd.h is assumed by gnulib these days, so we
68 * might as well assume it too.
70 #include <unistd.h> /* for readlink() */
73 #if STDC_HEADERS
74 # include <stdlib.h>
75 #else
76 char *getenv ();
77 extern int errno;
78 #endif
80 /* Since major is a function on SVR4, we can't use `ifndef major'. */
81 #ifdef MAJOR_IN_MKDEV
82 #include <sys/mkdev.h>
83 #define HAVE_MAJOR
84 #endif
85 #ifdef MAJOR_IN_SYSMACROS
86 #include <sys/sysmacros.h>
87 #define HAVE_MAJOR
88 #endif
94 #ifdef HAVE_LOCALE_H
95 #include <locale.h>
96 #endif
98 #if ENABLE_NLS
99 # include <libintl.h>
100 # define _(Text) gettext (Text)
101 #else
102 # define _(Text) Text
103 #define textdomain(Domain)
104 #define bindtextdomain(Package, Directory)
105 #endif
106 #ifdef gettext_noop
107 # define N_(String) gettext_noop (String)
108 #else
109 /* See locate.c for explanation as to why not use (String) */
110 # define N_(String) String
111 #endif
115 #ifdef STAT_MACROS_BROKEN
116 #undef S_ISCHR
117 #undef S_ISBLK
118 #undef S_ISLNK
119 #endif
121 #ifndef S_ISCHR
122 #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
123 #endif
124 #ifndef S_ISBLK
125 #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
126 #endif
127 #if defined(S_IFLNK) && !defined(S_ISLNK)
128 #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
129 #endif
131 /* Get or fake the disk device blocksize.
132 Usually defined by sys/param.h (if at all). */
133 #ifndef DEV_BSIZE
134 # ifdef BSIZE
135 # define DEV_BSIZE BSIZE
136 # else /* !BSIZE */
137 # define DEV_BSIZE 4096
138 # endif /* !BSIZE */
139 #endif /* !DEV_BSIZE */
141 /* Extract or fake data from a `struct stat'.
142 ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
143 ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
144 ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
145 #ifndef HAVE_STRUCT_STAT_ST_BLOCKS
146 # define ST_BLKSIZE(statbuf) DEV_BSIZE
147 # if defined(_POSIX_SOURCE) || !defined(BSIZE) /* fileblocks.c uses BSIZE. */
148 # define ST_NBLOCKS(statbuf) \
149 (S_ISREG ((statbuf).st_mode) \
150 || S_ISDIR ((statbuf).st_mode) \
151 ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0)
152 # else /* !_POSIX_SOURCE && BSIZE */
153 # define ST_NBLOCKS(statbuf) \
154 (S_ISREG ((statbuf).st_mode) \
155 || S_ISDIR ((statbuf).st_mode) \
156 ? st_blocks ((statbuf).st_size) : 0)
157 # endif /* !_POSIX_SOURCE && BSIZE */
158 #else /* HAVE_STRUCT_STAT_ST_BLOCKS */
159 /* Some systems, like Sequents, return st_blksize of 0 on pipes. */
160 # define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
161 ? (statbuf).st_blksize : DEV_BSIZE)
162 # if defined(hpux) || defined(__hpux__) || defined(__hpux)
163 /* HP-UX counts st_blocks in 1024-byte units.
164 This loses when mixing HP-UX and BSD filesystems with NFS. */
165 # define ST_NBLOCKSIZE 1024
166 # else /* !hpux */
167 # if defined(_AIX) && defined(_I386)
168 /* AIX PS/2 counts st_blocks in 4K units. */
169 # define ST_NBLOCKSIZE (4 * 1024)
170 # else /* not AIX PS/2 */
171 # if defined(_CRAY)
172 # define ST_NBLOCKS(statbuf) \
173 (S_ISREG ((statbuf).st_mode) \
174 || S_ISDIR ((statbuf).st_mode) \
175 ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
176 # endif /* _CRAY */
177 # endif /* not AIX PS/2 */
178 # endif /* !hpux */
179 #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
181 #ifndef ST_NBLOCKS
182 # define ST_NBLOCKS(statbuf) \
183 (S_ISREG ((statbuf).st_mode) \
184 || S_ISDIR ((statbuf).st_mode) \
185 ? (statbuf).st_blocks : 0)
186 #endif
188 #ifndef ST_NBLOCKSIZE
189 # define ST_NBLOCKSIZE 512
190 #endif
192 #ifdef major /* Might be defined in sys/types.h. */
193 #define HAVE_MAJOR
194 #endif
195 #ifndef HAVE_MAJOR
196 #define major(dev) (((dev) >> 8) & 0xff)
197 #define minor(dev) ((dev) & 0xff)
198 #endif
199 #undef HAVE_MAJOR
202 static void print_name (register char *p, FILE *stream, int literal_control_chars);
204 extern char * getgroup (gid_t gid);
205 extern char * getuser (uid_t uid);
209 size_t
210 file_blocksize(const struct stat *p)
212 return ST_NBLOCKSIZE;
217 /* NAME is the name to print.
218 RELNAME is the path to access it from the current directory.
219 STATP is the results of stat or lstat on it.
220 Use CURRENT_TIME to decide whether to print yyyy or hh:mm.
221 Use OUTPUT_BLOCK_SIZE to determine how to print file block counts
222 and sizes.
223 STREAM is the stdio stream to print on. */
225 void
226 list_file (char *name,
227 int dirfd,
228 char *relname,
229 const struct stat *statp,
230 time_t current_time,
231 int output_block_size,
232 int literal_control_chars,
233 FILE *stream)
235 char modebuf[11];
236 struct tm const *when_local;
237 char const *user_name;
238 char const *group_name;
239 char hbuf[LONGEST_HUMAN_READABLE + 1];
241 #if HAVE_ST_DM_MODE
242 /* Cray DMF: look at the file's migrated, not real, status */
243 strmode (statp->st_dm_mode, modebuf);
244 #else
245 strmode (statp->st_mode, modebuf);
246 #endif
247 modebuf[10] = '\0';
249 fprintf (stream, "%6s ",
250 human_readable ((uintmax_t) statp->st_ino, hbuf,
251 human_ceiling,
252 1, 1));
254 fprintf (stream, "%4s ",
255 human_readable ((uintmax_t) ST_NBLOCKS (*statp), hbuf,
256 human_ceiling,
257 ST_NBLOCKSIZE, output_block_size));
260 /* The space between the mode and the number of links is the POSIX
261 "optional alternate access method flag". */
262 fprintf (stream, "%s %3lu ", modebuf, (unsigned long) statp->st_nlink);
264 user_name = getuser (statp->st_uid);
265 if (user_name)
266 fprintf (stream, "%-8s ", user_name);
267 else
268 fprintf (stream, "%-8lu ", (unsigned long) statp->st_uid);
270 group_name = getgroup (statp->st_gid);
271 if (group_name)
272 fprintf (stream, "%-8s ", group_name);
273 else
274 fprintf (stream, "%-8lu ", (unsigned long) statp->st_gid);
276 if (S_ISCHR (statp->st_mode) || S_ISBLK (statp->st_mode))
277 #ifdef HAVE_ST_RDEV
278 fprintf (stream, "%3lu, %3lu ",
279 (unsigned long) major (statp->st_rdev),
280 (unsigned long) minor (statp->st_rdev));
281 #else
282 fprintf (stream, " ");
283 #endif
284 else
285 fprintf (stream, "%8s ",
286 human_readable ((uintmax_t) statp->st_size, hbuf,
287 human_ceiling,
289 output_block_size < 0 ? output_block_size : 1));
291 if ((when_local = localtime (&statp->st_mtime)))
293 char init_bigbuf[256];
294 char *buf = init_bigbuf;
295 size_t bufsize = sizeof init_bigbuf;
297 /* Use strftime rather than ctime, because the former can produce
298 locale-dependent names for the month (%b).
300 Output the year if the file is fairly old or in the future.
301 POSIX says the cutoff is 6 months old;
302 approximate this by 6*30 days.
303 Allow a 1 hour slop factor for what is considered "the future",
304 to allow for NFS server/client clock disagreement. */
305 char const *fmt =
306 ((current_time - 6 * 30 * 24 * 60 * 60 <= statp->st_mtime
307 && statp->st_mtime <= current_time + 60 * 60)
308 ? "%b %e %H:%M"
309 : "%b %e %Y");
311 while (!strftime (buf, bufsize, fmt, when_local))
312 buf = (char *) alloca (bufsize *= 2);
314 fprintf (stream, "%s ", buf);
316 else
318 /* The time cannot be represented as a local time;
319 print it as a huge integer number of seconds. */
320 int width = 12;
322 if (statp->st_mtime < 0)
324 char const *num = human_readable (- (uintmax_t) statp->st_mtime,
325 hbuf, human_ceiling, 1, 1);
326 int sign_width = width - strlen (num);
327 fprintf (stream, "%*s%s ",
328 sign_width < 0 ? 0 : sign_width, "-", num);
330 else
331 fprintf (stream, "%*s ", width,
332 human_readable ((uintmax_t) statp->st_mtime, hbuf,
333 human_ceiling,
334 1, 1));
337 print_name (name, stream, literal_control_chars);
339 #ifdef S_ISLNK
340 if (S_ISLNK (statp->st_mode))
342 char *linkname = get_link_name_at (name, dirfd, relname);
344 if (linkname)
346 fputs (" -> ", stream);
347 print_name (linkname, stream, literal_control_chars);
348 free (linkname);
351 #endif
352 putc ('\n', stream);
356 static void
357 print_name_without_quoting (char *p, FILE *stream)
359 fprintf(stream, "%s", p);
363 static void
364 print_name_with_quoting (register char *p, FILE *stream)
366 register unsigned char c;
368 while ((c = *p++) != '\0')
370 switch (c)
372 case '\\':
373 fprintf (stream, "\\\\");
374 break;
376 case '\n':
377 fprintf (stream, "\\n");
378 break;
380 case '\b':
381 fprintf (stream, "\\b");
382 break;
384 case '\r':
385 fprintf (stream, "\\r");
386 break;
388 case '\t':
389 fprintf (stream, "\\t");
390 break;
392 case '\f':
393 fprintf (stream, "\\f");
394 break;
396 case ' ':
397 fprintf (stream, "\\ ");
398 break;
400 case '"':
401 fprintf (stream, "\\\"");
402 break;
404 default:
405 if (c > 040 && c < 0177)
406 putc (c, stream);
407 else
408 fprintf (stream, "\\%03o", (unsigned int) c);
413 static void print_name (register char *p, FILE *stream, int literal_control_chars)
415 if (literal_control_chars)
416 print_name_without_quoting(p, stream);
417 else
418 print_name_with_quoting(p, stream);
421 #ifdef S_ISLNK
422 static char *
423 get_link_name (const char *name, char *relname)
425 register char *linkname;
426 register int linklen;
428 /* st_size is wrong for symlinks on AIX, and on
429 mount points with some automounters.
430 So allocate a pessimistic PATH_MAX + 1 bytes. */
431 #define LINK_BUF PATH_MAX
432 linkname = (char *) xmalloc (LINK_BUF + 1);
433 linklen = readlink (relname, linkname, LINK_BUF);
434 if (linklen < 0)
436 error (0, errno, "%s", name);
437 free (linkname);
438 return 0;
440 linkname[linklen] = '\0';
441 return linkname;
444 struct link_name_args
446 const char *name;
447 char *relname;
448 char *result;
451 static int
452 get_link_name_cb(void *context)
454 struct link_name_args *args = context;
455 args->result = get_link_name(args->name, args->relname);
456 return 0;
459 char *
460 get_link_name_at (const char *name, int dirfd, char *relname)
462 struct link_name_args args;
463 args.result = NULL;
464 args.name = name;
465 args.relname = relname;
466 if (0 == run_in_dir(dirfd, get_link_name_cb, &args))
467 return args.result;
468 else
469 return NULL;
473 #endif