/* Show where a file exists Copyright (C) 1995 Free Software Foundation, Inc. Written by Miles Bader This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include static struct argp_option options[] = { {"kind", 'k', 0, 0, "print the type of store behind FILE"}, {"name", 'n', 0, 0, "print the name of the store behind FILE"}, {"blocks", 'b', 0, 0, "print the number of blocks in FILE"}, {"block-size", 'B', 0, 0, "print the block size of FILE's store"}, {"size", 's', 0, 0, "print the size, in bytes, of FILE"}, {"runs", 'r', 0, 0, "print the runs of blocks in FILE"}, {"dereference", 'L', 0, 0, "if FILE is a symbolic link, follow it"}, {"prefix", 'p', 0, 0, "always print `FILE: ' before info"}, {"no-prefix", 'P', 0, 0, "never print `FILE: ' before info"}, {0, 0} }; static char *args_doc = "FILE..."; static char *doc = "With no FILE arguments, the file attached to standard \ input is used. The fields to be printed are separated by colons, in this \ order: PREFIX: KIND: NAME: BLOCK-SIZE: BLOCKS: SIZE: RUNS. By default, all \ fields are printed."; /* ---------------------------------------------------------------- */ /* Things we can print about a file's storage. */ #define W_SOURCE 0x01 #define W_KIND 0x02 #define W_NAME 0x04 #define W_BLOCKS 0x08 #define W_BLOCK_SIZE 0x10 #define W_SIZE 0x20 #define W_RUNS 0x40 #define W_ALL 0xFF /* Print a line of storage information for NODE to stdout. If PREFIX is non-NULL, print it first, followed by a colon. */ static error_t print_info (mach_port_t node, char *source, unsigned what) { error_t err; int flags; int first = 1; int kind, i; char *kind_name; char *misc; off_t *runs; unsigned misc_len, runs_len; size_t block_size; off_t blocks = 0, size = 0; string_t name; mach_port_t store_port; char unknown_kind_name[20]; void psep () { if (first) first = 0; else { putchar (':'); putchar (' '); } } void pstr (char *str, unsigned mask) { if (str && (what & mask) == mask) { psep (); fputs (str, stdout); } } void pint (off_t val, unsigned mask) { if ((what & mask) == mask) { psep (); printf ("%ld", val); } } err = file_get_storage_info (node, &kind, &runs, &runs_len, &block_size, name, &store_port, &misc, &misc_len, &flags); if (err) return err; mach_port_deallocate (mach_task_self (), store_port); vm_deallocate (mach_task_self (), (vm_address_t)misc, misc_len); switch (kind) { case STORAGE_OTHER: kind_name = "other"; break; case STORAGE_DEVICE: kind_name = "device"; break; case STORAGE_HURD_FILE: kind_name = "file"; break; case STORAGE_NETWORK: kind_name = "network"; break; case STORAGE_MEMORY: kind_name = "memory"; break; case STORAGE_TASK: kind_name = "task"; break; default: sprintf (unknown_kind_name, "%d", kind); kind_name = unknown_kind_name; } for (i = 0; i < runs_len; i += 2) { if (runs[i] >= 0) blocks += runs[i+1]; size += runs[i+1]; } size *= block_size; pstr (source, 0); pstr (kind_name, W_KIND); if ((flags & STORAGE_MUTATED) && (what & W_KIND)) fputs ("/mutated", stdout); pstr (name, W_NAME); pint (block_size, W_BLOCK_SIZE); pint (blocks, W_BLOCKS); pint (size, W_SIZE); if (what & W_RUNS) { psep (); for (i = 0; i < runs_len; i += 2) { if (i > 0) putchar (','); if (runs[i] < 0) printf ("[%ld]", runs[i+1]); else printf ("%ld[%ld]", runs[i], runs[i+1]); } } putchar ('\n'); return 0; } void main(int argc, char *argv[]) { int deref = 0, print_prefix = -1; unsigned what = 0; /* Parse our options... */ error_t parse_opt (int key, char *arg, struct argp_state *state) { void info (mach_port_t file, char *source, error_t err) { if (print_prefix < 0) /* By default, only print filename prefixes for multiple files. */ print_prefix = state->next < state->argc; if (what == 0) what = W_ALL; if (file == MACH_PORT_NULL) error (3, err, source); err = print_info (file, print_prefix ? source : 0, what); if (err) error (4, err, source); } switch (key) { case 'L': deref = 1; break; case 'p': print_prefix = 1; break; case 'P': print_prefix = 0; break; case 'k': what |= W_KIND; break; case 'n': what |= W_NAME; break; case 'b': what |= W_BLOCKS; break; case 'B': what |= W_BLOCK_SIZE; break; case 's': what |= W_SIZE; break; case 'r': what |= W_RUNS; break; case ARGP_KEY_NO_ARGS: info (getdport (0), "-", 0); break; case ARGP_KEY_ARG: if (strcmp (arg, "-") == 0) info (getdport (0), "-", 0); else { file_t file = file_name_lookup (arg, deref ? 0 : O_NOLINK, 0); info (file, arg, errno); mach_port_deallocate (mach_task_self (), file); } break; default: return EINVAL; } return 0; } struct argp argp = {options, parse_opt, args_doc, doc}; argp_parse (&argp, argc, argv, 0, 0); exit(0); }