Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/coreutils/stat.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 815 by niro, Sat Sep 1 22:45:15 2007 UTC revision 816 by niro, Fri Apr 24 18:33:46 2009 UTC
# Line 5  Line 5 
5   * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation.   * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation.
6   * Copyright (C) 2005 by Erik Andersen <andersen@codepoet.org>   * Copyright (C) 2005 by Erik Andersen <andersen@codepoet.org>
7   * Copyright (C) 2005 by Mike Frysinger <vapier@gentoo.org>   * Copyright (C) 2005 by Mike Frysinger <vapier@gentoo.org>
8     * Copyright (C) 2006 by Yoshinori Sato <ysato@users.sourceforge.jp>
9   *   *
10   * Written by Michael Meskes   * Written by Michael Meskes
11   * Taken from coreutils and turned into a busybox applet by Mike Frysinger   * Taken from coreutils and turned into a busybox applet by Mike Frysinger
# Line 12  Line 13 
13   * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.   * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
14   */   */
15    
16  #include "busybox.h"  #include "libbb.h"
17    
18  /* vars to control behavior */  /* vars to control behavior */
19  #define OPT_TERSE 2  #define OPT_FILESYS     (1 << 0)
20  #define OPT_DEREFERENCE 4  #define OPT_TERSE       (1 << 1)
21  static long flags;  #define OPT_DEREFERENCE (1 << 2)
22    #define OPT_SELINUX     (1 << 3)
23    
24  static char const *file_type(struct stat const *st)  #if ENABLE_FEATURE_STAT_FORMAT
25    typedef bool (*statfunc_ptr)(const char *, const char *);
26    #else
27    typedef bool (*statfunc_ptr)(const char *);
28    #endif
29    
30    static const char *file_type(const struct stat *st)
31  {  {
32   /* See POSIX 1003.1-2001 XCU Table 4-8 lines 17093-17107   /* See POSIX 1003.1-2001 XCU Table 4-8 lines 17093-17107
33   * for some of these formats.   * for some of these formats.
# Line 42  static char const *file_type(struct stat Line 50  static char const *file_type(struct stat
50   return "weird file";   return "weird file";
51  }  }
52    
53  static char const *human_time(time_t t)  static const char *human_time(time_t t)
54  {  {
55   /* Old   /* Old
56   static char *str;   static char *str;
# Line 51  static char const *human_time(time_t t) Line 59  static char const *human_time(time_t t)
59   return str;   return str;
60   */   */
61   /* coreutils 6.3 compat: */   /* coreutils 6.3 compat: */
62   static char buf[sizeof("YYYY-MM-DD HH:MM:SS.000000000")];  
63     /*static char buf[sizeof("YYYY-MM-DD HH:MM:SS.000000000")] ALIGN1;*/
64    #define buf bb_common_bufsiz1
65    
66   strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S.000000000", localtime(&t));   strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S.000000000", localtime(&t));
67   return buf;   return buf;
68    #undef buf
69  }  }
70    
71  /* Return the type of the specified file system.  /* Return the type of the specified file system.
# Line 61  static char const *human_time(time_t t) Line 73  static char const *human_time(time_t t)
73   * Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2)   * Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2)
74   * Still others have neither and have to get by with f_type (Linux).   * Still others have neither and have to get by with f_type (Linux).
75   */   */
76  static char const *human_fstype(long f_type)  static const char *human_fstype(uint32_t f_type)
77  {  {
  int i;  
78   static const struct types {   static const struct types {
79   long type;   uint32_t type;
80   const char *fs;   const char *const fs;
81   } humantypes[] = {   } humantypes[] = {
82   { 0xADFF,     "affs" },   { 0xADFF,     "affs" },
83   { 0x1Cd1,     "devpts" },   { 0x1Cd1,     "devpts" },
# Line 105  static char const *human_fstype(long f_t Line 116  static char const *human_fstype(long f_t
116   { 0x62656572, "sysfs" },   { 0x62656572, "sysfs" },
117   { 0, "UNKNOWN" }   { 0, "UNKNOWN" }
118   };   };
119   for (i=0; humantypes[i].type; ++i)  
120     int i;
121    
122     for (i = 0; humantypes[i].type; ++i)
123   if (humantypes[i].type == f_type)   if (humantypes[i].type == f_type)
124   break;   break;
125   return humantypes[i].fs;   return humantypes[i].fs;
126  }  }
127    
128  #ifdef CONFIG_FEATURE_STAT_FORMAT  #if ENABLE_FEATURE_STAT_FORMAT
129  /* print statfs info */  static void strcatc(char *str, char c)
 static void print_statfs(char *pformat, size_t buf_len, char m,  
  char const *filename, void const *data)  
130  {  {
131   struct statfs const *statfsbuf = data;   int len = strlen(str);
132     str[len++] = c;
133     str[len] = '\0';
134    }
135    
136   switch (m) {  static void printfs(char *pformat, const char *msg)
137   case 'n':  {
138   strncat(pformat, "s", buf_len);   strcatc(pformat, 's');
139   printf(pformat, filename);   printf(pformat, msg);
140   break;  }
141   case 'i':  
142   strncat(pformat, "Lx", buf_len);  /* print statfs info */
143    static void print_statfs(char *pformat, const char m,
144     const char *const filename, const void *data
145     USE_SELINUX(, security_context_t scontext))
146    {
147     const struct statfs *statfsbuf = data;
148     if (m == 'n') {
149     printfs(pformat, filename);
150     } else if (m == 'i') {
151     strcat(pformat, "Lx");
152   printf(pformat, statfsbuf->f_fsid);   printf(pformat, statfsbuf->f_fsid);
153   break;   } else if (m == 'l') {
154   case 'l':   strcat(pformat, "lu");
  strncat(pformat, "lu", buf_len);  
155   printf(pformat, statfsbuf->f_namelen);   printf(pformat, statfsbuf->f_namelen);
156   break;   } else if (m == 't') {
157   case 't':   strcat(pformat, "lx");
158   strncat(pformat, "lx", buf_len);   printf(pformat, (unsigned long) (statfsbuf->f_type)); /* no equiv */
159   printf(pformat, (unsigned long int) (statfsbuf->f_type));  /* no equiv. */   } else if (m == 'T') {
160   break;   printfs(pformat, human_fstype(statfsbuf->f_type));
161   case 'T':   } else if (m == 'b') {
162   strncat(pformat, "s", buf_len);   strcat(pformat, "jd");
  printf(pformat, human_fstype(statfsbuf->f_type));  
  break;  
  case 'b':  
  strncat(pformat, "jd", buf_len);  
163   printf(pformat, (intmax_t) (statfsbuf->f_blocks));   printf(pformat, (intmax_t) (statfsbuf->f_blocks));
164   break;   } else if (m == 'f') {
165   case 'f':   strcat(pformat, "jd");
  strncat(pformat, "jd", buf_len);  
166   printf(pformat, (intmax_t) (statfsbuf->f_bfree));   printf(pformat, (intmax_t) (statfsbuf->f_bfree));
167   break;   } else if (m == 'a') {
168   case 'a':   strcat(pformat, "jd");
  strncat(pformat, "jd", buf_len);  
169   printf(pformat, (intmax_t) (statfsbuf->f_bavail));   printf(pformat, (intmax_t) (statfsbuf->f_bavail));
170   break;   } else if (m == 's' || m == 'S') {
171   case 'S':   strcat(pformat, "lu");
172   case 's':   printf(pformat, (unsigned long) (statfsbuf->f_bsize));
173   strncat(pformat, "lu", buf_len);   } else if (m == 'c') {
174   printf(pformat, (unsigned long int) (statfsbuf->f_bsize));   strcat(pformat, "jd");
  break;  
  case 'c':  
  strncat(pformat, "jd", buf_len);  
175   printf(pformat, (intmax_t) (statfsbuf->f_files));   printf(pformat, (intmax_t) (statfsbuf->f_files));
176   break;   } else if (m == 'd') {
177   case 'd':   strcat(pformat, "jd");
  strncat(pformat, "jd", buf_len);  
178   printf(pformat, (intmax_t) (statfsbuf->f_ffree));   printf(pformat, (intmax_t) (statfsbuf->f_ffree));
179   break;  #if ENABLE_SELINUX
180   default:   } else if (m == 'C' && (option_mask32 & OPT_SELINUX)) {
181   strncat(pformat, "c", buf_len);   printfs(pformat, scontext);
182    #endif
183     } else {
184     strcatc(pformat, 'c');
185   printf(pformat, m);   printf(pformat, m);
  break;  
186   }   }
187  }  }
188    
189  /* print stat info */  /* print stat info */
190  static void print_stat(char *pformat, size_t buf_len, char m,  static void print_stat(char *pformat, const char m,
191         char const *filename, void const *data)   const char *const filename, const void *data
192     USE_SELINUX(, security_context_t scontext))
193  {  {
194  #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))  #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
195   struct stat *statbuf = (struct stat *) data;   struct stat *statbuf = (struct stat *) data;
196   struct passwd *pw_ent;   struct passwd *pw_ent;
197   struct group *gw_ent;   struct group *gw_ent;
198    
199   switch (m) {   if (m == 'n') {
200   case 'n':   printfs(pformat, filename);
201   strncat(pformat, "s", buf_len);   } else if (m == 'N') {
202   printf(pformat, filename);   strcatc(pformat, 's');
  break;  
  case 'N':  
  strncat(pformat, "s", buf_len);  
203   if (S_ISLNK(statbuf->st_mode)) {   if (S_ISLNK(statbuf->st_mode)) {
204   char *linkname = xreadlink(filename);   char *linkname = xmalloc_readlink_or_warn(filename);
205   if (linkname == NULL) {   if (linkname == NULL)
  bb_perror_msg("cannot read symbolic link '%s'", filename);  
206   return;   return;
  }  
207   /*printf("\"%s\" -> \"%s\"", filename, linkname); */   /*printf("\"%s\" -> \"%s\"", filename, linkname); */
208   printf(pformat, filename);   printf(pformat, filename);
209   printf(" -> ");   printf(" -> ");
210   printf(pformat, linkname);   printf(pformat, linkname);
211     free(linkname);
212   } else {   } else {
213   printf(pformat, filename);   printf(pformat, filename);
214   }   }
215   break;   } else if (m == 'd') {
216   case 'd':   strcat(pformat, "ju");
  strncat(pformat, "ju", buf_len);  
217   printf(pformat, (uintmax_t) statbuf->st_dev);   printf(pformat, (uintmax_t) statbuf->st_dev);
218   break;   } else if (m == 'D') {
219   case 'D':   strcat(pformat, "jx");
  strncat(pformat, "jx", buf_len);  
220   printf(pformat, (uintmax_t) statbuf->st_dev);   printf(pformat, (uintmax_t) statbuf->st_dev);
221   break;   } else if (m == 'i') {
222   case 'i':   strcat(pformat, "ju");
  strncat(pformat, "ju", buf_len);  
223   printf(pformat, (uintmax_t) statbuf->st_ino);   printf(pformat, (uintmax_t) statbuf->st_ino);
224   break;   } else if (m == 'a') {
225   case 'a':   strcat(pformat, "lo");
226   strncat(pformat, "lo", buf_len);   printf(pformat, (unsigned long) (statbuf->st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)));
227   printf(pformat, (unsigned long int) (statbuf->st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)));   } else if (m == 'A') {
228   break;   printfs(pformat, bb_mode_string(statbuf->st_mode));
229   case 'A':   } else if (m == 'f') {
230   strncat(pformat, "s", buf_len);   strcat(pformat, "lx");
231   printf(pformat, bb_mode_string(statbuf->st_mode));   printf(pformat, (unsigned long) statbuf->st_mode);
232   break;   } else if (m == 'F') {
233   case 'f':   printfs(pformat, file_type(statbuf));
234   strncat(pformat, "lx", buf_len);   } else if (m == 'h') {
235   printf(pformat, (unsigned long int) statbuf->st_mode);   strcat(pformat, "lu");
236   break;   printf(pformat, (unsigned long) statbuf->st_nlink);
237   case 'F':   } else if (m == 'u') {
238   strncat(pformat, "s", buf_len);   strcat(pformat, "lu");
239   printf(pformat, file_type(statbuf));   printf(pformat, (unsigned long) statbuf->st_uid);
240   break;   } else if (m == 'U') {
  case 'h':  
  strncat(pformat, "lu", buf_len);  
  printf(pformat, (unsigned long int) statbuf->st_nlink);  
  break;  
  case 'u':  
  strncat(pformat, "lu", buf_len);  
  printf(pformat, (unsigned long int) statbuf->st_uid);  
  break;  
  case 'U':  
  strncat(pformat, "s", buf_len);  
241   setpwent();   setpwent();
242   pw_ent = getpwuid(statbuf->st_uid);   pw_ent = getpwuid(statbuf->st_uid);
243   printf(pformat, (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN");   printfs(pformat, (pw_ent != NULL) ? pw_ent->pw_name : "UNKNOWN");
244   break;   } else if (m == 'g') {
245   case 'g':   strcat(pformat, "lu");
246   strncat(pformat, "lu", buf_len);   printf(pformat, (unsigned long) statbuf->st_gid);
247   printf(pformat, (unsigned long int) statbuf->st_gid);   } else if (m == 'G') {
  break;  
  case 'G':  
  strncat(pformat, "s", buf_len);  
248   setgrent();   setgrent();
249   gw_ent = getgrgid(statbuf->st_gid);   gw_ent = getgrgid(statbuf->st_gid);
250   printf(pformat, (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN");   printfs(pformat, (gw_ent != NULL) ? gw_ent->gr_name : "UNKNOWN");
251   break;   } else if (m == 't') {
252   case 't':   strcat(pformat, "lx");
253   strncat(pformat, "lx", buf_len);   printf(pformat, (unsigned long) major(statbuf->st_rdev));
254   printf(pformat, (unsigned long int) major(statbuf->st_rdev));   } else if (m == 'T') {
255   break;   strcat(pformat, "lx");
256   case 'T':   printf(pformat, (unsigned long) minor(statbuf->st_rdev));
257   strncat(pformat, "lx", buf_len);   } else if (m == 's') {
258   printf(pformat, (unsigned long int) minor(statbuf->st_rdev));   strcat(pformat, "ju");
  break;  
  case 's':  
  strncat(pformat, "ju", buf_len);  
259   printf(pformat, (uintmax_t) (statbuf->st_size));   printf(pformat, (uintmax_t) (statbuf->st_size));
260   break;   } else if (m == 'B') {
261   case 'B':   strcat(pformat, "lu");
262   strncat(pformat, "lu", buf_len);   printf(pformat, (unsigned long) 512); //ST_NBLOCKSIZE
263   printf(pformat, (unsigned long int) 512); //ST_NBLOCKSIZE   } else if (m == 'b') {
264   break;   strcat(pformat, "ju");
  case 'b':  
  strncat(pformat, "ju", buf_len);  
265   printf(pformat, (uintmax_t) statbuf->st_blocks);   printf(pformat, (uintmax_t) statbuf->st_blocks);
266   break;   } else if (m == 'o') {
267   case 'o':   strcat(pformat, "lu");
268   strncat(pformat, "lu", buf_len);   printf(pformat, (unsigned long) statbuf->st_blksize);
269   printf(pformat, (unsigned long int) statbuf->st_blksize);   } else if (m == 'x') {
270   break;   printfs(pformat, human_time(statbuf->st_atime));
271   case 'x':   } else if (m == 'X') {
272   strncat(pformat, "s", buf_len);   strcat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu");
273   printf(pformat, human_time(statbuf->st_atime));   printf(pformat, (unsigned long) statbuf->st_atime);
274   break;   } else if (m == 'y') {
275   case 'X':   printfs(pformat, human_time(statbuf->st_mtime));
276   strncat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu", buf_len);   } else if (m == 'Y') {
277   printf(pformat, (unsigned long int) statbuf->st_atime);   strcat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu");
278   break;   printf(pformat, (unsigned long) statbuf->st_mtime);
279   case 'y':   } else if (m == 'z') {
280   strncat(pformat, "s", buf_len);   printfs(pformat, human_time(statbuf->st_ctime));
281   printf(pformat, human_time(statbuf->st_mtime));   } else if (m == 'Z') {
282   break;   strcat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu");
283   case 'Y':   printf(pformat, (unsigned long) statbuf->st_ctime);
284   strncat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu", buf_len);  #if ENABLE_SELINUX
285   printf(pformat, (unsigned long int) statbuf->st_mtime);   } else if (m == 'C' && (option_mask32 & OPT_SELINUX)) {
286   break;   printfs(pformat, scontext);
287   case 'z':  #endif
288   strncat(pformat, "s", buf_len);   } else {
289   printf(pformat, human_time(statbuf->st_ctime));   strcatc(pformat, 'c');
  break;  
  case 'Z':  
  strncat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu", buf_len);  
  printf(pformat, (unsigned long int) statbuf->st_ctime);  
  break;  
  default:  
  strncat(pformat, "c", buf_len);  
290   printf(pformat, m);   printf(pformat, m);
  break;  
291   }   }
292  }  }
293    
294  static void print_it(char const *masterformat, char const *filename,  static void print_it(const char *masterformat, const char *filename,
295       void (*print_func) (char *, size_t, char, char const *, void const *),   void (*print_func) (char*, char, const char*, const void* USE_SELINUX(, security_context_t scontext)),
296       void const *data)   const void *data
297     USE_SELINUX(, security_context_t scontext) )
298  {  {
299   char *b;   /* Create a working copy of the format string */
   
  /* create a working copy of the format string */  
300   char *format = xstrdup(masterformat);   char *format = xstrdup(masterformat);
   
301   /* Add 2 to accomodate our conversion of the stat '%s' format string   /* Add 2 to accomodate our conversion of the stat '%s' format string
302   * to the printf '%llu' one.  */   * to the printf '%llu' one.  */
303   size_t n_alloc = strlen(format) + 2 + 1;   char *dest = xmalloc(strlen(format) + 2 + 1);
304   char *dest = xmalloc(n_alloc);   char *b;
305    
306   b = format;   b = format;
307   while (b) {   while (b) {
308   size_t len;   size_t len;
309   char *p = strchr(b, '%');   char *p = strchr(b, '%');
310   if (!p) {   if (!p) {
311   /* coreutils 6.3 always print <cr> at the end */   /* coreutils 6.3 always prints <cr> at the end */
312   /*fputs(b, stdout);*/   /*fputs(b, stdout);*/
313   puts(b);   puts(b);
314   break;   break;
# Line 335  static void print_it(char const *masterf Line 316  static void print_it(char const *masterf
316   *p++ = '\0';   *p++ = '\0';
317   fputs(b, stdout);   fputs(b, stdout);
318    
319     /* dest = "%<modifiers>" */
320   len = strspn(p, "#-+.I 0123456789");   len = strspn(p, "#-+.I 0123456789");
321   dest[0] = '%';   dest[0] = '%';
322   memcpy(dest + 1, p, len);   memcpy(dest + 1, p, len);
323   dest[1 + len] = 0;   dest[1 + len] = '\0';
324   p += len;   p += len;
325    
326   b = p + 1;   b = p + 1;
# Line 347  static void print_it(char const *masterf Line 329  static void print_it(char const *masterf
329   b = NULL;   b = NULL;
330   /* fall through */   /* fall through */
331   case '%':   case '%':
332   putchar('%');   bb_putchar('%');
333   break;   break;
334   default:   default:
335   print_func(dest, n_alloc, *p, filename, data);   /* Completes "%<modifiers>" with specifier and printfs */
336     print_func(dest, *p, filename, data USE_SELINUX(,scontext));
337   break;   break;
338   }   }
339   }   }
# Line 361  static void print_it(char const *masterf Line 344  static void print_it(char const *masterf
344  #endif  #endif
345    
346  /* Stat the file system and print what we find.  */  /* Stat the file system and print what we find.  */
347  static int do_statfs(char const *filename, char const *format)  #if !ENABLE_FEATURE_STAT_FORMAT
348    #define do_statfs(filename, format) do_statfs(filename)
349    #endif
350    static bool do_statfs(const char *filename, const char *format)
351  {  {
352    #if !ENABLE_FEATURE_STAT_FORMAT
353     const char *format;
354    #endif
355   struct statfs statfsbuf;   struct statfs statfsbuf;
356    #if ENABLE_SELINUX
357     security_context_t scontext = NULL;
358    
359     if (option_mask32 & OPT_SELINUX) {
360     if ((option_mask32 & OPT_DEREFERENCE
361         ? lgetfilecon(filename, &scontext)
362         : getfilecon(filename, &scontext)
363        ) < 0
364     ) {
365     bb_perror_msg(filename);
366     return 0;
367     }
368     }
369    #endif
370   if (statfs(filename, &statfsbuf) != 0) {   if (statfs(filename, &statfsbuf) != 0) {
371   bb_perror_msg("cannot read file system information for '%s'", filename);   bb_perror_msg("cannot read file system information for '%s'", filename);
372   return 0;   return 0;
373   }   }
374    
375  #ifdef CONFIG_FEATURE_STAT_FORMAT  #if ENABLE_FEATURE_STAT_FORMAT
376   if (format == NULL)   if (format == NULL) {
377   format = (flags & OPT_TERSE  #if !ENABLE_SELINUX
378     format = (option_mask32 & OPT_TERSE
379   ? "%n %i %l %t %s %b %f %a %c %d\n"   ? "%n %i %l %t %s %b %f %a %c %d\n"
380   : "  File: \"%n\"\n"   : "  File: \"%n\"\n"
381    "    ID: %-8i Namelen: %-7l Type: %T\n"    "    ID: %-8i Namelen: %-7l Type: %T\n"
382    "Block size: %-10s\n"    "Block size: %-10s\n"
383    "Blocks: Total: %-10b Free: %-10f Available: %a\n"    "Blocks: Total: %-10b Free: %-10f Available: %a\n"
384    "Inodes: Total: %-10c Free: %d");    "Inodes: Total: %-10c Free: %d");
  print_it(format, filename, print_statfs, &statfsbuf);  
385  #else  #else
386     format = (option_mask32 & OPT_TERSE
387   format = (flags & OPT_TERSE   ? (option_mask32 & OPT_SELINUX ? "%n %i %l %t %s %b %f %a %c %d %C\n":
388     "%n %i %l %t %s %b %f %a %c %d\n")
389     : (option_mask32 & OPT_SELINUX ?
390     "  File: \"%n\"\n"
391     "    ID: %-8i Namelen: %-7l Type: %T\n"
392     "Block size: %-10s\n"
393     "Blocks: Total: %-10b Free: %-10f Available: %a\n"
394     "Inodes: Total: %-10c Free: %d"
395     "  S_context: %C\n":
396     "  File: \"%n\"\n"
397     "    ID: %-8i Namelen: %-7l Type: %T\n"
398     "Block size: %-10s\n"
399     "Blocks: Total: %-10b Free: %-10f Available: %a\n"
400     "Inodes: Total: %-10c Free: %d\n")
401     );
402    #endif /* SELINUX */
403     }
404     print_it(format, filename, print_statfs, &statfsbuf USE_SELINUX(, scontext));
405    #else /* FEATURE_STAT_FORMAT */
406     format = (option_mask32 & OPT_TERSE
407   ? "%s %llx %lu "   ? "%s %llx %lu "
408   : "  File: \"%s\"\n"   : "  File: \"%s\"\n"
409    "    ID: %-8Lx Namelen: %-7lu ");    "    ID: %-8Lx Namelen: %-7lu ");
# Line 391  static int do_statfs(char const *filenam Line 412  static int do_statfs(char const *filenam
412         statfsbuf.f_fsid,         statfsbuf.f_fsid,
413         statfsbuf.f_namelen);         statfsbuf.f_namelen);
414    
415   if (flags & OPT_TERSE)   if (option_mask32 & OPT_TERSE)
416   printf("%lx ", (unsigned long int) (statfsbuf.f_type));   printf("%lx ", (unsigned long) (statfsbuf.f_type));
417   else   else
418   printf("Type: %s\n", human_fstype(statfsbuf.f_type));   printf("Type: %s\n", human_fstype(statfsbuf.f_type));
419    
420   format = (flags & OPT_TERSE  #if !ENABLE_SELINUX
421     format = (option_mask32 & OPT_TERSE
422   ? "%lu %ld %ld %ld %ld %ld\n"   ? "%lu %ld %ld %ld %ld %ld\n"
423   : "Block size: %-10lu\n"   : "Block size: %-10lu\n"
424    "Blocks: Total: %-10jd Free: %-10jd Available: %jd\n"    "Blocks: Total: %-10jd Free: %-10jd Available: %jd\n"
425    "Inodes: Total: %-10jd Free: %jd\n");    "Inodes: Total: %-10jd Free: %jd\n");
426   printf(format,   printf(format,
427         (unsigned long int) (statfsbuf.f_bsize),         (unsigned long) (statfsbuf.f_bsize),
428         (intmax_t) (statfsbuf.f_blocks),         (intmax_t) (statfsbuf.f_blocks),
429         (intmax_t) (statfsbuf.f_bfree),         (intmax_t) (statfsbuf.f_bfree),
430         (intmax_t) (statfsbuf.f_bavail),         (intmax_t) (statfsbuf.f_bavail),
431         (intmax_t) (statfsbuf.f_files),         (intmax_t) (statfsbuf.f_files),
432         (intmax_t) (statfsbuf.f_ffree));         (intmax_t) (statfsbuf.f_ffree));
433  #endif  #else
434     format = (option_mask32 & OPT_TERSE
435     ? (option_mask32 & OPT_SELINUX ? "%lu %ld %ld %ld %ld %ld %C\n":
436     "%lu %ld %ld %ld %ld %ld\n")
437     : (option_mask32 & OPT_SELINUX ?
438     "Block size: %-10lu\n"
439     "Blocks: Total: %-10jd Free: %-10jd Available: %jd\n"
440     "Inodes: Total: %-10jd Free: %jd"
441     "S_context: %C\n":
442     "Block size: %-10lu\n"
443     "Blocks: Total: %-10jd Free: %-10jd Available: %jd\n"
444     "Inodes: Total: %-10jd Free: %jd\n"));
445     printf(format,
446           (unsigned long) (statfsbuf.f_bsize),
447           (intmax_t) (statfsbuf.f_blocks),
448           (intmax_t) (statfsbuf.f_bfree),
449           (intmax_t) (statfsbuf.f_bavail),
450           (intmax_t) (statfsbuf.f_files),
451           (intmax_t) (statfsbuf.f_ffree),
452     scontext);
453    
454     if (scontext)
455     freecon(scontext);
456    #endif
457    #endif /* FEATURE_STAT_FORMAT */
458   return 1;   return 1;
459  }  }
460    
461  /* stat the file and print what we find */  /* stat the file and print what we find */
462  static int do_stat(char const *filename, char const *format)  #if !ENABLE_FEATURE_STAT_FORMAT
463    #define do_stat(filename, format) do_stat(filename)
464    #endif
465    static bool do_stat(const char *filename, const char *format)
466  {  {
467   struct stat statbuf;   struct stat statbuf;
468    #if ENABLE_SELINUX
469     security_context_t scontext = NULL;
470    
471   if ((flags & OPT_DEREFERENCE ? stat : lstat) (filename, &statbuf) != 0) {   if (option_mask32 & OPT_SELINUX) {
472     if ((option_mask32 & OPT_DEREFERENCE
473         ? lgetfilecon(filename, &scontext)
474         : getfilecon(filename, &scontext)
475        ) < 0
476     ) {
477     bb_perror_msg(filename);
478     return 0;
479     }
480     }
481    #endif
482     if ((option_mask32 & OPT_DEREFERENCE ? stat : lstat) (filename, &statbuf) != 0) {
483   bb_perror_msg("cannot stat '%s'", filename);   bb_perror_msg("cannot stat '%s'", filename);
484   return 0;   return 0;
485   }   }
486    
487  #ifdef CONFIG_FEATURE_STAT_FORMAT  #if ENABLE_FEATURE_STAT_FORMAT
488   if (format == NULL) {   if (format == NULL) {
489   if (flags & OPT_TERSE) {  #if !ENABLE_SELINUX
490     if (option_mask32 & OPT_TERSE) {
491   format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o";   format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o";
492   } else {   } else {
493   if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) {   if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) {
# Line 445  static int do_stat(char const *filename, Line 507  static int do_stat(char const *filename,
507   "Access: %x\n" "Modify: %y\n" "Change: %z\n";   "Access: %x\n" "Modify: %y\n" "Change: %z\n";
508   }   }
509   }   }
  }  
  print_it(format, filename, print_stat, &statbuf);  
510  #else  #else
511   if (flags & OPT_TERSE) {   if (option_mask32 & OPT_TERSE) {
512   printf("%s %ju %ju %lx %lu %lu %jx %ju %lu %lx %lx %lu %lu %lu %lu\n",   format = (option_mask32 & OPT_SELINUX ?
513      "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o %C\n":
514      "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n");
515     } else {
516     if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) {
517     format = (option_mask32 & OPT_SELINUX ?
518      "  File: \"%N\"\n"
519      "  Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
520      "Device: %Dh/%dd\tInode: %-10i  Links: %-5h"
521      " Device type: %t,%T\n"
522      "Access: (%04a/%10.10A)  Uid: (%5u/%8U)   Gid: (%5g/%8G)\n"
523      "   S_Context: %C\n"
524      "Access: %x\n" "Modify: %y\n" "Change: %z\n":
525      "  File: \"%N\"\n"
526      "  Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
527      "Device: %Dh/%dd\tInode: %-10i  Links: %-5h"
528      " Device type: %t,%T\n"
529      "Access: (%04a/%10.10A)  Uid: (%5u/%8U)   Gid: (%5g/%8G)\n"
530      "Access: %x\n" "Modify: %y\n" "Change: %z\n");
531     } else {
532     format = (option_mask32 & OPT_SELINUX ?
533      "  File: \"%N\"\n"
534      "  Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
535      "Device: %Dh/%dd\tInode: %-10i  Links: %h\n"
536      "Access: (%04a/%10.10A)  Uid: (%5u/%8U)   Gid: (%5g/%8G)\n"
537      "S_Context: %C\n"
538      "Access: %x\n" "Modify: %y\n" "Change: %z\n":
539      "  File: \"%N\"\n"
540      "  Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
541      "Device: %Dh/%dd\tInode: %-10i  Links: %h\n"
542      "Access: (%04a/%10.10A)  Uid: (%5u/%8U)   Gid: (%5g/%8G)\n"
543      "Access: %x\n" "Modify: %y\n" "Change: %z\n");
544     }
545     }
546    #endif
547     }
548     print_it(format, filename, print_stat, &statbuf USE_SELINUX(, scontext));
549    #else /* FEATURE_STAT_FORMAT */
550     if (option_mask32 & OPT_TERSE) {
551     printf("%s %ju %ju %lx %lu %lu %jx %ju %lu %lx %lx %lu %lu %lu %lu"
552           SKIP_SELINUX("\n"),
553         filename,         filename,
554         (uintmax_t) (statbuf.st_size),         (uintmax_t) (statbuf.st_size),
555         (uintmax_t) statbuf.st_blocks,         (uintmax_t) statbuf.st_blocks,
556         (unsigned long int) statbuf.st_mode,         (unsigned long) statbuf.st_mode,
557         (unsigned long int) statbuf.st_uid,         (unsigned long) statbuf.st_uid,
558         (unsigned long int) statbuf.st_gid,         (unsigned long) statbuf.st_gid,
559         (uintmax_t) statbuf.st_dev,         (uintmax_t) statbuf.st_dev,
560         (uintmax_t) statbuf.st_ino,         (uintmax_t) statbuf.st_ino,
561         (unsigned long int) statbuf.st_nlink,         (unsigned long) statbuf.st_nlink,
562         (unsigned long int) major(statbuf.st_rdev),         (unsigned long) major(statbuf.st_rdev),
563         (unsigned long int) minor(statbuf.st_rdev),         (unsigned long) minor(statbuf.st_rdev),
564         (unsigned long int) statbuf.st_atime,         (unsigned long) statbuf.st_atime,
565         (unsigned long int) statbuf.st_mtime,         (unsigned long) statbuf.st_mtime,
566         (unsigned long int) statbuf.st_ctime,         (unsigned long) statbuf.st_ctime,
567         (unsigned long int) statbuf.st_blksize         (unsigned long) statbuf.st_blksize
568   );   );
569    #if ENABLE_SELINUX
570     if (option_mask32 & OPT_SELINUX)
571     printf(" %lc\n", *scontext);
572     else
573     bb_putchar('\n');
574    #endif
575   } else {   } else {
576   char *linkname = NULL;   char *linkname = NULL;
577    
# Line 477  static int do_stat(char const *filename, Line 583  static int do_stat(char const *filename,
583   pw_ent = getpwuid(statbuf.st_uid);   pw_ent = getpwuid(statbuf.st_uid);
584    
585   if (S_ISLNK(statbuf.st_mode))   if (S_ISLNK(statbuf.st_mode))
586   linkname = xreadlink(filename);   linkname = xmalloc_readlink_or_warn(filename);
587   if (linkname)   if (linkname)
588   printf("  File: \"%s\" -> \"%s\"\n", filename, linkname);   printf("  File: \"%s\" -> \"%s\"\n", filename, linkname);
589   else   else
# Line 487  static int do_stat(char const *filename, Line 593  static int do_stat(char const *filename,
593         "Device: %jxh/%jud\tInode: %-10ju  Links: %-5lu",         "Device: %jxh/%jud\tInode: %-10ju  Links: %-5lu",
594         (uintmax_t) (statbuf.st_size),         (uintmax_t) (statbuf.st_size),
595         (uintmax_t) statbuf.st_blocks,         (uintmax_t) statbuf.st_blocks,
596         (unsigned long int) statbuf.st_blksize,         (unsigned long) statbuf.st_blksize,
597         file_type(&statbuf),         file_type(&statbuf),
598         (uintmax_t) statbuf.st_dev,         (uintmax_t) statbuf.st_dev,
599         (uintmax_t) statbuf.st_dev,         (uintmax_t) statbuf.st_dev,
600         (uintmax_t) statbuf.st_ino,         (uintmax_t) statbuf.st_ino,
601         (unsigned long int) statbuf.st_nlink);         (unsigned long) statbuf.st_nlink);
602   if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode))   if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode))
603   printf(" Device type: %lx,%lx\n",   printf(" Device type: %lx,%lx\n",
604         (unsigned long int) major(statbuf.st_rdev),         (unsigned long) major(statbuf.st_rdev),
605         (unsigned long int) minor(statbuf.st_rdev));         (unsigned long) minor(statbuf.st_rdev));
606   else   else
607   putchar('\n');   bb_putchar('\n');
608   printf("Access: (%04lo/%10.10s)  Uid: (%5lu/%8s)   Gid: (%5lu/%8s)\n"   printf("Access: (%04lo/%10.10s)  Uid: (%5lu/%8s)   Gid: (%5lu/%8s)\n",
609         "Access: %s\n" "Modify: %s\n" "Change: %s\n",         (unsigned long) (statbuf.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)),
        (unsigned long int) (statbuf.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)),  
610         bb_mode_string(statbuf.st_mode),         bb_mode_string(statbuf.st_mode),
611         (unsigned long int) statbuf.st_uid,         (unsigned long) statbuf.st_uid,
612         (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN",         (pw_ent != NULL) ? pw_ent->pw_name : "UNKNOWN",
613         (unsigned long int) statbuf.st_gid,         (unsigned long) statbuf.st_gid,
614         (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN",         (gw_ent != NULL) ? gw_ent->gr_name : "UNKNOWN");
615    #if ENABLE_SELINUX
616     printf("   S_Context: %lc\n", *scontext);
617    #endif
618     printf("Access: %s\n" "Modify: %s\n" "Change: %s\n",
619         human_time(statbuf.st_atime),         human_time(statbuf.st_atime),
620         human_time(statbuf.st_mtime),         human_time(statbuf.st_mtime),
621         human_time(statbuf.st_ctime));         human_time(statbuf.st_ctime));
622   }   }
623  #endif  #endif /* FEATURE_STAT_FORMAT */
624   return 1;   return 1;
625  }  }
626    
627    int stat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
628  int stat_main(int argc, char **argv)  int stat_main(int argc, char **argv)
629  {  {
630     USE_FEATURE_STAT_FORMAT(char *format = NULL;)
631   int i;   int i;
  char *format = NULL;  
632   int ok = 1;   int ok = 1;
633   int (*statfunc)(char const *, char const *) = do_stat;   statfunc_ptr statfunc = do_stat;
634    
635   flags = getopt32(argc, argv, "ftL"   getopt32(argv, "ftL"
636     USE_SELINUX("Z")
637   USE_FEATURE_STAT_FORMAT("c:", &format)   USE_FEATURE_STAT_FORMAT("c:", &format)
638   );   );
639    
640   if (flags & 1)                /* -f */   if (option_mask32 & OPT_FILESYS) /* -f */
641   statfunc = do_statfs;   statfunc = do_statfs;
642   if (argc == optind)           /* files */   if (argc == optind)           /* files */
643   bb_show_usage();   bb_show_usage();
644    
645    #if ENABLE_SELINUX
646     if (option_mask32 & OPT_SELINUX) {
647     selinux_or_die();
648     }
649    #endif /* ENABLE_SELINUX */
650   for (i = optind; i < argc; ++i)   for (i = optind; i < argc; ++i)
651   ok &= statfunc(argv[i], format);   ok &= statfunc(argv[i] USE_FEATURE_STAT_FORMAT(, format));
652    
653   return (ok ? EXIT_SUCCESS : EXIT_FAILURE);   return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
654  }  }

Legend:
Removed from v.815  
changed lines
  Added in v.816