* m4/Makefile.am.in: updated file
[findutils.git] / lib / listfile.c
blob2a938eb305f5e5310b0dd17738864ee645c381f4
1 /* listfile.c -- display a long listing of a file
2 Copyright (C) 1991, 1993 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
18 #if HAVE_CONFIG_H
19 # include <config.h>
20 #endif
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <stdio.h>
25 #include <pwd.h>
26 #include <grp.h>
27 #include <time.h>
28 #include <errno.h>
29 #include "pathmax.h"
31 #if HAVE_STRING_H || STDC_HEADERS
32 #include <string.h>
33 #else
34 #include <strings.h>
35 #endif
37 #if STDC_HEADERS
38 # include <stdlib.h>
39 #else
40 char *getenv ();
41 extern int errno;
42 #endif
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
54 #ifdef STAT_MACROS_BROKEN
55 #undef S_ISCHR
56 #undef S_ISBLK
57 #undef S_ISLNK
58 #endif
60 #ifndef S_ISCHR
61 #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
62 #endif
63 #ifndef S_ISBLK
64 #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
65 #endif
66 #if defined(S_IFLNK) && !defined(S_ISLNK)
67 #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
68 #endif
70 #if defined(S_ISLNK)
71 int readlink ();
72 #endif
74 /* Extract or fake data from a `struct stat'.
75 ST_NBLOCKS: Number of 512-byte blocks in the file
76 (including indirect blocks).
77 HP-UX, perhaps uniquely, counts st_blocks in 1024-byte units.
78 This workaround loses when mixing HP-UX and 4BSD filesystems, though. */
79 #ifdef _POSIX_SOURCE
80 # define ST_NBLOCKS(statp) (((statp)->st_size + 512 - 1) / 512)
81 #else
82 # ifndef HAVE_ST_BLOCKS
83 # define ST_NBLOCKS(statp) (st_blocks ((statp)->st_size))
84 # else
85 # if defined(hpux) || defined(__hpux__)
86 # define ST_NBLOCKS(statp) ((statp)->st_blocks * 2)
87 # else
88 # define ST_NBLOCKS(statp) ((statp)->st_blocks)
89 # endif
90 # endif
91 #endif
93 /* Convert NUMBER 512-byte blocks to kilobytes if KILOFLAG is nonzero,
94 otherwise return it unchanged. */
95 #define convert_blocks(Number, Kiloflag) \
96 ((Kiloflag) ? ((Number) + 1) / 2 : (Number))
98 #ifndef _POSIX_VERSION
99 struct passwd *getpwuid ();
100 struct group *getgrgid ();
101 #endif
103 #ifdef major /* Might be defined in sys/types.h. */
104 #define HAVE_MAJOR
105 #endif
106 #ifndef HAVE_MAJOR
107 #define major(dev) (((dev) >> 8) & 0xff)
108 #define minor(dev) ((dev) & 0xff)
109 #endif
110 #undef HAVE_MAJOR
112 char *xmalloc ();
113 void error ();
114 void mode_string ();
116 char *get_link_name ();
117 char *getgroup ();
118 char *getuser ();
119 void print_name_with_quoting ();
121 /* NAME is the name to print.
122 RELNAME is the path to access it from the current directory.
123 STATP is the results of stat or lstat on it.
124 STREAM is the stdio stream to print on. */
126 void
127 list_file (name, relname, statp, stream)
128 char *name;
129 char *relname;
130 struct stat *statp;
131 FILE *stream;
133 static int kilobytes = -1; /* -1 = uninitialized, 0 = 512, 1 = 1024. */
134 char modebuf[20];
135 char timebuf[40];
136 time_t current_time = time ((time_t *) 0);
138 if (kilobytes == -1)
139 kilobytes = getenv ("POSIXLY_CORRECT") == 0;
141 mode_string (statp->st_mode, modebuf);
142 modebuf[10] = '\0';
144 strcpy (timebuf, ctime (&statp->st_mtime));
145 if (current_time > statp->st_mtime + 6L * 30L * 24L * 60L * 60L /* Old. */
146 || current_time < statp->st_mtime - 60L * 60L) /* In the future. */
148 /* The file is fairly old or in the future.
149 POSIX says the cutoff is 6 months old;
150 approximate this by 6*30 days.
151 Allow a 1 hour slop factor for what is considered "the future",
152 to allow for NFS server/client clock disagreement.
153 Show the year instead of the time of day. */
154 strcpy (timebuf + 11, timebuf + 19);
156 timebuf[16] = 0;
158 fprintf (stream, "%6lu ", statp->st_ino);
160 fprintf (stream, "%4lu ",
161 (long) convert_blocks (ST_NBLOCKS (statp), kilobytes));
163 /* The space between the mode and the number of links is the POSIX
164 "optional alternate access method flag". */
165 fprintf (stream, "%s %3u ", modebuf, statp->st_nlink);
167 fprintf (stream, "%-8.8s ", getuser (statp->st_uid));
169 fprintf (stream, "%-8.8s ", getgroup (statp->st_gid));
171 if (S_ISCHR (statp->st_mode) || S_ISBLK (statp->st_mode))
172 #ifdef HAVE_ST_RDEV
173 fprintf (stream, "%3u, %3u ", major (statp->st_rdev), minor (statp->st_rdev));
174 #else
175 fprintf (stream, " ");
176 #endif
177 else
178 fprintf (stream, "%8lu ", statp->st_size);
180 fprintf (stream, "%s ", timebuf + 4);
182 print_name_with_quoting (name, stream);
184 #ifdef S_ISLNK
185 if (S_ISLNK (statp->st_mode))
187 char *linkname = get_link_name (name, relname);
189 if (linkname)
191 fputs (" -> ", stream);
192 print_name_with_quoting (linkname, stream);
193 free (linkname);
196 #endif
197 putc ('\n', stream);
200 void
201 print_name_with_quoting (p, stream)
202 register char *p;
203 FILE *stream;
205 register unsigned char c;
207 while ((c = *p++) != '\0')
209 switch (c)
211 case '\\':
212 fprintf (stream, "\\\\");
213 break;
215 case '\n':
216 fprintf (stream, "\\n");
217 break;
219 case '\b':
220 fprintf (stream, "\\b");
221 break;
223 case '\r':
224 fprintf (stream, "\\r");
225 break;
227 case '\t':
228 fprintf (stream, "\\t");
229 break;
231 case '\f':
232 fprintf (stream, "\\f");
233 break;
235 case ' ':
236 fprintf (stream, "\\ ");
237 break;
239 case '"':
240 fprintf (stream, "\\\"");
241 break;
243 default:
244 if (c > 040 && c < 0177)
245 putc (c, stream);
246 else
247 fprintf (stream, "\\%03o", (unsigned int) c);
252 #ifdef S_ISLNK
253 char *
254 get_link_name (name, relname)
255 char *name;
256 char *relname;
258 register char *linkname;
259 register int linklen;
261 /* st_size is wrong for symlinks on AIX, and on
262 mount points with some automounters.
263 So allocate a pessimistic PATH_MAX + 1 bytes. */
264 #define LINK_BUF PATH_MAX
265 linkname = (char *) xmalloc (LINK_BUF + 1);
266 linklen = readlink (relname, linkname, LINK_BUF);
267 if (linklen < 0)
269 error (0, errno, "%s", name);
270 free (linkname);
271 return 0;
273 linkname[linklen] = '\0';
274 return linkname;
276 #endif