2 * lafs - Examine and manipulate and LaFS image
4 * This program is essentially a front-end to liblafs. It allows
5 * a LaFS filesystem to be examined and modified. All interesting
6 * manipulations are function calls in to liblafs.
7 * The program simply parses textual commands converting them into
8 * library calls, and provides a readline interface with autocompletion
9 * and context-sensitive help.
11 * Copyright (C) 2011 NeilBrown <neil@brown.name>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 * Email: <neil@brown.name>
33 #include <sys/types.h>
41 #include <readline/readline.h>
42 #include <readline/history.h>
43 #include <lafs/lafs.h>
45 #include <uuid/uuid.h>
48 /* This is the global state which is passed around among
49 * the various commands.
57 static struct state *gen_state;
59 /* Every command can have arguments, both positional and
61 * Named arguments are specified with a leading hyphen, though
62 * multiple hyphens may be given in input (completion chooses 2).
63 * Tags for positional arguments must not start with '-', and is used
64 * only for help messages.
65 * Named arguments are normally followed by an '=' and a value. If an argument is
66 * defined as a 'flag' then no '=' is expected.
67 * A tag argument can provide a value to a positional argument, and the
68 * command can easily determine if the tag version was used.
69 * Each tag may only be given once.
70 * A positional argument can be a subcommand which links to a new set
71 * of argument descriptions.
73 * flag: expect --tagname This is either present or not.
74 * opaque: An uninterpreted string, often a number.
75 * choice: On of a defined list of strings.
76 * external: An external filename - completion is possible.
77 * internal: An internal filename - completion might be possible.
78 * subcommand: one of a list of subcommands.
79 * Any unique prefix of a tag is allowed to match.
81 enum argtype { flag, opaque, choice, external, internal, subcommand};
86 union { struct cmd *subcmd; char **options; };
89 #define TERMINAL_ARG {NULL, opaque, 0, {NULL}, NULL}
91 /* When a positional parameter is identified as 'subcommand' it is associated
92 * with a list of 'struct cmd' identifying the possible subcommands.
93 * Any unique prefix of a command is allowed to match.
94 * The initial argument list description allows a single argument which is
95 * a 'subcommand' identifying all the commands that lafs understands.
99 void (*cmd)(struct state *st, void **args);
104 /* Find a command in a list. The word must be an exact match, or
107 static struct cmd *find_cmd(struct cmd *cmds, char *word)
110 int l = strlen(word);
113 for (c = 0; cmds[c].name; c++) {
114 if (strcmp(word, cmds[c].name) == 0)
116 if (strncmp(word, cmds[c].name, l) == 0) {
128 /* Find a tag in an argument list. The given tag (up to the given length)
129 * must be an exact match or a unique prefix.
131 static int find_tag(struct args *args, const char *tag, int len)
136 for (i = 0; args[i].tag; i++)
137 if (args[i].tag[0] == '-') {
138 if (strncmp(tag, args[i].tag+1, len) != 0)
140 if (strlen(args[i].tag+1) == len)
150 /* Find an option in the list, return position.
151 * No prefixing is allowed
153 static int find_option(char **options, char *w)
156 for (i = 0; options[i]; i++)
157 if (strcmp(options[i], w) == 0)
162 /* Return the first word on the line, modifying the line in-place and
163 * updating *line to be ready to get the next word.
165 * Space/tab separates words. ' or " quotes words.
166 * \ protects quotes and spaces.
168 static char *take_word(char **line)
170 char *rv = *line; /* the buffer we will return - if non-empty */
171 char *lp = rv; /* the line we are examining */
172 char *wp = rv; /* the end of the word we are creating. */
173 static char *delim = " \t\n";
176 while (*lp && strchr(delim, *lp) != NULL)
179 while (*lp && (quote || strchr(delim, *lp) == NULL)) {
180 if (quote && *lp == quote) {
197 if (lp[1] == '\'' || lp[1] == '"' || lp[1] == ' ')
212 static int get_int(char *str, int *result)
217 num = strtol(str, &ep, 10);
225 /* Return an array of void* corresponding to the entries in
226 * 'args'. If an arg is present, the array entry is not NULL.
227 * For flags, the array entry will be the full flag.
228 * for --tag=, the array entry will be from after the '='
229 * for positional, the array entry will be the whole arg.
230 * where a tag can fill a positional, the value is placed in both
232 * If an arg is a subcommand, then the 'struct cmd' point is placed
233 * in the return array rather than a string.
234 * The 'args' pointer is updated to the most precise subcommand.
235 * '*offsetp' is set to the offset in the returned array of the
236 * first argument in the new 'args' list.
237 * '*lastp' is set to the last tag in 'args' that was matched.
238 * '*error' is an error message if something when astray.
240 * Named arguments can appear before, after, or among positional
243 static void **parse_line(struct args **argsp, char *line, int *offsetp,
244 int *lastp, char **error)
251 struct args *args = *argsp;
256 for (i = 0; args[i].tag; i++)
258 rv = calloc(i+offset, sizeof(char*));
261 while (!*error && (w = take_word(&line)) != NULL) {
263 /* Find the matching tag. */
269 while (*e && *e != '=')
271 n = n2 = find_tag(args, t, e-t);
273 asprintf(error, "Unrecognised option: %s", w);
278 if (args[n].pos >= 0)
280 if (rv[n+offset] != NULL || rv[n2+offset] != NULL) {
281 asprintf(error, "Duplicate option: %s", w);
286 else if (args[n].type != flag) {
287 w = take_word(&line);
290 "Missing value for --%s", t);
298 /* must be next positional */
300 args[i].tag && args[i].tag[0] != '-';
302 if (rv[i+offset] == NULL)
304 if (args[i].tag == NULL || args[i].tag[0] == '-') {
305 /* No positions left */
306 asprintf(error, "Extra positional parameter: %s", w);
310 /* If this is a subcommand arg then we need to
311 * parse the remaining args in the context of the
312 * given subcommand - if it exists.
314 switch(args[i].type) {
319 o = find_option(args[i].options, w);
321 asprintf(error, "Value %s for %s is not acceptable", w, args[i].tag);
324 c = find_cmd(args[i].subcmd, w);
332 for (i = 0; args[i].tag; i++)
334 rv = realloc(rv, (i+offset) * sizeof(void*));
335 while (size < i + offset) {
340 asprintf(error, "Unrecognised command: %s",w);
350 /* parse and execute the given command line against the given state. */
351 static int execute_line(struct state *st, char *line)
354 struct args *args = lafs_args;
358 arglist = parse_line(&args, line, NULL, NULL, &error);
361 fprintf(stderr, "lafs: %s\n", error);
366 c = (struct cmd*)arglist[0];
373 static char **complete_in_context(const char *word, int start, int end);
375 /* 'interact' is the main interface when used interactively.
376 * It reads lines using 'readline' and executes them.
377 * 'readline' is configured to provide context sensitive completion
380 static void interact(struct state *st)
383 rl_attempted_completion_function = complete_in_context;
384 rl_basic_word_break_characters = " \t\n=";
385 rl_completer_quote_characters = "\"'";
388 home = getenv("HOME");
391 asprintf(&hist, "%s/.lafs_history", home);
396 char *line = readline("LaFS: ");
405 execute_line(st, line);
412 /* 'runfile' is the alternate interface when a regular file is
413 * given with commands. It reads and executes commands until
416 static void runfile(struct state *st, FILE *f)
424 len = getline(&line, &size, f);
428 else if (execute_line(st, line) < 0)
436 int main(int argc, char *argv[])
438 struct state st = {0};
439 st.lafs = lafs_alloc();
441 if (strcmp(argv[1], "-") == 0)
444 FILE *f = fopen(argv[1], "r");
449 fprintf(stderr, "lafs: cannot open %s\n", argv[1]);
459 * Here be routines to provide context sensitive completion and
461 * Completion understands:
462 * - lists of subcommands
463 * - lists of tags for options
464 * - options that expect filenames, whether internal or external.
465 * Before listing possible matches, the description of the expected
469 /* cmd_gen is used to generate a list of matching commands.
470 * 'gen_cmds' must be initialised to point to the list.
472 static struct cmd *gen_cmds;
473 static char *cmd_gen(const char *prefix, int state)
476 int len = strlen(prefix);
479 for ( ; gen_cmds[next].name ; next++)
480 if (strncmp(prefix, gen_cmds[next].name, len) == 0) {
482 return strdup(gen_cmds[next-1].name);
487 /* tag_gen is used to generate a list of expected tags.
488 * 'gen_args' is the relevant argument list.
489 * 'gen_found' is used to determine which tags have already been given,
490 * so they are not offered again.
491 * generated tags always start "--" even if user types "-ta".
493 static struct args *gen_args;
494 static void **gen_found;
495 static char *tag_gen(const char *prefix, int state)
503 while (*prefix == '-')
505 len = strlen(prefix);
507 for ( ; gen_args[next].tag; next++) {
509 if (gen_args[next].tag[0] != '-')
513 if (gen_args[next].pos >= 0 &&
514 gen_found[gen_args[next].pos])
516 if (strncmp(prefix, gen_args[next].tag+1, len) != 0)
519 c = malloc(2 + strlen(gen_args[next].tag+1) + 2);
521 strcpy(c+2, gen_args[next].tag+1);
522 if (gen_args[next].type != flag) {
524 rl_completion_suppress_append = 1;
532 /* choice_gen is used to generate a list of possible values
533 * for a 'choice' field.
534 * 'gen_options' is the options that can go here.
536 static char **gen_options;
537 static char *choice_gen(const char *prefix, int state)
545 len = strlen(prefix);
546 for (; gen_options[next] ; next++) {
547 if (strncmp(prefix, gen_options[next], len) != 0)
550 return strdup(gen_options[next-1]);
555 static char *internal_gen(const char *prefix, int state)
558 static char *pre = NULL;
559 static struct lafs_ino *inode;
566 if (gen_state->lafs->ss.root == 0) {
567 rl_attempted_completion_over = 1;
573 pre = strdup(prefix);
574 cp = pre + strlen(pre);
575 while (cp > pre && cp[-1] != '/')
578 while (cp > pre && cp[-1] == '/')
581 /*pre is the directory, prefix is the component prefix */
582 inode = lafs_get_itable(gen_state->lafs);
583 inode = lafs_get_inode(inode, 2);
584 inode = lafs_lookup_path(inode, inode, pre, NULL);
587 if (index + 1 == 0) {
588 rl_attempted_completion_over = 1;
592 if (lafs_dir_next(inode, &index, name, &inum, &type) == 1)
595 rl_attempted_completion_over = 1;
599 * This is the brains of the completion handler.
600 * We parse the line-so-far to determine way options have already
601 * been provided, and so what is left to provide.
602 * We then look at the given prefix to determine if a positional or
603 * tag argument is most likely, and provide relevant completions.
605 static char **complete_in_context(const char *prefix, int start, int end)
607 static char *buf = NULL;
608 static int bufsize = 0;
616 char **matches = NULL;
618 while (bufsize < start+1) {
620 buf = realloc(buf, bufsize);
622 memcpy(buf, rl_line_buffer, start);
627 arglist = parse_line(&args, line, &offset, &last, &error);
630 error && strncmp(error, "Missing value for", 17) == 0) {
633 } else if (!(start && rl_line_buffer[start-1] == '='))
637 printf("\n *** %s ***\n", error);
642 if (last >= 0 && (arglist[last+offset] == NULL ||
643 ((char*)arglist[last+offset])[0] == '\0'))
647 for (p = 0; args[p].tag && args[p].tag[0] != '-' ; p++)
648 if (arglist[p+offset] == NULL)
650 if (args[p].tag == NULL || args[p].tag[0] == '-')
653 /* 'p' is the arg we expect here, either first positional arg that
654 * we haven't seen, or tag that we have "--tag=" for. */
656 if (last >= 0 || (p >= 0 && (!*prefix || *prefix != '-'))) {
657 switch(args[p].type) {
659 gen_cmds = args[p].subcmd;
660 matches = rl_completion_matches(prefix, cmd_gen);
663 matches = rl_completion_matches(
664 prefix, rl_filename_completion_function);
667 matches = rl_completion_matches(prefix, internal_gen);
670 gen_options = args[p].options;
671 matches = rl_completion_matches(
677 if (rl_completion_type == '?') {
678 printf("\n *** Please give: %s ***", args[p].desc);
684 rl_attempted_completion_over = 1;
687 if (!*prefix || *prefix == '-') {
689 gen_found = arglist + offset;
690 rl_attempted_completion_over = 1;
691 return rl_completion_matches(prefix, tag_gen);
694 printf("\n *** No further positional arguments expected:"
695 " try '-' instead ***\n");
698 rl_attempted_completion_over = 1;
702 /***********************************************************************8
703 * Here are the commands.
704 * Each command X must define
705 * static char help_X = "One line of description for the command";
707 * static struct args args_X[] = { list of arg definitions; TERMINAL_ARG};
708 * static void c_X(struct state *st, void *args) { implement command ;}
709 * and must be listed in lafs_cmds below.
712 /* common helper functions... */
713 static long long parse_size_print(char *arg, char **error, char *func, char *name)
715 long long rv = parse_size(arg, error);
717 printf("%s: %s: %s for %s\n", func, *error, arg, name);
720 static long parse_num_print(char *arg, char **error, char *func, char *name)
723 long rv = strtol(arg, &endp, 0);
724 if (!*arg || *endp) {
725 *error = "Not a valid number";
726 printf("%s: %s: %s for %s\n", func, *error, arg, name);
731 static struct lafs_ino *get_inode(struct lafs *fs, void *args[], char **err)
733 struct lafs_ino *inode;
735 if (fs->ss.root == 0) {
736 asprintf(err, "filesystem not ready for inode access");
739 inode = lafs_get_itable(fs);
741 char *inostr = args[1];
743 int ino = strtoul(inostr, &endp, 10);
744 if (endp == inostr || *endp) {
745 asprintf(err, "%s is not a valid inode number",
750 inode = lafs_get_inode(inode, ino);
752 asprintf(err, "cannot find inode %d",ino);
756 char *path = args[0];
757 inode = lafs_get_inode(inode, 2);
758 inode = lafs_lookup_path(inode, inode, path, NULL);
761 asprintf(err, "cannot find inode for %s", path);
769 static char help_exit[] = "Exit lafs";
770 static struct args args_exit[] = { TERMINAL_ARG };
771 static void c_exit(struct state *st, void **args)
776 #define help_quit help_exit
777 #define c_quit c_exit
778 #define args_quit args_exit
781 static char help_help[] = "Print help for a command or all commands";
782 static struct args args_help[] = {
783 { "COMMAND", subcommand, -1, {lafs_cmds}, "Command to display help for"},
784 { "-all", flag, -1, {NULL}, "List brief help for all commands"},
788 static void c_help(struct state *st, void **args)
791 struct cmd *cmd = args[1];
793 if (cmd == NULL && args[2] == NULL) {
794 for (c = 0; lafs_cmds[c].name; c++) {
795 printf("%-9s ", lafs_cmds[c].name);
804 printf("%s: %s\n", cmd->name, cmd->help);
805 if (cmd->args[0].tag) {
807 printf(" Usage: %s", cmd->name);
808 for (i=0; cmd->args[i].tag; i++) {
809 struct args *a = cmd->args+i;
810 if (a->tag[0] == '-') {
811 printf(" [--options...]");
814 printf(" %s", a->tag);
817 printf(" Arguments:\n");
818 for (i=0; cmd->args[i].tag; i++) {
819 struct args *a = cmd->args+i;
820 if (a->tag[0] != '-') {
821 printf(" %-15s: %s\n", a->tag, a->desc);
823 printf(" -%-14s: %s\n", a->tag, a->desc);
827 printf("-------------------------------------------\n");
828 for (c=0; lafs_cmds[c].name; c++)
829 printf("%-9s: %s\n", lafs_cmds[c].name, lafs_cmds[c].help);
833 /****** RESET ******/
834 static char help_reset[] = "Forget all fs information, and prepare to start afresh";
835 static struct args args_reset[] = {
836 { "-force", flag, -1, {NULL}, "Reset even if there are unflushed changes"},
839 static void c_reset(struct state *st, void **args)
842 if (st->lafs->blocksize == 0) {
843 printf("reset: Filesystem state is already clear\n");
847 if (args[1] == NULL &&
848 !list_empty(&st->lafs->wc[0].blocks)) {
849 printf("reset: filesystem has unflushed changes. Consider using\n"
850 " \"flush\" command of \"--force\" argument\n");
853 talloc_free(st->lafs);
854 st->lafs = lafs_alloc();
856 printf("Filesystem state has been reset\n");
860 /****** NEWFS ******/
861 static char help_newfs[] = "Create a new LaFS filesystem, which can then be stored on one or more devices.";
862 static char *block_sizes[] = { "512", "1024", "2048", "4096", NULL };
863 static char *state_sizes[] = { "512", "1024", "2048", "4096", "8192",
864 "16384", "32768", NULL };
865 static struct args args_newfs[] = {
866 { "BLOCK-SIZE", choice, -1, {.options=block_sizes},
867 "Block size, 512..4096, defaults to 1024"},
868 { "-block-size", choice, 0, {.options=block_sizes},
869 "Block size, 512..4096, defaults to 1024"},
870 { "-state-size", choice, -1, {.options=state_sizes},
871 "Size of state block, 512..32768, defaults to 1024"},
872 { "-uuid", opaque, -1, {NULL}, "UUID - normally randomly generated"},
873 { "-black", opaque, -1, {NULL}, "nothing (just testing)"},
876 static void c_newfs(struct state *st, void **args)
878 int blockbytes = 1024;
882 struct lafs_ino *ifile, *imfile, *rootdir;
883 int create_atime = 1;
885 if (st->lafs->blocksize) {
886 printf("newfs: Filesytem already has state"
887 " - consider using \"reset\"\n");
892 /* As this is a 'choice' it must be a valid number. */
893 get_int(args[1], &blockbytes);
896 /* state-size was given */
897 get_int(args[3], &state_size);
901 if (uuid_parse((char*)args[4], uu) < 0) {
902 printf("newfs: UUID in wrong format: %s\n", (char*)args[4]);
906 lafs_new(st->lafs, blockbytes);
908 st->lafs->statesize = state_size;
910 memcpy(st->lafs->uuid, uu, 16);
912 ifile = lafs_get_itable(st->lafs);
913 imfile = lafs_add_inode(ifile, 1, TypeInodeMap);
914 rootdir = lafs_add_inode(ifile, 2, TypeDir);
916 lafs_add_inode(ifile, 3, TypeAccessTime);
917 rootdir->md.file.linkcount = 2;
918 rootdir->md.file.mode = 0755;
919 rootdir->md.file.parent = 2;
920 lafs_dirty_inode(rootdir);
921 lafs_add_inode(ifile, 8, TypeOrphanList);
923 lafs_imap_set(imfile, 1);
924 lafs_imap_set(imfile, 2);
925 lafs_imap_set(imfile, 8);
927 lafs_cluster_init(st->lafs, 0, 0, 0, 1);
930 uuid_unparse(st->lafs->uuid, uuidstr);
931 printf("Filesystem has been initilised: block size %d, "
932 "state size %d\n UUID=%s\n",
933 st->lafs->blocksize, st->lafs->statesize,
939 /****** ADD_DEVICE ******/
940 static char help_add_device[] = "Add a device to the current LaFS";
941 static struct args args_add_device[] = {
942 /*1*/ { "DEVNAME", external, -1, {NULL}, "Device to store filesystem on"},
943 /*2*/ { "-file", external, 0, {NULL}, "Regular file to use like a device"},
944 /*3*/ { "-size", opaque, -1, {NULL}, "Size of regular file (K,M,G prefix allowed)"},
945 /*4*/ { "-segsize",opaque, -1, {NULL}, "Segment size for this device"},
946 /*5*/ { "-stride", opaque, -1, {NULL}, "Stride (from one member device to next)"},
947 /*6*/ { "-width", opaque, -1, {NULL}, "Width of array in data-devices"},
948 /*7*/ { "-usage_inum", opaque, -1, {NULL}, "Inode number for segment-usage file"},
951 static void c_add_device(struct state *st, void **args)
953 long block_bytes, segment_bytes = 0, stride_bytes = 0;
955 long long device_bytes = 0;
958 char *devname = args[1];
960 struct lafs_device *dev;
961 struct lafs_ino *ifile, *imfile, *segmap;
964 printf("add_device: No device or file name given to add\n");
968 block_bytes = st->lafs->blocksize;
969 if (block_bytes == 0) {
970 printf("add_device: filesystem is not ready for devices"
971 " - consider \"newfs\".\n");
975 ifile = st->lafs->ss.root;
977 printf("add_device: filesystem has no root inode - strange"
978 " - consider \"newfs\" again.\n");
982 imfile = lafs_get_inode(ifile, 1);
984 printf("add_device: Cannot find inode-map\n");
990 device_bytes = parse_size_print(args[3], &err, "add_device",
996 segment_bytes = parse_size_print(args[4], &err, "add_device",
1002 stride_bytes = parse_size_print(args[5], &err, "add_device",
1008 width = parse_num_print(args[6], &err, "add_device", "width");
1013 usage_inum = parse_num_print(args[7], &err,
1014 "add_device", "inode number");
1019 fd = open_device(devname, &device_bytes, args[2] != NULL, &err);
1022 printf("add_device: %s\n", err);
1027 err = lafs_validate_geometry(&block_bytes, &segment_bytes,
1028 &stride_bytes, &width, device_bytes);
1031 printf("add_device: %s\n", err);
1037 usage_inum = lafs_imap_alloc(imfile);
1039 if (lafs_imap_set(imfile, usage_inum) == 1) {
1040 printf("newfs: inum %d already in use.\n", usage_inum);
1044 dev = lafs_add_device(st->lafs, devname, fd,
1045 segment_bytes / block_bytes,
1046 stride_bytes / block_bytes,
1050 segmap = lafs_add_inode(ifile, usage_inum, TypeSegmentMap);
1051 if (segmap == NULL) {
1052 printf("ERROR: could not allocate segusage file.\n");
1053 st->lafs->flags |= LAFS_NEED_CHECK;
1056 dev->segsum = segmap;
1057 segmap->md.segmentusage.table_size = dev->tablesize * usage_inum;
1058 dev->tablesize = segmap->md.segmentusage.table_size;
1059 lafs_dirty_inode(segmap);
1060 lafs_imap_set(imfile, usage_inum);
1063 printf("Added device %s at %llu with %llu segments "
1064 "of %llu %dk blocks\n"
1065 " Usage inode %d\n",
1066 devname, (unsigned long long)dev->start,
1067 (unsigned long long)dev->segment_count,
1068 (unsigned long long)dev->segment_size,
1069 st->lafs->blocksize/1024, usage_inum);
1073 /****** WRITE *****/
1074 static struct cmd write_cmds[];
1076 static char help_write[] = "Write content of various structures";
1077 static struct args args_write[] = {
1078 { "STRUCT", subcommand, -1, {write_cmds}, "Structure type to write"},
1081 static void c_write(struct state *st, void **args)
1083 struct cmd *c = args[1];
1085 printf("write: Please give a structure to write\n");
1092 /****** WRITE_DEV ******/
1093 static char help_write_dev[] = "Write devices blocks to one or all devices";
1094 static struct args args_write_dev[] = {
1095 { "DEVNAME", external, -1, {NULL}, "Device to write devblocks to"},
1096 { "-all", flag, 0, {NULL}, "Write to all devices"},
1099 static void c_write_dev(struct state *st, void **args)
1101 struct lafs_device *dev;
1103 if (!args[2] && !args[3]) {
1104 printf("write dev: no device given for writing\n");
1108 for (dev = st->lafs->devs; dev; dev = dev->next) {
1109 if (args[3] || strcmp(dev->name, (char*)args[2]) == 0) {
1110 int err = lafs_write_dev(dev);
1113 printf("write dev: error when writing to %s\n",
1115 else if (st->verbose)
1116 printf("Device block written to %s\n", dev->name);
1122 printf("write dev: no devices exist to write to.\n");
1124 printf("write dev: %s is not a registered device in this LaFS.\n",
1128 /****** WRITE_STATE ******/
1129 static char help_write_state[] = "Write state blocks to all devices";
1130 static struct args args_write_state[] = {
1133 static void c_write_state(struct state *st, void **args)
1135 if (st->lafs->blocksize == 0)
1136 printf("write state: filesystem is not initialised\n");
1137 else if (st->lafs->devs == NULL)
1138 printf("write state: No devices exist to write to\n");
1139 else if (lafs_write_state(st->lafs))
1140 printf("write state: Error writing a state block\n");
1141 else if (st->verbose)
1142 printf("%s state blocks written: seq now %llu\n",
1143 (st->lafs->seq & 1) ? "Odd" : "Even",
1144 (unsigned long long) st->lafs->seq);
1147 /****** WRITE_CHECKPOINT ******/
1148 static char help_write_checkpoint[] = "Write a checkpoint with all committed blocks";
1149 static struct args args_write_checkpoint[] = {
1152 static void c_write_checkpoint(struct state *st, void **args)
1154 if (st->lafs->blocksize == 0)
1155 printf("write checkpoint: filesystem is not initialised\n");
1156 else if (st->lafs->devs == NULL)
1157 printf("write checkpoint: No devices exist to write to\n");
1158 else if (st->lafs->free_head == st->lafs->free_tail)
1159 printf("write checkpoint: No free segments - try find_free\n");
1160 else if (lafs_checkpoint(st->lafs))
1161 printf("write state: Error writing checkpoint\n");
1162 else if (st->verbose)
1163 printf("Checkpoint written: seq now %llu\n",
1164 (unsigned long long) st->lafs->seq);
1167 #define WCMD(x) {#x, c_write_##x, args_write_##x, help_write_##x}
1168 static struct cmd write_cmds[] = {
1172 { NULL, NULL, NULL, NULL}
1175 /****** LOAD_DEV ******/
1176 static char help_load_dev[] = "Allow access to LaFS filesystem stored on given device";
1177 static struct args args_load_dev[] = {
1178 { "DEVNAME", external, -1, {NULL}, "Device to load filesystem info from"},
1179 { "-file", external, 0, {NULL}, "Regular file to load filesystem info from"},
1182 static void c_load_dev(struct state *st, void **args)
1184 char *devname = args[1];
1186 long long device_bytes = 0;
1188 struct lafs_device *dev;
1191 printf("load_dev: No device of file name given to load\n");
1195 fd = open_device(devname, &device_bytes, args[2] != NULL, &err);
1198 printf("load_dev: %s\n", err);
1203 dev = lafs_load(fd, device_bytes, &err);
1206 printf("load_dev: Cannot load %s: %s\n", devname, err);
1213 dev->name = talloc_strdup(dev, devname);
1215 if (lafs_include_dev(st->lafs, dev, &err) != 0) {
1216 printf("load_dev: Cannot include %s: %s\n", devname, err);
1221 printf("loaded device %s - have %d of %d\n", devname,
1222 st->lafs->loaded_devs, st->lafs->devices);
1226 /****** MOUNT ******/
1227 static char help_mount[] = "Coalesce loaded devices into a filesystem";
1228 static struct args args_mount[] = {
1229 { "DEVNAME", external, -1, {NULL}, "Device to load and mount"},
1230 { "-file", external, 0, {NULL}, "File to load and mount"},
1231 { "-force", flag, -1, {NULL}, "Try to mount even if there are problems"},
1234 static void c_mount(struct state *st, void **args)
1238 /* Load the device first, then mount */
1239 char *devname = args[1];
1240 long long device_bytes = 0;
1242 struct lafs_device *dev;
1243 if (st->lafs->blocksize) {
1244 printf("mount: lafs already initialised - cannot load %s\n",
1248 fd = open_device(devname, &device_bytes, args[2] != NULL, &err);
1250 printf("mount: %s\n", err);
1254 dev = lafs_load(fd, device_bytes, &err);
1256 printf("mount: Cannot load %s: %s\n", devname, err);
1262 dev->name = talloc_strdup(dev, devname);
1263 if (lafs_include_dev(st->lafs, dev, &err) != 0) {
1264 printf("mount: Cannot use %s: %s\n", devname, err);
1268 printf("loaded device %s\n", devname);
1270 err = lafs_mount(st->lafs, args[3] != NULL);
1272 printf("mount: cannot mount filesystem: %s\n", err);
1274 } else if (st->verbose)
1275 printf("filesystem mounted\n");
1279 static struct cmd show_cmds[];
1281 static char help_show[] = "Show content of various structures";
1282 static struct args args_show[] = {
1283 { "STRUCT", subcommand, -1, {show_cmds}, "Structure type to show"},
1286 static void c_show(struct state *st, void **args)
1288 struct cmd *c = args[1];
1290 printf("show: Please give a structure to show\n");
1297 /****** SHOW INODE ******/
1298 static char help_show_inode[] = "Show inode given name or number";
1299 static struct args args_show_inode[] = {
1300 { "PATH", internal, -1, {NULL}, "Path to inode to show"},
1301 { "-inum", opaque, 0, {NULL}, "Inode number to show"},
1304 static void c_show_inode(struct state *st, void **args)
1306 struct lafs_ino *inode;
1309 printf("show inode: please give file name or inode number\n");
1312 inode = get_inode(st->lafs, args+2, &err);
1314 printf("show inode: %s\n", err);
1318 lafs_print_inode(inode);
1321 /****** SHOW DEVICE ******/
1322 static char help_show_device[] = "Show the device-block stored on a device";
1323 static struct args args_show_device[] = {
1324 { "DEVNAME", external, -1, {NULL}, "Device to show info for"},
1325 { "-file", external, 0, {NULL}, "File to read as a device"},
1326 { "-addr", opaque, -1, {NULL}, "Byte address to read block from"},
1329 static void c_show_device(struct state *st, void **args)
1331 struct lafs_device *dev;
1332 char *devname = args[2];
1334 long long device_bytes = 0;
1338 if (!devname && !st->lafs->devs) {
1339 printf("show device: no devices loaded - please give a device name\n");
1343 char *addrstr = args[4];
1347 printf("show device: device name must be given with address\n");
1350 addr = strtoll(addrstr, &endp, 0);
1351 if (endp == addrstr || *endp) {
1352 printf("show device: %s is not a valid number\n",
1356 fd = open_device(devname, &device_bytes, args[3] != NULL, &err);
1358 printf("show device: %s\n", err);
1362 if (lseek64(fd, addr, 0) != addr ||
1363 read(fd, &dv, sizeof(dv)) != sizeof(dv)) {
1364 printf("show device: Cannot read device block at %lld on %s\n",
1367 lafs_print_devblock(&dv);
1372 for (dev = st->lafs->devs; dev; dev = dev->next) {
1373 if (devname && strcmp(devname, dev->name) != 0)
1375 printf("Device %s: %d out of %d\n", dev->name,
1376 dev->devnum, dev->devices);
1377 lafs_print_device(dev);
1383 /* Not already loaded, try to load-and-print */
1384 fd = open_device(devname, &device_bytes, args[3] != NULL, &err);
1386 printf("show device: %s\n", err);
1390 dev = lafs_load(fd, device_bytes, &err);
1392 printf("show device: Cannot load %s: %s\n",
1399 printf("Loaded device %s, however: %s\n", devname, err);
1401 printf("Loaded device %s\n", devname);
1402 lafs_print_device(dev);
1406 /****** SHOW STATE ******/
1407 static char help_show_state[] = "Show the current fs state or content of a state block";
1408 static struct args args_show_state[] = {
1409 { "DEVNAME", external, -1, {NULL}, "Device to find state block on"},
1410 { "-file", external, 0, {NULL}, "File to read state block from"},
1411 { "-addr", opaque, -1, {NULL}, "Byte address to read block from"},
1414 static void c_show_state(struct state *st, void **args)
1418 struct lafs_device *dv;
1419 struct lafs_state *state;
1422 if (args[4] && !args[2]) {
1423 printf("show state: Cannot give address without device name\n");
1427 /* Show currently loaded state */
1428 if (!st->lafs->ss.root_addr) {
1429 printf("show state: LaFS not mounted, no state available\n");
1432 lafs_print_lafs(st->lafs);
1438 char *addrstr = args[4];
1440 long long device_bytes = 0;
1443 addr = strtoll(addrstr, &endp, 0);
1444 if (endp == addrstr || *endp) {
1445 printf("show state: %s is not a valid number\n",
1450 fd = open_device(devname, &device_bytes, args[3] != NULL, &err);
1452 printf("show state: %s\n", err);
1457 for (dv = st->lafs->devs; dv ; dv = dv->next)
1458 if (strcmp(devname, dv->name) == 0)
1462 printf("show state: device %s not loaded and no address given\n",
1467 addr = dv->stateaddr[dv->recent_state];
1469 state = malloc(st->lafs->statesize);
1470 if (lseek64(fd, addr, 0) != addr ||
1471 read(fd, state, st->lafs->statesize) != st->lafs->statesize) {
1472 printf("show state: cannot load state block\n");
1475 lafs_print_state(state, st->lafs->statesize);
1481 /****** SHOW CLUSTER ******/
1482 static char help_show_cluster[] = "Show one or more cluster headers";
1483 static struct args args_show_cluster[] = {
1484 { "ADDR", opaque, -1, {NULL}, "Virtual address of cluster to display"},
1485 { "-verbose", flag, -1, {NULL}, "Show fine detail of descriptors"},
1486 { "-segment", flag, -1, {NULL}, "Show all following clusters in segment"},
1487 { "-checkpoint", flag, -1, {NULL}, "Show following clusters in checkpoint"},
1488 { "-reverse", flag, -1, {NULL}, "Follow backward chain rather than forward"},
1489 { "-n", opaque, -1, {NULL}, "Show this many clusters"},
1492 static void c_show_cluster(struct state *st, void **args)
1494 long long start, addr;
1500 if (!st->lafs->blocksize) {
1501 printf("show cluster: lafs not ready to find clusters\n");
1505 if (args[2] == NULL)
1506 start = st->lafs->checkpoint_cluster;
1508 char *addrstr = args[2];
1510 start = strtoll(addrstr, &endp, 0);
1511 if (endp == addrstr || *endp) {
1512 printf("show cluster: %s is not a valid address\n", addrstr);
1517 char *nstr = args[7];
1519 max = strtoll(nstr, &endp, 0);
1520 if (endp == nstr || *endp) {
1521 printf("show cluster: %s is not a valid number\n", nstr);
1530 struct cluster_head *ch;
1532 int err = lafs_load_cluster(st->lafs, addr, &ch);
1534 printf("show cluster: read error at %llu\n",
1535 (unsigned long long) addr);
1540 lafs_print_cluster(ch, st->lafs->blocksize, 0, 1);
1541 printf("(bad cluster header)\n");
1545 lafs_print_cluster(ch, st->lafs->blocksize, 1, verbose);
1549 addr = __le64_to_cpu(ch->prev_addr);
1551 addr = __le64_to_cpu(ch->next_addr);
1555 loff_t seg1, seg2, off1, off2;
1556 virttoseg(st->lafs, start, &dev1, &seg1, &off1);
1557 virttoseg(st->lafs, addr, &dev2, &seg2, &off2);
1558 if (dev1 == dev2 && seg1 == seg2)
1560 /* Avoid going in wrong direction */
1570 int f = __le32_to_cpu(ch->flags);
1571 if (f & CH_Checkpoint) {
1572 if (args[6] && !(f & CH_CheckpointStart))
1574 if (!args[6] && !(f & CH_CheckpointEnd))
1578 if (max && cnt < max)
1586 /****** SHOW DIRBLOCK ******/
1587 static char help_show_dirblock[] = "Show the detailed contents of directory block";
1588 static struct args args_show_dirblock[] = {
1589 { "BLOCK", opaque, -1, {NULL}, "Block number in file or LaFS"},
1590 { "PATH", internal, -1, {NULL}, "Path of directory containing block"},
1591 { "-inum", opaque, 1, {NULL}, "Inode number containing block"},
1594 static void c_show_dirblock(struct state *st, void **args)
1598 char *bstr = args[2];
1601 printf("show dirblock: no block number given\n");
1604 if (get_int(bstr, &bnum) < 0) {
1605 printf("show dirblock: %s is not a valid address\n", bstr);
1608 if (!st->lafs->blocksize) {
1609 printf("show dirblock: LaFS not ready to show blocks\n");
1614 struct lafs_dblk *db;
1615 struct lafs_ino *inode = get_inode(st->lafs, args+3, &err);
1617 printf("show dirblock: %s\n", err);
1621 db = lafs_dblk(inode, bnum);
1622 if (lafs_load_dblk(db)) {
1623 printf("show dirblock: cannot load block %d of inode %d\n",
1629 buf = malloc(st->lafs->blocksize);
1630 if (lafs_read_virtual(st->lafs, buf, bnum)) {
1631 printf("show dirblock: cannot read block at %d\n", bnum);
1636 lafs_dir_print(buf, st->lafs->blockbits-8);
1641 /****** SHOW SEGUSAGE ******/
1642 static char help_show_segusage[] = "Show counts in segusage block";
1643 static struct args args_show_segusage[] = {
1644 { "BLOCK", opaque, -1, {NULL}, "Block number in file or LaFS"},
1647 static void c_show_segusage(struct state *st, void **args)
1651 char *bstr = args[2];
1654 printf("show segusage: no block number given\n");
1657 if (get_int(bstr, &bnum) < 0) {
1658 printf("show segusage: %s is not a valid address\n", bstr);
1661 if (!st->lafs->blocksize) {
1662 printf("show segusage: LaFS not ready to show blocks\n");
1666 buf = malloc(st->lafs->blocksize);
1667 if (lafs_read_virtual(st->lafs, buf, bnum)) {
1668 printf("show segusage: cannot read block at %d\n", bnum);
1673 lafs_print_segusage(buf, st->lafs->blocksize, 0, st->lafs->blocksize);
1678 #define SCMD(x) {#x, c_show_##x, args_show_##x, help_show_##x}
1679 static struct cmd show_cmds[] = {
1686 { NULL, NULL, NULL, NULL}
1689 /****** STORE ******/
1690 static char help_store[] = "Create a file in the LaFS from an external file";
1691 static struct args args_store[] = {
1692 { "FROM", external, -1, {NULL}, "File to copy into LaFS"},
1693 { "TO", internal, -1, {NULL}, "Where to store file in LaFS"},
1694 { "-from", external, 0, {NULL}, "File to copy into LaFS"},
1697 static void c_store(struct state *st, void **args)
1699 char *from = args[1];
1701 struct lafs_ino *dir, *fs, *imfile, *inode;
1708 printf("ERROR: Source file is missing\n");
1712 printf("ERROR: destination file name is missing\n");
1716 fs = lafs_get_itable(st->lafs);
1717 dir = lafs_get_inode(fs, 2);
1718 dir = lafs_lookup_path(dir, dir, to, &tail);
1720 printf("store: lookup error in %s\n",to);
1724 printf("store: %s already exists\n", to);
1727 if (dir->type != TypeDir) {
1729 printf("store: non-directory found at %s\n", to);
1732 if (strchr(tail, '/') != NULL) {
1733 printf("store: non-final name does not exist: %s\n", tail);
1737 fd = open(from, O_RDONLY);
1739 printf("store: Cannot open %s: %s\n", from, strerror(errno));
1743 imfile = lafs_get_inode(fs, 1);
1744 inum = lafs_imap_alloc(imfile);
1745 inode = lafs_add_inode(fs, inum, TypeFile);
1746 lafs_dir_add(dir, tail, inum, lafs_dt_type(inode));
1747 inode->md.file.linkcount = 1;
1748 lafs_dirty_inode(inode);
1752 struct lafs_dblk *db = lafs_dblk(inode, bnum);
1753 int n = read(fd, db->b.data, st->lafs->blocksize);
1756 inode->md.file.size = (bnum << st->lafs->blockbits) + n;
1757 db->b.flags |= B_Valid;
1762 printf("Created %s as inode %d in %d\n", tail, inum, dir->inum);
1766 //static char *types[16] = { "unknown","FIFO","CHR","3","DIR","5","BLK","7","REG","9","LNK","11","SOCK","13","WHT","15"};
1767 static char ctypes[] = "?pc3d5b7-9lBsDWF";
1768 static char help_ls[] = "List files in a directory";
1769 static struct args args_ls[] = {
1770 {"DIRECTORY", internal, -1, {NULL}, "Directory to list"},
1771 {"-inum", opaque, 0, {NULL}, "Inode number of directory to list"},
1772 {"-long", flag, -1, {NULL}, "Get a long, detailed listing"},
1775 static void c_ls(struct state *st, void **args)
1777 struct lafs_ino *ino;
1784 char *path = args[1];
1787 args[1] = path = "";
1788 ino = get_inode(st->lafs, args+1, &err);
1790 printf("ls: %s\n", err);
1795 if (ino->type != TypeDir) {
1796 printf("ls: %s exists but is not a directory\n", path);
1800 while (lafs_dir_next(ino, &index, name, &inum, &type) == 1) {
1802 printf("%5lu %cxxxxxxxxx %s\n",
1803 (unsigned long)inum, ctypes[type], name);
1805 printf("%-12s ", name);
1815 if (args[3] == NULL && col)
1819 /****** FLUSH ******/
1820 static char help_flush[] = "Flush out all changes to one or all files";
1821 static struct args args_flush[] = {
1822 { "PATH", internal, -1, {NULL}, "Path to inode to flush"},
1823 { "-inum", opaque, 0, {NULL}, "Inode number to flush"},
1826 static void c_flush(struct state *st, void **args)
1828 struct lafs_ino *inode;
1831 lafs_flush(st->lafs);
1832 lafs_cluster_flush(st->lafs, 0);
1834 printf("Filesystem flushed\n");
1837 inode = get_inode(st->lafs, args+1, &err);
1839 printf("flush: %s\n", err);
1843 lafs_flush_inode(inode);
1844 lafs_cluster_flush(st->lafs, 0);
1846 printf("Inode %d flushed\n", (int)inode->inum);
1849 /****** TRACE ******/
1850 static char help_trace[] = "Control internal tracing";
1851 static struct args args_trace[] = {
1852 { "LEVEL", opaque, -1, {NULL}, "New tracing verbosity level"},
1855 static void c_trace(struct state *st, void **args)
1857 char *levelstr = args[1];
1859 extern int lafs_trace_level;
1860 int old = lafs_trace_level;
1862 if (get_int(levelstr, &level) < 0) {
1863 printf("trace: %s not a valid number\n", levelstr);
1869 printf("Tracing unchanged at %d\n", old);
1871 printf("Tracing change from %d to %d\n", old, level);
1873 lafs_trace_level = level;
1876 /****** SOURCE ******/
1877 static char help_source[] = "Read commands from a file";
1878 static struct args args_source[] = {
1879 { "FILE", external, -1, {NULL}, "File to read commands from"},
1882 static void c_source(struct state *st, void *args[])
1884 char *fname = args[1];
1887 printf("source: no file name given\n");
1890 f = fopen(fname, "r");
1898 printf("source: cannot open %s\n", fname);
1901 /***********************************************************/
1902 /* list of all commands - preferably in alphabetical order */
1903 #define CMD(x) {#x, c_##x, args_##x, help_##x}
1904 static struct cmd lafs_cmds[] = {
1905 {"?", c_help, args_help, help_help},
1921 { NULL, NULL, NULL, NULL}
1924 static struct args lafs_args[] = {
1925 { "COMMAND", subcommand, -1, {lafs_cmds}, "Command for lafs to execute"},