*** empty log message ***
[findutils.git] / lib / listfile.c
blob7e32079f24f0c8f3f3b0c8e0622b0433d38335f0
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 #ifdef 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 defined(HAVE_STRING_H) || defined(STDC_HEADERS)
32 #include <string.h>
33 #else
34 #include <strings.h>
35 #endif
36 #ifdef STDC_HEADERS
37 #include <stdlib.h>
38 #else
39 char *getenv ();
40 extern int errno;
41 #endif
43 /* Since major is a function on SVR4, we can't use `ifndef major'. */
44 #ifdef MAJOR_IN_MKDEV
45 #include <sys/mkdev.h>
46 #define HAVE_MAJOR
47 #endif
48 #ifdef MAJOR_IN_SYSMACROS
49 #include <sys/sysmacros.h>
50 #define HAVE_MAJOR
51 #endif
53 #ifdef STAT_MACROS_BROKEN
54 #undef S_ISCHR
55 #undef S_ISBLK
56 #undef S_ISLNK
57 #endif
59 #ifndef S_ISCHR
60 #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
61 #endif
62 #ifndef S_ISBLK
63 #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
64 #endif
65 #if defined(S_IFLNK) && !defined(S_ISLNK)
66 #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
67 #endif
69 #if defined(S_ISLNK)
70 int readlink ();
71 #endif
73 /* Extract or fake data from a `struct stat'.
74 ST_NBLOCKS: Number of 512-byte blocks in the file
75 (including indirect blocks).
76 HP-UX, perhaps uniquely, counts st_blocks in 1024-byte units.
77 This workaround loses when mixing HP-UX and 4BSD filesystems, though. */
78 #ifdef _POSIX_SOURCE
79 # define ST_NBLOCKS(statp) (((statp)->st_size + 512 - 1) / 512)
80 #else
81 # ifndef HAVE_ST_BLOCKS
82 # define ST_NBLOCKS(statp) (st_blocks ((statp)->st_size))
83 # else
84 # if defined(hpux) || defined(__hpux__)
85 # define ST_NBLOCKS(statp) ((statp)->st_blocks * 2)
86 # else
87 # define ST_NBLOCKS(statp) ((statp)->st_blocks)
88 # endif
89 # endif
90 #endif
92 /* Convert B 512-byte blocks to kilobytes if K is nonzero,
93 otherwise return it unchanged. */
94 #define convert_blocks(b, k) ((k) ? ((b) + 1) / 2 : (b))
96 #ifndef _POSIX_VERSION
97 struct passwd *getpwuid ();
98 struct group *getgrgid ();
99 #endif
101 #ifdef major /* Might be defined in sys/types.h. */
102 #define HAVE_MAJOR
103 #endif
104 #ifndef HAVE_MAJOR
105 #define major(dev) (((dev) >> 8) & 0xff)
106 #define minor(dev) ((dev) & 0xff)
107 #endif
108 #undef HAVE_MAJOR
110 char *xmalloc ();
111 void error ();
112 void mode_string ();
114 char *get_link_name ();
115 char *getgroup ();
116 char *getuser ();
117 void print_name_with_quoting ();
119 /* NAME is the name to print.
120 RELNAME is the path to access it from the current directory.
121 STATP is the results of stat or lstat on it.
122 STREAM is the stdio stream to print on. */
124 void
125 list_file (name, relname, statp, stream)
126 char *name;
127 char *relname;
128 struct stat *statp;
129 FILE *stream;
131 static int kilobytes = -1; /* -1 = uninitialized, 0 = 512, 1 = 1024. */
132 char modebuf[20];
133 char timebuf[40];
134 time_t current_time = time ((time_t *) 0);
136 if (kilobytes == -1)
137 kilobytes = getenv ("POSIXLY_CORRECT") == 0;
139 mode_string (statp->st_mode, modebuf);
140 modebuf[10] = '\0';
142 strcpy (timebuf, ctime (&statp->st_mtime));
143 if (current_time > statp->st_mtime + 6L * 30L * 24L * 60L * 60L /* Old. */
144 || current_time < statp->st_mtime - 60L * 60L) /* In the future. */
146 /* The file is fairly old or in the future.
147 POSIX says the cutoff is 6 months old;
148 approximate this by 6*30 days.
149 Allow a 1 hour slop factor for what is considered "the future",
150 to allow for NFS server/client clock disagreement.
151 Show the year instead of the time of day. */
152 strcpy (timebuf + 11, timebuf + 19);
154 timebuf[16] = 0;
156 fprintf (stream, "%6lu ", statp->st_ino);
158 fprintf (stream, "%4u ", convert_blocks (ST_NBLOCKS (statp), kilobytes));
160 /* The space between the mode and the number of links is the POSIX
161 "optional alternate access method flag". */
162 fprintf (stream, "%s %3u ", modebuf, statp->st_nlink);
164 fprintf (stream, "%-8.8s ", getuser (statp->st_uid));
166 fprintf (stream, "%-8.8s ", getgroup (statp->st_gid));
168 if (S_ISCHR (statp->st_mode) || S_ISBLK (statp->st_mode))
169 #ifdef HAVE_ST_RDEV
170 fprintf (stream, "%3u, %3u ", major (statp->st_rdev), minor (statp->st_rdev));
171 #else
172 fprintf (stream, " ");
173 #endif
174 else
175 fprintf (stream, "%8lu ", statp->st_size);
177 fprintf (stream, "%s ", timebuf + 4);
179 print_name_with_quoting (name, stream);
181 #ifdef S_ISLNK
182 if (S_ISLNK (statp->st_mode))
184 char *linkname = get_link_name (name, relname);
186 if (linkname)
188 fputs (" -> ", stream);
189 print_name_with_quoting (linkname, stream);
190 free (linkname);
193 #endif
194 putc ('\n', stream);
197 void
198 print_name_with_quoting (p, stream)
199 register char *p;
200 FILE *stream;
202 register unsigned char c;
204 while ((c = *p++) != '\0')
206 switch (c)
208 case '\\':
209 fprintf (stream, "\\\\");
210 break;
212 case '\n':
213 fprintf (stream, "\\n");
214 break;
216 case '\b':
217 fprintf (stream, "\\b");
218 break;
220 case '\r':
221 fprintf (stream, "\\r");
222 break;
224 case '\t':
225 fprintf (stream, "\\t");
226 break;
228 case '\f':
229 fprintf (stream, "\\f");
230 break;
232 case ' ':
233 fprintf (stream, "\\ ");
234 break;
236 case '"':
237 fprintf (stream, "\\\"");
238 break;
240 default:
241 if (c > 040 && c < 0177)
242 putc (c, stream);
243 else
244 fprintf (stream, "\\%03o", (unsigned int) c);
249 #ifdef S_ISLNK
250 char *
251 get_link_name (name, relname)
252 char *name;
253 char *relname;
255 register char *linkname;
256 register int linklen;
258 /* st_size is wrong for symlinks on AIX, and on
259 mount points with some automounters.
260 So allocate a pessimistic PATH_MAX + 1 bytes. */
261 #define LINK_BUF PATH_MAX
262 linkname = (char *) xmalloc (LINK_BUF + 1);
263 linklen = readlink (relname, linkname, LINK_BUF);
264 if (linklen < 0)
266 error (0, errno, "%s", name);
267 free (linkname);
268 return 0;
270 linkname[linklen] = '\0';
271 return linkname;
273 #endif