Use const char* parameters for pathnames
[findutils.git] / lib / listfile.c
blob0d09ad94d0d06a6b2d53d6703d258bec6db48fff
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"
45 #include "listfile.h"
47 /* Since major is a function on SVR4, we can't use `ifndef major'. */
48 #ifdef MAJOR_IN_MKDEV
49 #include <sys/mkdev.h>
50 #define HAVE_MAJOR
51 #endif
52 #ifdef MAJOR_IN_SYSMACROS
53 #include <sys/sysmacros.h>
54 #define HAVE_MAJOR
55 #endif
61 #ifdef HAVE_LOCALE_H
62 #include <locale.h>
63 #endif
65 #if ENABLE_NLS
66 # include <libintl.h>
67 # define _(Text) gettext (Text)
68 #else
69 # define _(Text) Text
70 #define textdomain(Domain)
71 #define bindtextdomain(Package, Directory)
72 #endif
73 #ifdef gettext_noop
74 # define N_(String) gettext_noop (String)
75 #else
76 /* See locate.c for explanation as to why not use (String) */
77 # define N_(String) String
78 #endif
82 #ifdef STAT_MACROS_BROKEN
83 #undef S_ISCHR
84 #undef S_ISBLK
85 #undef S_ISLNK
86 #endif
88 #ifndef S_ISCHR
89 #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
90 #endif
91 #ifndef S_ISBLK
92 #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
93 #endif
94 #if defined(S_IFLNK) && !defined(S_ISLNK)
95 #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
96 #endif
98 /* Get or fake the disk device blocksize.
99 Usually defined by sys/param.h (if at all). */
100 #ifndef DEV_BSIZE
101 # ifdef BSIZE
102 # define DEV_BSIZE BSIZE
103 # else /* !BSIZE */
104 # define DEV_BSIZE 4096
105 # endif /* !BSIZE */
106 #endif /* !DEV_BSIZE */
108 /* Extract or fake data from a `struct stat'.
109 ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
110 ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
111 ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
112 #ifndef HAVE_STRUCT_STAT_ST_BLOCKS
113 # define ST_BLKSIZE(statbuf) DEV_BSIZE
114 # if defined(_POSIX_SOURCE) || !defined(BSIZE) /* fileblocks.c uses BSIZE. */
115 # define ST_NBLOCKS(statbuf) \
116 (S_ISREG ((statbuf).st_mode) \
117 || S_ISDIR ((statbuf).st_mode) \
118 ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0)
119 # else /* !_POSIX_SOURCE && BSIZE */
120 # define ST_NBLOCKS(statbuf) \
121 (S_ISREG ((statbuf).st_mode) \
122 || S_ISDIR ((statbuf).st_mode) \
123 ? st_blocks ((statbuf).st_size) : 0)
124 # endif /* !_POSIX_SOURCE && BSIZE */
125 #else /* HAVE_STRUCT_STAT_ST_BLOCKS */
126 /* Some systems, like Sequents, return st_blksize of 0 on pipes. */
127 # define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
128 ? (statbuf).st_blksize : DEV_BSIZE)
129 # if defined(hpux) || defined(__hpux__) || defined(__hpux)
130 /* HP-UX counts st_blocks in 1024-byte units.
131 This loses when mixing HP-UX and BSD filesystems with NFS. */
132 # define ST_NBLOCKSIZE 1024
133 # else /* !hpux */
134 # if defined(_AIX) && defined(_I386)
135 /* AIX PS/2 counts st_blocks in 4K units. */
136 # define ST_NBLOCKSIZE (4 * 1024)
137 # else /* not AIX PS/2 */
138 # if defined(_CRAY)
139 # define ST_NBLOCKS(statbuf) \
140 (S_ISREG ((statbuf).st_mode) \
141 || S_ISDIR ((statbuf).st_mode) \
142 ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
143 # endif /* _CRAY */
144 # endif /* not AIX PS/2 */
145 # endif /* !hpux */
146 #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
148 #ifndef ST_NBLOCKS
149 # define ST_NBLOCKS(statbuf) \
150 (S_ISREG ((statbuf).st_mode) \
151 || S_ISDIR ((statbuf).st_mode) \
152 ? (statbuf).st_blocks : 0)
153 #endif
155 #ifndef ST_NBLOCKSIZE
156 # define ST_NBLOCKSIZE 512
157 #endif
159 #ifdef major /* Might be defined in sys/types.h. */
160 #define HAVE_MAJOR
161 #endif
162 #ifndef HAVE_MAJOR
163 #define major(dev) (((dev) >> 8) & 0xff)
164 #define minor(dev) ((dev) & 0xff)
165 #endif
166 #undef HAVE_MAJOR
169 static void print_name (register const char *p, FILE *stream, int literal_control_chars);
171 extern char * getgroup (gid_t gid);
172 extern char * getuser (uid_t uid);
176 size_t
177 file_blocksize(const struct stat *p)
179 return ST_NBLOCKSIZE;
184 /* NAME is the name to print.
185 RELNAME is the path to access it from the current directory.
186 STATP is the results of stat or lstat on it.
187 Use CURRENT_TIME to decide whether to print yyyy or hh:mm.
188 Use OUTPUT_BLOCK_SIZE to determine how to print file block counts
189 and sizes.
190 STREAM is the stdio stream to print on. */
192 void
193 list_file (const char *name,
194 int dirfd,
195 char *relname,
196 const struct stat *statp,
197 time_t current_time,
198 int output_block_size,
199 int literal_control_chars,
200 FILE *stream)
202 char modebuf[11];
203 struct tm const *when_local;
204 char const *user_name;
205 char const *group_name;
206 char hbuf[LONGEST_HUMAN_READABLE + 1];
208 #if HAVE_ST_DM_MODE
209 /* Cray DMF: look at the file's migrated, not real, status */
210 strmode (statp->st_dm_mode, modebuf);
211 #else
212 strmode (statp->st_mode, modebuf);
213 #endif
214 modebuf[10] = '\0';
216 fprintf (stream, "%6s ",
217 human_readable ((uintmax_t) statp->st_ino, hbuf,
218 human_ceiling,
219 1, 1));
221 fprintf (stream, "%4s ",
222 human_readable ((uintmax_t) ST_NBLOCKS (*statp), hbuf,
223 human_ceiling,
224 ST_NBLOCKSIZE, output_block_size));
227 /* The space between the mode and the number of links is the POSIX
228 "optional alternate access method flag". */
229 fprintf (stream, "%s %3lu ", modebuf, (unsigned long) statp->st_nlink);
231 user_name = getuser (statp->st_uid);
232 if (user_name)
233 fprintf (stream, "%-8s ", user_name);
234 else
235 fprintf (stream, "%-8lu ", (unsigned long) statp->st_uid);
237 group_name = getgroup (statp->st_gid);
238 if (group_name)
239 fprintf (stream, "%-8s ", group_name);
240 else
241 fprintf (stream, "%-8lu ", (unsigned long) statp->st_gid);
243 if (S_ISCHR (statp->st_mode) || S_ISBLK (statp->st_mode))
244 #ifdef HAVE_ST_RDEV
245 fprintf (stream, "%3lu, %3lu ",
246 (unsigned long) major (statp->st_rdev),
247 (unsigned long) minor (statp->st_rdev));
248 #else
249 fprintf (stream, " ");
250 #endif
251 else
252 fprintf (stream, "%8s ",
253 human_readable ((uintmax_t) statp->st_size, hbuf,
254 human_ceiling,
256 output_block_size < 0 ? output_block_size : 1));
258 if ((when_local = localtime (&statp->st_mtime)))
260 char init_bigbuf[256];
261 char *buf = init_bigbuf;
262 size_t bufsize = sizeof init_bigbuf;
264 /* Use strftime rather than ctime, because the former can produce
265 locale-dependent names for the month (%b).
267 Output the year if the file is fairly old or in the future.
268 POSIX says the cutoff is 6 months old;
269 approximate this by 6*30 days.
270 Allow a 1 hour slop factor for what is considered "the future",
271 to allow for NFS server/client clock disagreement. */
272 char const *fmt =
273 ((current_time - 6 * 30 * 24 * 60 * 60 <= statp->st_mtime
274 && statp->st_mtime <= current_time + 60 * 60)
275 ? "%b %e %H:%M"
276 : "%b %e %Y");
278 while (!strftime (buf, bufsize, fmt, when_local))
279 buf = (char *) alloca (bufsize *= 2);
281 fprintf (stream, "%s ", buf);
283 else
285 /* The time cannot be represented as a local time;
286 print it as a huge integer number of seconds. */
287 int width = 12;
289 if (statp->st_mtime < 0)
291 char const *num = human_readable (- (uintmax_t) statp->st_mtime,
292 hbuf, human_ceiling, 1, 1);
293 int sign_width = width - strlen (num);
294 fprintf (stream, "%*s%s ",
295 sign_width < 0 ? 0 : sign_width, "-", num);
297 else
298 fprintf (stream, "%*s ", width,
299 human_readable ((uintmax_t) statp->st_mtime, hbuf,
300 human_ceiling,
301 1, 1));
304 print_name (name, stream, literal_control_chars);
306 #ifdef S_ISLNK
307 if (S_ISLNK (statp->st_mode))
309 char *linkname = get_link_name_at (name, dirfd, relname);
311 if (linkname)
313 fputs (" -> ", stream);
314 print_name (linkname, stream, literal_control_chars);
315 free (linkname);
318 #endif
319 putc ('\n', stream);
323 static void
324 print_name_without_quoting (const char *p, FILE *stream)
326 fprintf(stream, "%s", p);
330 static void
331 print_name_with_quoting (register const char *p, FILE *stream)
333 register unsigned char c;
335 while ((c = *p++) != '\0')
337 switch (c)
339 case '\\':
340 fprintf (stream, "\\\\");
341 break;
343 case '\n':
344 fprintf (stream, "\\n");
345 break;
347 case '\b':
348 fprintf (stream, "\\b");
349 break;
351 case '\r':
352 fprintf (stream, "\\r");
353 break;
355 case '\t':
356 fprintf (stream, "\\t");
357 break;
359 case '\f':
360 fprintf (stream, "\\f");
361 break;
363 case ' ':
364 fprintf (stream, "\\ ");
365 break;
367 case '"':
368 fprintf (stream, "\\\"");
369 break;
371 default:
372 if (c > 040 && c < 0177)
373 putc (c, stream);
374 else
375 fprintf (stream, "\\%03o", (unsigned int) c);
380 static void print_name (register const char *p, FILE *stream, int literal_control_chars)
382 if (literal_control_chars)
383 print_name_without_quoting(p, stream);
384 else
385 print_name_with_quoting(p, stream);
388 #ifdef S_ISLNK
389 static char *
390 get_link_name (const char *name, char *relname)
392 register char *linkname;
393 register int linklen;
395 /* st_size is wrong for symlinks on AIX, and on
396 mount points with some automounters.
397 So allocate a pessimistic PATH_MAX + 1 bytes. */
398 #define LINK_BUF PATH_MAX
399 linkname = (char *) xmalloc (LINK_BUF + 1);
400 linklen = readlink (relname, linkname, LINK_BUF);
401 if (linklen < 0)
403 error (0, errno, "%s", name);
404 free (linkname);
405 return 0;
407 linkname[linklen] = '\0';
408 return linkname;
411 struct link_name_args
413 const char *name;
414 char *relname;
415 char *result;
418 static int
419 get_link_name_cb(void *context)
421 struct link_name_args *args = context;
422 args->result = get_link_name(args->name, args->relname);
423 return 0;
426 char *
427 get_link_name_at (const char *name, int dirfd, char *relname)
429 struct link_name_args args;
430 args.result = NULL;
431 args.name = name;
432 args.relname = relname;
433 if (0 == run_in_dir(dirfd, get_link_name_cb, &args))
434 return args.result;
435 else
436 return NULL;
440 #endif