diff options
| author | vapier <vapier@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2005-04-23 06:26:38 +0000 |
|---|---|---|
| committer | vapier <vapier@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2005-04-23 06:26:38 +0000 |
| commit | ce3873bf725005e8db4e54252017090efbb94496 (patch) | |
| tree | 962bf98157f322d70e5c0fdd7fce5ef6865bbd3d | |
| parent | 5493cf2f49d88fd81b4b2b67851a70187702c3e9 (diff) | |
| download | busybox-w32-ce3873bf725005e8db4e54252017090efbb94496.tar.gz busybox-w32-ce3873bf725005e8db4e54252017090efbb94496.tar.bz2 busybox-w32-ce3873bf725005e8db4e54252017090efbb94496.zip | |
stat implementation based upon coreutils
git-svn-id: svn://busybox.net/trunk/busybox@10163 69ca8d6d-28ef-0310-b511-8ec308f3f277
| -rw-r--r-- | coreutils/Config.in | 15 | ||||
| -rw-r--r-- | coreutils/Makefile.in | 1 | ||||
| -rw-r--r-- | coreutils/stat.c | 599 | ||||
| -rw-r--r-- | include/applets.h | 3 | ||||
| -rw-r--r-- | include/usage.h | 57 |
5 files changed, 675 insertions, 0 deletions
diff --git a/coreutils/Config.in b/coreutils/Config.in index 677970d1f..b292e2568 100644 --- a/coreutils/Config.in +++ b/coreutils/Config.in | |||
| @@ -422,6 +422,21 @@ config CONFIG_SORT_BIG | |||
| 422 | The SuSv3 sort standard is available at: | 422 | The SuSv3 sort standard is available at: |
| 423 | http://www.opengroup.org/onlinepubs/007904975/utilities/sort.html | 423 | http://www.opengroup.org/onlinepubs/007904975/utilities/sort.html |
| 424 | 424 | ||
| 425 | config CONFIG_STAT | ||
| 426 | bool "stat" | ||
| 427 | default n | ||
| 428 | help | ||
| 429 | display file or filesystem status. | ||
| 430 | |||
| 431 | config CONFIG_FEATURE_STAT_FORMAT | ||
| 432 | bool " Enable custom formats (-c)" | ||
| 433 | default n | ||
| 434 | depends on CONFIG_STAT | ||
| 435 | help | ||
| 436 | Without this, stat will not support the '-c format' option where | ||
| 437 | users can pass a custom format string for output. This adds about | ||
| 438 | 7k to a nonstatic build on amd64. | ||
| 439 | |||
| 425 | config CONFIG_STTY | 440 | config CONFIG_STTY |
| 426 | bool "stty" | 441 | bool "stty" |
| 427 | default n | 442 | default n |
diff --git a/coreutils/Makefile.in b/coreutils/Makefile.in index c9c42e091..de5dfea85 100644 --- a/coreutils/Makefile.in +++ b/coreutils/Makefile.in | |||
| @@ -70,6 +70,7 @@ COREUTILS-$(CONFIG_SEQ) += seq.o | |||
| 70 | COREUTILS-$(CONFIG_SHA1SUM) += md5_sha1_sum.o | 70 | COREUTILS-$(CONFIG_SHA1SUM) += md5_sha1_sum.o |
| 71 | COREUTILS-$(CONFIG_SLEEP) += sleep.o | 71 | COREUTILS-$(CONFIG_SLEEP) += sleep.o |
| 72 | COREUTILS-$(CONFIG_SORT) += sort.o | 72 | COREUTILS-$(CONFIG_SORT) += sort.o |
| 73 | COREUTILS-$(CONFIG_STAT) += stat.o | ||
| 73 | COREUTILS-$(CONFIG_STTY) += stty.o | 74 | COREUTILS-$(CONFIG_STTY) += stty.o |
| 74 | COREUTILS-$(CONFIG_SUM) += sum.o | 75 | COREUTILS-$(CONFIG_SUM) += sum.o |
| 75 | COREUTILS-$(CONFIG_SYNC) += sync.o | 76 | COREUTILS-$(CONFIG_SYNC) += sync.o |
diff --git a/coreutils/stat.c b/coreutils/stat.c new file mode 100644 index 000000000..e386d75a0 --- /dev/null +++ b/coreutils/stat.c | |||
| @@ -0,0 +1,599 @@ | |||
| 1 | /* | ||
| 2 | * stat -- display file or file system status | ||
| 3 | * | ||
| 4 | * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation. | ||
| 5 | * Copyright (C) 2005 by Erik Andersen <andersen@codepoet.org> | ||
| 6 | * Copyright (C) 2005 by Mike Frysinger <vapier@gentoo.org> | ||
| 7 | * | ||
| 8 | * Written by Michael Meskes | ||
| 9 | * Taken from coreutils and turned into a busybox applet by Mike Frysinger | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or modify | ||
| 12 | * it under the terms of the GNU General Public License as published by | ||
| 13 | * the Free Software Foundation; either version 2 of the License, or | ||
| 14 | * (at your option) any later version. | ||
| 15 | * | ||
| 16 | * This program is distributed in the hope that it will be useful, | ||
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 19 | * General Public License for more details. | ||
| 20 | * | ||
| 21 | * You should have received a copy of the GNU General Public License | ||
| 22 | * along with this program; if not, write to the Free Software | ||
| 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 24 | * | ||
| 25 | */ | ||
| 26 | |||
| 27 | #include <stdio.h> | ||
| 28 | #include <sys/types.h> | ||
| 29 | #include <pwd.h> | ||
| 30 | #include <grp.h> | ||
| 31 | #include <sys/vfs.h> | ||
| 32 | #include <time.h> | ||
| 33 | #include <getopt.h> | ||
| 34 | #include <sys/stat.h> | ||
| 35 | #include <string.h> | ||
| 36 | #include "busybox.h" | ||
| 37 | |||
| 38 | /* vars to control behavior */ | ||
| 39 | static int follow_links = 0; | ||
| 40 | static int terse = 0; | ||
| 41 | |||
| 42 | static char const *file_type(struct stat const *st) | ||
| 43 | { | ||
| 44 | /* See POSIX 1003.1-2001 XCU Table 4-8 lines 17093-17107 | ||
| 45 | * for some of these formats. | ||
| 46 | * To keep diagnostics grammatical in English, the | ||
| 47 | * returned string must start with a consonant. | ||
| 48 | */ | ||
| 49 | if (S_ISREG(st->st_mode)) return st->st_size == 0 ? "regular empty file" : "regular file"; | ||
| 50 | if (S_ISDIR(st->st_mode)) return "directory"; | ||
| 51 | if (S_ISBLK(st->st_mode)) return "block special file"; | ||
| 52 | if (S_ISCHR(st->st_mode)) return "character special file"; | ||
| 53 | if (S_ISFIFO(st->st_mode)) return "fifo"; | ||
| 54 | if (S_ISLNK(st->st_mode)) return "symbolic link"; | ||
| 55 | if (S_ISSOCK(st->st_mode)) return "socket"; | ||
| 56 | if (S_TYPEISMQ(st)) return "message queue"; | ||
| 57 | if (S_TYPEISSEM(st)) return "semaphore"; | ||
| 58 | if (S_TYPEISSHM(st)) return "shared memory object"; | ||
| 59 | #ifdef S_TYPEISTMO | ||
| 60 | if (S_TYPEISTMO(st)) return "typed memory object"; | ||
| 61 | #endif | ||
| 62 | return "weird file"; | ||
| 63 | } | ||
| 64 | |||
| 65 | static char const *human_time(time_t t) | ||
| 66 | { | ||
| 67 | static char *str; | ||
| 68 | str = ctime(&t); | ||
| 69 | str[strlen(str)-1] = '\0'; | ||
| 70 | return str; | ||
| 71 | } | ||
| 72 | |||
| 73 | /* Return the type of the specified file system. | ||
| 74 | * Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris) | ||
| 75 | * Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2) | ||
| 76 | * Still others have neither and have to get by with f_type (Linux). | ||
| 77 | */ | ||
| 78 | static char const *human_fstype(long f_type) | ||
| 79 | { | ||
| 80 | #define S_MAGIC_AFFS 0xADFF | ||
| 81 | #define S_MAGIC_DEVPTS 0x1CD1 | ||
| 82 | #define S_MAGIC_EXT 0x137D | ||
| 83 | #define S_MAGIC_EXT2_OLD 0xEF51 | ||
| 84 | #define S_MAGIC_EXT2 0xEF53 | ||
| 85 | #define S_MAGIC_JFS 0x3153464a | ||
| 86 | #define S_MAGIC_XFS 0x58465342 | ||
| 87 | #define S_MAGIC_HPFS 0xF995E849 | ||
| 88 | #define S_MAGIC_ISOFS 0x9660 | ||
| 89 | #define S_MAGIC_ISOFS_WIN 0x4000 | ||
| 90 | #define S_MAGIC_ISOFS_R_WIN 0x4004 | ||
| 91 | #define S_MAGIC_MINIX 0x137F | ||
| 92 | #define S_MAGIC_MINIX_30 0x138F | ||
| 93 | #define S_MAGIC_MINIX_V2 0x2468 | ||
| 94 | #define S_MAGIC_MINIX_V2_30 0x2478 | ||
| 95 | #define S_MAGIC_MSDOS 0x4d44 | ||
| 96 | #define S_MAGIC_FAT 0x4006 | ||
| 97 | #define S_MAGIC_NCP 0x564c | ||
| 98 | #define S_MAGIC_NFS 0x6969 | ||
| 99 | #define S_MAGIC_PROC 0x9fa0 | ||
| 100 | #define S_MAGIC_SMB 0x517B | ||
| 101 | #define S_MAGIC_XENIX 0x012FF7B4 | ||
| 102 | #define S_MAGIC_SYSV4 0x012FF7B5 | ||
| 103 | #define S_MAGIC_SYSV2 0x012FF7B6 | ||
| 104 | #define S_MAGIC_COH 0x012FF7B7 | ||
| 105 | #define S_MAGIC_UFS 0x00011954 | ||
| 106 | #define S_MAGIC_XIAFS 0x012FD16D | ||
| 107 | #define S_MAGIC_NTFS 0x5346544e | ||
| 108 | #define S_MAGIC_TMPFS 0x1021994 | ||
| 109 | #define S_MAGIC_REISERFS 0x52654973 | ||
| 110 | #define S_MAGIC_CRAMFS 0x28cd3d45 | ||
| 111 | #define S_MAGIC_ROMFS 0x7275 | ||
| 112 | #define S_MAGIC_RAMFS 0x858458f6 | ||
| 113 | #define S_MAGIC_SQUASHFS 0x73717368 | ||
| 114 | #define S_MAGIC_SYSFS 0x62656572 | ||
| 115 | switch (f_type) { | ||
| 116 | case S_MAGIC_AFFS: return "affs"; | ||
| 117 | case S_MAGIC_DEVPTS: return "devpts"; | ||
| 118 | case S_MAGIC_EXT: return "ext"; | ||
| 119 | case S_MAGIC_EXT2_OLD: return "ext2"; | ||
| 120 | case S_MAGIC_EXT2: return "ext2/ext3"; | ||
| 121 | case S_MAGIC_JFS: return "jfs"; | ||
| 122 | case S_MAGIC_XFS: return "xfs"; | ||
| 123 | case S_MAGIC_HPFS: return "hpfs"; | ||
| 124 | case S_MAGIC_ISOFS: return "isofs"; | ||
| 125 | case S_MAGIC_ISOFS_WIN: return "isofs"; | ||
| 126 | case S_MAGIC_ISOFS_R_WIN: return "isofs"; | ||
| 127 | case S_MAGIC_MINIX: return "minix"; | ||
| 128 | case S_MAGIC_MINIX_30: return "minix (30 char.)"; | ||
| 129 | case S_MAGIC_MINIX_V2: return "minix v2"; | ||
| 130 | case S_MAGIC_MINIX_V2_30: return "minix v2 (30 char.)"; | ||
| 131 | case S_MAGIC_MSDOS: return "msdos"; | ||
| 132 | case S_MAGIC_FAT: return "fat"; | ||
| 133 | case S_MAGIC_NCP: return "novell"; | ||
| 134 | case S_MAGIC_NFS: return "nfs"; | ||
| 135 | case S_MAGIC_PROC: return "proc"; | ||
| 136 | case S_MAGIC_SMB: return "smb"; | ||
| 137 | case S_MAGIC_XENIX: return "xenix"; | ||
| 138 | case S_MAGIC_SYSV4: return "sysv4"; | ||
| 139 | case S_MAGIC_SYSV2: return "sysv2"; | ||
| 140 | case S_MAGIC_COH: return "coh"; | ||
| 141 | case S_MAGIC_UFS: return "ufs"; | ||
| 142 | case S_MAGIC_XIAFS: return "xia"; | ||
| 143 | case S_MAGIC_NTFS: return "ntfs"; | ||
| 144 | case S_MAGIC_TMPFS: return "tmpfs"; | ||
| 145 | case S_MAGIC_REISERFS: return "reiserfs"; | ||
| 146 | case S_MAGIC_CRAMFS: return "cramfs"; | ||
| 147 | case S_MAGIC_ROMFS: return "romfs"; | ||
| 148 | case S_MAGIC_RAMFS: return "ramfs"; | ||
| 149 | case S_MAGIC_SQUASHFS: return "squashfs"; | ||
| 150 | case S_MAGIC_SYSFS: return "sysfs"; | ||
| 151 | default: { | ||
| 152 | static char buf[sizeof("UNKNOWN (0x%lx)") - 3 | ||
| 153 | + (sizeof(f_type) * CHAR_BIT + 3) / 4]; | ||
| 154 | sprintf(buf, "UNKNOWN (0x%lx)", f_type); | ||
| 155 | return buf; | ||
| 156 | } | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | #ifdef CONFIG_FEATURE_STAT_FORMAT | ||
| 161 | /* print statfs info */ | ||
| 162 | static void print_statfs(char *pformat, size_t buf_len, char m, | ||
| 163 | char const *filename, void const *data) | ||
| 164 | { | ||
| 165 | struct statfs const *statfsbuf = data; | ||
| 166 | |||
| 167 | switch (m) { | ||
| 168 | case 'n': | ||
| 169 | strncat(pformat, "s", buf_len); | ||
| 170 | printf(pformat, filename); | ||
| 171 | break; | ||
| 172 | case 'i': | ||
| 173 | strncat(pformat, "Lx", buf_len); | ||
| 174 | printf(pformat, statfsbuf->f_fsid); | ||
| 175 | break; | ||
| 176 | case 'l': | ||
| 177 | strncat(pformat, "lu", buf_len); | ||
| 178 | printf(pformat, statfsbuf->f_namelen); | ||
| 179 | break; | ||
| 180 | case 't': | ||
| 181 | strncat(pformat, "lx", buf_len); | ||
| 182 | printf(pformat, (unsigned long int) (statfsbuf->f_type)); /* no equiv. */ | ||
| 183 | break; | ||
| 184 | case 'T': | ||
| 185 | strncat(pformat, "s", buf_len); | ||
| 186 | printf(pformat, human_fstype(statfsbuf->f_type)); | ||
| 187 | break; | ||
| 188 | case 'b': | ||
| 189 | strncat(pformat, "ld", buf_len); | ||
| 190 | printf(pformat, (intmax_t) (statfsbuf->f_blocks)); | ||
| 191 | break; | ||
| 192 | case 'f': | ||
| 193 | strncat(pformat, "ld", buf_len); | ||
| 194 | printf(pformat, (intmax_t) (statfsbuf->f_bfree)); | ||
| 195 | break; | ||
| 196 | case 'a': | ||
| 197 | strncat(pformat, "ld", buf_len); | ||
| 198 | printf(pformat, (intmax_t) (statfsbuf->f_bavail)); | ||
| 199 | break; | ||
| 200 | case 's': | ||
| 201 | strncat(pformat, "lu", buf_len); | ||
| 202 | printf(pformat, (unsigned long int) (statfsbuf->f_bsize)); | ||
| 203 | break; | ||
| 204 | case 'S': { | ||
| 205 | unsigned long int frsize = statfsbuf->f_frsize; | ||
| 206 | if (!frsize) | ||
| 207 | frsize = statfsbuf->f_bsize; | ||
| 208 | strncat(pformat, "lu", buf_len); | ||
| 209 | printf(pformat, frsize); | ||
| 210 | break; | ||
| 211 | } | ||
| 212 | case 'c': | ||
| 213 | strncat(pformat, "ld", buf_len); | ||
| 214 | printf(pformat, (intmax_t) (statfsbuf->f_files)); | ||
| 215 | break; | ||
| 216 | case 'd': | ||
| 217 | strncat(pformat, "ld", buf_len); | ||
| 218 | printf(pformat, (intmax_t) (statfsbuf->f_ffree)); | ||
| 219 | break; | ||
| 220 | default: | ||
| 221 | strncat(pformat, "c", buf_len); | ||
| 222 | printf(pformat, m); | ||
| 223 | break; | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | /* print stat info */ | ||
| 228 | static void print_stat(char *pformat, size_t buf_len, char m, | ||
| 229 | char const *filename, void const *data) | ||
| 230 | { | ||
| 231 | #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) | ||
| 232 | struct stat *statbuf = (struct stat *) data; | ||
| 233 | struct passwd *pw_ent; | ||
| 234 | struct group *gw_ent; | ||
| 235 | |||
| 236 | switch (m) { | ||
| 237 | case 'n': | ||
| 238 | strncat(pformat, "s", buf_len); | ||
| 239 | printf(pformat, filename); | ||
| 240 | break; | ||
| 241 | case 'N': | ||
| 242 | strncat(pformat, "s", buf_len); | ||
| 243 | if (S_ISLNK(statbuf->st_mode)) { | ||
| 244 | char *linkname = xreadlink(filename); | ||
| 245 | if (linkname == NULL) { | ||
| 246 | bb_perror_msg("cannot read symbolic link '%s'", filename); | ||
| 247 | return; | ||
| 248 | } | ||
| 249 | /*printf("\"%s\" -> \"%s\"", filename, linkname); */ | ||
| 250 | printf(pformat, filename); | ||
| 251 | printf(" -> "); | ||
| 252 | printf(pformat, linkname); | ||
| 253 | } else { | ||
| 254 | printf(pformat, filename); | ||
| 255 | } | ||
| 256 | break; | ||
| 257 | case 'd': | ||
| 258 | strncat(pformat, "lu", buf_len); | ||
| 259 | printf(pformat, (uintmax_t) statbuf->st_dev); | ||
| 260 | break; | ||
| 261 | case 'D': | ||
| 262 | strncat(pformat, "lx", buf_len); | ||
| 263 | printf(pformat, (uintmax_t) statbuf->st_dev); | ||
| 264 | break; | ||
| 265 | case 'i': | ||
| 266 | strncat(pformat, "lu", buf_len); | ||
| 267 | printf(pformat, (uintmax_t) statbuf->st_ino); | ||
| 268 | break; | ||
| 269 | case 'a': | ||
| 270 | strncat(pformat, "lo", buf_len); | ||
| 271 | printf(pformat, (unsigned long int) (statbuf->st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO))); | ||
| 272 | break; | ||
| 273 | case 'A': | ||
| 274 | strncat(pformat, "s", buf_len); | ||
| 275 | printf(pformat, bb_mode_string(statbuf->st_mode)); | ||
| 276 | break; | ||
| 277 | case 'f': | ||
| 278 | strncat(pformat, "lx", buf_len); | ||
| 279 | printf(pformat, (unsigned long int) statbuf->st_mode); | ||
| 280 | break; | ||
| 281 | case 'F': | ||
| 282 | strncat(pformat, "s", buf_len); | ||
| 283 | printf(pformat, file_type(statbuf)); | ||
| 284 | break; | ||
| 285 | case 'h': | ||
| 286 | strncat(pformat, "lu", buf_len); | ||
| 287 | printf(pformat, (unsigned long int) statbuf->st_nlink); | ||
| 288 | break; | ||
| 289 | case 'u': | ||
| 290 | strncat(pformat, "lu", buf_len); | ||
| 291 | printf(pformat, (unsigned long int) statbuf->st_uid); | ||
| 292 | break; | ||
| 293 | case 'U': | ||
| 294 | strncat(pformat, "s", buf_len); | ||
| 295 | setpwent(); | ||
| 296 | pw_ent = getpwuid(statbuf->st_uid); | ||
| 297 | printf(pformat, (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN"); | ||
| 298 | break; | ||
| 299 | case 'g': | ||
| 300 | strncat(pformat, "lu", buf_len); | ||
| 301 | printf(pformat, (unsigned long int) statbuf->st_gid); | ||
| 302 | break; | ||
| 303 | case 'G': | ||
| 304 | strncat(pformat, "s", buf_len); | ||
| 305 | setgrent(); | ||
| 306 | gw_ent = getgrgid(statbuf->st_gid); | ||
| 307 | printf(pformat, (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN"); | ||
| 308 | break; | ||
| 309 | case 't': | ||
| 310 | strncat(pformat, "lx", buf_len); | ||
| 311 | printf(pformat, (unsigned long int) major(statbuf->st_rdev)); | ||
| 312 | break; | ||
| 313 | case 'T': | ||
| 314 | strncat(pformat, "lx", buf_len); | ||
| 315 | printf(pformat, (unsigned long int) minor(statbuf->st_rdev)); | ||
| 316 | break; | ||
| 317 | case 's': | ||
| 318 | strncat(pformat, "lu", buf_len); | ||
| 319 | printf(pformat, (uintmax_t) (statbuf->st_size)); | ||
| 320 | break; | ||
| 321 | case 'B': | ||
| 322 | strncat(pformat, "lu", buf_len); | ||
| 323 | printf(pformat, (unsigned long int) 512); //ST_NBLOCKSIZE | ||
| 324 | break; | ||
| 325 | case 'b': | ||
| 326 | strncat(pformat, "lu", buf_len); | ||
| 327 | printf(pformat, (uintmax_t) statbuf->st_blocks); | ||
| 328 | break; | ||
| 329 | case 'o': | ||
| 330 | strncat(pformat, "lu", buf_len); | ||
| 331 | printf(pformat, (unsigned long int) statbuf->st_blksize); | ||
| 332 | break; | ||
| 333 | case 'x': | ||
| 334 | strncat(pformat, "s", buf_len); | ||
| 335 | printf(pformat, human_time(statbuf->st_atime)); | ||
| 336 | break; | ||
| 337 | case 'X': | ||
| 338 | strncat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu", buf_len); | ||
| 339 | printf(pformat, (unsigned long int) statbuf->st_atime); | ||
| 340 | break; | ||
| 341 | case 'y': | ||
| 342 | strncat(pformat, "s", buf_len); | ||
| 343 | printf(pformat, human_time(statbuf->st_mtime)); | ||
| 344 | break; | ||
| 345 | case 'Y': | ||
| 346 | strncat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu", buf_len); | ||
| 347 | printf(pformat, (unsigned long int) statbuf->st_mtime); | ||
| 348 | break; | ||
| 349 | case 'z': | ||
| 350 | strncat(pformat, "s", buf_len); | ||
| 351 | printf(pformat, human_time(statbuf->st_ctime)); | ||
| 352 | break; | ||
| 353 | case 'Z': | ||
| 354 | strncat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu", buf_len); | ||
| 355 | printf(pformat, (unsigned long int) statbuf->st_ctime); | ||
| 356 | break; | ||
| 357 | default: | ||
| 358 | strncat(pformat, "c", buf_len); | ||
| 359 | printf(pformat, m); | ||
| 360 | break; | ||
| 361 | } | ||
| 362 | } | ||
| 363 | |||
| 364 | static void print_it(char const *masterformat, char const *filename, | ||
| 365 | void (*print_func) (char *, size_t, char, char const *, void const *), | ||
| 366 | void const *data) | ||
| 367 | { | ||
| 368 | char *b; | ||
| 369 | |||
| 370 | /* create a working copy of the format string */ | ||
| 371 | char *format = bb_xstrdup(masterformat); | ||
| 372 | |||
| 373 | /* Add 2 to accommodate our conversion of the stat `%s' format string | ||
| 374 | * to the printf `%llu' one. */ | ||
| 375 | size_t n_alloc = strlen(format) + 2 + 1; | ||
| 376 | char *dest = xmalloc(n_alloc); | ||
| 377 | |||
| 378 | b = format; | ||
| 379 | while (b) { | ||
| 380 | char *p = strchr(b, '%'); | ||
| 381 | if (p != NULL) { | ||
| 382 | size_t len; | ||
| 383 | *p++ = '\0'; | ||
| 384 | fputs(b, stdout); | ||
| 385 | |||
| 386 | len = strspn(p, "#-+.I 0123456789"); | ||
| 387 | dest[0] = '%'; | ||
| 388 | memcpy(dest + 1, p, len); | ||
| 389 | dest[1 + len] = 0; | ||
| 390 | p += len; | ||
| 391 | |||
| 392 | b = p + 1; | ||
| 393 | switch (*p) { | ||
| 394 | case '\0': | ||
| 395 | b = NULL; | ||
| 396 | /* fall through */ | ||
| 397 | case '%': | ||
| 398 | putchar('%'); | ||
| 399 | break; | ||
| 400 | default: | ||
| 401 | print_func(dest, n_alloc, *p, filename, data); | ||
| 402 | break; | ||
| 403 | } | ||
| 404 | |||
| 405 | } else { | ||
| 406 | fputs(b, stdout); | ||
| 407 | b = NULL; | ||
| 408 | } | ||
| 409 | } | ||
| 410 | |||
| 411 | free(format); | ||
| 412 | free(dest); | ||
| 413 | } | ||
| 414 | #endif | ||
| 415 | |||
| 416 | /* Stat the file system and print what we find. */ | ||
| 417 | static int do_statfs(char const *filename, char const *format) | ||
| 418 | { | ||
| 419 | struct statfs statfsbuf; | ||
| 420 | |||
| 421 | if (statfs(filename, &statfsbuf) != 0) { | ||
| 422 | bb_perror_msg("cannot read file system information for '%s'", filename); | ||
| 423 | return 0; | ||
| 424 | } | ||
| 425 | |||
| 426 | #ifdef CONFIG_FEATURE_STAT_FORMAT | ||
| 427 | if (format == NULL) | ||
| 428 | format = (terse | ||
| 429 | ? "%n %i %l %t %s %S %b %f %a %c %d\n" | ||
| 430 | : " File: \"%n\"\n" | ||
| 431 | " ID: %-8i Namelen: %-7l Type: %T\n" | ||
| 432 | "Block size: %-10s Fundamental block size: %S\n" | ||
| 433 | "Blocks: Total: %-10b Free: %-10f Available: %a\n" | ||
| 434 | "Inodes: Total: %-10c Free: %d\n"); | ||
| 435 | print_it(format, filename, print_statfs, &statfsbuf); | ||
| 436 | #else | ||
| 437 | |||
| 438 | format = (terse | ||
| 439 | ? "%s %Lx %lu " | ||
| 440 | : " File: \"%s\"\n" | ||
| 441 | " ID: %-8Lx Namelen: %-7lu "); | ||
| 442 | printf(format, | ||
| 443 | filename, | ||
| 444 | statfsbuf.f_fsid, | ||
| 445 | statfsbuf.f_namelen); | ||
| 446 | |||
| 447 | if (terse) | ||
| 448 | printf("%lx ", (unsigned long int) (statfsbuf.f_type)); | ||
| 449 | else | ||
| 450 | printf("Type: %s\n", human_fstype(statfsbuf.f_type)); | ||
| 451 | |||
| 452 | format = (terse | ||
| 453 | ? "%lu %lu %ld %ld %ld %ld %ld\n" | ||
| 454 | : "Block size: %-10lu Fundamental block size: %lu\n" | ||
| 455 | "Blocks: Total: %-10ld Free: %-10ld Available: %ld\n" | ||
| 456 | "Inodes: Total: %-10ld Free: %ld\n"); | ||
| 457 | printf(format, | ||
| 458 | (unsigned long int) (statfsbuf.f_bsize), | ||
| 459 | statfsbuf.f_frsize ? statfsbuf.f_frsize : statfsbuf.f_bsize, | ||
| 460 | (intmax_t) (statfsbuf.f_blocks), | ||
| 461 | (intmax_t) (statfsbuf.f_bfree), | ||
| 462 | (intmax_t) (statfsbuf.f_bavail), | ||
| 463 | (intmax_t) (statfsbuf.f_files), | ||
| 464 | (intmax_t) (statfsbuf.f_ffree)); | ||
| 465 | #endif | ||
| 466 | |||
| 467 | return 1; | ||
| 468 | } | ||
| 469 | |||
| 470 | /* stat the file and print what we find */ | ||
| 471 | static int do_stat(char const *filename, char const *format) | ||
| 472 | { | ||
| 473 | struct stat statbuf; | ||
| 474 | |||
| 475 | if ((follow_links ? stat : lstat) (filename, &statbuf) != 0) { | ||
| 476 | bb_perror_msg("cannot stat '%s'", filename); | ||
| 477 | return 0; | ||
| 478 | } | ||
| 479 | |||
| 480 | #ifdef CONFIG_FEATURE_STAT_FORMAT | ||
| 481 | if (format == NULL) { | ||
| 482 | if (terse) { | ||
| 483 | format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n"; | ||
| 484 | } else { | ||
| 485 | if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) { | ||
| 486 | format = | ||
| 487 | " File: \"%N\"\n" | ||
| 488 | " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" | ||
| 489 | "Device: %Dh/%dd\tInode: %-10i Links: %-5h" | ||
| 490 | " Device type: %t,%T\n" | ||
| 491 | "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" | ||
| 492 | "Access: %x\n" "Modify: %y\n" "Change: %z\n"; | ||
| 493 | } else { | ||
| 494 | format = | ||
| 495 | " File: \"%N\"\n" | ||
| 496 | " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" | ||
| 497 | "Device: %Dh/%dd\tInode: %-10i Links: %h\n" | ||
| 498 | "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" | ||
| 499 | "Access: %x\n" "Modify: %y\n" "Change: %z\n"; | ||
| 500 | } | ||
| 501 | } | ||
| 502 | } | ||
| 503 | print_it(format, filename, print_stat, &statbuf); | ||
| 504 | #else | ||
| 505 | if (terse) { | ||
| 506 | printf("%s %lu %lu %lx %lu %lu %lx %lu %lu %lx %lx %lu %lu %lu %lu\n", | ||
| 507 | filename, | ||
| 508 | (uintmax_t) (statbuf.st_size), | ||
| 509 | (uintmax_t) statbuf.st_blocks, | ||
| 510 | (unsigned long int) statbuf.st_mode, | ||
| 511 | (unsigned long int) statbuf.st_uid, | ||
| 512 | (unsigned long int) statbuf.st_gid, | ||
| 513 | (uintmax_t) statbuf.st_dev, | ||
| 514 | (uintmax_t) statbuf.st_ino, | ||
| 515 | (unsigned long int) statbuf.st_nlink, | ||
| 516 | (unsigned long int) major(statbuf.st_rdev), | ||
| 517 | (unsigned long int) minor(statbuf.st_rdev), | ||
| 518 | (unsigned long int) statbuf.st_atime, | ||
| 519 | (unsigned long int) statbuf.st_mtime, | ||
| 520 | (unsigned long int) statbuf.st_ctime, | ||
| 521 | (unsigned long int) statbuf.st_blksize | ||
| 522 | ); | ||
| 523 | } else { | ||
| 524 | char *linkname = NULL; | ||
| 525 | |||
| 526 | struct passwd *pw_ent; | ||
| 527 | struct group *gw_ent; | ||
| 528 | setgrent(); | ||
| 529 | gw_ent = getgrgid(statbuf.st_gid); | ||
| 530 | setpwent(); | ||
| 531 | pw_ent = getpwuid(statbuf.st_uid); | ||
| 532 | |||
| 533 | if (S_ISLNK(statbuf.st_mode)) | ||
| 534 | linkname = xreadlink(filename); | ||
| 535 | if (linkname) | ||
| 536 | printf(" File: \"%s\" -> \"%s\"\n", filename, linkname); | ||
| 537 | else | ||
| 538 | printf(" File: \"%s\"\n", filename); | ||
| 539 | |||
| 540 | printf(" Size: %-10lu\tBlocks: %-10lu IO Block: %-6lu %s\n" | ||
| 541 | "Device: %lxh/%lud\tInode: %-10lu Links: %-5lu", | ||
| 542 | (uintmax_t) (statbuf.st_size), | ||
| 543 | (uintmax_t) statbuf.st_blocks, | ||
| 544 | (unsigned long int) statbuf.st_blksize, | ||
| 545 | file_type(&statbuf), | ||
| 546 | (uintmax_t) statbuf.st_dev, | ||
| 547 | (uintmax_t) statbuf.st_dev, | ||
| 548 | (uintmax_t) statbuf.st_ino, | ||
| 549 | (unsigned long int) statbuf.st_nlink); | ||
| 550 | if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) | ||
| 551 | printf(" Device type: %lx,%lx\n", | ||
| 552 | (unsigned long int) major(statbuf.st_rdev), | ||
| 553 | (unsigned long int) minor(statbuf.st_rdev)); | ||
| 554 | else | ||
| 555 | putchar('\n'); | ||
| 556 | printf("Access: (%04lo/%10.10s) Uid: (%5lu/%8s) Gid: (%5lu/%8s)\n" | ||
| 557 | "Access: %s\n" "Modify: %s\n" "Change: %s\n", | ||
| 558 | (unsigned long int) (statbuf.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)), | ||
| 559 | bb_mode_string(statbuf.st_mode), | ||
| 560 | (unsigned long int) statbuf.st_uid, | ||
| 561 | (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN", | ||
| 562 | (unsigned long int) statbuf.st_gid, | ||
| 563 | (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN", | ||
| 564 | human_time(statbuf.st_atime), | ||
| 565 | human_time(statbuf.st_mtime), | ||
| 566 | human_time(statbuf.st_ctime)); | ||
| 567 | } | ||
| 568 | #endif | ||
| 569 | return 1; | ||
| 570 | } | ||
| 571 | |||
| 572 | int stat_main(int argc, char **argv) | ||
| 573 | { | ||
| 574 | int i; | ||
| 575 | char *format = NULL; | ||
| 576 | int ok = 1; | ||
| 577 | long flags; | ||
| 578 | int (*statfunc)(char const *, char const *) = do_stat; | ||
| 579 | |||
| 580 | flags = bb_getopt_ulflags(argc, argv, "fLlt" | ||
| 581 | #ifdef CONFIG_FEATURE_STAT_FORMAT | ||
| 582 | "c:", &format | ||
| 583 | #endif | ||
| 584 | ); | ||
| 585 | |||
| 586 | if (flags & 1) /* -f */ | ||
| 587 | statfunc = do_statfs; | ||
| 588 | if (flags & 2 || flags & 4) /* -L, -l */ | ||
| 589 | follow_links = 1; | ||
| 590 | if (flags & 8) /* -t */ | ||
| 591 | terse = 1; | ||
| 592 | if (argc == optind) /* files */ | ||
| 593 | bb_show_usage(); | ||
| 594 | |||
| 595 | for (i = optind; i < argc; ++i) | ||
| 596 | ok &= statfunc(argv[i], format); | ||
| 597 | |||
| 598 | return (ok ? EXIT_SUCCESS : EXIT_FAILURE); | ||
| 599 | } | ||
diff --git a/include/applets.h b/include/applets.h index 5ecdf7949..957bc2018 100644 --- a/include/applets.h +++ b/include/applets.h | |||
| @@ -542,6 +542,9 @@ | |||
| 542 | #ifdef CONFIG_START_STOP_DAEMON | 542 | #ifdef CONFIG_START_STOP_DAEMON |
| 543 | APPLET_ODDNAME("start-stop-daemon", start_stop_daemon_main, _BB_DIR_SBIN, _BB_SUID_NEVER, start_stop_daemon) | 543 | APPLET_ODDNAME("start-stop-daemon", start_stop_daemon_main, _BB_DIR_SBIN, _BB_SUID_NEVER, start_stop_daemon) |
| 544 | #endif | 544 | #endif |
| 545 | #ifdef CONFIG_STAT | ||
| 546 | APPLET(stat, stat_main, _BB_DIR_BIN, _BB_SUID_NEVER) | ||
| 547 | #endif | ||
| 545 | #ifdef CONFIG_STRINGS | 548 | #ifdef CONFIG_STRINGS |
| 546 | APPLET(strings, strings_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER) | 549 | APPLET(strings, strings_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER) |
| 547 | #endif | 550 | #endif |
diff --git a/include/usage.h b/include/usage.h index cc2aa3274..8941e1841 100644 --- a/include/usage.h +++ b/include/usage.h | |||
| @@ -2320,6 +2320,63 @@ | |||
| 2320 | "\n\t-q|--quiet\t\t\tbe quiet" \ | 2320 | "\n\t-q|--quiet\t\t\tbe quiet" \ |
| 2321 | "\n\t-s|--signal <signal>\t\tsignal to send (default TERM)" | 2321 | "\n\t-s|--signal <signal>\t\tsignal to send (default TERM)" |
| 2322 | 2322 | ||
| 2323 | #ifdef CONFIG_FEATURE_STAT_FORMAT | ||
| 2324 | # define USAGE_STAT_FORMAT(a) a | ||
| 2325 | #else | ||
| 2326 | # define USAGE_STAT_FORMAT(a) | ||
| 2327 | #endif | ||
| 2328 | #define stat_trivial_usage \ | ||
| 2329 | "[OPTION] FILE..." | ||
| 2330 | #define stat_full_usage \ | ||
| 2331 | "display file (default) or filesystem status.\n\n" \ | ||
| 2332 | "Options:\n" \ | ||
| 2333 | USAGE_STAT_FORMAT("\t-c fmt\tuse the specified format\n") \ | ||
| 2334 | "\t-f\tdisplay filesystem status\n" \ | ||
| 2335 | "\t-L,-l\tdereference links\n" \ | ||
| 2336 | "\t-t\tdisplay info in terse form\n" \ | ||
| 2337 | USAGE_STAT_FORMAT( \ | ||
| 2338 | "\nValid format sequences for files:\n" \ | ||
| 2339 | " %a Access rights in octal\n" \ | ||
| 2340 | " %A Access rights in human readable form\n" \ | ||
| 2341 | " %b Number of blocks allocated (see %B)\n" \ | ||
| 2342 | " %B The size in bytes of each block reported by %b\n" \ | ||
| 2343 | " %d Device number in decimal\n" \ | ||
| 2344 | " %D Device number in hex\n" \ | ||
| 2345 | " %f Raw mode in hex\n" \ | ||
| 2346 | " %F File type\n" \ | ||
| 2347 | " %g Group ID of owner\n" \ | ||
| 2348 | " %G Group name of owner\n" \ | ||
| 2349 | " %h Number of hard links\n" \ | ||
| 2350 | " %i Inode number\n" \ | ||
| 2351 | " %n File name\n" \ | ||
| 2352 | " %N Quoted file name with dereference if symbolic link\n" \ | ||
| 2353 | " %o I/O block size\n" \ | ||
| 2354 | " %s Total size, in bytes\n" \ | ||
| 2355 | " %t Major device type in hex\n" \ | ||
| 2356 | " %T Minor device type in hex\n" \ | ||
| 2357 | " %u User ID of owner\n" \ | ||
| 2358 | " %U User name of owner\n" \ | ||
| 2359 | " %x Time of last access\n" \ | ||
| 2360 | " %X Time of last access as seconds since Epoch\n" \ | ||
| 2361 | " %y Time of last modification\n" \ | ||
| 2362 | " %Y Time of last modification as seconds since Epoch\n" \ | ||
| 2363 | " %z Time of last change\n" \ | ||
| 2364 | " %Z Time of last change as seconds since Epoch\n" \ | ||
| 2365 | "\nValid format sequences for file systems:\n" \ | ||
| 2366 | " %a Free blocks available to non-superuser\n" \ | ||
| 2367 | " %b Total data blocks in file system\n" \ | ||
| 2368 | " %c Total file nodes in file system\n" \ | ||
| 2369 | " %d Free file nodes in file system\n" \ | ||
| 2370 | " %f Free blocks in file system\n" \ | ||
| 2371 | " %i File System ID in hex\n" \ | ||
| 2372 | " %l Maximum length of filenames\n" \ | ||
| 2373 | " %n File name\n" \ | ||
| 2374 | " %s Block size (for faster transfers)\n" \ | ||
| 2375 | " %S Fundamental block size (for block counts)\n" \ | ||
| 2376 | " %t Type in hex\n" \ | ||
| 2377 | " %T Type in human readable form\n" \ | ||
| 2378 | ) | ||
| 2379 | |||
| 2323 | #define strings_trivial_usage \ | 2380 | #define strings_trivial_usage \ |
| 2324 | "[-afo] [-n length] [file ... ]" | 2381 | "[-afo] [-n length] [file ... ]" |
| 2325 | #define strings_full_usage \ | 2382 | #define strings_full_usage \ |
