Fixed typos in NEWS file
[findutils.git] / lib / listfile.c
blob5e6e37457c05971d9fba06d8609f0d893b6f207c
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"
42 #include "listfile.h"
44 /* Since major is a function on SVR4, we can't use `ifndef major'. */
45 #ifdef MAJOR_IN_MKDEV
46 #include <sys/mkdev.h>
47 #define HAVE_MAJOR
48 #endif
49 #ifdef MAJOR_IN_SYSMACROS
50 #include <sys/sysmacros.h>
51 #define HAVE_MAJOR
52 #endif
58 #ifdef HAVE_LOCALE_H
59 #include <locale.h>
60 #endif
62 #if ENABLE_NLS
63 # include <libintl.h>
64 # define _(Text) gettext (Text)
65 #else
66 # define _(Text) Text
67 #define textdomain(Domain)
68 #define bindtextdomain(Package, Directory)
69 #endif
70 #ifdef gettext_noop
71 # define N_(String) gettext_noop (String)
72 #else
73 /* See locate.c for explanation as to why not use (String) */
74 # define N_(String) String
75 #endif
79 #ifdef STAT_MACROS_BROKEN
80 #undef S_ISCHR
81 #undef S_ISBLK
82 #undef S_ISLNK
83 #endif
85 #ifndef S_ISCHR
86 #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
87 #endif
88 #ifndef S_ISBLK
89 #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
90 #endif
91 #if defined S_IFLNK && !defined S_ISLNK
92 #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
93 #endif
95 /* Get or fake the disk device blocksize.
96 Usually defined by sys/param.h (if at all). */
97 #ifndef DEV_BSIZE
98 # ifdef BSIZE
99 # define DEV_BSIZE BSIZE
100 # else /* !BSIZE */
101 # define DEV_BSIZE 4096
102 # endif /* !BSIZE */
103 #endif /* !DEV_BSIZE */
105 /* Extract or fake data from a `struct stat'.
106 ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
107 ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
108 ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
109 #ifndef HAVE_STRUCT_STAT_ST_BLOCKS
110 # define ST_BLKSIZE(statbuf) DEV_BSIZE
111 # if defined _POSIX_SOURCE || !defined BSIZE /* fileblocks.c uses BSIZE. */
112 # define ST_NBLOCKS(statbuf) \
113 (S_ISREG ((statbuf).st_mode) \
114 || S_ISDIR ((statbuf).st_mode) \
115 ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0)
116 # else /* !_POSIX_SOURCE && BSIZE */
117 # define ST_NBLOCKS(statbuf) \
118 (S_ISREG ((statbuf).st_mode) \
119 || S_ISDIR ((statbuf).st_mode) \
120 ? st_blocks ((statbuf).st_size) : 0)
121 # endif /* !_POSIX_SOURCE && BSIZE */
122 #else /* HAVE_STRUCT_STAT_ST_BLOCKS */
123 /* Some systems, like Sequents, return st_blksize of 0 on pipes. */
124 # define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
125 ? (statbuf).st_blksize : DEV_BSIZE)
126 # if defined hpux || defined __hpux__ || defined __hpux
127 /* HP-UX counts st_blocks in 1024-byte units.
128 This loses when mixing HP-UX and BSD filesystems with NFS. */
129 # define ST_NBLOCKSIZE 1024
130 # else /* !hpux */
131 # if defined _AIX && defined _I386
132 /* AIX PS/2 counts st_blocks in 4K units. */
133 # define ST_NBLOCKSIZE (4 * 1024)
134 # else /* not AIX PS/2 */
135 # if defined _CRAY
136 # define ST_NBLOCKS(statbuf) \
137 (S_ISREG ((statbuf).st_mode) \
138 || S_ISDIR ((statbuf).st_mode) \
139 ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
140 # endif /* _CRAY */
141 # endif /* not AIX PS/2 */
142 # endif /* !hpux */
143 #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
145 #ifndef ST_NBLOCKS
146 # define ST_NBLOCKS(statbuf) \
147 (S_ISREG ((statbuf).st_mode) \
148 || S_ISDIR ((statbuf).st_mode) \
149 ? (statbuf).st_blocks : 0)
150 #endif
152 #ifndef ST_NBLOCKSIZE
153 # define ST_NBLOCKSIZE 512
154 #endif
156 #ifdef major /* Might be defined in sys/types.h. */
157 #define HAVE_MAJOR
158 #endif
159 #ifndef HAVE_MAJOR
160 #define major(dev) (((dev) >> 8) & 0xff)
161 #define minor(dev) ((dev) & 0xff)
162 #endif
163 #undef HAVE_MAJOR
166 static void print_name (register const char *p, FILE *stream, int literal_control_chars);
168 extern char * getgroup (gid_t gid);
169 extern char * getuser (uid_t uid);
173 size_t
174 file_blocksize(const struct stat *p)
176 return ST_NBLOCKSIZE;
181 /* NAME is the name to print.
182 RELNAME is the path to access it from the current directory.
183 STATP is the results of stat or lstat on it.
184 Use CURRENT_TIME to decide whether to print yyyy or hh:mm.
185 Use OUTPUT_BLOCK_SIZE to determine how to print file block counts
186 and sizes.
187 STREAM is the stdio stream to print on. */
189 void
190 list_file (const char *name,
191 int dirfd,
192 char *relname,
193 const struct stat *statp,
194 time_t current_time,
195 int output_block_size,
196 int literal_control_chars,
197 FILE *stream)
199 char modebuf[11];
200 struct tm const *when_local;
201 char const *user_name;
202 char const *group_name;
203 char hbuf[LONGEST_HUMAN_READABLE + 1];
205 #if HAVE_ST_DM_MODE
206 /* Cray DMF: look at the file's migrated, not real, status */
207 strmode (statp->st_dm_mode, modebuf);
208 #else
209 strmode (statp->st_mode, modebuf);
210 #endif
211 modebuf[10] = '\0';
213 fprintf (stream, "%6s ",
214 human_readable ((uintmax_t) statp->st_ino, hbuf,
215 human_ceiling,
216 1, 1));
218 fprintf (stream, "%4s ",
219 human_readable ((uintmax_t) ST_NBLOCKS (*statp), hbuf,
220 human_ceiling,
221 ST_NBLOCKSIZE, output_block_size));
224 /* The space between the mode and the number of links is the POSIX
225 "optional alternate access method flag". */
226 fprintf (stream, "%s %3lu ", modebuf, (unsigned long) statp->st_nlink);
228 user_name = getuser (statp->st_uid);
229 if (user_name)
230 fprintf (stream, "%-8s ", user_name);
231 else
232 fprintf (stream, "%-8lu ", (unsigned long) statp->st_uid);
234 group_name = getgroup (statp->st_gid);
235 if (group_name)
236 fprintf (stream, "%-8s ", group_name);
237 else
238 fprintf (stream, "%-8lu ", (unsigned long) statp->st_gid);
240 if (S_ISCHR (statp->st_mode) || S_ISBLK (statp->st_mode))
241 #ifdef HAVE_ST_RDEV
242 fprintf (stream, "%3lu, %3lu ",
243 (unsigned long) major (statp->st_rdev),
244 (unsigned long) minor (statp->st_rdev));
245 #else
246 fprintf (stream, " ");
247 #endif
248 else
249 fprintf (stream, "%8s ",
250 human_readable ((uintmax_t) statp->st_size, hbuf,
251 human_ceiling,
253 output_block_size < 0 ? output_block_size : 1));
255 if ((when_local = localtime (&statp->st_mtime)))
257 char init_bigbuf[256];
258 char *buf = init_bigbuf;
259 size_t bufsize = sizeof init_bigbuf;
261 /* Use strftime rather than ctime, because the former can produce
262 locale-dependent names for the month (%b).
264 Output the year if the file is fairly old or in the future.
265 POSIX says the cutoff is 6 months old;
266 approximate this by 6*30 days.
267 Allow a 1 hour slop factor for what is considered "the future",
268 to allow for NFS server/client clock disagreement. */
269 char const *fmt =
270 ((current_time - 6 * 30 * 24 * 60 * 60 <= statp->st_mtime
271 && statp->st_mtime <= current_time + 60 * 60)
272 ? "%b %e %H:%M"
273 : "%b %e %Y");
275 while (!strftime (buf, bufsize, fmt, when_local))
276 buf = alloca (bufsize *= 2);
278 fprintf (stream, "%s ", buf);
280 else
282 /* The time cannot be represented as a local time;
283 print it as a huge integer number of seconds. */
284 int width = 12;
286 if (statp->st_mtime < 0)
288 char const *num = human_readable (- (uintmax_t) statp->st_mtime,
289 hbuf, human_ceiling, 1, 1);
290 int sign_width = width - strlen (num);
291 fprintf (stream, "%*s%s ",
292 sign_width < 0 ? 0 : sign_width, "-", num);
294 else
295 fprintf (stream, "%*s ", width,
296 human_readable ((uintmax_t) statp->st_mtime, hbuf,
297 human_ceiling,
298 1, 1));
301 print_name (name, stream, literal_control_chars);
303 #ifdef S_ISLNK
304 if (S_ISLNK (statp->st_mode))
306 char *linkname = get_link_name_at (name, dirfd, relname);
308 if (linkname)
310 fputs (" -> ", stream);
311 print_name (linkname, stream, literal_control_chars);
312 free (linkname);
315 #endif
316 putc ('\n', stream);
320 static void
321 print_name_without_quoting (const char *p, FILE *stream)
323 fprintf(stream, "%s", p);
327 static void
328 print_name_with_quoting (register const char *p, FILE *stream)
330 register unsigned char c;
332 while ((c = *p++) != '\0')
334 switch (c)
336 case '\\':
337 fprintf (stream, "\\\\");
338 break;
340 case '\n':
341 fprintf (stream, "\\n");
342 break;
344 case '\b':
345 fprintf (stream, "\\b");
346 break;
348 case '\r':
349 fprintf (stream, "\\r");
350 break;
352 case '\t':
353 fprintf (stream, "\\t");
354 break;
356 case '\f':
357 fprintf (stream, "\\f");
358 break;
360 case ' ':
361 fprintf (stream, "\\ ");
362 break;
364 case '"':
365 fprintf (stream, "\\\"");
366 break;
368 default:
369 if (c > 040 && c < 0177)
370 putc (c, stream);
371 else
372 fprintf (stream, "\\%03o", (unsigned int) c);
377 static void print_name (register const char *p, FILE *stream, int literal_control_chars)
379 if (literal_control_chars)
380 print_name_without_quoting(p, stream);
381 else
382 print_name_with_quoting(p, stream);
385 #ifdef S_ISLNK
386 static char *
387 get_link_name (const char *name, char *relname)
389 register char *linkname;
390 register int linklen;
392 /* st_size is wrong for symlinks on AIX, and on
393 mount points with some automounters.
394 So allocate a pessimistic PATH_MAX + 1 bytes. */
395 #define LINK_BUF PATH_MAX
396 linkname = xmalloc (LINK_BUF + 1);
397 linklen = readlink (relname, linkname, LINK_BUF);
398 if (linklen < 0)
400 error (0, errno, "%s", name);
401 free (linkname);
402 return 0;
404 linkname[linklen] = '\0';
405 return linkname;
408 struct link_name_args
410 const char *name;
411 char *relname;
412 char *result;
415 static int
416 get_link_name_cb(void *context)
418 struct link_name_args *args = context;
419 args->result = get_link_name(args->name, args->relname);
420 return 0;
423 char *
424 get_link_name_at (const char *name, int dirfd, char *relname)
426 struct link_name_args args;
427 args.result = NULL;
428 args.name = name;
429 args.relname = relname;
430 if (0 == run_in_dir(dirfd, get_link_name_cb, &args))
431 return args.result;
432 else
433 return NULL;
437 #endif