2e18aae3bc7cba26dfa669f0734834f7a67f08b3
[platform/upstream/findutils.git] / lib / listfile.c
1 /* listfile.c -- display a long listing of a file
2    Copyright (C) 1991, 1993, 2000, 2004, 2005, 2007,
3                  2008, 2010 Free Software Foundation, Inc.
4
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation, either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <config.h>
20
21 #include <alloca.h>
22
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <pwd.h>
28 #include <grp.h>
29 #include <time.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <string.h>
33 #include <unistd.h> /* for readlink() */
34 #include <openat.h>
35 #include <locale.h>
36
37 #include "human.h"
38 #include "pathmax.h"
39 #include "error.h"
40 #include "filemode.h"
41 #include "idcache.h"
42 #include "areadlink.h"
43
44 #include "listfile.h"
45
46 /* Since major is a function on SVR4, we can't use `ifndef major'.  */
47 #ifdef MAJOR_IN_MKDEV
48 #include <sys/mkdev.h>
49 #define HAVE_MAJOR
50 #endif
51 #ifdef MAJOR_IN_SYSMACROS
52 #include <sys/sysmacros.h>
53 #define HAVE_MAJOR
54 #endif
55
56
57
58 /* Get or fake the disk device blocksize.
59    Usually defined by sys/param.h (if at all).  */
60 #ifndef DEV_BSIZE
61 # ifdef BSIZE
62 #  define DEV_BSIZE BSIZE
63 # else /* !BSIZE */
64 #  define DEV_BSIZE 4096
65 # endif /* !BSIZE */
66 #endif /* !DEV_BSIZE */
67
68 /* Extract or fake data from a `struct stat'.
69    ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
70    ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
71    ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS.  */
72 #ifndef HAVE_STRUCT_STAT_ST_BLOCKS
73 # define ST_BLKSIZE(statbuf) DEV_BSIZE
74 # if defined _POSIX_SOURCE || !defined BSIZE /* fileblocks.c uses BSIZE.  */
75 #  define ST_NBLOCKS(statbuf) \
76   (S_ISREG ((statbuf).st_mode) \
77    || S_ISDIR ((statbuf).st_mode) \
78    ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0)
79 # else /* !_POSIX_SOURCE && BSIZE */
80 #  define ST_NBLOCKS(statbuf) \
81   (S_ISREG ((statbuf).st_mode) \
82    || S_ISDIR ((statbuf).st_mode) \
83    ? st_blocks ((statbuf).st_size) : 0)
84 # endif /* !_POSIX_SOURCE && BSIZE */
85 #else /* HAVE_STRUCT_STAT_ST_BLOCKS */
86 /* Some systems, like Sequents, return st_blksize of 0 on pipes. */
87 # define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
88                                ? (statbuf).st_blksize : DEV_BSIZE)
89 # if defined hpux || defined __hpux__ || defined __hpux
90 /* HP-UX counts st_blocks in 1024-byte units.
91    This loses when mixing HP-UX and BSD filesystems with NFS.  */
92 #  define ST_NBLOCKSIZE 1024
93 # else /* !hpux */
94 #  if defined _AIX && defined _I386
95 /* AIX PS/2 counts st_blocks in 4K units.  */
96 #   define ST_NBLOCKSIZE (4 * 1024)
97 #  else /* not AIX PS/2 */
98 #   if defined _CRAY
99 #    define ST_NBLOCKS(statbuf) \
100   (S_ISREG ((statbuf).st_mode) \
101    || S_ISDIR ((statbuf).st_mode) \
102    ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
103 #   endif /* _CRAY */
104 #  endif /* not AIX PS/2 */
105 # endif /* !hpux */
106 #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
107
108 #ifndef ST_NBLOCKS
109 # define ST_NBLOCKS(statbuf) \
110   (S_ISREG ((statbuf).st_mode) \
111    || S_ISDIR ((statbuf).st_mode) \
112    ? (statbuf).st_blocks : 0)
113 #endif
114
115 #ifndef ST_NBLOCKSIZE
116 # define ST_NBLOCKSIZE 512
117 #endif
118
119 #ifdef major                    /* Might be defined in sys/types.h.  */
120 #define HAVE_MAJOR
121 #endif
122 #ifndef HAVE_MAJOR
123 #define major(dev)  (((dev) >> 8) & 0xff)
124 #define minor(dev)  ((dev) & 0xff)
125 #endif
126 #undef HAVE_MAJOR
127
128
129 static void print_name (register const char *p, FILE *stream, int literal_control_chars);
130
131
132 size_t
133 file_blocksize (const struct stat *p)
134 {
135   return ST_NBLOCKSIZE;
136 }
137
138
139
140 /* NAME is the name to print.
141    RELNAME is the path to access it from the current directory.
142    STATP is the results of stat or lstat on it.
143    Use CURRENT_TIME to decide whether to print yyyy or hh:mm.
144    Use OUTPUT_BLOCK_SIZE to determine how to print file block counts
145    and sizes.
146    STREAM is the stdio stream to print on.  */
147
148 void
149 list_file (const char *name,
150            int dir_fd,
151            char *relname,
152            const struct stat *statp,
153            time_t current_time,
154            int output_block_size,
155            int literal_control_chars,
156            FILE *stream)
157 {
158   char modebuf[12];
159   struct tm const *when_local;
160   char const *user_name;
161   char const *group_name;
162   char hbuf[LONGEST_HUMAN_READABLE + 1];
163
164 #if HAVE_ST_DM_MODE
165   /* Cray DMF: look at the file's migrated, not real, status */
166   strmode (statp->st_dm_mode, modebuf);
167 #else
168   strmode (statp->st_mode, modebuf);
169 #endif
170
171   fprintf (stream, "%6s ",
172            human_readable ((uintmax_t) statp->st_ino, hbuf,
173                            human_ceiling,
174                            1, 1));
175
176   fprintf (stream, "%4s ",
177            human_readable ((uintmax_t) ST_NBLOCKS (*statp), hbuf,
178                            human_ceiling,
179                            ST_NBLOCKSIZE, output_block_size));
180
181
182   /* modebuf includes the space between the mode and the number of links,
183      as the POSIX "optional alternate access method flag".  */
184   fprintf (stream, "%s%3lu ", modebuf, (unsigned long) statp->st_nlink);
185
186   user_name = getuser (statp->st_uid);
187   if (user_name)
188     fprintf (stream, "%-8s ", user_name);
189   else
190     fprintf (stream, "%-8lu ", (unsigned long) statp->st_uid);
191
192   group_name = getgroup (statp->st_gid);
193   if (group_name)
194     fprintf (stream, "%-8s ", group_name);
195   else
196     fprintf (stream, "%-8lu ", (unsigned long) statp->st_gid);
197
198   if (S_ISCHR (statp->st_mode) || S_ISBLK (statp->st_mode))
199 #ifdef HAVE_ST_RDEV
200     fprintf (stream, "%3lu, %3lu ",
201              (unsigned long) major (statp->st_rdev),
202              (unsigned long) minor (statp->st_rdev));
203 #else
204     fprintf (stream, "         ");
205 #endif
206   else
207     fprintf (stream, "%8s ",
208              human_readable ((uintmax_t) statp->st_size, hbuf,
209                              human_ceiling,
210                              1,
211                              output_block_size < 0 ? output_block_size : 1));
212
213   if ((when_local = localtime (&statp->st_mtime)))
214     {
215       char init_bigbuf[256];
216       char *buf = init_bigbuf;
217       size_t bufsize = sizeof init_bigbuf;
218
219       /* Use strftime rather than ctime, because the former can produce
220          locale-dependent names for the month (%b).
221
222          Output the year if the file is fairly old or in the future.
223          POSIX says the cutoff is 6 months old;
224          approximate this by 6*30 days.
225          Allow a 1 hour slop factor for what is considered "the future",
226          to allow for NFS server/client clock disagreement.  */
227       char const *fmt =
228         ((current_time - 6 * 30 * 24 * 60 * 60 <= statp->st_mtime
229           && statp->st_mtime <= current_time + 60 * 60)
230          ? "%b %e %H:%M"
231          : "%b %e  %Y");
232
233       while (!strftime (buf, bufsize, fmt, when_local))
234         buf = alloca (bufsize *= 2);
235
236       fprintf (stream, "%s ", buf);
237     }
238   else
239     {
240       /* The time cannot be represented as a local time;
241          print it as a huge integer number of seconds.  */
242       int width = 12;
243
244       if (statp->st_mtime < 0)
245         {
246           char const *num = human_readable (- (uintmax_t) statp->st_mtime,
247                                             hbuf, human_ceiling, 1, 1);
248           int sign_width = width - strlen (num);
249           fprintf (stream, "%*s%s ",
250                    sign_width < 0 ? 0 : sign_width, "-", num);
251         }
252       else
253         fprintf (stream, "%*s ", width,
254                  human_readable ((uintmax_t) statp->st_mtime, hbuf,
255                                  human_ceiling,
256                                  1, 1));
257     }
258
259   print_name (name, stream, literal_control_chars);
260
261   if (S_ISLNK (statp->st_mode))
262     {
263       char *linkname = areadlinkat (dir_fd, relname);
264       if (linkname)
265         {
266           fputs (" -> ", stream);
267           print_name (linkname, stream, literal_control_chars);
268         }
269       else
270         {
271           /* POSIX requires in the case of find that if we issue a
272            * diagnostic we should have a nonzero status.  However,
273            * this function doesn't have a way of telling the caller to
274            * do that.  However, since this function is only used when
275            * processing "-ls", we're already using an extension.
276            */
277           error (0, errno, "%s", name);
278         }
279       free (linkname);
280     }
281   putc ('\n', stream);
282 }
283
284
285 static void
286 print_name_without_quoting (const char *p, FILE *stream)
287 {
288   fprintf (stream, "%s", p);
289 }
290
291
292 static void
293 print_name_with_quoting (register const char *p, FILE *stream)
294 {
295   register unsigned char c;
296
297   while ((c = *p++) != '\0')
298     {
299       switch (c)
300         {
301         case '\\':
302           fprintf (stream, "\\\\");
303           break;
304
305         case '\n':
306           fprintf (stream, "\\n");
307           break;
308
309         case '\b':
310           fprintf (stream, "\\b");
311           break;
312
313         case '\r':
314           fprintf (stream, "\\r");
315           break;
316
317         case '\t':
318           fprintf (stream, "\\t");
319           break;
320
321         case '\f':
322           fprintf (stream, "\\f");
323           break;
324
325         case ' ':
326           fprintf (stream, "\\ ");
327           break;
328
329         case '"':
330           fprintf (stream, "\\\"");
331           break;
332
333         default:
334           if (c > 040 && c < 0177)
335             putc (c, stream);
336           else
337             fprintf (stream, "\\%03o", (unsigned int) c);
338         }
339     }
340 }
341
342 static void print_name (register const char *p, FILE *stream, int literal_control_chars)
343 {
344   if (literal_control_chars)
345     print_name_without_quoting (p, stream);
346   else
347     print_name_with_quoting (p, stream);
348 }