cvsimport
[findutils.git] / lib / listfile.c
blobca9eae251f7ec70a92ed866d2af016b9fd186bd4
1 /* listfile.c -- display a long listing of a file
2 Copyright (C) 1991, 1993, 2000, 2004, 2005, 2007,
3 2008 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <config.h>
21 #include <alloca.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <pwd.h>
28 #include <grp.h>
29 #include <time.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <string.h>
33 #include <unistd.h> /* for readlink() */
34 #include <openat.h>
36 #include "human.h"
37 #include "xalloc.h"
38 #include "pathmax.h"
39 #include "error.h"
40 #include "filemode.h"
41 #include "dircallback.h"
42 #include "idcache.h"
44 #include "listfile.h"
46 /* Since major is a function on SVR4, we can't use `ifndef major'. */
47 #ifdef MAJOR_IN_MKDEV
48 #include <sys/mkdev.h>
49 #define HAVE_MAJOR
50 #endif
51 #ifdef MAJOR_IN_SYSMACROS
52 #include <sys/sysmacros.h>
53 #define HAVE_MAJOR
54 #endif
60 #ifdef HAVE_LOCALE_H
61 #include <locale.h>
62 #endif
64 #if ENABLE_NLS
65 # include <libintl.h>
66 # define _(Text) gettext (Text)
67 #else
68 # define _(Text) Text
69 #define textdomain(Domain)
70 #define bindtextdomain(Package, Directory)
71 #endif
72 #ifdef gettext_noop
73 # define N_(String) gettext_noop (String)
74 #else
75 /* See locate.c for explanation as to why not use (String) */
76 # define N_(String) String
77 #endif
81 #ifdef STAT_MACROS_BROKEN
82 #undef S_ISCHR
83 #undef S_ISBLK
84 #undef S_ISLNK
85 #endif
87 #ifndef S_ISCHR
88 #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
89 #endif
90 #ifndef S_ISBLK
91 #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
92 #endif
93 #if defined S_IFLNK && !defined S_ISLNK
94 #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
95 #endif
97 /* Get or fake the disk device blocksize.
98 Usually defined by sys/param.h (if at all). */
99 #ifndef DEV_BSIZE
100 # ifdef BSIZE
101 # define DEV_BSIZE BSIZE
102 # else /* !BSIZE */
103 # define DEV_BSIZE 4096
104 # endif /* !BSIZE */
105 #endif /* !DEV_BSIZE */
107 /* Extract or fake data from a `struct stat'.
108 ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
109 ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
110 ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
111 #ifndef HAVE_STRUCT_STAT_ST_BLOCKS
112 # define ST_BLKSIZE(statbuf) DEV_BSIZE
113 # if defined _POSIX_SOURCE || !defined BSIZE /* fileblocks.c uses BSIZE. */
114 # define ST_NBLOCKS(statbuf) \
115 (S_ISREG ((statbuf).st_mode) \
116 || S_ISDIR ((statbuf).st_mode) \
117 ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0)
118 # else /* !_POSIX_SOURCE && BSIZE */
119 # define ST_NBLOCKS(statbuf) \
120 (S_ISREG ((statbuf).st_mode) \
121 || S_ISDIR ((statbuf).st_mode) \
122 ? st_blocks ((statbuf).st_size) : 0)
123 # endif /* !_POSIX_SOURCE && BSIZE */
124 #else /* HAVE_STRUCT_STAT_ST_BLOCKS */
125 /* Some systems, like Sequents, return st_blksize of 0 on pipes. */
126 # define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
127 ? (statbuf).st_blksize : DEV_BSIZE)
128 # if defined hpux || defined __hpux__ || defined __hpux
129 /* HP-UX counts st_blocks in 1024-byte units.
130 This loses when mixing HP-UX and BSD filesystems with NFS. */
131 # define ST_NBLOCKSIZE 1024
132 # else /* !hpux */
133 # if defined _AIX && defined _I386
134 /* AIX PS/2 counts st_blocks in 4K units. */
135 # define ST_NBLOCKSIZE (4 * 1024)
136 # else /* not AIX PS/2 */
137 # if defined _CRAY
138 # define ST_NBLOCKS(statbuf) \
139 (S_ISREG ((statbuf).st_mode) \
140 || S_ISDIR ((statbuf).st_mode) \
141 ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
142 # endif /* _CRAY */
143 # endif /* not AIX PS/2 */
144 # endif /* !hpux */
145 #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
147 #ifndef ST_NBLOCKS
148 # define ST_NBLOCKS(statbuf) \
149 (S_ISREG ((statbuf).st_mode) \
150 || S_ISDIR ((statbuf).st_mode) \
151 ? (statbuf).st_blocks : 0)
152 #endif
154 #ifndef ST_NBLOCKSIZE
155 # define ST_NBLOCKSIZE 512
156 #endif
158 #ifdef major /* Might be defined in sys/types.h. */
159 #define HAVE_MAJOR
160 #endif
161 #ifndef HAVE_MAJOR
162 #define major(dev) (((dev) >> 8) & 0xff)
163 #define minor(dev) ((dev) & 0xff)
164 #endif
165 #undef HAVE_MAJOR
168 static void print_name (register const char *p, FILE *stream, int literal_control_chars);
171 size_t
172 file_blocksize(const struct stat *p)
174 return ST_NBLOCKSIZE;
179 /* NAME is the name to print.
180 RELNAME is the path to access it from the current directory.
181 STATP is the results of stat or lstat on it.
182 Use CURRENT_TIME to decide whether to print yyyy or hh:mm.
183 Use OUTPUT_BLOCK_SIZE to determine how to print file block counts
184 and sizes.
185 STREAM is the stdio stream to print on. */
187 void
188 list_file (const char *name,
189 int dir_fd,
190 char *relname,
191 const struct stat *statp,
192 time_t current_time,
193 int output_block_size,
194 int literal_control_chars,
195 FILE *stream)
197 char modebuf[12];
198 struct tm const *when_local;
199 char const *user_name;
200 char const *group_name;
201 char hbuf[LONGEST_HUMAN_READABLE + 1];
203 #if HAVE_ST_DM_MODE
204 /* Cray DMF: look at the file's migrated, not real, status */
205 strmode (statp->st_dm_mode, modebuf);
206 #else
207 strmode (statp->st_mode, modebuf);
208 #endif
210 fprintf (stream, "%6s ",
211 human_readable ((uintmax_t) statp->st_ino, hbuf,
212 human_ceiling,
213 1, 1));
215 fprintf (stream, "%4s ",
216 human_readable ((uintmax_t) ST_NBLOCKS (*statp), hbuf,
217 human_ceiling,
218 ST_NBLOCKSIZE, output_block_size));
221 /* modebuf includes the space between the mode and the number of links,
222 as the POSIX "optional alternate access method flag". */
223 fprintf (stream, "%s%3lu ", modebuf, (unsigned long) statp->st_nlink);
225 user_name = getuser (statp->st_uid);
226 if (user_name)
227 fprintf (stream, "%-8s ", user_name);
228 else
229 fprintf (stream, "%-8lu ", (unsigned long) statp->st_uid);
231 group_name = getgroup (statp->st_gid);
232 if (group_name)
233 fprintf (stream, "%-8s ", group_name);
234 else
235 fprintf (stream, "%-8lu ", (unsigned long) statp->st_gid);
237 if (S_ISCHR (statp->st_mode) || S_ISBLK (statp->st_mode))
238 #ifdef HAVE_ST_RDEV
239 fprintf (stream, "%3lu, %3lu ",
240 (unsigned long) major (statp->st_rdev),
241 (unsigned long) minor (statp->st_rdev));
242 #else
243 fprintf (stream, " ");
244 #endif
245 else
246 fprintf (stream, "%8s ",
247 human_readable ((uintmax_t) statp->st_size, hbuf,
248 human_ceiling,
250 output_block_size < 0 ? output_block_size : 1));
252 if ((when_local = localtime (&statp->st_mtime)))
254 char init_bigbuf[256];
255 char *buf = init_bigbuf;
256 size_t bufsize = sizeof init_bigbuf;
258 /* Use strftime rather than ctime, because the former can produce
259 locale-dependent names for the month (%b).
261 Output the year if the file is fairly old or in the future.
262 POSIX says the cutoff is 6 months old;
263 approximate this by 6*30 days.
264 Allow a 1 hour slop factor for what is considered "the future",
265 to allow for NFS server/client clock disagreement. */
266 char const *fmt =
267 ((current_time - 6 * 30 * 24 * 60 * 60 <= statp->st_mtime
268 && statp->st_mtime <= current_time + 60 * 60)
269 ? "%b %e %H:%M"
270 : "%b %e %Y");
272 while (!strftime (buf, bufsize, fmt, when_local))
273 buf = alloca (bufsize *= 2);
275 fprintf (stream, "%s ", buf);
277 else
279 /* The time cannot be represented as a local time;
280 print it as a huge integer number of seconds. */
281 int width = 12;
283 if (statp->st_mtime < 0)
285 char const *num = human_readable (- (uintmax_t) statp->st_mtime,
286 hbuf, human_ceiling, 1, 1);
287 int sign_width = width - strlen (num);
288 fprintf (stream, "%*s%s ",
289 sign_width < 0 ? 0 : sign_width, "-", num);
291 else
292 fprintf (stream, "%*s ", width,
293 human_readable ((uintmax_t) statp->st_mtime, hbuf,
294 human_ceiling,
295 1, 1));
298 print_name (name, stream, literal_control_chars);
300 #ifdef S_ISLNK
301 if (S_ISLNK (statp->st_mode))
303 char *linkname = get_link_name_at (name, dir_fd, relname);
305 if (linkname)
307 fputs (" -> ", stream);
308 print_name (linkname, stream, literal_control_chars);
309 free (linkname);
312 #endif
313 putc ('\n', stream);
317 static void
318 print_name_without_quoting (const char *p, FILE *stream)
320 fprintf(stream, "%s", p);
324 static void
325 print_name_with_quoting (register const char *p, FILE *stream)
327 register unsigned char c;
329 while ((c = *p++) != '\0')
331 switch (c)
333 case '\\':
334 fprintf (stream, "\\\\");
335 break;
337 case '\n':
338 fprintf (stream, "\\n");
339 break;
341 case '\b':
342 fprintf (stream, "\\b");
343 break;
345 case '\r':
346 fprintf (stream, "\\r");
347 break;
349 case '\t':
350 fprintf (stream, "\\t");
351 break;
353 case '\f':
354 fprintf (stream, "\\f");
355 break;
357 case ' ':
358 fprintf (stream, "\\ ");
359 break;
361 case '"':
362 fprintf (stream, "\\\"");
363 break;
365 default:
366 if (c > 040 && c < 0177)
367 putc (c, stream);
368 else
369 fprintf (stream, "\\%03o", (unsigned int) c);
374 static void print_name (register const char *p, FILE *stream, int literal_control_chars)
376 if (literal_control_chars)
377 print_name_without_quoting(p, stream);
378 else
379 print_name_with_quoting(p, stream);
382 #ifdef S_ISLNK
383 static char *
384 get_link_name (const char *name, char *relname)
386 register char *linkname;
387 register int linklen;
389 /* st_size is wrong for symlinks on AIX, and on
390 mount points with some automounters.
391 So allocate a pessimistic PATH_MAX + 1 bytes. */
392 #define LINK_BUF PATH_MAX
393 linkname = xmalloc (LINK_BUF + 1);
394 linklen = readlink (relname, linkname, LINK_BUF);
395 if (linklen < 0)
397 error (0, errno, "%s", name);
398 free (linkname);
399 return 0;
401 linkname[linklen] = '\0';
402 return linkname;
405 struct link_name_args
407 const char *name;
408 char *relname;
409 char *result;
412 static int
413 get_link_name_cb(void *context)
415 struct link_name_args *args = context;
416 args->result = get_link_name(args->name, args->relname);
417 return 0;
420 char *
421 get_link_name_at (const char *name, int dir_fd, char *relname)
423 struct link_name_args args;
424 args.result = NULL;
425 args.name = name;
426 args.relname = relname;
427 if (0 == run_in_dir(dir_fd, get_link_name_cb, &args))
428 return args.result;
429 else
430 return NULL;
434 #endif