]> git.neil.brown.name Git - lafs-utils.git/blob - tools/lafs.c
Show seguage
[lafs-utils.git] / tools / lafs.c
1 /*
2  * lafs - Examine and manipulate and LaFS image
3  *
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.
10  *
11  * Copyright (C) 2011 NeilBrown <neil@brown.name>
12  *
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.
17  *
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.
22  *
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
26  *
27  *    Author: Neil Brown
28  *    Email: <neil@brown.name>
29  *
30  */
31
32 #define _GNU_SOURCE
33 #include <sys/types.h>
34 #include <unistd.h>
35 #include <stdlib.h>
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <getopt.h>
39 #include <stdio.h>
40 #include <errno.h>
41 #include <readline/readline.h>
42 #include <readline/history.h>
43 #include <lafs/lafs.h>
44 #include <talloc.h>
45 #include <uuid/uuid.h>
46 #include "internal.h"
47
48 /* This is the global state which is passed around among
49  * the various commands.
50  */
51 struct state {
52         struct lafs *lafs;
53         int done;
54         int verbose;
55 };
56
57 static struct state *gen_state;
58
59 /* Every command can have arguments, both positional and
60  * named.
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.
72  * types are:
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.
80  */
81 enum argtype { flag, opaque, choice, external, internal, subcommand};
82 static struct args {
83         char *tag;
84         enum argtype type;
85         int pos;
86         union { struct cmd *subcmd; char **options; };
87         char *desc;
88 } lafs_args[];
89 #define TERMINAL_ARG {NULL, opaque, 0, {NULL}, NULL}
90
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.
96  */
97 static struct cmd {
98         char *name;
99         void (*cmd)(struct state *st, void **args);
100         struct args *args;
101         char *help;
102 } lafs_cmds[];
103
104 /* Find a command in a list.  The word must be an exact match, or
105  * a unique prefix.
106  */
107 static struct cmd *find_cmd(struct cmd *cmds, char *word)
108 {
109         int c;
110         int l = strlen(word);
111         int best = -1;
112
113         for (c = 0; cmds[c].name; c++) {
114                 if (strcmp(word, cmds[c].name) == 0)
115                         return cmds+c;
116                 if (strncmp(word, cmds[c].name, l) == 0) {
117                         if (best == -1)
118                                 best = c;
119                         else
120                                 best = -2;
121                 }
122         }
123         if (best < 0)
124                 return NULL;
125         return cmds + best;
126 }
127
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.
130  */
131 static int find_tag(struct args *args, const char *tag, int len)
132 {
133         int i;
134         int best = -1;
135
136         for (i = 0; args[i].tag; i++)
137                 if (args[i].tag[0] == '-') {
138                         if (strncmp(tag, args[i].tag+1, len) != 0)
139                                 continue;
140                         if (strlen(args[i].tag+1) == len)
141                                 return i;
142                         if (best == -1)
143                                 best = i;
144                         else
145                                 best = -2;
146                 }
147         return best;
148 }
149
150 /* Find an option in the list, return position.
151  * No prefixing is allowed
152  */
153 static int find_option(char **options, char *w)
154 {
155         int i;
156         for (i = 0; options[i]; i++)
157                 if (strcmp(options[i], w) == 0)
158                         return i;
159         return -1;
160 }
161
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.
164  *
165  * Space/tab separates words.  ' or " quotes words.
166  * \ protects quotes and spaces.
167  */
168 static char *take_word(char **line)
169 {
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";
174         char quote = '\0';
175
176         while (*lp && strchr(delim, *lp) != NULL)
177                 lp++;
178
179         while (*lp && (quote || strchr(delim, *lp) == NULL)) {
180                 if (quote && *lp == quote) {
181                         lp++;
182                         continue;
183                 }
184                 switch(*lp) {
185                 case '\'':
186                 case '"':
187                         if (quote == *lp) {
188                                 quote = '\0';
189                                 continue;
190                         }
191                         if (!quote) {
192                                 quote = *lp++;
193                                 continue;
194                         }
195                         break;
196                 case '\\':
197                         if (lp[1] == '\'' || lp[1] == '"' || lp[1] == ' ')
198                                 lp++;
199                         break;
200                 }
201                 *wp++ = *lp++;
202         }
203         if (*lp)
204                 lp++;
205         *line = lp;
206         *wp = '\0';
207         if (wp > rv)
208                 return rv;
209         return NULL;
210 }
211
212 static int get_int(char *str, int *result)
213 {
214         long int num;
215         char *ep;
216
217         num = strtol(str, &ep, 10);
218         if (*str && !*ep) {
219                 *result = num;
220                 return 0;
221         }
222         return -1;
223 }
224
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
231  * slots.
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.
239  *
240  * Named arguments can appear before, after, or among positional
241  * arguments.
242  */
243 static void **parse_line(struct args **argsp, char *line, int *offsetp,
244                          int *lastp, char **error)
245 {
246         void **rv;
247         int i;
248         char *w;
249         int offset = 0;
250         int size;
251         struct args *args = *argsp;
252
253         if (lastp)
254                 *lastp = -1;
255
256         for (i = 0; args[i].tag; i++)
257                 ;
258         rv = calloc(i+offset, sizeof(char*));
259         size = i+offset;
260
261         while (!*error && (w = take_word(&line)) != NULL) {
262                 if (*w == '-') {
263                         /* Find the matching tag. */
264                         char *t = w, *e;
265                         int n, n2;
266                         while (*t == '-')
267                                 t++;
268                         e = t;
269                         while (*e && *e != '=')
270                                 e++;
271                         n = n2 = find_tag(args, t, e-t);
272                         if (n < 0) {
273                                 asprintf(error, "Unrecognised option: %s", w);
274                                 break;
275                         }
276                         if (lastp)
277                                 *lastp = n;
278                         if (args[n].pos >= 0)
279                                 n2 = args[n].pos;
280                         if (rv[n+offset] != NULL || rv[n2+offset] != NULL) {
281                                 asprintf(error, "Duplicate option: %s", w);
282                                 break;
283                         } else {
284                                 if (*e == '=')
285                                         w = e+1;
286                                 else if (args[n].type != flag) {
287                                         w = take_word(&line);
288                                         if (!w) {
289                                                 asprintf(error,
290                                                          "Missing value for --%s", t);
291                                                 break;
292                                         }
293                                 }
294                                 rv[n+offset] = w;
295                                 rv[n2+offset] = w;
296                         }
297                 } else {
298                         /* must be next positional */
299                         for (i=0;
300                              args[i].tag && args[i].tag[0] != '-';
301                              i++)
302                                 if (rv[i+offset] == NULL)
303                                         break;
304                         if (args[i].tag == NULL || args[i].tag[0] == '-') {
305                                 /* No positions left */
306                                 asprintf(error, "Extra positional parameter: %s", w);
307                                 break;
308                         }
309                         rv[i+offset] = 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.
313                          */
314                         switch(args[i].type) {
315                                 struct cmd *c;
316                                 int o;
317                         default: break;
318                         case choice:
319                                 o = find_option(args[i].options, w);
320                                 if (o < 0)
321                                         asprintf(error, "Value %s for %s is not acceptable", w, args[i].tag);
322                                 break;
323                         case subcommand:
324                                 c = find_cmd(args[i].subcmd, w);
325                                 rv[i+offset] = c;
326                                 if (c) {
327                                         args = c->args;
328                                         *argsp = args;
329                                         offset += i+1;
330                                         if (lastp)
331                                                 *lastp = -1;
332                                         for (i = 0; args[i].tag; i++)
333                                                 ;
334                                         rv = realloc(rv, (i+offset) * sizeof(void*));
335                                         while (size < i + offset) {
336                                                 rv[size] = NULL;
337                                                 size++;
338                                         }
339                                 } else
340                                         asprintf(error, "Unrecognised command: %s",w);
341                                 break;
342                         }
343                 }
344         }
345         if (offsetp)
346                 *offsetp = offset;
347         return rv;
348 }
349
350 /* parse and execute the given command line against the given state. */
351 static int execute_line(struct state *st, char *line)
352 {
353         struct cmd *c;
354         struct args *args = lafs_args;
355         void **arglist;
356         char *error = NULL;
357
358         arglist = parse_line(&args, line, NULL, NULL, &error);
359         
360         if (error) {
361                 fprintf(stderr, "lafs: %s\n", error);
362                 free(error);
363                 free(arglist);
364                 return -1;
365         }
366         c = (struct cmd*)arglist[0];
367         if (c)
368                 c->cmd(st, arglist);
369         free(arglist);
370         return 1;
371 }
372
373 static char **complete_in_context(const char *word, int start, int end);
374
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
378  * and help.
379  */
380 static void interact(struct state *st)
381 {
382         char *home, *hist;
383         rl_attempted_completion_function = complete_in_context;
384         rl_basic_word_break_characters = " \t\n=";
385         rl_completer_quote_characters = "\"'";
386         rl_initialize();
387
388         home = getenv("HOME");
389         if (!home)
390                 home = ".";
391         asprintf(&hist, "%s/.lafs_history", home);
392         read_history(hist);
393         
394         gen_state = st;
395         while (!st->done) {
396                 char *line = readline("LaFS: ");
397
398                 if (!line) {
399                         printf("\n");
400                         break;
401                 }
402
403                 if (*line)
404                         add_history(line);
405                 execute_line(st, line);
406
407                 free(line);
408         }
409         write_history(hist);
410 }
411
412 /* 'runfile' is the alternate interface when a regular file is
413  * given with commands.  It reads and executes commands until
414  * it finds an error.
415  */
416 static void runfile(struct state *st, FILE *f)
417 {
418
419         while (!st->done) {
420                 char *line = NULL;
421                 ssize_t len;
422                 size_t size;
423
424                 len = getline(&line, &size, f);
425
426                 if (len <= 0)
427                         st->done = 1;
428                 else if (execute_line(st, line) < 0)
429                         st->done = 1;
430
431                 free(line);
432         }
433 }
434
435
436 int main(int argc, char *argv[])
437 {
438         struct state st = {0};
439         st.lafs = lafs_alloc();
440         if (argc > 1) {
441                 if (strcmp(argv[1], "-") == 0)
442                         runfile(&st, stdin);
443                 else {
444                         FILE *f = fopen(argv[1], "r");
445                         if (f) {
446                                 runfile(&st, f);
447                                 fclose(f);
448                         } else
449                                 fprintf(stderr, "lafs: cannot open %s\n", argv[1]);
450                 }
451         } else {
452                 st.verbose = 1;
453                 interact(&st);
454         }
455         exit(0);
456 }
457
458 /*
459  * Here be routines to provide context sensitive completion and
460  * help.
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
466  * option is given.
467  */
468
469 /* cmd_gen is used to generate a list of matching commands.
470  * 'gen_cmds' must be initialised to point to the list.
471  */
472 static struct cmd *gen_cmds;
473 static char *cmd_gen(const char *prefix, int state)
474 {
475         static int next;
476         int len = strlen(prefix);
477         if (state == 0)
478                 next = 0;
479         for ( ; gen_cmds[next].name ; next++)
480                 if (strncmp(prefix, gen_cmds[next].name, len) == 0) {
481                         next++;
482                         return strdup(gen_cmds[next-1].name);
483                 }
484         return NULL;
485 }
486
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".
492  */
493 static struct args *gen_args;
494 static void **gen_found;
495 static char *tag_gen(const char *prefix, int state)
496 {
497         static int next;
498         int len;
499
500         if (state == 0)
501                 next = 0;
502
503         while (*prefix == '-')
504                 prefix++;
505         len = strlen(prefix);
506
507         for ( ; gen_args[next].tag; next++) {
508                 char *c;
509                 if (gen_args[next].tag[0] != '-')
510                         continue;
511                 if (gen_found[next])
512                         continue;
513                 if (gen_args[next].pos >= 0 &&
514                     gen_found[gen_args[next].pos])
515                         continue;
516                 if (strncmp(prefix, gen_args[next].tag+1, len) != 0)
517                         continue;
518
519                 c = malloc(2 + strlen(gen_args[next].tag+1) + 2);
520                 strcpy(c, "--");
521                 strcpy(c+2, gen_args[next].tag+1);
522                 if (gen_args[next].type != flag) {
523                         strcat(c, "=");
524                         rl_completion_suppress_append = 1;
525                 }
526                 next++;
527                 return c;
528         }
529         return NULL;
530 }
531
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.
535  */
536 static char **gen_options;
537 static char *choice_gen(const char *prefix, int state)
538 {
539         static int next;
540         int len;
541
542         if (state == 0)
543                 next = 0;
544
545         len = strlen(prefix);
546         for (; gen_options[next] ; next++) {
547                 if (strncmp(prefix, gen_options[next], len) != 0)
548                         continue;
549                 next++;
550                 return strdup(gen_options[next-1]);
551         }
552         return NULL;
553 }
554
555 static char *internal_gen(const char *prefix, int state)
556 {
557         static char *cp;
558         static char *pre = NULL;
559         static struct lafs_ino *inode;
560         static u32 index;
561
562         u32 inum;
563         int type;
564         char name[257];
565
566         if (gen_state->lafs->ss.root == 0) {
567                 rl_attempted_completion_over = 1;
568                 return NULL;
569         }
570         if (state == 0) {
571                 if (pre)
572                         free(pre);
573                 pre = strdup(prefix);
574                 cp = pre + strlen(pre);
575                 while (cp > pre && cp[-1] != '/')
576                         cp--;
577                 prefix = cp;
578                 while (cp > pre && cp[-1] == '/')
579                         cp--;
580                 cp[0] = 0;
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);
585                 index = -1;
586         } else {
587                 if (index + 1 == 0) {
588                         rl_attempted_completion_over = 1;
589                         return NULL;
590                 }
591         }
592         if (lafs_dir_next(inode, &index, name, &inum, &type) == 1)
593                 return strdup(name);
594
595         rl_attempted_completion_over = 1;
596         return NULL;
597 }
598 /*
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.
604  */
605 static char **complete_in_context(const char *prefix, int start, int end)
606 {
607         static char *buf = NULL;
608         static int bufsize = 0;
609
610         char *line;
611         void **arglist;
612         struct args *args;
613         int offset, last;
614         int p;
615         char *error = NULL;
616         char **matches = NULL;
617
618         while (bufsize < start+1) {
619                 bufsize += 80;
620                 buf = realloc(buf, bufsize);
621         }
622         memcpy(buf, rl_line_buffer, start);
623         buf[start] = 0;
624         line = buf;
625
626         args = lafs_args;
627         arglist = parse_line(&args, line, &offset, &last, &error);
628
629         if (last >= 0 &&
630             error && strncmp(error, "Missing value for", 17) == 0) {
631                 free(error);
632                 error = 0;
633         } else if (!(start && rl_line_buffer[start-1] == '='))
634                 last = -1;
635
636         if (error) {
637                 printf("\n *** %s ***\n", error);
638                 free(error);
639                 goto after_message;
640         }
641
642         if (last >= 0 && (arglist[last+offset] == NULL ||
643                           ((char*)arglist[last+offset])[0] == '\0'))
644                 p = last;
645         else {
646                 last = -1;
647                 for (p = 0; args[p].tag && args[p].tag[0] != '-' ; p++)
648                         if (arglist[p+offset] == NULL)
649                                 break;
650                 if (args[p].tag == NULL || args[p].tag[0] == '-')
651                         p = -1;
652         }
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. */
655
656         if (last >= 0 || (p >= 0 && (!*prefix || *prefix != '-'))) {
657                 switch(args[p].type) {
658                 case subcommand:
659                         gen_cmds = args[p].subcmd;
660                         matches = rl_completion_matches(prefix, cmd_gen);
661                         break;
662                 case external:
663                         matches = rl_completion_matches(
664                                 prefix, rl_filename_completion_function);
665                         break;
666                 case internal:
667                         matches = rl_completion_matches(prefix, internal_gen);
668                         break;
669                 case choice:
670                         gen_options = args[p].options;
671                         matches = rl_completion_matches(
672                                 prefix, choice_gen);
673                         break;
674                 default:
675                         break;
676                 }
677                 if (rl_completion_type == '?') {
678                         printf("\n *** Please give: %s ***", args[p].desc);
679                         if (!matches) {
680                                 printf("\n");
681                                 rl_on_new_line();
682                         }
683                 }
684                 rl_attempted_completion_over = 1;
685                 return matches;
686         }
687         if (!*prefix || *prefix == '-') {
688                 gen_args = args;
689                 gen_found = arglist + offset;
690                 rl_attempted_completion_over = 1;
691                 return rl_completion_matches(prefix, tag_gen);
692         }
693
694         printf("\n *** No further positional arguments expected:"
695                " try '-' instead ***\n");
696 after_message:
697         rl_on_new_line();
698         rl_attempted_completion_over = 1;
699         return NULL;
700 }
701
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";
706
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.
710  */
711
712 /* common helper functions... */
713 static long long parse_size_print(char *arg, char **error, char *func, char *name)
714 {
715         long long rv = parse_size(arg, error);
716         if (*error)
717                 printf("%s: %s: %s for %s\n", func, *error, arg, name);
718         return rv;
719 }
720 static long parse_num_print(char *arg, char **error, char *func, char *name)
721 {
722         char *endp;
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);
727         }
728         return rv;
729 }
730
731 static struct lafs_ino *get_inode(struct lafs *fs, void *args[], char **err)
732 {
733         struct lafs_ino *inode;
734         *err = NULL;
735         if (fs->ss.root == 0) {
736                 asprintf(err, "filesystem not ready for inode access");
737                 return NULL;
738         }
739         inode = lafs_get_itable(fs);
740         if (args[1]) {
741                 char *inostr = args[1];
742                 char *endp;
743                 int ino = strtoul(inostr, &endp, 10);
744                 if (endp == inostr || *endp) {
745                         asprintf(err, "%s is not a valid inode number",
746                                  inostr);
747                         return NULL;
748                 }
749                 if (ino)
750                         inode = lafs_get_inode(inode, ino);
751                 if (!inode) {
752                         asprintf(err, "cannot find inode %d",ino);
753                         return NULL;
754                 }
755         } else {
756                 char *path = args[0];
757                 inode = lafs_get_inode(inode, 2);
758                 inode = lafs_lookup_path(inode, inode, path, NULL);
759
760                 if (!inode) {
761                         asprintf(err, "cannot find inode for %s", path);
762                         return NULL;
763                 }
764         }
765         return inode;
766 }
767
768 /****** EXIT ******/
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)
772 {
773         st->done = 1;
774 }
775 /****** QUIT ******/
776 #define help_quit help_exit
777 #define c_quit c_exit
778 #define args_quit args_exit
779
780 /****** HELP ******/
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"},
785         TERMINAL_ARG
786 };
787
788 static void c_help(struct state *st, void **args)
789 {
790         int c;
791         struct cmd *cmd = args[1];
792
793         if (cmd == NULL && args[2] == NULL) {
794                 for (c = 0; lafs_cmds[c].name; c++) {
795                         printf("%-9s ", lafs_cmds[c].name);
796                         if ((c%8)==7)
797                                 printf("\n");
798                 }
799                 printf("\n");
800                 return;
801         }
802
803         if (cmd) {
804                 printf("%s: %s\n", cmd->name, cmd->help);
805                 if (cmd->args[0].tag) {
806                         int i;
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...]");
812                                         break;
813                                 }
814                                 printf(" %s", a->tag);
815                         }
816                         printf("\n");
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);
822                                 } else
823                                         printf("  -%-14s: %s\n", a->tag, a->desc);
824                         }
825                 }
826         } else {
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);
830         }
831 }
832
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"},
837         TERMINAL_ARG
838 };
839 static void c_reset(struct state *st, void **args)
840 {
841
842         if (st->lafs->blocksize == 0) {
843                 printf("reset: Filesystem state is already clear\n");
844                 return;
845         }
846
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");
851                 return;
852         }
853         talloc_free(st->lafs);
854         st->lafs = lafs_alloc();
855         if (st->verbose)
856                 printf("Filesystem state has been reset\n");
857 }
858
859
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)"},
874         TERMINAL_ARG
875 };
876 static void c_newfs(struct state *st, void **args)
877 {
878         int blockbytes = 1024;
879         int state_size = 0;
880         char uuidstr[37];
881         uuid_t uu;
882         struct lafs_ino *ifile, *imfile, *rootdir;
883         int create_atime = 1;
884
885         if (st->lafs->blocksize) {
886                 printf("newfs: Filesytem already has state"
887                        " - consider using \"reset\"\n");
888                 return;
889         }
890
891         if (args[1])
892                 /* As this is a 'choice' it must be a valid number. */
893                 get_int(args[1], &blockbytes);
894
895         if (args[3]) {
896                 /* state-size was given */
897                 get_int(args[3], &state_size);
898         }
899         if (args[4]) {
900                 /* uuid was given */
901                 if (uuid_parse((char*)args[4], uu) < 0) {
902                         printf("newfs: UUID in wrong format: %s\n", (char*)args[4]);
903                         return;
904                 }
905         }
906         lafs_new(st->lafs, blockbytes);
907         if (state_size)
908                 st->lafs->statesize = state_size;
909         if (args[4])
910                 memcpy(st->lafs->uuid, uu, 16);
911
912         ifile = lafs_get_itable(st->lafs);
913         imfile = lafs_add_inode(ifile, 1, TypeInodeMap);
914         rootdir = lafs_add_inode(ifile, 2, TypeDir);
915         if (create_atime)
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);
922
923         lafs_imap_set(imfile, 1);
924         lafs_imap_set(imfile, 2);
925         lafs_imap_set(imfile, 8);
926
927         lafs_cluster_init(st->lafs, 0, 0, 0, 1);
928
929         if (st->verbose) {
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,
934                        uuidstr);
935         }
936         return;
937 }
938
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"},
949         TERMINAL_ARG
950 };
951 static void c_add_device(struct state *st, void **args)
952 {
953         long block_bytes, segment_bytes = 0, stride_bytes = 0;
954         int width = 0;
955         long long device_bytes = 0;
956         int usage_inum = 0;
957         char *err = NULL;
958         char *devname = args[1];
959         int fd;
960         struct lafs_device *dev;
961         struct lafs_ino *ifile, *imfile, *segmap;
962
963         if (!devname) {
964                 printf("add_device: No device or file name given to add\n");
965                 return;
966         }
967
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");
972                 return;
973         }
974
975         ifile = st->lafs->ss.root;
976         if (!ifile) {
977                 printf("add_device: filesystem has no root inode - strange"
978                        " - consider \"newfs\" again.\n");
979                 return;
980         }
981
982         imfile = lafs_get_inode(ifile, 1);
983         if (!imfile) {
984                 printf("add_device: Cannot find inode-map\n");
985                 return;
986         }
987         
988
989         if (args[3]) {
990                 device_bytes = parse_size_print(args[3], &err, "add_device",
991                                            "file size");
992                 if (err)
993                         return;
994         }
995         if (args[4]) {
996                 segment_bytes = parse_size_print(args[4], &err, "add_device",
997                                            "segment size");
998                 if (err)
999                         return;
1000         }
1001         if (args[5]) {
1002                 stride_bytes = parse_size_print(args[5], &err, "add_device",
1003                                           "stride size");
1004                 if (err)
1005                         return;
1006         }
1007         if (args[6]) {
1008                 width = parse_num_print(args[6], &err, "add_device", "width");
1009                 if (err)
1010                         return;
1011         }
1012         if (args[7]) {
1013                 usage_inum = parse_num_print(args[7], &err,
1014                                              "add_device", "inode number");
1015                 if (err)
1016                         return;
1017         }
1018
1019         fd = open_device(devname, &device_bytes, args[2] != NULL, &err);
1020
1021         if (fd < 0) {
1022                 printf("add_device: %s\n", err);
1023                 free(err);
1024                 return;
1025         }
1026
1027         err = lafs_validate_geometry(&block_bytes, &segment_bytes,
1028                                      &stride_bytes, &width, device_bytes);
1029
1030         if (err) {
1031                 printf("add_device: %s\n", err);
1032                 free(err);
1033                 return;
1034         }
1035
1036         if (!usage_inum) {
1037                 usage_inum = lafs_imap_alloc(imfile);
1038         } else {
1039                 if (lafs_imap_set(imfile, usage_inum) == 1) {
1040                         printf("newfs: inum %d already in use.\n", usage_inum);
1041                         return;
1042                 }
1043         }
1044         dev = lafs_add_device(st->lafs, devname, fd,
1045                               segment_bytes / block_bytes,
1046                               stride_bytes / block_bytes,
1047                               width,
1048                               usage_inum);
1049
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;
1054                 return;
1055         }
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);
1061
1062         if (st->verbose)
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);
1070
1071 }
1072
1073 /****** WRITE *****/
1074 static struct cmd write_cmds[];
1075
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"},
1079         TERMINAL_ARG
1080 };
1081 static void c_write(struct state *st, void **args)
1082 {
1083         struct cmd *c = args[1];
1084         if (!c) {
1085                 printf("write: Please give a structure to write\n");
1086                 return;
1087         }
1088
1089         c->cmd(st, args);
1090 }
1091
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"},
1097         TERMINAL_ARG
1098 };
1099 static void c_write_dev(struct state *st, void **args)
1100 {
1101         struct lafs_device *dev;
1102         int found = 0;
1103         if (!args[2] && !args[3]) {
1104                 printf("write dev: no device given for writing\n");
1105                 return;
1106         }
1107
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);
1111                         found = 1;
1112                         if (err)
1113                                 printf("write dev: error when writing to %s\n",
1114                                        dev->name);
1115                         else if (st->verbose)
1116                                 printf("Device block written to %s\n", dev->name);
1117                 }
1118         }
1119         if (found)
1120                 return;
1121         if (args[3])
1122                 printf("write dev: no devices exist to write to.\n");
1123         else
1124                 printf("write dev: %s is not a registered device in this LaFS.\n",
1125                        (char*)args[2]);
1126 }
1127
1128 /****** WRITE_STATE ******/
1129 static char help_write_state[] = "Write state blocks to all devices";
1130 static struct args args_write_state[] = {
1131         TERMINAL_ARG
1132 };
1133 static void c_write_state(struct state *st, void **args)
1134 {
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);
1145 }
1146
1147 /****** WRITE_CHECKPOINT ******/
1148 static char help_write_checkpoint[] = "Write a checkpoint with all committed blocks";
1149 static struct args args_write_checkpoint[] = {
1150         TERMINAL_ARG
1151 };
1152 static void c_write_checkpoint(struct state *st, void **args)
1153 {
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);
1165 }
1166
1167 #define WCMD(x) {#x, c_write_##x, args_write_##x, help_write_##x}
1168 static struct cmd write_cmds[] = {
1169         WCMD(checkpoint),
1170         WCMD(dev),
1171         WCMD(state),
1172         { NULL, NULL, NULL, NULL}
1173 };
1174
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"},
1180         TERMINAL_ARG
1181 };
1182 static void c_load_dev(struct state *st, void **args)
1183 {
1184         char *devname = args[1];
1185         int fd;
1186         long long device_bytes = 0;
1187         char *err;
1188         struct lafs_device *dev;
1189
1190         if (!devname) {
1191                 printf("load_dev: No device of file name given to load\n");
1192                 return;
1193         }
1194
1195         fd = open_device(devname, &device_bytes, args[2] != NULL, &err);
1196
1197         if (fd < 0) {
1198                 printf("load_dev: %s\n", err);
1199                 free(err);
1200                 return;
1201         }
1202
1203         dev = lafs_load(fd, device_bytes, &err);
1204
1205         if (err) {
1206                 printf("load_dev: Cannot load %s: %s\n", devname, err);
1207                 if (dev)
1208                         talloc_free(dev);
1209                 close(fd);
1210                 return;
1211         }
1212
1213         dev->name = talloc_strdup(dev, devname);
1214
1215         if (lafs_include_dev(st->lafs, dev, &err) != 0) {
1216                 printf("load_dev: Cannot include %s: %s\n", devname, err);
1217                 talloc_free(dev);
1218                 return;
1219         }
1220         if (st->verbose) {
1221                 printf("loaded device %s - have %d of %d\n", devname,
1222                        st->lafs->loaded_devs, st->lafs->devices);
1223         }
1224 }
1225
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"},
1232         TERMINAL_ARG
1233 };
1234 static void c_mount(struct state *st, void **args)
1235 {
1236         char *err;
1237         if (args[1]) {
1238                 /* Load the device first, then mount */
1239                 char *devname = args[1];
1240                 long long device_bytes = 0;
1241                 int fd;
1242                 struct lafs_device *dev;
1243                 if (st->lafs->blocksize) {
1244                         printf("mount: lafs already initialised - cannot load %s\n",
1245                                devname);
1246                         return;
1247                 }
1248                 fd = open_device(devname, &device_bytes, args[2] != NULL, &err);
1249                 if (fd < 0) {
1250                         printf("mount: %s\n", err);
1251                         free(err);
1252                         return;
1253                 }
1254                 dev = lafs_load(fd, device_bytes, &err);
1255                 if (err) {
1256                         printf("mount: Cannot load %s: %s\n", devname, err);
1257                         if (dev)
1258                                 talloc_free(dev);
1259                         close(fd);
1260                         return;
1261                 }
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);
1265                         talloc_free(dev);
1266                         return;
1267                 }
1268                 printf("loaded device %s\n", devname);
1269         }
1270         err = lafs_mount(st->lafs, args[3] != NULL);
1271         if (err) {
1272                 printf("mount: cannot mount filesystem: %s\n", err);
1273                 free(err);
1274         } else if (st->verbose)
1275                 printf("filesystem mounted\n");
1276 }
1277
1278 /****** SHOW *****/
1279 static struct cmd show_cmds[];
1280
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"},
1284         TERMINAL_ARG
1285 };
1286 static void c_show(struct state *st, void **args)
1287 {
1288         struct cmd *c = args[1];
1289         if (!c) {
1290                 printf("show: Please give a structure to show\n");
1291                 return;
1292         }
1293
1294         c->cmd(st, args);
1295 }
1296
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"},
1302         TERMINAL_ARG
1303 };
1304 static void c_show_inode(struct state *st, void **args)
1305 {
1306         struct lafs_ino *inode;
1307         char *err;
1308         if (!args[2]) {
1309                 printf("show inode: please give file name or inode number\n");
1310                 return;
1311         }
1312         inode = get_inode(st->lafs, args+2, &err);
1313         if (!inode) {
1314                 printf("show inode: %s\n", err);
1315                 free(err);
1316                 return;
1317         }
1318         lafs_print_inode(inode);
1319 }
1320
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"},
1327         TERMINAL_ARG
1328 };
1329 static void c_show_device(struct state *st, void **args)
1330 {
1331         struct lafs_device *dev;
1332         char *devname = args[2];
1333         char *err;
1334         long long device_bytes = 0;
1335         long long addr;
1336         int fd;
1337
1338         if (!devname && !st->lafs->devs) {
1339                 printf("show device: no devices loaded - please give a device name\n");
1340                 return;
1341         }
1342         if (args[4]) {
1343                 char *addrstr = args[4];
1344                 char *endp;
1345                 struct lafs_dev dv;
1346                 if (!devname) {
1347                         printf("show device: device name must be given with address\n");
1348                         return;
1349                 }
1350                 addr = strtoll(addrstr, &endp, 0);
1351                 if (endp == addrstr || *endp) {
1352                         printf("show device: %s is not a valid number\n",
1353                                addrstr);
1354                         return;
1355                 }
1356                 fd = open_device(devname, &device_bytes, args[3] != NULL, &err);
1357                 if (fd < 0) {
1358                         printf("show device: %s\n", err);       
1359                         free(err);
1360                         return;
1361                 }
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",
1365                                addr, devname);
1366                 } else
1367                         lafs_print_devblock(&dv);
1368                 close(fd);
1369                 return;
1370         }
1371
1372         for (dev = st->lafs->devs; dev; dev = dev->next) {
1373                 if (devname && strcmp(devname, dev->name) != 0)
1374                         continue;
1375                 printf("Device %s: %d out of %d\n", dev->name, 
1376                        dev->devnum, dev->devices);
1377                 lafs_print_device(dev);
1378                 if (devname)
1379                         return;
1380         }
1381         if (!devname)
1382                 return;
1383         /* Not already loaded, try to load-and-print */
1384         fd = open_device(devname, &device_bytes, args[3] != NULL, &err);
1385         if (fd < 0) {
1386                 printf("show device: %s\n", err);
1387                 free(err);
1388                 return;
1389         }
1390         dev = lafs_load(fd, device_bytes, &err);
1391         if (!dev) {
1392                 printf("show device: Cannot load %s: %s\n",
1393                        devname, err);
1394                 close(fd);
1395                 return;
1396         }
1397
1398         if (err)
1399                 printf("Loaded device %s, however: %s\n", devname, err);
1400         else
1401                 printf("Loaded device %s\n", devname);
1402         lafs_print_device(dev);
1403         talloc_free(dev);
1404 }
1405
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"},
1412         TERMINAL_ARG
1413 };
1414 static void c_show_state(struct state *st, void **args)
1415 {
1416         char *devname;
1417         long long addr;
1418         struct lafs_device *dv;
1419         struct lafs_state *state;
1420         int fd;
1421
1422         if (args[4] && !args[2]) {
1423                 printf("show state: Cannot give address without device name\n");
1424                 return;
1425         }
1426         if (!args[2]) {
1427                 /* Show currently loaded state */
1428                 if (!st->lafs->ss.root_addr) {
1429                         printf("show state: LaFS not mounted, no state available\n");
1430                         return;
1431                 }
1432                 lafs_print_lafs(st->lafs);
1433                 return;
1434         }
1435
1436         devname = args[2];
1437         if (args[4]) {
1438                 char *addrstr = args[4];
1439                 char *endp;
1440                 long long device_bytes = 0;
1441                 char *err;
1442
1443                 addr = strtoll(addrstr, &endp, 0);
1444                 if (endp == addrstr || *endp) {
1445                         printf("show state: %s is not a valid number\n",
1446                                addrstr);
1447                         return;
1448                 }
1449                 dv = NULL;
1450                 fd = open_device(devname, &device_bytes, args[3] != NULL, &err);
1451                 if (fd < 0) {
1452                         printf("show state: %s\n", err);
1453                         free(err);
1454                         return;
1455                 }
1456         } else {
1457                 for (dv = st->lafs->devs; dv ; dv = dv->next)
1458                         if (strcmp(devname, dv->name) == 0)
1459                                 break;
1460                 if (!dv) {
1461
1462                         printf("show state: device %s not loaded and no address given\n",
1463                                devname);
1464                         return;
1465                 }
1466                 fd = dv->fd;
1467                 addr = dv->stateaddr[dv->recent_state];
1468         }
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");
1473                 return;
1474         }
1475         lafs_print_state(state, st->lafs->statesize);
1476         free(state);
1477         if (!dv)
1478                 close(fd);
1479 }
1480
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"},
1490         TERMINAL_ARG
1491 };
1492 static void c_show_cluster(struct state *st, void **args)
1493 {
1494         long long start, addr;
1495         int again = 1;
1496         int verbose = 0;
1497         int cnt;
1498         int max = 0;
1499
1500         if (!st->lafs->blocksize) {
1501                 printf("show cluster: lafs not ready to find clusters\n");
1502                 return;
1503         }
1504
1505         if (args[2] == NULL)
1506                 start = st->lafs->checkpoint_cluster;
1507         else {
1508                 char *addrstr = args[2];
1509                 char *endp;
1510                 start = strtoll(addrstr, &endp, 0);
1511                 if (endp == addrstr || *endp) {
1512                         printf("show cluster: %s is not a valid address\n", addrstr);
1513                         return;
1514                 }
1515         }
1516         if (args[7]) {
1517                 char *nstr = args[7];
1518                 char *endp;
1519                 max = strtoll(nstr, &endp, 0);
1520                 if (endp == nstr || *endp) {
1521                         printf("show cluster: %s is not a valid number\n", nstr);
1522                         return;
1523                 }
1524         }
1525
1526         addr = start;
1527         if (args[3])
1528                 verbose = 1;
1529         while (again) {
1530                 struct cluster_head *ch;
1531                 long long prev;
1532                 int err = lafs_load_cluster(st->lafs, addr, &ch);
1533                 if (err < 0) {
1534                         printf("show cluster: read error at %llu\n",
1535                                (unsigned long long) addr);
1536                         return;
1537                 }
1538                 if (err == 1) {
1539                         if (verbose)
1540                                 lafs_print_cluster(ch, st->lafs->blocksize, 0, 1);
1541                         printf("(bad cluster header)\n");
1542                         free(ch);
1543                         return;
1544                 }
1545                 lafs_print_cluster(ch, st->lafs->blocksize, 1, verbose);
1546                 cnt++;
1547                 prev = addr;
1548                 if (args[6])
1549                         addr = __le64_to_cpu(ch->prev_addr);
1550                 else
1551                         addr = __le64_to_cpu(ch->next_addr);
1552                 again = 0;
1553                 if (args[4]) {
1554                         int dev1, dev2;
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)
1559                                 again = 1;
1560                         /* Avoid going in wrong direction */
1561                         if (args[6]) {
1562                                 if (addr >= prev)
1563                                         again = 0;
1564                         } else {
1565                                 if (addr <= prev)
1566                                         again = 0;
1567                         }
1568                 }
1569                 if (args[5]) {
1570                         int f = __le32_to_cpu(ch->flags);
1571                         if (f & CH_Checkpoint) {
1572                                 if (args[6] && !(f & CH_CheckpointStart))
1573                                         again = 1;
1574                                 if (!args[6] && !(f & CH_CheckpointEnd))
1575                                         again = 1;
1576                         }
1577                 }
1578                 if (max && cnt < max)
1579                         again = 1;
1580                 if (addr == prev)
1581                         again = 0;
1582                 free(ch);
1583         }
1584 }
1585
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"},
1592         TERMINAL_ARG
1593 };
1594 static void c_show_dirblock(struct state *st, void **args)
1595 {
1596         int bnum;
1597         char *buf;
1598         char *bstr = args[2];
1599
1600         if (!bstr) {
1601                 printf("show dirblock: no block number given\n");
1602                 return;
1603         }
1604         if (get_int(bstr, &bnum) < 0) {
1605                 printf("show dirblock: %s is not a valid address\n", bstr);
1606                 return;
1607         }
1608         if (!st->lafs->blocksize) {
1609                 printf("show dirblock: LaFS not ready to show blocks\n");
1610                 return;
1611         }
1612         if (args[3]) {
1613                 char *err;
1614                 struct lafs_dblk *db;
1615                 struct lafs_ino *inode = get_inode(st->lafs, args+3, &err);
1616                 if (!inode) {
1617                         printf("show dirblock: %s\n", err);
1618                         free(err);
1619                         return;
1620                 }
1621                 db = lafs_dblk(inode, bnum);
1622                 if (lafs_load_dblk(db)) {
1623                         printf("show dirblock: cannot load block %d of inode %d\n",
1624                                bnum, inode->inum);
1625                         return;
1626                 }
1627                 buf = db->b.data;
1628         } else {
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);
1632                         free(buf);
1633                         return;
1634                 }
1635         }
1636         lafs_dir_print(buf, st->lafs->blockbits-8);
1637         if (!args[3])
1638                 free(buf);
1639 }
1640
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"},
1645         TERMINAL_ARG
1646 };
1647 static void c_show_segusage(struct state *st, void **args)
1648 {
1649         int bnum;
1650         char *buf;
1651         char *bstr = args[2];
1652
1653         if (!bstr) {
1654                 printf("show segusage: no block number given\n");
1655                 return;
1656         }
1657         if (get_int(bstr, &bnum) < 0) {
1658                 printf("show segusage: %s is not a valid address\n", bstr);
1659                 return;
1660         }
1661         if (!st->lafs->blocksize) {
1662                 printf("show segusage: LaFS not ready to show blocks\n");
1663                 return;
1664         }
1665
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);
1669                 free(buf);
1670                 return;
1671         }
1672
1673         lafs_print_segusage(buf, st->lafs->blocksize, 0, st->lafs->blocksize);
1674         if (!args[3])
1675                 free(buf);
1676 }
1677
1678 #define SCMD(x) {#x, c_show_##x, args_show_##x, help_show_##x}
1679 static struct cmd show_cmds[] = {
1680         SCMD(cluster),
1681         SCMD(device),
1682         SCMD(dirblock),
1683         SCMD(inode),
1684         SCMD(segusage),
1685         SCMD(state),
1686         { NULL, NULL, NULL, NULL}
1687 };
1688
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"},
1695         TERMINAL_ARG
1696 };
1697 static void c_store(struct state *st, void **args)
1698 {
1699         char *from = args[1];
1700         char *to = args[2];
1701         struct lafs_ino *dir, *fs, *imfile, *inode;
1702         char *tail = NULL;
1703         int fd;
1704         loff_t bnum;
1705         u32 inum;
1706
1707         if (!from) {
1708                 printf("ERROR: Source file is missing\n");
1709                 return;
1710         }
1711         if (!to) {
1712                 printf("ERROR: destination file name is missing\n");
1713                 return;
1714         }
1715
1716         fs = lafs_get_itable(st->lafs);
1717         dir = lafs_get_inode(fs, 2);
1718         dir = lafs_lookup_path(dir, dir, to, &tail);
1719         if (!dir) {
1720                 printf("store: lookup error in %s\n",to);
1721                 return;
1722         }
1723         if (tail == NULL) {
1724                 printf("store: %s already exists\n", to);
1725                 return;
1726         }
1727         if (dir->type != TypeDir) {
1728                 *tail = 0;
1729                 printf("store: non-directory found at %s\n", to);
1730                 return;
1731         }
1732         if (strchr(tail, '/') != NULL) {
1733                 printf("store: non-final name does not exist: %s\n", tail);
1734                 return;
1735         }
1736
1737         fd = open(from, O_RDONLY);
1738         if (fd < 0) {
1739                 printf("store: Cannot open %s: %s\n", from, strerror(errno));
1740                 return;
1741         }
1742
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);
1749
1750         bnum = 0;
1751         while(1) {
1752                 struct lafs_dblk *db = lafs_dblk(inode, bnum);
1753                 int n = read(fd, db->b.data, st->lafs->blocksize);
1754                 if (n <= 0)
1755                         break;
1756                 inode->md.file.size = (bnum << st->lafs->blockbits) + n;
1757                 db->b.flags |= B_Valid;
1758                 lafs_dirty_blk(db);
1759                 bnum++;
1760         }
1761         if (st->verbose)
1762                 printf("Created %s as inode %d in %d\n", tail, inum, dir->inum);
1763 }
1764
1765 /****** LS ******/
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"},
1773         TERMINAL_ARG
1774 };
1775 static void c_ls(struct state *st, void **args)
1776 {
1777         struct lafs_ino *ino;
1778         u32 index = -1;
1779         char name[257];
1780         u32 inum;
1781         int type;
1782         int col;
1783         char *err;
1784         char *path = args[1];
1785
1786         if (!path)
1787                 args[1] = path = "";
1788         ino = get_inode(st->lafs, args+1, &err);
1789         if (!ino) {
1790                 printf("ls: %s\n", err);
1791                 free(err);
1792                 return;
1793         }
1794
1795         if (ino->type != TypeDir) {
1796                 printf("ls: %s exists but is not a directory\n", path);
1797                 return;
1798         }
1799         col = 0;
1800         while (lafs_dir_next(ino, &index, name, &inum, &type) == 1) {
1801                 if (args[3]) {
1802                         printf("%5lu %cxxxxxxxxx %s\n",
1803                                (unsigned long)inum, ctypes[type], name);
1804                 } else {
1805                         printf("%-12s ", name);
1806                         col += 13;
1807                         if (col > 60) {
1808                                 printf("\n");
1809                                 col = 0;
1810                         }
1811                 }
1812                 if (index+1 == 0)
1813                         break;
1814         }
1815         if (args[3] == NULL && col)
1816                 printf("\n");
1817 }
1818
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"},
1824         TERMINAL_ARG
1825 };
1826 static void c_flush(struct state *st, void **args)
1827 {
1828         struct lafs_ino *inode;
1829         char *err;
1830         if (!args[1]) {
1831                 lafs_flush(st->lafs);
1832                 lafs_cluster_flush(st->lafs, 0);
1833                 if (st->verbose)
1834                         printf("Filesystem flushed\n");
1835                 return;
1836         }
1837         inode = get_inode(st->lafs, args+1, &err);
1838         if (!inode) {
1839                 printf("flush: %s\n", err);
1840                 free(err);
1841                 return;
1842         }
1843         lafs_flush_inode(inode);
1844         lafs_cluster_flush(st->lafs, 0);
1845         if (st->verbose)
1846                 printf("Inode %d flushed\n", (int)inode->inum);
1847 }
1848
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"},
1853         TERMINAL_ARG
1854 };
1855 static void c_trace(struct state *st, void **args)
1856 {
1857         char *levelstr = args[1];
1858         int level = 1;
1859         extern int lafs_trace_level;
1860         int old = lafs_trace_level;
1861         if (levelstr) {
1862                 if (get_int(levelstr, &level) < 0) {
1863                         printf("trace: %s not a valid number\n", levelstr);
1864                         return;
1865                 }
1866         }
1867         if (st->verbose) {
1868                 if (level == old)
1869                         printf("Tracing unchanged at %d\n", old);
1870                 else
1871                         printf("Tracing change from %d to %d\n", old, level);
1872         }
1873         lafs_trace_level = level;
1874 }
1875
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"},
1880         TERMINAL_ARG
1881 };
1882 static void c_source(struct state *st, void *args[])
1883 {
1884         char *fname = args[1];
1885         FILE *f;
1886         if (!fname) {
1887                 printf("source: no file name given\n");
1888                 return;
1889         }
1890         f = fopen(fname, "r");
1891         if (f) {
1892                 st->verbose = 0;
1893                 runfile(st, f);
1894                 st->verbose = 1;
1895                 st->done = 0;
1896                 fclose(f);
1897         } else
1898                 printf("source: cannot open %s\n", fname);
1899 }
1900
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},
1906         CMD(add_device),
1907         CMD(exit),
1908         CMD(flush),
1909         CMD(help),
1910         CMD(load_dev),
1911         CMD(ls),
1912         CMD(mount),
1913         CMD(newfs),
1914         CMD(quit),
1915         CMD(reset),
1916         CMD(show),
1917         CMD(source),
1918         CMD(store),
1919         CMD(trace),
1920         CMD(write),
1921         { NULL, NULL, NULL, NULL}
1922 };
1923
1924 static struct args lafs_args[] = {
1925         { "COMMAND",    subcommand, -1, {lafs_cmds}, "Command for lafs to execute"},
1926         TERMINAL_ARG
1927 };