Describe implication of upstream ICU-22610
[samba.git] / source3 / utils / regedit.c
blob32590766921b7129ad1ec4c88855b04051f654ae
1 /*
2 * Samba Unix/Linux SMB client library
3 * Registry Editor
4 * Copyright (C) Christopher Davis 2012
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "lib/cmdline/cmdline.h"
22 #include "lib/param/param.h"
23 #include "lib/util/data_blob.h"
24 #include "lib/registry/registry.h"
25 #include "regedit.h"
26 #include "regedit_treeview.h"
27 #include "regedit_valuelist.h"
28 #include "regedit_dialog.h"
29 #include "regedit_list.h"
30 #include <ncurses.h>
31 #include <menu.h>
32 #include <panel.h>
34 #define KEY_START_X 0
35 #define KEY_START_Y 1
36 #define KEY_WIDTH (COLS / 4)
37 #define KEY_HEIGHT (LINES - KEY_START_Y - 2)
38 #define VAL_START_X KEY_WIDTH
39 #define VAL_START_Y 1
40 #define VAL_WIDTH (COLS - KEY_WIDTH)
41 #define VAL_HEIGHT (LINES - VAL_START_Y - 2)
43 #define HELP1_START_Y (LINES - 2)
44 #define HELP1_START_X 0
45 #define HELP1_WIDTH (LINES)
46 #define HELP2_START_Y (LINES - 1)
47 #define HELP2_START_X 0
48 #define HELP2_WIDTH (LINES)
49 #define PATH_START_Y 0
50 #define PATH_START_X 6
51 #define PATH_MAX_Y (COLS - 1)
52 #define PATH_WIDTH (COLS - 6)
53 #define PATH_WIDTH_MAX 1024
55 struct regedit {
56 struct registry_context *registry_context;
57 WINDOW *main_window;
58 WINDOW *path_label;
59 size_t path_len;
60 struct value_list *vl;
61 struct tree_view *keys;
62 bool tree_input;
63 struct regedit_search_opts active_search;
66 static struct regedit *regedit_main = NULL;
68 static void show_path(struct regedit *regedit)
70 int start_pad = 0;
71 int start_win = PATH_START_X;
73 if (PATH_START_X + regedit->path_len > COLS) {
74 start_pad = 3 + PATH_START_X + regedit->path_len - COLS;
75 mvprintw(PATH_START_Y, start_win, "...");
76 start_win += 3;
78 copywin(regedit->path_label, regedit->main_window, 0, start_pad,
79 PATH_START_Y, start_win, PATH_START_Y, PATH_MAX_Y, false);
81 mvchgat(0, 0, COLS, A_BOLD, PAIR_YELLOW_CYAN, NULL);
84 static void print_path(struct regedit *regedit, struct tree_node *node)
86 regedit->path_len = tree_node_print_path(regedit->path_label, node);
87 show_path(regedit);
90 static void print_help(struct regedit *regedit)
92 const char *khelp = "[n] New Key [s] New Subkey [d] Del Key "
93 "[LEFT] Ascend [RIGHT] Descend";
94 const char *vhelp = "[n] New Value [d] Del Value [ENTER] Edit "
95 "[b] Edit binary";
96 const char *msg = "KEYS";
97 const char *help = khelp;
98 const char *genhelp = "[TAB] Switch sections [q] Quit "
99 "[UP] List up [DOWN] List down "
100 "[/] Search [x] Next";
101 int i, pad;
103 if (!regedit->tree_input) {
104 msg = "VALUES";
105 help = vhelp;
108 move(HELP1_START_Y, HELP1_START_X);
109 clrtoeol();
110 attron(COLOR_PAIR(PAIR_BLACK_CYAN));
111 mvaddstr(HELP1_START_Y, HELP1_START_X, help);
112 pad = COLS - strlen(msg) - strlen(help);
113 for (i = 0; i < pad; ++i) {
114 addch(' ');
116 attroff(COLOR_PAIR(PAIR_BLACK_CYAN));
117 attron(COLOR_PAIR(PAIR_YELLOW_CYAN) | A_BOLD);
118 addstr(msg);
119 attroff(COLOR_PAIR(PAIR_YELLOW_CYAN) | A_BOLD);
121 move(HELP2_START_Y, HELP2_START_X);
122 clrtoeol();
123 mvaddstr(HELP2_START_Y, HELP2_START_X, genhelp);
126 static void print_heading(struct regedit *regedit)
128 if (regedit->tree_input) {
129 tree_view_set_selected(regedit->keys, true);
130 value_list_set_selected(regedit->vl, false);
131 } else {
132 tree_view_set_selected(regedit->keys, false);
133 value_list_set_selected(regedit->vl, true);
136 print_help(regedit);
139 static void load_values(struct regedit *regedit)
141 struct tree_node *node;
143 node = tree_view_get_current_node(regedit->keys);
144 value_list_load(regedit->vl, node->key);
147 static void add_reg_key(struct regedit *regedit, struct tree_node *node,
148 bool subkey)
150 const char *name;
151 const char *msg;
153 if (!subkey && tree_node_is_top_level(node)) {
154 return;
157 msg = "Enter name of new key";
158 if (subkey) {
159 msg = "Enter name of new subkey";
161 dialog_input(regedit, &name, "New Key", "%s", msg);
162 if (name) {
163 WERROR rv;
164 struct registry_key *new_key;
165 struct tree_node *new_node = NULL;
166 struct tree_node *list;
167 struct tree_node *parent;
169 if (subkey) {
170 parent = node;
171 list = node->child_head;
172 } else {
173 parent = node->parent;
174 list = tree_node_first(node);
175 SMB_ASSERT(list != NULL);
177 rv = reg_key_add_name(regedit, parent->key, name,
178 NULL, NULL, &new_key);
179 if (W_ERROR_IS_OK(rv)) {
180 /* The list of subkeys may not be present in
181 cache yet, so if not, don't bother allocating
182 a new node for the key. */
183 if (list) {
184 new_node = tree_node_new(parent, parent,
185 name, new_key);
186 SMB_ASSERT(new_node);
187 tree_node_insert_sorted(list, new_node);
188 } else {
189 /* Reopen the parent key to make sure the
190 new subkey will be noticed. */
191 tree_node_reopen_key(regedit->registry_context,
192 parent);
195 list = tree_node_first(node);
196 tree_view_clear(regedit->keys);
197 tree_view_update(regedit->keys, list);
198 if (!subkey) {
199 node = new_node;
201 tree_view_set_current_node(regedit->keys, node);
202 load_values(regedit);
203 } else {
204 msg = get_friendly_werror_msg(rv);
205 dialog_notice(regedit, DIA_ALERT, "New Key",
206 "Failed to create key: %s", msg);
208 talloc_free(discard_const(name));
212 enum search_flags {
213 SEARCH_NEXT = (1<<0),
214 SEARCH_PREV = (1<<1),
215 SEARCH_REPEAT = (1<<2)
217 static WERROR regedit_search(struct regedit *regedit, struct tree_node *node,
218 struct value_item *vitem, unsigned flags)
220 struct regedit_search_opts *opts;
221 struct tree_node *found;
222 struct value_item *found_value;
223 bool search_key, need_sync;
224 char *save_value_name;
225 WERROR rv;
226 bool (*iterate)(struct tree_node **, bool, WERROR *);
227 struct value_item *(*find_item)(struct value_list *,
228 struct value_item *,
229 const char *,
230 regedit_search_match_fn_t);
232 opts = &regedit->active_search;
234 if (!opts->query || !opts->match) {
235 return WERR_OK;
238 SMB_ASSERT(opts->search_key || opts->search_value);
240 rv = WERR_OK;
241 found = NULL;
242 found_value = NULL;
243 save_value_name = NULL;
244 search_key = opts->search_key;
245 need_sync = false;
246 iterate = tree_node_next;
247 find_item = value_list_find_next_item;
249 if (flags & SEARCH_PREV) {
250 iterate = tree_node_prev;
251 find_item = value_list_find_prev_item;
254 if (opts->search_value) {
255 struct value_item *it;
257 it = value_list_get_current_item(regedit->vl);
258 if (it) {
259 save_value_name = talloc_strdup(regedit,
260 it->value_name);
261 if (save_value_name == NULL) {
262 return WERR_NOT_ENOUGH_MEMORY;
266 if (vitem) {
267 search_key = false;
271 if (!vitem && (flags & SEARCH_REPEAT)) {
272 if (opts->search_value) {
273 search_key = false;
274 } else if (!iterate(&node, opts->search_recursive, &rv)) {
275 beep();
276 return rv;
280 do {
281 if (search_key) {
282 SMB_ASSERT(opts->search_key == true);
283 if (opts->match(node->name, opts->query)) {
284 found = node;
285 } else if (opts->search_value) {
286 search_key = false;
289 if (!search_key) {
290 SMB_ASSERT(opts->search_value == true);
291 if (!vitem) {
292 rv = value_list_load_quick(regedit->vl,
293 node->key);
294 if (!W_ERROR_IS_OK(rv)) {
295 goto out;
297 need_sync = true;
299 found_value = find_item(regedit->vl, vitem, opts->query,
300 opts->match);
301 if (found_value) {
302 found = node;
303 } else {
304 vitem = NULL;
305 search_key = opts->search_key;
308 } while (!found && iterate(&node, opts->search_recursive, &rv));
310 if (!W_ERROR_IS_OK(rv)) {
311 goto out;
314 if (found) {
315 /* Put the cursor on the node that was found */
316 if (!tree_view_is_node_visible(regedit->keys, found)) {
317 tree_view_update(regedit->keys,
318 tree_node_first(found));
319 print_path(regedit, found);
321 tree_view_set_current_node(regedit->keys, found);
322 if (found_value) {
323 if (need_sync) {
324 value_list_sync(regedit->vl);
326 value_list_set_current_item(regedit->vl, found_value);
327 regedit->tree_input = false;
328 } else {
329 load_values(regedit);
330 regedit->tree_input = true;
332 tree_view_show(regedit->keys);
333 value_list_show(regedit->vl);
334 print_heading(regedit);
335 } else {
336 if (need_sync) {
337 load_values(regedit);
338 value_list_set_current_item_by_name(regedit->vl,
339 save_value_name);
341 beep();
344 out:
345 talloc_free(save_value_name);
347 return rv;
350 static void regedit_search_repeat(struct regedit *regedit, unsigned flags)
352 struct tree_node *node;
353 struct value_item *vitem;
354 struct regedit_search_opts *opts;
356 opts = &regedit->active_search;
357 if (opts->query == NULL) {
358 return;
361 node = tree_view_get_current_node(regedit->keys);
362 vitem = NULL;
363 if (opts->search_value && !regedit->tree_input) {
364 vitem = value_list_get_current_item(regedit->vl);
366 regedit_search(regedit, node, vitem, flags | SEARCH_REPEAT);
369 static void handle_tree_input(struct regedit *regedit, int c)
371 struct tree_node *node;
373 switch (c) {
374 case KEY_DOWN:
375 tree_view_driver(regedit->keys, ML_CURSOR_DOWN);
376 load_values(regedit);
377 break;
378 case KEY_UP:
379 tree_view_driver(regedit->keys, ML_CURSOR_UP);
380 load_values(regedit);
381 break;
382 case KEY_NPAGE:
383 tree_view_driver(regedit->keys, ML_CURSOR_PGDN);
384 load_values(regedit);
385 break;
386 case KEY_PPAGE:
387 tree_view_driver(regedit->keys, ML_CURSOR_PGUP);
388 load_values(regedit);
389 break;
390 case KEY_HOME:
391 tree_view_driver(regedit->keys, ML_CURSOR_HOME);
392 load_values(regedit);
393 break;
394 case KEY_END:
395 tree_view_driver(regedit->keys, ML_CURSOR_END);
396 load_values(regedit);
397 break;
398 case '\n':
399 case KEY_ENTER:
400 case KEY_RIGHT:
401 node = tree_view_get_current_node(regedit->keys);
402 if (node && tree_node_has_children(node)) {
403 WERROR rv;
405 rv = tree_node_load_children(node);
406 if (W_ERROR_IS_OK(rv)) {
407 print_path(regedit, node->child_head);
408 tree_view_update(regedit->keys, node->child_head);
409 value_list_load(regedit->vl, node->child_head->key);
410 } else {
411 const char *msg = get_friendly_werror_msg(rv);
412 dialog_notice(regedit, DIA_ALERT, "Loading Subkeys",
413 "Failed to load subkeys: %s", msg);
416 break;
417 case KEY_LEFT:
418 node = tree_view_get_current_node(regedit->keys);
419 if (node && !tree_node_is_top_level(node)) {
420 print_path(regedit, node->parent);
421 node = node->parent;
422 tree_view_update(regedit->keys, tree_node_first(node));
423 tree_view_set_current_node(regedit->keys, node);
424 value_list_load(regedit->vl, node->key);
426 break;
427 case 'n':
428 case 'N':
429 node = tree_view_get_current_node(regedit->keys);
430 add_reg_key(regedit, node, false);
431 break;
432 case 's':
433 case 'S':
434 node = tree_view_get_current_node(regedit->keys);
435 add_reg_key(regedit, node, true);
436 break;
437 case 'd':
438 case 'D': {
439 int sel;
441 node = tree_view_get_current_node(regedit->keys);
442 if (tree_node_is_top_level(node)) {
443 break;
445 sel = dialog_notice(regedit, DIA_CONFIRM,
446 "Delete Key",
447 "Really delete key \"%s\"?",
448 node->name);
449 if (sel == DIALOG_OK) {
450 WERROR rv;
451 struct tree_node *pop;
452 struct tree_node *parent = node->parent;
454 rv = reg_key_del(node, parent->key, node->name);
455 if (W_ERROR_IS_OK(rv)) {
456 tree_node_reopen_key(regedit->registry_context,
457 parent);
458 tree_view_clear(regedit->keys);
459 pop = tree_node_pop(&node);
460 talloc_free(pop);
461 node = parent->child_head;
462 if (node == NULL) {
463 node = tree_node_first(parent);
464 print_path(regedit, node);
466 tree_view_update(regedit->keys, node);
467 value_list_load(regedit->vl, node->key);
468 } else {
469 const char *msg = get_friendly_werror_msg(rv);
470 dialog_notice(regedit, DIA_ALERT, "Delete Key",
471 "Failed to delete key: %s", msg);
474 break;
478 tree_view_show(regedit->keys);
479 value_list_show(regedit->vl);
482 static void handle_value_input(struct regedit *regedit, int c)
484 struct value_item *vitem;
485 bool binmode = false;
486 WERROR err;
487 int sel;
489 switch (c) {
490 case KEY_DOWN:
491 value_list_driver(regedit->vl, ML_CURSOR_DOWN);
492 break;
493 case KEY_UP:
494 value_list_driver(regedit->vl, ML_CURSOR_UP);
495 break;
496 case KEY_NPAGE:
497 value_list_driver(regedit->vl, ML_CURSOR_PGDN);
498 break;
499 case KEY_PPAGE:
500 value_list_driver(regedit->vl, ML_CURSOR_PGUP);
501 break;
502 case KEY_HOME:
503 value_list_driver(regedit->vl, ML_CURSOR_HOME);
504 break;
505 case KEY_END:
506 value_list_driver(regedit->vl, ML_CURSOR_END);
507 break;
508 case 'b':
509 case 'B':
510 binmode = true;
512 FALL_THROUGH;
513 case '\n':
514 case KEY_ENTER:
515 vitem = value_list_get_current_item(regedit->vl);
516 if (vitem) {
517 struct tree_node *node;
518 const char *name = NULL;
519 node = tree_view_get_current_node(regedit->keys);
520 sel = dialog_edit_value(regedit, node->key, vitem->type,
521 vitem, binmode, &err, &name);
522 if (!W_ERROR_IS_OK(err)) {
523 const char *msg = get_friendly_werror_msg(err);
524 dialog_notice(regedit, DIA_ALERT, "Error",
525 "Error editing value:\n%s", msg);
526 } else if (sel == DIALOG_OK) {
527 tree_node_reopen_key(regedit->registry_context,
528 node);
529 value_list_load(regedit->vl, node->key);
530 value_list_set_current_item_by_name(regedit->vl,
531 name);
532 talloc_free(discard_const(name));
535 break;
536 case 'n':
537 case 'N': {
538 int new_type;
540 sel = dialog_select_type(regedit, &new_type);
541 if (sel == DIALOG_OK) {
542 struct tree_node *node;
543 const char *name = NULL;
544 node = tree_view_get_current_node(regedit->keys);
545 sel = dialog_edit_value(regedit, node->key, new_type,
546 NULL, false, &err, &name);
547 if (!W_ERROR_IS_OK(err)) {
548 const char *msg = get_friendly_werror_msg(err);
549 dialog_notice(regedit, DIA_ALERT, "Error",
550 "Error creating value:\n%s", msg);
551 } else if (sel == DIALOG_OK) {
552 tree_node_reopen_key(regedit->registry_context,
553 node);
554 value_list_load(regedit->vl, node->key);
555 value_list_set_current_item_by_name(regedit->vl,
556 name);
557 talloc_free(discard_const(name));
560 break;
562 case 'd':
563 case 'D':
564 vitem = value_list_get_current_item(regedit->vl);
565 if (vitem) {
566 sel = dialog_notice(regedit, DIA_CONFIRM,
567 "Delete Value",
568 "Really delete value \"%s\"?",
569 vitem->value_name);
570 if (sel == DIALOG_OK) {
571 struct tree_node *node;
572 node = tree_view_get_current_node(regedit->keys);
573 reg_del_value(regedit, node->key,
574 vitem->value_name);
575 tree_node_reopen_key(regedit->registry_context,
576 node);
577 value_list_load(regedit->vl, node->key);
580 break;
583 value_list_show(regedit->vl);
586 static bool find_substring(const char *haystack, const char *needle)
588 return strstr(haystack, needle) != NULL;
591 static bool find_substring_nocase(const char *haystack, const char *needle)
593 return strcasestr(haystack, needle) != NULL;
596 static void handle_main_input(struct regedit *regedit, int c)
598 switch (c) {
599 case 18: { /* CTRL-R */
600 struct tree_node *root, *node;
601 const char **path;
603 node = tree_view_get_current_node(regedit->keys);
604 path = tree_node_get_path(regedit, node);
605 SMB_ASSERT(path != NULL);
607 root = tree_node_new_root(regedit, regedit->registry_context);
608 SMB_ASSERT(root != NULL);
610 tree_view_set_root(regedit->keys, root);
611 tree_view_set_path(regedit->keys, path);
612 node = tree_view_get_current_node(regedit->keys);
613 value_list_load(regedit->vl, node->key);
614 tree_view_show(regedit->keys);
615 value_list_show(regedit->vl);
616 print_path(regedit, node);
617 talloc_free(discard_const(path));
618 break;
620 case 'f':
621 case 'F':
622 case '/': {
623 int rv;
624 struct regedit_search_opts *opts;
625 struct tree_node *node;
627 opts = &regedit->active_search;
628 rv = dialog_search_input(regedit, opts);
629 if (rv == DIALOG_OK) {
630 SMB_ASSERT(opts->query != NULL);
631 opts->match = find_substring_nocase;
632 node = regedit->keys->root->child_head;
633 if (opts->search_case) {
634 opts->match = find_substring;
636 if (!opts->search_recursive) {
637 node = tree_view_get_current_node(regedit->keys);
638 node = tree_node_first(node);
640 regedit_search(regedit, node, NULL, SEARCH_NEXT);
642 break;
644 case 'x':
645 regedit_search_repeat(regedit, SEARCH_NEXT);
646 break;
647 case 'X':
648 regedit_search_repeat(regedit, SEARCH_PREV);
649 break;
650 case '\t':
651 regedit->tree_input = !regedit->tree_input;
652 print_heading(regedit);
653 break;
654 default:
655 if (regedit->tree_input) {
656 handle_tree_input(regedit, c);
657 } else {
658 handle_value_input(regedit, c);
663 int regedit_getch(void)
665 int c;
667 SMB_ASSERT(regedit_main);
669 c = getch();
670 if (c == KEY_RESIZE) {
671 tree_view_resize(regedit_main->keys, KEY_HEIGHT, KEY_WIDTH,
672 KEY_START_Y, KEY_START_X);
673 value_list_resize(regedit_main->vl, VAL_HEIGHT, VAL_WIDTH,
674 VAL_START_Y, VAL_START_X);
675 print_heading(regedit_main);
676 show_path(regedit_main);
679 return c;
682 static void regedit_panic_handler(const char *msg)
684 endwin();
685 smb_panic_log(msg);
686 smb_panic_s3(msg);
689 static void display_window(TALLOC_CTX *mem_ctx, struct registry_context *ctx)
691 struct regedit *regedit;
692 struct tree_node *root;
693 bool colors;
694 int key;
696 initscr();
698 cbreak();
699 noecho();
701 fault_configure(regedit_panic_handler);
703 colors = has_colors();
704 if (colors) {
705 start_color();
706 use_default_colors();
707 assume_default_colors(COLOR_WHITE, COLOR_BLUE);
708 init_pair(PAIR_YELLOW_CYAN, COLOR_YELLOW, COLOR_CYAN);
709 init_pair(PAIR_BLACK_CYAN, COLOR_BLACK, COLOR_CYAN);
710 init_pair(PAIR_YELLOW_BLUE, COLOR_YELLOW, COLOR_BLUE);
713 regedit = talloc_zero(mem_ctx, struct regedit);
714 SMB_ASSERT(regedit != NULL);
715 regedit_main = regedit;
717 regedit->registry_context = ctx;
718 regedit->main_window = stdscr;
719 keypad(regedit->main_window, TRUE);
721 mvwprintw(regedit->main_window, 0, 0, "Path: ");
722 regedit->path_label = newpad(1, PATH_WIDTH_MAX);
723 SMB_ASSERT(regedit->path_label);
724 wprintw(regedit->path_label, "/");
725 show_path(regedit_main);
727 root = tree_node_new_root(regedit, ctx);
728 SMB_ASSERT(root != NULL);
730 regedit->keys = tree_view_new(regedit, root, KEY_HEIGHT, KEY_WIDTH,
731 KEY_START_Y, KEY_START_X);
732 SMB_ASSERT(regedit->keys != NULL);
734 regedit->vl = value_list_new(regedit, VAL_HEIGHT, VAL_WIDTH,
735 VAL_START_Y, VAL_START_X);
736 SMB_ASSERT(regedit->vl != NULL);
738 regedit->tree_input = true;
739 print_heading(regedit);
741 tree_view_show(regedit->keys);
742 load_values(regedit);
743 value_list_show(regedit->vl);
745 update_panels();
746 doupdate();
748 do {
749 key = regedit_getch();
751 handle_main_input(regedit, key);
752 update_panels();
753 doupdate();
754 } while (key != 'q' && key != 'Q');
756 endwin();
759 int main(int argc, char **argv)
761 const char **argv_const = discard_const_p(const char *, argv);
762 struct poptOption long_options[] = {
763 POPT_AUTOHELP
764 /* ... */
765 POPT_COMMON_SAMBA
766 POPT_COMMON_CONNECTION
767 POPT_COMMON_CREDENTIALS
768 POPT_COMMON_VERSION
769 POPT_TABLEEND
771 int opt;
772 poptContext pc;
773 TALLOC_CTX *frame;
774 struct registry_context *ctx;
775 WERROR rv;
776 bool ok;
777 struct loadparm_context *lp_ctx = NULL;
779 frame = talloc_stackframe();
781 smb_init_locale();
783 ok = samba_cmdline_init(frame,
784 SAMBA_CMDLINE_CONFIG_CLIENT,
785 false /* require_smbconf */);
786 if (!ok) {
787 DBG_ERR("Failed to init cmdline parser!\n");
788 TALLOC_FREE(frame);
789 exit(1);
791 lp_ctx = samba_cmdline_get_lp_ctx();
792 lpcfg_set_cmdline(lp_ctx, "log level", "0");
794 /* process options */
795 pc = samba_popt_get_context(getprogname(),
796 argc,
797 argv_const,
798 long_options,
800 if (pc == NULL) {
801 DBG_ERR("Failed to setup popt context!\n");
802 TALLOC_FREE(frame);
803 exit(1);
806 while ((opt = poptGetNextOpt(pc)) != -1) {
807 switch (opt) {
808 case POPT_ERROR_BADOPT:
809 fprintf(stderr, "\nInvalid option %s: %s\n\n",
810 poptBadOption(pc, 0), poptStrerror(opt));
811 poptPrintUsage(pc, stderr, 0);
812 exit(1);
816 poptFreeContext(pc);
817 samba_cmdline_burn(argc, argv);
819 rv = reg_open_samba3(frame, &ctx);
820 if (!W_ERROR_IS_OK(rv)) {
821 fprintf(stderr, "Unable to open registry: %s\n",
822 win_errstr(rv));
823 TALLOC_FREE(frame);
825 return 1;
828 display_window(frame, ctx);
830 gfree_all();
832 TALLOC_FREE(frame);
834 return 0;