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_with_quoting (register char *p
, FILE *stream
);
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
,
204 struct tm
const *when_local
;
205 char const *user_name
;
206 char const *group_name
;
207 char hbuf
[LONGEST_HUMAN_READABLE
+ 1];
210 /* Cray DMF: look at the file's migrated, not real, status */
211 mode_string (statp
->st_dm_mode
, modebuf
);
213 mode_string (statp
->st_mode
, modebuf
);
217 fprintf (stream
, "%6s ",
218 human_readable ((uintmax_t) statp
->st_ino
, hbuf
,
222 fprintf (stream
, "%4s ",
223 human_readable ((uintmax_t) ST_NBLOCKS (*statp
), hbuf
,
225 ST_NBLOCKSIZE
, output_block_size
));
228 /* The space between the mode and the number of links is the POSIX
229 "optional alternate access method flag". */
230 fprintf (stream
, "%s %3lu ", modebuf
, (unsigned long) statp
->st_nlink
);
232 user_name
= getuser (statp
->st_uid
);
234 fprintf (stream
, "%-8s ", user_name
);
236 fprintf (stream
, "%-8lu ", (unsigned long) statp
->st_uid
);
238 group_name
= getgroup (statp
->st_gid
);
240 fprintf (stream
, "%-8s ", group_name
);
242 fprintf (stream
, "%-8lu ", (unsigned long) statp
->st_gid
);
244 if (S_ISCHR (statp
->st_mode
) || S_ISBLK (statp
->st_mode
))
246 fprintf (stream
, "%3lu, %3lu ",
247 (unsigned long) major (statp
->st_rdev
),
248 (unsigned long) minor (statp
->st_rdev
));
250 fprintf (stream
, " ");
253 fprintf (stream
, "%8s ",
254 human_readable ((uintmax_t) statp
->st_size
, hbuf
,
257 output_block_size
< 0 ? output_block_size
: 1));
259 if ((when_local
= localtime (&statp
->st_mtime
)))
261 char init_bigbuf
[256];
262 char *buf
= init_bigbuf
;
263 size_t bufsize
= sizeof init_bigbuf
;
265 /* Use strftime rather than ctime, because the former can produce
266 locale-dependent names for the month (%b).
268 Output the year if the file is fairly old or in the future.
269 POSIX says the cutoff is 6 months old;
270 approximate this by 6*30 days.
271 Allow a 1 hour slop factor for what is considered "the future",
272 to allow for NFS server/client clock disagreement. */
274 ((current_time
- 6 * 30 * 24 * 60 * 60 <= statp
->st_mtime
275 && statp
->st_mtime
<= current_time
+ 60 * 60)
279 while (!strftime (buf
, bufsize
, fmt
, when_local
))
280 buf
= (char *) alloca (bufsize
*= 2);
282 fprintf (stream
, "%s ", buf
);
286 /* The time cannot be represented as a local time;
287 print it as a huge integer number of seconds. */
290 if (statp
->st_mtime
< 0)
292 char const *num
= human_readable (- (uintmax_t) statp
->st_mtime
,
293 hbuf
, human_ceiling
, 1, 1);
294 int sign_width
= width
- strlen (num
);
295 fprintf (stream
, "%*s%s ",
296 sign_width
< 0 ? 0 : sign_width
, "-", num
);
299 fprintf (stream
, "%*s ", width
,
300 human_readable ((uintmax_t) statp
->st_mtime
, hbuf
,
305 print_name_with_quoting (name
, stream
);
308 if (S_ISLNK (statp
->st_mode
))
310 char *linkname
= get_link_name (name
, relname
);
314 fputs (" -> ", stream
);
315 print_name_with_quoting (linkname
, stream
);
324 print_name_with_quoting (register char *p
, FILE *stream
)
326 register unsigned char c
;
328 while ((c
= *p
++) != '\0')
333 fprintf (stream
, "\\\\");
337 fprintf (stream
, "\\n");
341 fprintf (stream
, "\\b");
345 fprintf (stream
, "\\r");
349 fprintf (stream
, "\\t");
353 fprintf (stream
, "\\f");
357 fprintf (stream
, "\\ ");
361 fprintf (stream
, "\\\"");
365 if (c
> 040 && c
< 0177)
368 fprintf (stream
, "\\%03o", (unsigned int) c
);
375 get_link_name (char *name
, char *relname
)
377 register char *linkname
;
378 register int linklen
;
380 /* st_size is wrong for symlinks on AIX, and on
381 mount points with some automounters.
382 So allocate a pessimistic PATH_MAX + 1 bytes. */
383 #define LINK_BUF PATH_MAX
384 linkname
= (char *) xmalloc (LINK_BUF
+ 1);
385 linklen
= readlink (relname
, linkname
, LINK_BUF
);
388 error (0, errno
, "%s", name
);
392 linkname
[linklen
] = '\0';