Enhancements to format strings in hman-readable messages intended to allow better...
[findutils.git] / lib / listfile.c
blob9b4ed20d48139aebb78ac9370bbc00eeaa6c2a5a
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 3 of the License, or
7 (at your option) 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, see <http://www.gnu.org/licenses/>.
18 #include <config.h>
20 #include <alloca.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <pwd.h>
27 #include <grp.h>
28 #include <time.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <unistd.h> /* for readlink() */
33 #include <openat.h>
35 #include "human.h"
36 #include "xalloc.h"
37 #include "pathmax.h"
38 #include "error.h"
39 #include "filemode.h"
40 #include "dircallback.h"
41 #include "idcache.h"
43 #include "listfile.h"
45 /* Since major is a function on SVR4, we can't use `ifndef major'. */
46 #ifdef MAJOR_IN_MKDEV
47 #include <sys/mkdev.h>
48 #define HAVE_MAJOR
49 #endif
50 #ifdef MAJOR_IN_SYSMACROS
51 #include <sys/sysmacros.h>
52 #define HAVE_MAJOR
53 #endif
59 #ifdef HAVE_LOCALE_H
60 #include <locale.h>
61 #endif
63 #if ENABLE_NLS
64 # include <libintl.h>
65 # define _(Text) gettext (Text)
66 #else
67 # define _(Text) Text
68 #define textdomain(Domain)
69 #define bindtextdomain(Package, Directory)
70 #endif
71 #ifdef gettext_noop
72 # define N_(String) gettext_noop (String)
73 #else
74 /* See locate.c for explanation as to why not use (String) */
75 # define N_(String) String
76 #endif
80 #ifdef STAT_MACROS_BROKEN
81 #undef S_ISCHR
82 #undef S_ISBLK
83 #undef S_ISLNK
84 #endif
86 #ifndef S_ISCHR
87 #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
88 #endif
89 #ifndef S_ISBLK
90 #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
91 #endif
92 #if defined S_IFLNK && !defined S_ISLNK
93 #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
94 #endif
96 /* Get or fake the disk device blocksize.
97 Usually defined by sys/param.h (if at all). */
98 #ifndef DEV_BSIZE
99 # ifdef BSIZE
100 # define DEV_BSIZE BSIZE
101 # else /* !BSIZE */
102 # define DEV_BSIZE 4096
103 # endif /* !BSIZE */
104 #endif /* !DEV_BSIZE */
106 /* Extract or fake data from a `struct stat'.
107 ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
108 ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
109 ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
110 #ifndef HAVE_STRUCT_STAT_ST_BLOCKS
111 # define ST_BLKSIZE(statbuf) DEV_BSIZE
112 # if defined _POSIX_SOURCE || !defined BSIZE /* fileblocks.c uses BSIZE. */
113 # define ST_NBLOCKS(statbuf) \
114 (S_ISREG ((statbuf).st_mode) \
115 || S_ISDIR ((statbuf).st_mode) \
116 ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0)
117 # else /* !_POSIX_SOURCE && BSIZE */
118 # define ST_NBLOCKS(statbuf) \
119 (S_ISREG ((statbuf).st_mode) \
120 || S_ISDIR ((statbuf).st_mode) \
121 ? st_blocks ((statbuf).st_size) : 0)
122 # endif /* !_POSIX_SOURCE && BSIZE */
123 #else /* HAVE_STRUCT_STAT_ST_BLOCKS */
124 /* Some systems, like Sequents, return st_blksize of 0 on pipes. */
125 # define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
126 ? (statbuf).st_blksize : DEV_BSIZE)
127 # if defined hpux || defined __hpux__ || defined __hpux
128 /* HP-UX counts st_blocks in 1024-byte units.
129 This loses when mixing HP-UX and BSD filesystems with NFS. */
130 # define ST_NBLOCKSIZE 1024
131 # else /* !hpux */
132 # if defined _AIX && defined _I386
133 /* AIX PS/2 counts st_blocks in 4K units. */
134 # define ST_NBLOCKSIZE (4 * 1024)
135 # else /* not AIX PS/2 */
136 # if defined _CRAY
137 # define ST_NBLOCKS(statbuf) \
138 (S_ISREG ((statbuf).st_mode) \
139 || S_ISDIR ((statbuf).st_mode) \
140 ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
141 # endif /* _CRAY */
142 # endif /* not AIX PS/2 */
143 # endif /* !hpux */
144 #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
146 #ifndef ST_NBLOCKS
147 # define ST_NBLOCKS(statbuf) \
148 (S_ISREG ((statbuf).st_mode) \
149 || S_ISDIR ((statbuf).st_mode) \
150 ? (statbuf).st_blocks : 0)
151 #endif
153 #ifndef ST_NBLOCKSIZE
154 # define ST_NBLOCKSIZE 512
155 #endif
157 #ifdef major /* Might be defined in sys/types.h. */
158 #define HAVE_MAJOR
159 #endif
160 #ifndef HAVE_MAJOR
161 #define major(dev) (((dev) >> 8) & 0xff)
162 #define minor(dev) ((dev) & 0xff)
163 #endif
164 #undef HAVE_MAJOR
167 static void print_name (register const char *p, FILE *stream, int literal_control_chars);
170 size_t
171 file_blocksize(const struct stat *p)
173 return ST_NBLOCKSIZE;
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 (const char *name,
188 int dirfd,
189 char *relname,
190 const struct stat *statp,
191 time_t current_time,
192 int output_block_size,
193 int literal_control_chars,
194 FILE *stream)
196 char modebuf[12];
197 struct tm const *when_local;
198 char const *user_name;
199 char const *group_name;
200 char hbuf[LONGEST_HUMAN_READABLE + 1];
202 #if HAVE_ST_DM_MODE
203 /* Cray DMF: look at the file's migrated, not real, status */
204 strmode (statp->st_dm_mode, modebuf);
205 #else
206 strmode (statp->st_mode, modebuf);
207 #endif
209 fprintf (stream, "%6s ",
210 human_readable ((uintmax_t) statp->st_ino, hbuf,
211 human_ceiling,
212 1, 1));
214 fprintf (stream, "%4s ",
215 human_readable ((uintmax_t) ST_NBLOCKS (*statp), hbuf,
216 human_ceiling,
217 ST_NBLOCKSIZE, output_block_size));
220 /* modebuf includes the space between the mode and the number of links,
221 as the POSIX "optional alternate access method flag". */
222 fprintf (stream, "%s%3lu ", modebuf, (unsigned long) statp->st_nlink);
224 user_name = getuser (statp->st_uid);
225 if (user_name)
226 fprintf (stream, "%-8s ", user_name);
227 else
228 fprintf (stream, "%-8lu ", (unsigned long) statp->st_uid);
230 group_name = getgroup (statp->st_gid);
231 if (group_name)
232 fprintf (stream, "%-8s ", group_name);
233 else
234 fprintf (stream, "%-8lu ", (unsigned long) statp->st_gid);
236 if (S_ISCHR (statp->st_mode) || S_ISBLK (statp->st_mode))
237 #ifdef HAVE_ST_RDEV
238 fprintf (stream, "%3lu, %3lu ",
239 (unsigned long) major (statp->st_rdev),
240 (unsigned long) minor (statp->st_rdev));
241 #else
242 fprintf (stream, " ");
243 #endif
244 else
245 fprintf (stream, "%8s ",
246 human_readable ((uintmax_t) statp->st_size, hbuf,
247 human_ceiling,
249 output_block_size < 0 ? output_block_size : 1));
251 if ((when_local = localtime (&statp->st_mtime)))
253 char init_bigbuf[256];
254 char *buf = init_bigbuf;
255 size_t bufsize = sizeof init_bigbuf;
257 /* Use strftime rather than ctime, because the former can produce
258 locale-dependent names for the month (%b).
260 Output the year if the file is fairly old or in the future.
261 POSIX says the cutoff is 6 months old;
262 approximate this by 6*30 days.
263 Allow a 1 hour slop factor for what is considered "the future",
264 to allow for NFS server/client clock disagreement. */
265 char const *fmt =
266 ((current_time - 6 * 30 * 24 * 60 * 60 <= statp->st_mtime
267 && statp->st_mtime <= current_time + 60 * 60)
268 ? "%b %e %H:%M"
269 : "%b %e %Y");
271 while (!strftime (buf, bufsize, fmt, when_local))
272 buf = alloca (bufsize *= 2);
274 fprintf (stream, "%s ", buf);
276 else
278 /* The time cannot be represented as a local time;
279 print it as a huge integer number of seconds. */
280 int width = 12;
282 if (statp->st_mtime < 0)
284 char const *num = human_readable (- (uintmax_t) statp->st_mtime,
285 hbuf, human_ceiling, 1, 1);
286 int sign_width = width - strlen (num);
287 fprintf (stream, "%*s%s ",
288 sign_width < 0 ? 0 : sign_width, "-", num);
290 else
291 fprintf (stream, "%*s ", width,
292 human_readable ((uintmax_t) statp->st_mtime, hbuf,
293 human_ceiling,
294 1, 1));
297 print_name (name, stream, literal_control_chars);
299 #ifdef S_ISLNK
300 if (S_ISLNK (statp->st_mode))
302 char *linkname = get_link_name_at (name, dirfd, relname);
304 if (linkname)
306 fputs (" -> ", stream);
307 print_name (linkname, stream, literal_control_chars);
308 free (linkname);
311 #endif
312 putc ('\n', stream);
316 static void
317 print_name_without_quoting (const char *p, FILE *stream)
319 fprintf(stream, "%s", p);
323 static void
324 print_name_with_quoting (register const char *p, FILE *stream)
326 register unsigned char c;
328 while ((c = *p++) != '\0')
330 switch (c)
332 case '\\':
333 fprintf (stream, "\\\\");
334 break;
336 case '\n':
337 fprintf (stream, "\\n");
338 break;
340 case '\b':
341 fprintf (stream, "\\b");
342 break;
344 case '\r':
345 fprintf (stream, "\\r");
346 break;
348 case '\t':
349 fprintf (stream, "\\t");
350 break;
352 case '\f':
353 fprintf (stream, "\\f");
354 break;
356 case ' ':
357 fprintf (stream, "\\ ");
358 break;
360 case '"':
361 fprintf (stream, "\\\"");
362 break;
364 default:
365 if (c > 040 && c < 0177)
366 putc (c, stream);
367 else
368 fprintf (stream, "\\%03o", (unsigned int) c);
373 static void print_name (register const char *p, FILE *stream, int literal_control_chars)
375 if (literal_control_chars)
376 print_name_without_quoting(p, stream);
377 else
378 print_name_with_quoting(p, stream);
381 #ifdef S_ISLNK
382 static char *
383 get_link_name (const char *name, char *relname)
385 register char *linkname;
386 register int linklen;
388 /* st_size is wrong for symlinks on AIX, and on
389 mount points with some automounters.
390 So allocate a pessimistic PATH_MAX + 1 bytes. */
391 #define LINK_BUF PATH_MAX
392 linkname = xmalloc (LINK_BUF + 1);
393 linklen = readlink (relname, linkname, LINK_BUF);
394 if (linklen < 0)
396 error (0, errno, "%s", name);
397 free (linkname);
398 return 0;
400 linkname[linklen] = '\0';
401 return linkname;
404 struct link_name_args
406 const char *name;
407 char *relname;
408 char *result;
411 static int
412 get_link_name_cb(void *context)
414 struct link_name_args *args = context;
415 args->result = get_link_name(args->name, args->relname);
416 return 0;
419 char *
420 get_link_name_at (const char *name, int dirfd, char *relname)
422 struct link_name_args args;
423 args.result = NULL;
424 args.name = name;
425 args.relname = relname;
426 if (0 == run_in_dir(dirfd, get_link_name_cb, &args))
427 return args.result;
428 else
429 return NULL;
433 #endif