Bugfixes for Savannah bugs #19768 and #19766
[findutils.git] / lib / listfile.c
blob0bdf99d3f82e3486f62fd4eda80108d583d20d38
1 /* listfile.c -- display a long listing of a file
2 Copyright (C) 1991, 1993, 2000, 2004, 2005, 2007 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 #include <alloca.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <pwd.h>
31 #include <grp.h>
32 #include <time.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <string.h>
36 #include <unistd.h> /* for readlink() */
37 #include <openat.h>
39 #include "human.h"
40 #include "xalloc.h"
41 #include "pathmax.h"
42 #include "error.h"
43 #include "filemode.h"
44 #include "dircallback.h"
46 #include "listfile.h"
48 /* Since major is a function on SVR4, we can't use `ifndef major'. */
49 #ifdef MAJOR_IN_MKDEV
50 #include <sys/mkdev.h>
51 #define HAVE_MAJOR
52 #endif
53 #ifdef MAJOR_IN_SYSMACROS
54 #include <sys/sysmacros.h>
55 #define HAVE_MAJOR
56 #endif
62 #ifdef HAVE_LOCALE_H
63 #include <locale.h>
64 #endif
66 #if ENABLE_NLS
67 # include <libintl.h>
68 # define _(Text) gettext (Text)
69 #else
70 # define _(Text) Text
71 #define textdomain(Domain)
72 #define bindtextdomain(Package, Directory)
73 #endif
74 #ifdef gettext_noop
75 # define N_(String) gettext_noop (String)
76 #else
77 /* See locate.c for explanation as to why not use (String) */
78 # define N_(String) String
79 #endif
83 #ifdef STAT_MACROS_BROKEN
84 #undef S_ISCHR
85 #undef S_ISBLK
86 #undef S_ISLNK
87 #endif
89 #ifndef S_ISCHR
90 #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
91 #endif
92 #ifndef S_ISBLK
93 #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
94 #endif
95 #if defined(S_IFLNK) && !defined(S_ISLNK)
96 #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
97 #endif
99 /* Get or fake the disk device blocksize.
100 Usually defined by sys/param.h (if at all). */
101 #ifndef DEV_BSIZE
102 # ifdef BSIZE
103 # define DEV_BSIZE BSIZE
104 # else /* !BSIZE */
105 # define DEV_BSIZE 4096
106 # endif /* !BSIZE */
107 #endif /* !DEV_BSIZE */
109 /* Extract or fake data from a `struct stat'.
110 ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
111 ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
112 ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
113 #ifndef HAVE_STRUCT_STAT_ST_BLOCKS
114 # define ST_BLKSIZE(statbuf) DEV_BSIZE
115 # if defined(_POSIX_SOURCE) || !defined(BSIZE) /* fileblocks.c uses BSIZE. */
116 # define ST_NBLOCKS(statbuf) \
117 (S_ISREG ((statbuf).st_mode) \
118 || S_ISDIR ((statbuf).st_mode) \
119 ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0)
120 # else /* !_POSIX_SOURCE && BSIZE */
121 # define ST_NBLOCKS(statbuf) \
122 (S_ISREG ((statbuf).st_mode) \
123 || S_ISDIR ((statbuf).st_mode) \
124 ? st_blocks ((statbuf).st_size) : 0)
125 # endif /* !_POSIX_SOURCE && BSIZE */
126 #else /* HAVE_STRUCT_STAT_ST_BLOCKS */
127 /* Some systems, like Sequents, return st_blksize of 0 on pipes. */
128 # define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
129 ? (statbuf).st_blksize : DEV_BSIZE)
130 # if defined(hpux) || defined(__hpux__) || defined(__hpux)
131 /* HP-UX counts st_blocks in 1024-byte units.
132 This loses when mixing HP-UX and BSD filesystems with NFS. */
133 # define ST_NBLOCKSIZE 1024
134 # else /* !hpux */
135 # if defined(_AIX) && defined(_I386)
136 /* AIX PS/2 counts st_blocks in 4K units. */
137 # define ST_NBLOCKSIZE (4 * 1024)
138 # else /* not AIX PS/2 */
139 # if defined(_CRAY)
140 # define ST_NBLOCKS(statbuf) \
141 (S_ISREG ((statbuf).st_mode) \
142 || S_ISDIR ((statbuf).st_mode) \
143 ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
144 # endif /* _CRAY */
145 # endif /* not AIX PS/2 */
146 # endif /* !hpux */
147 #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
149 #ifndef ST_NBLOCKS
150 # define ST_NBLOCKS(statbuf) \
151 (S_ISREG ((statbuf).st_mode) \
152 || S_ISDIR ((statbuf).st_mode) \
153 ? (statbuf).st_blocks : 0)
154 #endif
156 #ifndef ST_NBLOCKSIZE
157 # define ST_NBLOCKSIZE 512
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
170 static void print_name (register const char *p, FILE *stream, int literal_control_chars);
172 extern char * getgroup (gid_t gid);
173 extern char * getuser (uid_t uid);
177 size_t
178 file_blocksize(const struct stat *p)
180 return ST_NBLOCKSIZE;
185 /* NAME is the name to print.
186 RELNAME is the path to access it from the current directory.
187 STATP is the results of stat or lstat on it.
188 Use CURRENT_TIME to decide whether to print yyyy or hh:mm.
189 Use OUTPUT_BLOCK_SIZE to determine how to print file block counts
190 and sizes.
191 STREAM is the stdio stream to print on. */
193 void
194 list_file (const char *name,
195 int dirfd,
196 char *relname,
197 const struct stat *statp,
198 time_t current_time,
199 int output_block_size,
200 int literal_control_chars,
201 FILE *stream)
203 char modebuf[11];
204 struct tm const *when_local;
205 char const *user_name;
206 char const *group_name;
207 char hbuf[LONGEST_HUMAN_READABLE + 1];
209 #if HAVE_ST_DM_MODE
210 /* Cray DMF: look at the file's migrated, not real, status */
211 strmode (statp->st_dm_mode, modebuf);
212 #else
213 strmode (statp->st_mode, modebuf);
214 #endif
215 modebuf[10] = '\0';
217 fprintf (stream, "%6s ",
218 human_readable ((uintmax_t) statp->st_ino, hbuf,
219 human_ceiling,
220 1, 1));
222 fprintf (stream, "%4s ",
223 human_readable ((uintmax_t) ST_NBLOCKS (*statp), hbuf,
224 human_ceiling,
225 ST_NBLOCKSIZE, output_block_size));
228 /* The space between the mode and the number of links is the POSIX
229 "optional alternate access method flag". */
230 fprintf (stream, "%s %3lu ", modebuf, (unsigned long) statp->st_nlink);
232 user_name = getuser (statp->st_uid);
233 if (user_name)
234 fprintf (stream, "%-8s ", user_name);
235 else
236 fprintf (stream, "%-8lu ", (unsigned long) statp->st_uid);
238 group_name = getgroup (statp->st_gid);
239 if (group_name)
240 fprintf (stream, "%-8s ", group_name);
241 else
242 fprintf (stream, "%-8lu ", (unsigned long) statp->st_gid);
244 if (S_ISCHR (statp->st_mode) || S_ISBLK (statp->st_mode))
245 #ifdef HAVE_ST_RDEV
246 fprintf (stream, "%3lu, %3lu ",
247 (unsigned long) major (statp->st_rdev),
248 (unsigned long) minor (statp->st_rdev));
249 #else
250 fprintf (stream, " ");
251 #endif
252 else
253 fprintf (stream, "%8s ",
254 human_readable ((uintmax_t) statp->st_size, hbuf,
255 human_ceiling,
257 output_block_size < 0 ? output_block_size : 1));
259 if ((when_local = localtime (&statp->st_mtime)))
261 char init_bigbuf[256];
262 char *buf = init_bigbuf;
263 size_t bufsize = sizeof init_bigbuf;
265 /* Use strftime rather than ctime, because the former can produce
266 locale-dependent names for the month (%b).
268 Output the year if the file is fairly old or in the future.
269 POSIX says the cutoff is 6 months old;
270 approximate this by 6*30 days.
271 Allow a 1 hour slop factor for what is considered "the future",
272 to allow for NFS server/client clock disagreement. */
273 char const *fmt =
274 ((current_time - 6 * 30 * 24 * 60 * 60 <= statp->st_mtime
275 && statp->st_mtime <= current_time + 60 * 60)
276 ? "%b %e %H:%M"
277 : "%b %e %Y");
279 while (!strftime (buf, bufsize, fmt, when_local))
280 buf = (char *) alloca (bufsize *= 2);
282 fprintf (stream, "%s ", buf);
284 else
286 /* The time cannot be represented as a local time;
287 print it as a huge integer number of seconds. */
288 int width = 12;
290 if (statp->st_mtime < 0)
292 char const *num = human_readable (- (uintmax_t) statp->st_mtime,
293 hbuf, human_ceiling, 1, 1);
294 int sign_width = width - strlen (num);
295 fprintf (stream, "%*s%s ",
296 sign_width < 0 ? 0 : sign_width, "-", num);
298 else
299 fprintf (stream, "%*s ", width,
300 human_readable ((uintmax_t) statp->st_mtime, hbuf,
301 human_ceiling,
302 1, 1));
305 print_name (name, stream, literal_control_chars);
307 #ifdef S_ISLNK
308 if (S_ISLNK (statp->st_mode))
310 char *linkname = get_link_name_at (name, dirfd, relname);
312 if (linkname)
314 fputs (" -> ", stream);
315 print_name (linkname, stream, literal_control_chars);
316 free (linkname);
319 #endif
320 putc ('\n', stream);
324 static void
325 print_name_without_quoting (const char *p, FILE *stream)
327 fprintf(stream, "%s", p);
331 static void
332 print_name_with_quoting (register const char *p, FILE *stream)
334 register unsigned char c;
336 while ((c = *p++) != '\0')
338 switch (c)
340 case '\\':
341 fprintf (stream, "\\\\");
342 break;
344 case '\n':
345 fprintf (stream, "\\n");
346 break;
348 case '\b':
349 fprintf (stream, "\\b");
350 break;
352 case '\r':
353 fprintf (stream, "\\r");
354 break;
356 case '\t':
357 fprintf (stream, "\\t");
358 break;
360 case '\f':
361 fprintf (stream, "\\f");
362 break;
364 case ' ':
365 fprintf (stream, "\\ ");
366 break;
368 case '"':
369 fprintf (stream, "\\\"");
370 break;
372 default:
373 if (c > 040 && c < 0177)
374 putc (c, stream);
375 else
376 fprintf (stream, "\\%03o", (unsigned int) c);
381 static void print_name (register const char *p, FILE *stream, int literal_control_chars)
383 if (literal_control_chars)
384 print_name_without_quoting(p, stream);
385 else
386 print_name_with_quoting(p, stream);
389 #ifdef S_ISLNK
390 static char *
391 get_link_name (const char *name, char *relname)
393 register char *linkname;
394 register int linklen;
396 /* st_size is wrong for symlinks on AIX, and on
397 mount points with some automounters.
398 So allocate a pessimistic PATH_MAX + 1 bytes. */
399 #define LINK_BUF PATH_MAX
400 linkname = (char *) xmalloc (LINK_BUF + 1);
401 linklen = readlink (relname, linkname, LINK_BUF);
402 if (linklen < 0)
404 error (0, errno, "%s", name);
405 free (linkname);
406 return 0;
408 linkname[linklen] = '\0';
409 return linkname;
412 struct link_name_args
414 const char *name;
415 char *relname;
416 char *result;
419 static int
420 get_link_name_cb(void *context)
422 struct link_name_args *args = context;
423 args->result = get_link_name(args->name, args->relname);
424 return 0;
427 char *
428 get_link_name_at (const char *name, int dirfd, char *relname)
430 struct link_name_args args;
431 args.result = NULL;
432 args.name = name;
433 args.relname = relname;
434 if (0 == run_in_dir(dirfd, get_link_name_cb, &args))
435 return args.result;
436 else
437 return NULL;
441 #endif