Fix conditional test for HAVE_HIVEXSH.
[hivex.git] / sh / hivexsh.c
1 /* hivexsh - Hive shell.
2  * Copyright (C) 2009 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdint.h>
25 #include <inttypes.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <locale.h>
31
32 #ifdef HAVE_LIBINTL_H
33 #include <libintl.h>
34 #endif
35
36 #ifdef HAVE_LIBREADLINE
37 #include <readline/readline.h>
38 #include <readline/history.h>
39 #endif
40
41 #ifdef HAVE_GETTEXT
42 #include "gettext.h"
43 #define _(str) dgettext(PACKAGE, (str))
44 //#define N_(str) dgettext(PACKAGE, (str))
45 #else
46 #define _(str) str
47 //#define N_(str) str
48 #endif
49
50 #define STREQ(a,b) (strcmp((a),(b)) == 0)
51 #define STRCASEEQ(a,b) (strcasecmp((a),(b)) == 0)
52 #define STRNEQ(a,b) (strcmp((a),(b)) != 0)
53 //#define STRCASENEQ(a,b) (strcasecmp((a),(b)) != 0)
54 //#define STREQLEN(a,b,n) (strncmp((a),(b),(n)) == 0)
55 //#define STRCASEEQLEN(a,b,n) (strncasecmp((a),(b),(n)) == 0)
56 //#define STRNEQLEN(a,b,n) (strncmp((a),(b),(n)) != 0)
57 //#define STRCASENEQLEN(a,b,n) (strncasecmp((a),(b),(n)) != 0)
58 #define STRPREFIX(a,b) (strncmp((a),(b),strlen((b))) == 0)
59
60 #include "c-ctype.h"
61 #include "xstrtol.h"
62
63 #include "hivex.h"
64 #include "byte_conversions.h"
65
66 #define HIVEX_MAX_VALUES         1000
67
68 static int quit = 0;
69 static int is_tty;
70 static hive_h *h = NULL;
71 static char *prompt_string = NULL; /* Normal prompt string. */
72 static char *loaded = NULL;     /* Basename of loaded file, if any. */
73 static hive_node_h cwd;         /* Current node. */
74 static int open_flags = 0;      /* Flags used when loading a hive file. */
75
76 static void usage (void) __attribute__((noreturn));
77 static void print_node_path (hive_node_h, FILE *);
78 static void set_prompt_string (void);
79 static void initialize_readline (void);
80 static void cleanup_readline (void);
81 static void add_history_line (const char *);
82 static char *rl_gets (const char *prompt_string);
83 static void sort_strings (char **strings, int len);
84 static int get_xdigit (char c);
85 static int dispatch (char *cmd, char *args);
86 static int cmd_add (char *name);
87 static int cmd_cd (char *path);
88 static int cmd_close (char *path);
89 static int cmd_commit (char *path);
90 static int cmd_del (char *args);
91 static int cmd_help (char *args);
92 static int cmd_load (char *hivefile);
93 static int cmd_ls (char *args);
94 static int cmd_lsval (char *args);
95 static int cmd_setval (char *args);
96
97 static void
98 usage (void)
99 {
100   fprintf (stderr, "hivexsh [-dfw] [hivefile]\n");
101   exit (EXIT_FAILURE);
102 }
103
104 int
105 main (int argc, char *argv[])
106 {
107   setlocale (LC_ALL, "");
108 #ifdef HAVE_BINDTEXTDOMAIN
109   bindtextdomain (PACKAGE, LOCALEBASEDIR);
110   textdomain (PACKAGE);
111 #endif
112
113   int c;
114   const char *filename = NULL;
115
116   set_prompt_string ();
117
118   while ((c = getopt (argc, argv, "df:w")) != EOF) {
119     switch (c) {
120     case 'd':
121       open_flags |= HIVEX_OPEN_DEBUG;
122       break;
123     case 'f':
124       filename = optarg;
125       break;
126     case 'w':
127       open_flags |= HIVEX_OPEN_WRITE;
128       break;
129     default:
130       usage ();
131     }
132   }
133
134   if (optind < argc) {
135     if (optind + 1 != argc)
136       usage ();
137     if (cmd_load (argv[optind]) == -1)
138       exit (EXIT_FAILURE);
139   }
140
141   /* -f filename parameter */
142   if (filename) {
143     close (0);
144     if (open (filename, O_RDONLY) == -1) {
145       perror (filename);
146       exit (EXIT_FAILURE);
147     }
148   }
149
150   /* Main loop. */
151   is_tty = isatty (0);
152   initialize_readline ();
153
154   if (is_tty)
155     printf (_(
156 "\n"
157 "Welcome to hivexsh, the hivex interactive shell for examining\n"
158 "Windows Registry binary hive files.\n"
159 "\n"
160 "Type: 'help' for help summary\n"
161 "      'quit' to quit the shell\n"
162 "\n"));
163
164   while (!quit) {
165     char *buf = rl_gets (prompt_string);
166     if (!buf) {
167       quit = 1;
168       if (is_tty)
169         printf ("\n");
170       break;
171     }
172
173     while (*buf && c_isspace (*buf))
174       buf++;
175
176     /* Ignore blank line. */
177     if (!*buf) continue;
178
179     /* If the next character is '#' then this is a comment. */
180     if (*buf == '#') continue;
181
182     /* Parsing is very simple - much simpler than guestfish.  This is
183      * because Registry keys often contain spaces, and we don't want
184      * to bother with quoting.  Therefore here we just split at the
185      * first whitespace into "cmd<whitespace>arg(s)".  We let the
186      * command decide how to deal with arg(s), if at all.
187      */
188     size_t len = strcspn (buf, " \t");
189
190     if (len == 0) continue;
191
192     char *cmd = buf;
193     char *args;
194
195     if (buf[len] == '\0') {
196       /* This is mostly safe.  Although the cmd_* functions do sometimes
197        * modify args, then shouldn't do so when args is "".
198        */
199       args = (char *) "";
200       goto got_command;
201     }
202
203     buf[len] = '\0';
204     args = buf + len + 1 + strspn (&buf[len+1], " \t");
205
206     len = strlen (args);
207     while (len > 0 && c_isspace (args[len-1])) {
208       args[len-1] = '\0';
209       len--;
210     }
211
212   got_command:
213     /*printf ("command: '%s'  args: '%s'\n", cmd, args)*/;
214     int r = dispatch (cmd, args);
215     if (!is_tty && r == -1)
216       exit (EXIT_FAILURE);
217   }
218
219   cleanup_readline ();
220   free (prompt_string);
221   free (loaded);
222   if (h) hivex_close (h);
223   exit (0);
224 }
225
226 /* Set the prompt string.  This is called whenever it could change, eg.
227  * after loading a file or changing directory.
228  */
229 static void
230 set_prompt_string (void)
231 {
232   free (prompt_string);
233   prompt_string = NULL;
234
235   FILE *fp;
236   char *ptr;
237   size_t size;
238   fp = open_memstream (&ptr, &size);
239   if (fp == NULL) {
240     perror ("open_memstream");
241     exit (EXIT_FAILURE);
242   }
243
244   if (h) {
245     assert (loaded != NULL);
246     assert (cwd != 0);
247
248     fputs (loaded, fp);
249     print_node_path (cwd, fp);
250   }
251
252   fprintf (fp, "> ");
253   fclose (fp);
254   prompt_string = ptr;
255 }
256
257 /* Print the \full\path of a node. */
258 static void
259 print_node_path (hive_node_h node, FILE *fp)
260 {
261   hive_node_h root = hivex_root (h);
262
263   if (node == root) {
264     fputc ('\\', fp);
265     return;
266   }
267
268   hive_node_h parent = hivex_node_parent (h, node);
269   if (parent == 0) {
270     fprintf (stderr, _("hivexsh: error getting parent of node %zu\n"), node);
271     return;
272   }
273   print_node_path (parent, fp);
274
275   if (parent != root)
276     fputc ('\\', fp);
277
278   char *name = hivex_node_name (h, node);
279   if (name == NULL) {
280     fprintf (stderr, _("hivexsh: error getting node name of node %zx\n"), node);
281     return;
282   }
283
284   fputs (name, fp);
285   free (name);
286 }
287
288 static char *line_read = NULL;
289
290 static char *
291 rl_gets (const char *prompt_string)
292 {
293 #ifdef HAVE_LIBREADLINE
294
295   if (is_tty) {
296     if (line_read) {
297       free (line_read);
298       line_read = NULL;
299     }
300
301     line_read = readline (prompt_string);
302
303     if (line_read && *line_read)
304       add_history_line (line_read);
305
306     return line_read;
307   }
308
309 #endif /* HAVE_LIBREADLINE */
310
311   static char buf[8192];
312   int len;
313
314   if (is_tty)
315     printf ("%s", prompt_string);
316   line_read = fgets (buf, sizeof buf, stdin);
317
318   if (line_read) {
319     len = strlen (line_read);
320     if (len > 0 && buf[len-1] == '\n') buf[len-1] = '\0';
321   }
322
323   return line_read;
324 }
325
326 #ifdef HAVE_LIBREADLINE
327 static char histfile[1024];
328 static int nr_history_lines = 0;
329 #endif
330
331 static void
332 initialize_readline (void)
333 {
334 #ifdef HAVE_LIBREADLINE
335   const char *home;
336
337   home = getenv ("HOME");
338   if (home) {
339     snprintf (histfile, sizeof histfile, "%s/.hivexsh", home);
340     using_history ();
341     (void) read_history (histfile);
342   }
343
344   rl_readline_name = "hivexsh";
345 #endif
346 }
347
348 static void
349 cleanup_readline (void)
350 {
351 #ifdef HAVE_LIBREADLINE
352   int fd;
353
354   if (histfile[0] != '\0') {
355     fd = open (histfile, O_WRONLY|O_CREAT, 0644);
356     if (fd == -1) {
357       perror (histfile);
358       return;
359     }
360     close (fd);
361
362     (void) append_history (nr_history_lines, histfile);
363   }
364 #endif
365 }
366
367 static void
368 add_history_line (const char *line)
369 {
370 #ifdef HAVE_LIBREADLINE
371   add_history (line);
372   nr_history_lines++;
373 #endif
374 }
375
376 static int
377 compare (const void *vp1, const void *vp2)
378 {
379   char * const *p1 = (char * const *) vp1;
380   char * const *p2 = (char * const *) vp2;
381   return strcasecmp (*p1, *p2);
382 }
383
384 static void
385 sort_strings (char **strings, int len)
386 {
387   qsort (strings, len, sizeof (char *), compare);
388 }
389
390 static int
391 get_xdigit (char c)
392 {
393   switch (c) {
394   case '0'...'9': return c - '0';
395   case 'a'...'f': return c - 'a' + 10;
396   case 'A'...'F': return c - 'A' + 10;
397   default: return -1;
398   }
399 }
400
401 static int
402 dispatch (char *cmd, char *args)
403 {
404   if (STRCASEEQ (cmd, "help"))
405     return cmd_help (args);
406   else if (STRCASEEQ (cmd, "load"))
407     return cmd_load (args);
408   else if (STRCASEEQ (cmd, "exit") ||
409            STRCASEEQ (cmd, "q") ||
410            STRCASEEQ (cmd, "quit")) {
411     quit = 1;
412     return 0;
413   }
414
415   /* If no hive file is loaded (!h) then only the small selection of
416    * commands above will work.
417    */
418   if (!h) {
419     fprintf (stderr, _("hivexsh: you must load a hive file first using 'load hivefile'\n"));
420     return -1;
421   }
422
423   if (STRCASEEQ (cmd, "add"))
424     return cmd_add (args);
425   else if (STRCASEEQ (cmd, "cd"))
426     return cmd_cd (args);
427   else if (STRCASEEQ (cmd, "close") || STRCASEEQ (cmd, "unload"))
428     return cmd_close (args);
429   else if (STRCASEEQ (cmd, "commit"))
430     return cmd_commit (args);
431   else if (STRCASEEQ (cmd, "del"))
432     return cmd_del (args);
433   else if (STRCASEEQ (cmd, "ls"))
434     return cmd_ls (args);
435   else if (STRCASEEQ (cmd, "lsval"))
436     return cmd_lsval (args);
437   else if (STRCASEEQ (cmd, "setval"))
438     return cmd_setval (args);
439   else {
440     fprintf (stderr, _("hivexsh: unknown command '%s', use 'help' for help summary\n"),
441              cmd);
442     return -1;
443   }
444 }
445
446 static int
447 cmd_load (char *hivefile)
448 {
449   if (STREQ (hivefile, "")) {
450     fprintf (stderr, _("hivexsh: load: no hive file name given to load\n"));
451     return -1;
452   }
453
454   if (h) hivex_close (h);
455   h = NULL;
456
457   free (loaded);
458   loaded = NULL;
459
460   cwd = 0;
461
462   h = hivex_open (hivefile, open_flags);
463   if (h == NULL) {
464     fprintf (stderr,
465              _(
466 "hivexsh: failed to open hive file: %s: %m\n"
467 "\n"
468 "If you think this file is a valid Windows binary hive file (_not_\n"
469 "a regedit *.reg file) then please run this command again using the\n"
470 "hivexsh option '-d' and attach the complete output _and_ the hive file\n"
471 "which fails into a bug report at https://bugzilla.redhat.com/\n"
472 "\n"),
473              hivefile);
474     return -1;
475   }
476
477   /* Get the basename of the file for the prompt. */
478   char *p = strrchr (hivefile, '/');
479   if (p)
480     loaded = strdup (p+1);
481   else
482     loaded = strdup (hivefile);
483   if (!loaded) {
484     perror ("strdup");
485     exit (EXIT_FAILURE);
486   }
487
488   cwd = hivex_root (h);
489
490   set_prompt_string ();
491
492   return 0;
493 }
494
495 static int
496 cmd_close (char *args)
497 {
498   if (STRNEQ (args, "")) {
499     fprintf (stderr, _("hivexsh: '%s' command should not be given arguments\n"),
500              "close");
501     return -1;
502   }
503
504   if (h) hivex_close (h);
505   h = NULL;
506
507   free (loaded);
508   loaded = NULL;
509
510   cwd = 0;
511
512   set_prompt_string ();
513
514   return 0;
515 }
516
517 static int
518 cmd_commit (char *path)
519 {
520   if (STREQ (path, ""))
521     path = NULL;
522
523   if (hivex_commit (h, path, 0) == -1) {
524     perror ("hivexsh: commit");
525     return -1;
526   }
527
528   return 0;
529 }
530
531 static int
532 cmd_cd (char *path)
533 {
534   if (STREQ (path, "")) {
535     print_node_path (cwd, stdout);
536     fputc ('\n', stdout);
537     return 0;
538   }
539
540   if (path[0] == '\\' && path[1] == '\\') {
541     fprintf (stderr, _("%s: %s: \\ characters in path are doubled - are you escaping the path parameter correctly?\n"), "hivexsh", path);
542     return -1;
543   }
544
545   hive_node_h new_cwd = cwd;
546   hive_node_h root = hivex_root (h);
547
548   if (path[0] == '\\') {
549     new_cwd = root;
550     path++;
551   }
552
553   while (path[0]) {
554     size_t len = strcspn (path, "\\");
555     if (len == 0) {
556       path++;
557       continue;
558     }
559
560     char *elem = path;
561     path = path[len] == '\0' ? &path[len] : &path[len+1];
562     elem[len] = '\0';
563
564     if (len == 1 && STREQ (elem, "."))
565       continue;
566
567     if (len == 2 && STREQ (elem, "..")) {
568       if (new_cwd != root)
569         new_cwd = hivex_node_parent (h, new_cwd);
570       continue;
571     }
572
573     errno = 0;
574     new_cwd = hivex_node_get_child (h, new_cwd, elem);
575     if (new_cwd == 0) {
576       if (errno)
577         perror ("hivexsh: cd");
578       else
579         fprintf (stderr, _("hivexsh: cd: subkey '%s' not found\n"),
580                  elem);
581       return -1;
582     }
583   }
584
585   if (new_cwd != cwd) {
586     cwd = new_cwd;
587     set_prompt_string ();
588   }
589
590   return 0;
591 }
592
593 static int
594 cmd_help (char *args)
595 {
596   printf (_(
597 "Navigate through the hive's keys using the 'cd' command, as if it\n"
598 "contained a filesystem, and use 'ls' to list the subkeys of the\n"
599 "current key.  Full documentation is in the hivexsh(1) manual page.\n"));
600
601   return 0;
602 }
603
604 static int
605 cmd_ls (char *args)
606 {
607   if (STRNEQ (args, "")) {
608     fprintf (stderr, _("hivexsh: '%s' command should not be given arguments\n"),
609              "ls");
610     return -1;
611   }
612
613   /* Get the subkeys. */
614   hive_node_h *children = hivex_node_children (h, cwd);
615   if (children == NULL) {
616     perror ("ls");
617     return -1;
618   }
619
620   /* Get names for each subkey. */
621   size_t len;
622   for (len = 0; children[len] != 0; ++len)
623     ;
624
625   char **names = calloc (len, sizeof (char *));
626   if (names == NULL) {
627     perror ("malloc");
628     exit (EXIT_FAILURE);
629   }
630
631   int ret = -1;
632   size_t i;
633   for (i = 0; i < len; ++i) {
634     names[i] = hivex_node_name (h, children[i]);
635     if (names[i] == NULL) {
636       perror ("hivex_node_name");
637       goto error;
638     }
639   }
640
641   /* Sort the names. */
642   sort_strings (names, len);
643
644   for (i = 0; i < len; ++i)
645     printf ("%s\n", names[i]);
646
647   ret = 0;
648  error:
649   free (children);
650   for (i = 0; i < len; ++i)
651     free (names[i]);
652   free (names);
653   return ret;
654 }
655
656 static int
657 cmd_lsval (char *key)
658 {
659   if (STRNEQ (key, "")) {
660     hive_value_h value;
661
662     errno = 0;
663     if (STREQ (key, "@"))       /* default key written as "@" */
664       value = hivex_node_get_value (h, cwd, "");
665     else
666       value = hivex_node_get_value (h, cwd, key);
667
668     if (value == 0) {
669       if (errno)
670         goto error;
671       /* else key not found */
672       fprintf (stderr, _("%s: %s: key not found\n"), "hivexsh", key);
673       return -1;
674     }
675
676     /* Print the value. */
677     hive_type t;
678     size_t len;
679     if (hivex_value_type (h, value, &t, &len) == -1)
680       goto error;
681
682     switch (t) {
683     case hive_t_string:
684     case hive_t_expand_string:
685     case hive_t_link: {
686       char *str = hivex_value_string (h, value);
687       if (!str)
688         goto error;
689
690       puts (str); /* note: this adds a single \n character */
691       free (str);
692       break;
693     }
694
695     case hive_t_dword:
696     case hive_t_dword_be: {
697       int32_t j = hivex_value_dword (h, value);
698       printf ("%" PRIi32 "\n", j);
699       break;
700     }
701
702     case hive_t_qword: {
703       int64_t j = hivex_value_qword (h, value);
704       printf ("%" PRIi64 "\n", j);
705       break;
706     }
707
708     case hive_t_multiple_strings: {
709       char **strs = hivex_value_multiple_strings (h, value);
710       if (!strs)
711         goto error;
712       size_t j;
713       for (j = 0; strs[j] != NULL; ++j) {
714         puts (strs[j]);
715         free (strs[j]);
716       }
717       free (strs);
718       break;
719     }
720
721     case hive_t_none:
722     case hive_t_binary:
723     case hive_t_resource_list:
724     case hive_t_full_resource_description:
725     case hive_t_resource_requirements_list:
726     default: {
727       char *data = hivex_value_value (h, value, &t, &len);
728       if (!data)
729         goto error;
730
731       if (fwrite (data, 1, len, stdout) != len)
732         goto error;
733
734       free (data);
735       break;
736     }
737     } /* switch */
738   } else {
739     /* No key specified, so print all keys in this node.  We do this
740      * in a format which looks like the output of regedit, although
741      * this isn't a particularly useful format.
742      */
743     hive_value_h *values;
744
745     values = hivex_node_values (h, cwd);
746     if (values == NULL)
747       goto error;
748
749     size_t i;
750     for (i = 0; values[i] != 0; ++i) {
751       char *key = hivex_value_key (h, values[i]);
752       if (!key) goto error;
753
754       if (*key) {
755         putchar ('"');
756         size_t j;
757         for (j = 0; key[j] != 0; ++j) {
758           if (key[j] == '"' || key[j] == '\\')
759             putchar ('\\');
760           putchar (key[j]);
761         }
762         putchar ('"');
763       } else
764         printf ("\"@\"");       /* default key in regedit files */
765       putchar ('=');
766       free (key);
767
768       hive_type t;
769       size_t len;
770       if (hivex_value_type (h, values[i], &t, &len) == -1)
771         goto error;
772
773       switch (t) {
774       case hive_t_string:
775       case hive_t_expand_string:
776       case hive_t_link: {
777         char *str = hivex_value_string (h, values[i]);
778         if (!str)
779           goto error;
780
781         if (t != hive_t_string)
782           printf ("str(%d):", t);
783         putchar ('"');
784         size_t j;
785         for (j = 0; str[j] != 0; ++j) {
786           if (str[j] == '"' || str[j] == '\\')
787             putchar ('\\');
788           putchar (str[j]);
789         }
790         putchar ('"');
791         free (str);
792         break;
793       }
794
795       case hive_t_dword:
796       case hive_t_dword_be: {
797         int32_t j = hivex_value_dword (h, values[i]);
798         printf ("dword:%08" PRIx32, j);
799         break;
800       }
801
802       case hive_t_qword: /* sic */
803       case hive_t_none:
804       case hive_t_binary:
805       case hive_t_multiple_strings:
806       case hive_t_resource_list:
807       case hive_t_full_resource_description:
808       case hive_t_resource_requirements_list:
809       default: {
810         unsigned char *data =
811           (unsigned char *) hivex_value_value (h, values[i], &t, &len);
812         if (!data)
813           goto error;
814
815         printf ("hex(%d):", t);
816         size_t j;
817         for (j = 0; j < len; ++j) {
818           if (j > 0)
819             putchar (',');
820           printf ("%02x", data[j]);
821         }
822         break;
823       }
824       } /* switch */
825
826       putchar ('\n');
827     } /* for */
828
829     free (values);
830   }
831
832   return 0;
833
834  error:
835   perror ("hivexsh: lsval");
836   return -1;
837 }
838
839 static int
840 cmd_setval (char *nrvals_str)
841 {
842   strtol_error xerr;
843
844   /* Parse number of values. */
845   long nrvals;
846   xerr = xstrtol (nrvals_str, NULL, 0, &nrvals, "");
847   if (xerr != LONGINT_OK) {
848     fprintf (stderr, _("%s: %s: invalid integer parameter (%s returned %d)\n"),
849              "setval", "nrvals", "xstrtol", xerr);
850     return -1;
851   }
852   if (nrvals < 0 || nrvals > HIVEX_MAX_VALUES) {
853     fprintf (stderr, _("%s: %s: integer out of range\n"),
854              "setval", "nrvals");
855     return -1;
856   }
857
858   struct hive_set_value *values =
859     calloc (nrvals, sizeof (struct hive_set_value));
860   if (values == NULL) {
861     perror ("calloc");
862     exit (EXIT_FAILURE);
863   }
864
865   int ret = -1;
866
867   /* Read nrvals * 2 lines of input, nrvals * (key, value) pairs, as
868    * explained in the man page.
869    */
870   int i, j;
871   for (i = 0; i < nrvals; ++i) {
872     /* Read key. */
873     char *buf = rl_gets ("  key> ");
874     if (!buf) {
875       fprintf (stderr, _("hivexsh: setval: unexpected end of input\n"));
876       quit = 1;
877       goto error;
878     }
879
880     /* Note that buf will be overwritten by the next call to rl_gets. */
881     if (STREQ (buf, "@"))
882       values[i].key = strdup ("");
883     else
884       values[i].key = strdup (buf);
885     if (values[i].key == NULL) {
886       perror ("strdup");
887       exit (EXIT_FAILURE);
888     }
889
890     /* Read value. */
891     buf = rl_gets ("value> ");
892     if (!buf) {
893       fprintf (stderr, _("hivexsh: setval: unexpected end of input\n"));
894       quit = 1;
895       goto error;
896     }
897
898     if (STREQ (buf, "none")) {
899       values[i].t = hive_t_none;
900       values[i].len = 0;
901     }
902     else if (STRPREFIX (buf, "string:")) {
903       buf += 7;
904       values[i].t = hive_t_string;
905       int nr_chars = strlen (buf);
906       values[i].len = 2 * (nr_chars + 1);
907       values[i].value = malloc (values[i].len);
908       if (!values[i].value) {
909         perror ("malloc");
910         exit (EXIT_FAILURE);
911       }
912       for (j = 0; j <= /* sic */ nr_chars; ++j) {
913         if (buf[j] & 0x80) {
914           fprintf (stderr, _("hivexsh: string(utf16le): only 7 bit ASCII strings are supported for input\n"));
915           goto error;
916         }
917         values[i].value[2*j] = buf[j];
918         values[i].value[2*j+1] = '\0';
919       }
920     }
921     else if (STRPREFIX (buf, "expandstring:")) {
922       buf += 13;
923       values[i].t = hive_t_expand_string;
924       int nr_chars = strlen (buf);
925       values[i].len = 2 * (nr_chars + 1);
926       values[i].value = malloc (values[i].len);
927       if (!values[i].value) {
928         perror ("malloc");
929         exit (EXIT_FAILURE);
930       }
931       for (j = 0; j <= /* sic */ nr_chars; ++j) {
932         if (buf[j] & 0x80) {
933           fprintf (stderr, _("hivexsh: string(utf16le): only 7 bit ASCII strings are supported for input\n"));
934           goto error;
935         }
936         values[i].value[2*j] = buf[j];
937         values[i].value[2*j+1] = '\0';
938       }
939     }
940     else if (STRPREFIX (buf, "dword:")) {
941       buf += 6;
942       values[i].t = hive_t_dword;
943       values[i].len = 4;
944       values[i].value = malloc (4);
945       if (!values[i].value) {
946         perror ("malloc");
947         exit (EXIT_FAILURE);
948       }
949       long n;
950       xerr = xstrtol (buf, NULL, 0, &n, "");
951       if (xerr != LONGINT_OK) {
952         fprintf (stderr, _("%s: %s: invalid integer parameter (%s returned %d)\n"),
953                  "setval", "dword", "xstrtol", xerr);
954         goto error;
955       }
956 #if SIZEOF_LONG > 4
957       if (n < 0 || n > UINT32_MAX) {
958         fprintf (stderr, _("%s: %s: integer out of range\n"),
959                  "setval", "dword");
960         goto error;
961       }
962 #endif
963       uint32_t u32 = htole32 (n);
964       memcpy (values[i].value, &u32, 4);
965     }
966     else if (STRPREFIX (buf, "qword:")) {
967       buf += 6;
968       values[i].t = hive_t_qword;
969       values[i].len = 8;
970       values[i].value = malloc (8);
971       if (!values[i].value) {
972         perror ("malloc");
973         exit (EXIT_FAILURE);
974       }
975       long long n;
976       xerr = xstrtoll (buf, NULL, 0, &n, "");
977       if (xerr != LONGINT_OK) {
978         fprintf (stderr, _("%s: %s: invalid integer parameter (%s returned %d)\n"),
979                  "setval", "dword", "xstrtoll", xerr);
980         goto error;
981       }
982 #if 0
983       if (n < 0 || n > UINT64_MAX) {
984         fprintf (stderr, _("%s: %s: integer out of range\n"),
985                  "setval", "dword");
986         goto error;
987       }
988 #endif
989       uint64_t u64 = htole64 (n);
990       memcpy (values[i].value, &u64, 4);
991     }
992     else if (STRPREFIX (buf, "hex:")) {
993       /* Read the type. */
994       buf += 4;
995       size_t len = strcspn (buf, ":");
996       char *nextbuf;
997       if (buf[len] == '\0')     /* "hex:t" */
998         nextbuf = &buf[len];
999       else {                    /* "hex:t:..." */
1000         buf[len] = '\0';
1001         nextbuf = &buf[len+1];
1002       }
1003
1004       long t;
1005       xerr = xstrtol (buf, NULL, 0, &t, "");
1006       if (xerr != LONGINT_OK) {
1007         fprintf (stderr, _("%s: %s: invalid integer parameter (%s returned %d)\n"),
1008                  "setval", "hex", "xstrtol", xerr);
1009         goto error;
1010       }
1011 #if SIZEOF_LONG > 4
1012       if (t < 0 || t > UINT32_MAX) {
1013         fprintf (stderr, _("%s: %s: integer out of range\n"),
1014                  "setval", "hex");
1015         goto error;
1016       }
1017 #endif
1018       values[i].t = t;
1019
1020       /* Read the hex data. */
1021       buf = nextbuf;
1022
1023       /* The allocation length is an overestimate, but it doesn't matter. */
1024       values[i].value = malloc (1 + strlen (buf) / 2);
1025       if (!values[i].value) {
1026         perror ("malloc");
1027         exit (EXIT_FAILURE);
1028       }
1029       values[i].len = 0;
1030
1031       while (*buf) {
1032         int c = 0;
1033
1034         for (j = 0; *buf && j < 2; buf++) {
1035           if (c_isxdigit (*buf)) { /* NB: ignore non-hex digits. */
1036             c <<= 4;
1037             c |= get_xdigit (*buf);
1038             j++;
1039           }
1040         }
1041
1042         if (j == 2) values[i].value[values[i].len++] = c;
1043         else if (j == 1) {
1044           fprintf (stderr, _("hivexsh: setval: trailing garbage after hex string\n"));
1045           goto error;
1046         }
1047       }
1048     }
1049     else {
1050       fprintf (stderr,
1051                _("hivexsh: setval: cannot parse value string, please refer to the man page hivexsh(1) for help: %s\n"),
1052                buf);
1053       goto error;
1054     }
1055   }
1056
1057   ret = hivex_node_set_values (h, cwd, nrvals, values, 0);
1058
1059  error:
1060   /* Free values array. */
1061   for (i = 0; i < nrvals; ++i) {
1062     free (values[i].key);
1063     free (values[i].value);
1064   }
1065   free (values);
1066
1067   return ret;
1068 }
1069
1070 static int
1071 cmd_del (char *args)
1072 {
1073   if (STRNEQ (args, "")) {
1074     fprintf (stderr, _("hivexsh: '%s' command should not be given arguments\n"),
1075              "del");
1076     return -1;
1077   }
1078
1079   if (cwd == hivex_root (h)) {
1080     fprintf (stderr, _("hivexsh: del: the root node cannot be deleted\n"));
1081     return -1;
1082   }
1083
1084   hive_node_h new_cwd = hivex_node_parent (h, cwd);
1085
1086   if (hivex_node_delete_child (h, cwd) == -1) {
1087     perror ("hivexsh: del");
1088     return -1;
1089   }
1090
1091   cwd = new_cwd;
1092   set_prompt_string ();
1093   return 0;
1094 }
1095
1096 static int
1097 cmd_add (char *name)
1098 {
1099   hive_node_h node = hivex_node_add_child (h, cwd, name);
1100   if (node == 0) {
1101     perror ("hivexsh: add");
1102     return -1;
1103   }
1104   return 0;
1105 }