diff options
-rw-r--r-- | utils/storeinfo.c | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/utils/storeinfo.c b/utils/storeinfo.c new file mode 100644 index 00000000..18cfd287 --- /dev/null +++ b/utils/storeinfo.c @@ -0,0 +1,224 @@ +/* Show where a file exists + + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by Miles Bader <miles@gnu.ai.mit.edu> + + 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 <hurd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <argp.h> +#include <unistd.h> +#include <sys/fcntl.h> + +#include <error.h> + +#include <hurd/fs.h> + +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, "never print `FILE: ' before info"}, + {"no-prefix", 'P', 0, 0, "always 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 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); + 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_DEVICE_MUTATED: kind_name = "device_mutated"; break; + case STORAGE_HURD_FILE: kind_name = "file"; break; + case STORAGE_HURD_FILE_MUTATED: kind_name = "file_mutated"; break; + case STORAGE_NETWORK: kind_name = "network"; break; + default: + sprintf (unknown_kind_name, "%d", kind); + kind_name = unknown_kind_name; + } + + for (i = 0; i < runs_len; i += 2) + { + if (runs[0] >= 0) + blocks += runs[1]; + size += runs[1]; + } + size *= block_size; + + pstr (source, 0); + pstr (kind_name, W_KIND); + 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 a filename prefix if there are multiple + files. */ + print_prefix = (state->argc != state->index + 1); + 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); +} |