1 /* listfile.c -- display a long listing of a file
2 Copyright (C) 1991, 1993, 2000 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)
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,
43 #include <sys/types.h>
58 #if HAVE_STRING_H || STDC_HEADERS
65 /* The presence of unistd.h is assumed by gnulib these days, so we
66 * might as well assume it too.
68 #include <unistd.h> /* for readlink() */
78 /* Since major is a function on SVR4, we can't use `ifndef major'. */
80 #include <sys/mkdev.h>
83 #ifdef MAJOR_IN_SYSMACROS
84 #include <sys/sysmacros.h>
88 #ifdef STAT_MACROS_BROKEN
95 #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
98 #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
100 #if defined(S_IFLNK) && !defined(S_ISLNK)
101 #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
104 /* Get or fake the disk device blocksize.
105 Usually defined by sys/param.h (if at all). */
108 # define DEV_BSIZE BSIZE
110 # define DEV_BSIZE 4096
112 #endif /* !DEV_BSIZE */
114 /* Extract or fake data from a `struct stat'.
115 ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
116 ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
117 ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
118 #ifndef HAVE_STRUCT_STAT_ST_BLOCKS
119 # define ST_BLKSIZE(statbuf) DEV_BSIZE
120 # if defined(_POSIX_SOURCE) || !defined(BSIZE) /* fileblocks.c uses BSIZE. */
121 # define ST_NBLOCKS(statbuf) \
122 (S_ISREG ((statbuf).st_mode) \
123 || S_ISDIR ((statbuf).st_mode) \
124 ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0)
125 # else /* !_POSIX_SOURCE && BSIZE */
126 # define ST_NBLOCKS(statbuf) \
127 (S_ISREG ((statbuf).st_mode) \
128 || S_ISDIR ((statbuf).st_mode) \
129 ? st_blocks ((statbuf).st_size) : 0)
130 # endif /* !_POSIX_SOURCE && BSIZE */
131 #else /* HAVE_STRUCT_STAT_ST_BLOCKS */
132 /* Some systems, like Sequents, return st_blksize of 0 on pipes. */
133 # define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
134 ? (statbuf).st_blksize : DEV_BSIZE)
135 # if defined(hpux) || defined(__hpux__) || defined(__hpux)
136 /* HP-UX counts st_blocks in 1024-byte units.
137 This loses when mixing HP-UX and BSD filesystems with NFS. */
138 # define ST_NBLOCKSIZE 1024
140 # if defined(_AIX) && defined(_I386)
141 /* AIX PS/2 counts st_blocks in 4K units. */
142 # define ST_NBLOCKSIZE (4 * 1024)
143 # else /* not AIX PS/2 */
145 # define ST_NBLOCKS(statbuf) \
146 (S_ISREG ((statbuf).st_mode) \
147 || S_ISDIR ((statbuf).st_mode) \
148 ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
150 # endif /* not AIX PS/2 */
152 #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
155 # define ST_NBLOCKS(statbuf) \
156 (S_ISREG ((statbuf).st_mode) \
157 || S_ISDIR ((statbuf).st_mode) \
158 ? (statbuf).st_blocks : 0)
161 #ifndef ST_NBLOCKSIZE
162 # define ST_NBLOCKSIZE 512
165 #ifndef _POSIX_VERSION
166 struct passwd
*getpwuid ();
167 struct group
*getgrgid ();
170 #ifdef major /* Might be defined in sys/types.h. */
174 #define major(dev) (((dev) >> 8) & 0xff)
175 #define minor(dev) ((dev) & 0xff)
180 char * get_link_name (char *name
, char *relname
);
181 static void print_name (register char *p
, FILE *stream
, int literal_control_chars
);
183 extern char * getgroup (gid_t gid
);
184 extern char * getuser (uid_t uid
);
187 /* NAME is the name to print.
188 RELNAME is the path to access it from the current directory.
189 STATP is the results of stat or lstat on it.
190 Use CURRENT_TIME to decide whether to print yyyy or hh:mm.
191 Use OUTPUT_BLOCK_SIZE to determine how to print file block counts
193 STREAM is the stdio stream to print on. */
196 list_file (char *name
,
200 int output_block_size
,
201 int literal_control_chars
,
205 struct tm
const *when_local
;
206 char const *user_name
;
207 char const *group_name
;
208 char hbuf
[LONGEST_HUMAN_READABLE
+ 1];
211 /* Cray DMF: look at the file's migrated, not real, status */
212 strmode (statp
->st_dm_mode
, modebuf
);
214 strmode (statp
->st_mode
, modebuf
);
218 fprintf (stream
, "%6s ",
219 human_readable ((uintmax_t) statp
->st_ino
, hbuf
,
223 fprintf (stream
, "%4s ",
224 human_readable ((uintmax_t) ST_NBLOCKS (*statp
), hbuf
,
226 ST_NBLOCKSIZE
, output_block_size
));
229 /* The space between the mode and the number of links is the POSIX
230 "optional alternate access method flag". */
231 fprintf (stream
, "%s %3lu ", modebuf
, (unsigned long) statp
->st_nlink
);
233 user_name
= getuser (statp
->st_uid
);
235 fprintf (stream
, "%-8s ", user_name
);
237 fprintf (stream
, "%-8lu ", (unsigned long) statp
->st_uid
);
239 group_name
= getgroup (statp
->st_gid
);
241 fprintf (stream
, "%-8s ", group_name
);
243 fprintf (stream
, "%-8lu ", (unsigned long) statp
->st_gid
);
245 if (S_ISCHR (statp
->st_mode
) || S_ISBLK (statp
->st_mode
))
247 fprintf (stream
, "%3lu, %3lu ",
248 (unsigned long) major (statp
->st_rdev
),
249 (unsigned long) minor (statp
->st_rdev
));
251 fprintf (stream
, " ");
254 fprintf (stream
, "%8s ",
255 human_readable ((uintmax_t) statp
->st_size
, hbuf
,
258 output_block_size
< 0 ? output_block_size
: 1));
260 if ((when_local
= localtime (&statp
->st_mtime
)))
262 char init_bigbuf
[256];
263 char *buf
= init_bigbuf
;
264 size_t bufsize
= sizeof init_bigbuf
;
266 /* Use strftime rather than ctime, because the former can produce
267 locale-dependent names for the month (%b).
269 Output the year if the file is fairly old or in the future.
270 POSIX says the cutoff is 6 months old;
271 approximate this by 6*30 days.
272 Allow a 1 hour slop factor for what is considered "the future",
273 to allow for NFS server/client clock disagreement. */
275 ((current_time
- 6 * 30 * 24 * 60 * 60 <= statp
->st_mtime
276 && statp
->st_mtime
<= current_time
+ 60 * 60)
280 while (!strftime (buf
, bufsize
, fmt
, when_local
))
281 buf
= (char *) alloca (bufsize
*= 2);
283 fprintf (stream
, "%s ", buf
);
287 /* The time cannot be represented as a local time;
288 print it as a huge integer number of seconds. */
291 if (statp
->st_mtime
< 0)
293 char const *num
= human_readable (- (uintmax_t) statp
->st_mtime
,
294 hbuf
, human_ceiling
, 1, 1);
295 int sign_width
= width
- strlen (num
);
296 fprintf (stream
, "%*s%s ",
297 sign_width
< 0 ? 0 : sign_width
, "-", num
);
300 fprintf (stream
, "%*s ", width
,
301 human_readable ((uintmax_t) statp
->st_mtime
, hbuf
,
306 print_name (name
, stream
, literal_control_chars
);
309 if (S_ISLNK (statp
->st_mode
))
311 char *linkname
= get_link_name (name
, relname
);
315 fputs (" -> ", stream
);
316 print_name (linkname
, stream
, literal_control_chars
);
326 print_name_without_quoting (char *p
, FILE *stream
)
328 fprintf(stream
, "%s", p
);
333 print_name_with_quoting (register char *p
, FILE *stream
)
335 register unsigned char c
;
337 while ((c
= *p
++) != '\0')
342 fprintf (stream
, "\\\\");
346 fprintf (stream
, "\\n");
350 fprintf (stream
, "\\b");
354 fprintf (stream
, "\\r");
358 fprintf (stream
, "\\t");
362 fprintf (stream
, "\\f");
366 fprintf (stream
, "\\ ");
370 fprintf (stream
, "\\\"");
374 if (c
> 040 && c
< 0177)
377 fprintf (stream
, "\\%03o", (unsigned int) c
);
382 static void print_name (register char *p
, FILE *stream
, int literal_control_chars
)
384 if (literal_control_chars
)
385 print_name_without_quoting(p
, stream
);
387 print_name_with_quoting(p
, stream
);
392 get_link_name (char *name
, char *relname
)
394 register char *linkname
;
395 register int linklen
;
397 /* st_size is wrong for symlinks on AIX, and on
398 mount points with some automounters.
399 So allocate a pessimistic PATH_MAX + 1 bytes. */
400 #define LINK_BUF PATH_MAX
401 linkname
= (char *) xmalloc (LINK_BUF
+ 1);
402 linklen
= readlink (relname
, linkname
, LINK_BUF
);
405 error (0, errno
, "%s", name
);
409 linkname
[linklen
] = '\0';