summaryrefslogtreecommitdiff
path: root/source4/lib/registry/tools
diff options
context:
space:
mode:
authorJelmer Vernooij <jelmer@samba.org>2004-04-04 16:24:08 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:50:33 -0500
commitc424c2b857fe08587eb81a5c5e3625545119d1c2 (patch)
tree03505d09ccd72cdfd1218066d355e2d01d403bd0 /source4/lib/registry/tools
parent3855ee0164d1c8ff3c3c4ba8a5556d8cfb6546b3 (diff)
downloadsamba-c424c2b857fe08587eb81a5c5e3625545119d1c2.tar.gz
samba-c424c2b857fe08587eb81a5c5e3625545119d1c2.tar.bz2
samba-c424c2b857fe08587eb81a5c5e3625545119d1c2.zip
r20: Add the registry library. Still needs a lot of work,
see source/lib/registry/TODO for details. (This used to be commit 7cab3a00d7b4b1d95a3bfa6b28f318b4aaa5d493)
Diffstat (limited to 'source4/lib/registry/tools')
-rw-r--r--source4/lib/registry/tools/regdiff.c148
-rw-r--r--source4/lib/registry/tools/regpatch.c808
-rw-r--r--source4/lib/registry/tools/regshell.c243
-rw-r--r--source4/lib/registry/tools/regtree.c91
4 files changed, 1290 insertions, 0 deletions
diff --git a/source4/lib/registry/tools/regdiff.c b/source4/lib/registry/tools/regdiff.c
new file mode 100644
index 0000000000..070516b798
--- /dev/null
+++ b/source4/lib/registry/tools/regdiff.c
@@ -0,0 +1,148 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple registry frontend
+
+ Copyright (C) Jelmer Vernooij 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+void writediff(REG_KEY *oldkey, REG_KEY *newkey, FILE *out)
+{
+ int i, numvals1, numvals2, numkeys2;
+
+ numkeys2 = reg_key_num_subkeys(newkey);
+ for(i = 0; i < numkeys2; i++) {
+ REG_KEY *t1 = reg_key_get_subkey_by_index(newkey, i);
+ REG_KEY *t2 = reg_key_get_subkey_by_name(oldkey, reg_key_name(t1));
+ if(!t2) {
+ fprintf(out, "[%s]\n", reg_key_get_path(t1));
+ }
+ writediff(t2, t1, out);
+ }
+
+ numvals2 = reg_key_num_values(newkey);
+ for(i = 0; i < numvals2; i++) {
+ REG_VAL *t1 = reg_key_get_value_by_index(newkey, i);
+ REG_VAL *t2 = reg_key_get_value_by_name(oldkey, reg_val_name(t1));
+ if(!t2 || reg_val_size(t2) != reg_val_size(t1) || memcmp(reg_val_data_blk(t1), reg_val_data_blk(t2), reg_val_size(t1))) {
+ fprintf(out, "\"%s\"=%s:%s\n", reg_val_name(t1), str_regtype(reg_val_type(t1)), reg_val_data_string(t1));
+ }
+ }
+
+ numvals1 = reg_key_num_values(oldkey);
+ for(i = 0; i < numvals1; i++) {
+ REG_VAL *t1 = reg_key_get_value_by_index(oldkey, i);
+ if(!reg_key_get_value_by_name(newkey, reg_val_name(t1))) {
+ fprintf(out, "\"%s\"=-\n", reg_val_name(t1));
+ }
+ }
+}
+
+int main (int argc, char **argv)
+{
+ uint32 setparms, checkparms;
+ int opt;
+ poptContext pc;
+ REG_KEY *root;
+ const char *backend1 = NULL, *backend2 = NULL;
+ const char *location2;
+ char *outputfile = NULL;
+ FILE *fd = stdout;
+ REG_HANDLE *h2;
+ REG_KEY *root1 = NULL, *root2;
+ int from_null = 0;
+ int fullpath = 0, no_values = 0;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"backend", 'b', POPT_ARG_STRING, NULL, 'b', "backend to use", NULL},
+ {"output", 'o', POPT_ARG_STRING, &outputfile, 'o', "output file to use", NULL },
+ {"null", 'n', POPT_ARG_NONE, &from_null, 'n', "Diff from NULL" },
+ POPT_TABLEEND
+ };
+
+ pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0);
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch(opt) {
+ case 'b':
+ if(!backend1 && !from_null) backend1 = poptGetOptArg(pc);
+ else if(!backend2) backend2 = poptGetOptArg(pc);
+ break;
+ }
+ }
+ setup_logging(argv[0], True);
+
+ if(!from_null) {
+ REG_HANDLE *h1;
+ const char *location1;
+ location1 = poptGetArg(pc);
+ if(!location1) {
+ poptPrintUsage(pc, stderr, 0);
+ return 1;
+ }
+
+ if(!backend1) backend1 = "dir";
+
+ h1 = reg_open(backend1, location1, True);
+ if(!h1) {
+ fprintf(stderr, "Unable to open '%s' with backend '%s'\n", location1, backend1);
+ return 1;
+ }
+
+ root1 = reg_get_root(h1);
+ }
+
+ location2 = poptGetArg(pc);
+ if(!location2) {
+ poptPrintUsage(pc, stderr, 0);
+ return 2;
+ }
+
+ if(!backend2) backend2 = "dir";
+
+ h2 = reg_open(backend2, location2, True);
+ if(!h2) {
+ fprintf(stderr, "Unable to open '%s' with backend '%s'\n", location2, backend2);
+ return 1;
+ }
+
+ root2 = reg_get_root(h2);
+ if(!root2) {
+ fprintf(stderr, "Can't open root key for '%s:%s'\n", backend2, location2);
+ return 1;
+ }
+
+ poptFreeContext(pc);
+
+ if(outputfile) {
+ fd = fopen(outputfile, "w+");
+ if(!fd) {
+ fprintf(stderr, "Unable to open '%s'\n", outputfile);
+ return 1;
+ }
+ }
+
+ fprintf(fd, "REGEDIT4\n\n");
+ fprintf(fd, "; Generated using regdiff\n");
+
+ writediff(root1, root2, fd);
+
+ fclose(fd);
+
+ return 0;
+}
diff --git a/source4/lib/registry/tools/regpatch.c b/source4/lib/registry/tools/regpatch.c
new file mode 100644
index 0000000000..f76da7ebf9
--- /dev/null
+++ b/source4/lib/registry/tools/regpatch.c
@@ -0,0 +1,808 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple registry frontend
+
+ Copyright (C) 2002, Richard Sharpe, rsharpe@richardsharpe.com
+ Copyright (C) 2004, Jelmer Vernooij, jelmer@samba.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ * Routines to parse a REGEDIT4 file
+ *
+ * The file consists of:
+ *
+ * REGEDIT4
+ * \[[-]key-path\]\n
+ * <value-spec>*
+ *
+ * Format:
+ * [cmd:]name=type:value
+ *
+ * cmd = a|d|c|add|delete|change|as|ds|cs
+ *
+ * There can be more than one key-path and value-spec.
+ *
+ * Since we want to support more than one type of file format, we
+ * construct a command-file structure that keeps info about the command file
+ */
+
+#define FMT_UNREC -1
+#define FMT_REGEDIT4 0
+#define FMT_EDITREG1_1 1
+
+#define FMT_STRING_REGEDIT4 "REGEDIT4"
+#define FMT_STRING_EDITREG1_0 "EDITREG1.0"
+
+#define CMD_NONE 0
+#define CMD_ADD_KEY 1
+#define CMD_DEL_KEY 2
+
+#define CMD_KEY 1
+#define CMD_VAL 2
+
+#include <include/includes.h>
+
+typedef struct val_spec_list {
+ struct val_spec_list *next;
+ char *name;
+ int type;
+ char *val; /* Kept as a char string, really? */
+} VAL_SPEC_LIST;
+
+typedef struct command_s {
+ int cmd;
+ char *key;
+ int val_count;
+ VAL_SPEC_LIST *val_spec_list, *val_spec_last;
+} CMD;
+
+typedef struct cmd_line {
+ int len, line_len;
+ char *line;
+} CMD_LINE;
+
+static void free_val_spec_list(VAL_SPEC_LIST *vl)
+{
+ if (!vl) return;
+ if (vl->name) free(vl->name);
+ if (vl->val) free(vl->val);
+ free(vl);
+
+}
+
+/*
+ * Some routines to handle lines of info in the command files
+ */
+static void skip_to_eol(int fd)
+{
+ int rc;
+ char ch = 0;
+
+ while ((rc = read(fd, &ch, 1)) == 1) {
+ if (ch == 0x0A) return;
+ }
+ if (rc < 0) {
+ DEBUG(0, ("Could not read file descriptor: %d, %s\n",
+ fd, strerror(errno)));
+ exit(1);
+ }
+}
+
+static void free_cmd(CMD *cmd)
+{
+ if (!cmd) return;
+
+ while (cmd->val_spec_list) {
+ VAL_SPEC_LIST *tmp;
+
+ tmp = cmd->val_spec_list;
+ cmd->val_spec_list = tmp->next;
+ free(tmp);
+ }
+
+ free(cmd);
+
+}
+
+static void free_cmd_line(CMD_LINE *cmd_line)
+{
+ if (cmd_line) {
+ if (cmd_line->line) free(cmd_line->line);
+ free(cmd_line);
+ }
+}
+
+static void print_line(struct cmd_line *cl)
+{
+ char *pl;
+
+ if (!cl) return;
+
+ pl = smb_xmalloc(cl->line_len + 1);
+
+ strncpy(pl, cl->line, cl->line_len);
+ pl[cl->line_len] = 0;
+
+ fprintf(stdout, "%s\n", pl);
+ free(pl);
+}
+
+#define INIT_ALLOC 10
+
+/*
+ * Read a line from the input file.
+ * NULL returned when EOF and no chars read
+ * Otherwise we return a cmd_line *
+ * Exit if other errors
+ */
+static struct cmd_line *get_cmd_line(int fd)
+{
+ struct cmd_line *cl = (CMD_LINE *)smb_xmalloc(sizeof(CMD_LINE));
+ int i = 0, rc;
+ unsigned char ch;
+
+ cl->len = INIT_ALLOC;
+
+ /*
+ * Allocate some space for the line. We extend later if needed.
+ */
+
+ cl->line = (char *)smb_xmalloc(INIT_ALLOC);
+
+ /*
+ * Now read in the chars to EOL. Don't store the EOL in the
+ * line. What about CR?
+ */
+
+ while ((rc = read(fd, &ch, 1)) == 1 && ch != '\n') {
+ if (ch == '\r') continue; /* skip CR */
+ if (i == cl->len) {
+ /*
+ * Allocate some more memory
+ */
+ if ((cl->line = realloc(cl->line, cl->len + INIT_ALLOC)) == NULL) {
+ DEBUG(0, ("Unable to realloc space for line: %s\n",
+ strerror(errno)));
+ exit(1);
+ }
+ cl->len += INIT_ALLOC;
+ }
+ cl->line[i] = ch;
+ i++;
+ }
+
+ /* read 0 and we were at loc'n 0, return NULL */
+ if (rc == 0 && i == 0) {
+ free_cmd_line(cl);
+ return NULL;
+ }
+
+ cl->line_len = i;
+
+ return cl;
+
+}
+
+/*
+ * parse_value: parse out a value. We pull it apart as:
+ *
+ * <value> ::= <value-name>=<type>:<value-string>
+ *
+ * <value-name> ::= char-string-without-spaces | '"' char-string '"'
+ *
+ * If it parsed OK, return the <value-name> as a string, and the
+ * value type and value-string in parameters.
+ *
+ * The value name can be empty. There can only be one empty name in
+ * a list of values. A value of - removes the value entirely.
+ */
+
+static char *parse_name(char *nstr)
+{
+ int len = 0, start = 0;
+ if (!nstr) return NULL;
+
+ len = strlen(nstr);
+
+ while (len && nstr[len - 1] == ' ') len--;
+
+ nstr[len] = 0; /* Trim any spaces ... if there were none, doesn't matter */
+
+ /*
+ * Beginning and end should be '"' or neither should be so
+ */
+ if ((nstr[0] == '"' && nstr[len - 1] != '"') ||
+ (nstr[0] != '"' && nstr[len - 1] == '"'))
+ return NULL;
+
+ if (nstr[0] == '"') {
+ start = 1;
+ len -= 2;
+ }
+
+ return strndup(&nstr[start], len);
+}
+
+static int parse_value_type(char *tstr)
+{
+ int len = strlen(tstr);
+
+ while (len && tstr[len - 1] == ' ') len--;
+ tstr[len] = 0;
+
+ if (strcmp(tstr, "REG_DWORD") == 0)
+ return REG_DWORD;
+ else if (strcmp(tstr, "dword") == 0)
+ return REG_DWORD;
+ else if (strcmp(tstr, "REG_EXPAND_SZ") == 0)
+ return REG_EXPAND_SZ;
+ else if (strcmp(tstr, "REG_BIN") == 0)
+ return REG_BINARY;
+ else if (strcmp(tstr, "REG_SZ") == 0)
+ return REG_SZ;
+ else if (strcmp(tstr, "REG_MULTI_SZ") == 0)
+ return REG_MULTI_SZ;
+ else if (strcmp(tstr, "-") == 0)
+ return REG_DELETE;
+
+ return 0;
+}
+
+static char *parse_val_str(char *vstr)
+{
+
+ return strndup(vstr, strlen(vstr));
+
+}
+
+static char *parse_value(struct cmd_line *cl, int *vtype, char **val)
+{
+ char *p1 = NULL, *p2 = NULL, *nstr = NULL, *tstr = NULL, *vstr = NULL;
+
+ if (!cl || !vtype || !val) return NULL;
+ if (!cl->line_len) return NULL;
+
+ p1 = strndup(cl->line, cl->line_len);
+ /* FIXME: Better return codes etc ... */
+ if (!p1) return NULL;
+ p2 = strchr(p1, '=');
+ if (!p2) return NULL;
+
+ *p2 = 0; p2++; /* Split into two strings at p2 */
+
+ /* Now, parse the name ... */
+
+ nstr = parse_name(p1);
+ if (!nstr) goto error;
+
+ /* Now, split the remainder and parse on type and val ... */
+
+ tstr = p2;
+ while (*tstr == ' ') tstr++; /* Skip leading white space */
+ p2 = strchr(p2, ':');
+
+ if (p2) {
+ *p2 = 0; p2++; /* split on the : */
+ }
+
+ *vtype = parse_value_type(tstr);
+
+ if (!vtype) goto error;
+
+ if (!p2 || !*p2) return nstr;
+
+ /* Now, parse the value string. It should return a newly malloc'd string */
+
+ while (*p2 == ' ') p2++; /* Skip leading space */
+ vstr = parse_val_str(p2);
+
+ if (!vstr) goto error;
+
+ *val = vstr;
+
+ return nstr;
+
+ error:
+ if (p1) free(p1);
+ if (nstr) free(nstr);
+ if (vstr) free(vstr);
+ return NULL;
+}
+
+/*
+ * Parse out a key. Look for a correctly formatted key [...]
+ * and whether it is a delete or add? A delete is signalled
+ * by a - in front of the key.
+ * Assumes that there are no leading and trailing spaces
+ */
+
+static char *parse_key(struct cmd_line *cl, int *cmd)
+{
+ int start = 1;
+ char *tmp;
+
+ if (cl->line[0] != '[' ||
+ cl->line[cl->line_len - 1] != ']') return NULL;
+ if (cl->line_len == 2) return NULL;
+ *cmd = CMD_ADD_KEY;
+ if (cl->line[1] == '-') {
+ if (cl->line_len == 3) return NULL;
+ start = 2;
+ *cmd = CMD_DEL_KEY;
+ }
+ tmp = smb_xmalloc(cl->line_len - 1 - start + 1);
+ strncpy(tmp, &cl->line[start], cl->line_len - 1 - start);
+ tmp[cl->line_len - 1 - start] = 0;
+ return tmp;
+}
+
+/*
+ * Parse a line to determine if we have a key or a value
+ * We only check for key or val ...
+ */
+
+static int parse_line(struct cmd_line *cl)
+{
+
+ if (!cl || cl->len == 0) return 0;
+
+ if (cl->line[0] == '[') /* No further checking for now */
+ return CMD_KEY;
+ else
+ return CMD_VAL;
+}
+
+/*
+ * We seek to offset 0, read in the required number of bytes,
+ * and compare to the correct value.
+ * We then seek back to the original location
+ */
+static int regedit4_file_type(int fd)
+{
+ int cur_ofs = 0;
+ char desc[9];
+
+ cur_ofs = lseek(fd, 0, SEEK_CUR); /* Get current offset */
+ if (cur_ofs < 0) {
+ DEBUG(0, ("Unable to get current offset: %s\n", strerror(errno)));
+ exit(1); /* FIXME */
+ }
+
+ if (cur_ofs) {
+ lseek(fd, 0, SEEK_SET);
+ }
+
+ if (read(fd, desc, 8) < 8) {
+ DEBUG(0, ("Unable to read command file format\n"));
+ exit(2); /* FIXME */
+ }
+
+ desc[8] = 0;
+
+ if (strcmp(desc, FMT_STRING_REGEDIT4) == 0) {
+ if (cur_ofs) {
+ lseek(fd, cur_ofs, SEEK_SET);
+ }
+ else {
+ skip_to_eol(fd);
+ }
+ return FMT_REGEDIT4;
+ }
+
+ return FMT_UNREC;
+}
+
+/*
+ * Run though the data in the line and strip anything after a comment
+ * char.
+ */
+static void strip_comment(struct cmd_line *cl)
+{
+ int i;
+
+ if (!cl) return;
+
+ for (i = 0; i < cl->line_len; i++) {
+ if (cl->line[i] == ';') {
+ cl->line_len = i;
+ return;
+ }
+ }
+}
+
+/*
+ * trim leading space
+ */
+
+static void trim_leading_spaces(struct cmd_line *cl)
+{
+ int i;
+
+ if (!cl) return;
+
+ for (i = 0; i < cl->line_len; i++) {
+ if (cl->line[i] != ' '){
+ if (i) memcpy(cl->line, &cl->line[i], cl->line_len - i);
+ return;
+ }
+ }
+}
+
+/*
+ * trim trailing spaces
+ */
+static void trim_trailing_spaces(struct cmd_line *cl)
+{
+ int i;
+
+ if (!cl) return;
+
+ for (i = cl->line_len; i == 0; i--) {
+ if (cl->line[i-1] != ' ' &&
+ cl->line[i-1] != '\t') {
+ cl->line_len = i;
+ }
+ }
+}
+
+/*
+ * Get a command ... This consists of possibly multiple lines:
+ * [key]
+ * values*
+ * possibly Empty line
+ *
+ * value ::= <value-name>=<value-type>':'<value-string>
+ * <value-name> is some path, possibly enclosed in quotes ...
+ * We alctually look for the next key to terminate a previous key
+ * if <value-type> == '-', then it is a delete type.
+ */
+static CMD *regedit4_get_cmd(int fd)
+{
+ struct command_s *cmd = NULL;
+ struct cmd_line *cl = NULL;
+ struct val_spec_list *vl = NULL;
+
+ cmd = (struct command_s *)smb_xmalloc(sizeof(struct command_s));
+
+ cmd->cmd = CMD_NONE;
+ cmd->key = NULL;
+ cmd->val_count = 0;
+ cmd->val_spec_list = cmd->val_spec_last = NULL;
+ while ((cl = get_cmd_line(fd))) {
+
+ /*
+ * If it is an empty command line, and we already have a key
+ * then exit from here ... FIXME: Clean up the parser
+ */
+
+ if (cl->line_len == 0 && cmd->key) {
+ free_cmd_line(cl);
+ break;
+ }
+
+ strip_comment(cl); /* remove anything beyond a comment char */
+ trim_trailing_spaces(cl);
+ trim_leading_spaces(cl);
+
+ if (cl->line_len == 0) { /* An empty line */
+ free_cmd_line(cl);
+ }
+ else { /* Else, non-empty ... */
+ /*
+ * Parse out the bits ...
+ */
+ switch (parse_line(cl)) {
+ case CMD_KEY:
+ if ((cmd->key = parse_key(cl, &cmd->cmd)) == NULL) {
+ DEBUG(0, ("Error parsing key from line: "));
+ print_line(cl);
+ DEBUG(0, ("\n"));
+ }
+ break;
+
+ case CMD_VAL:
+ /*
+ * We need to add the value stuff to the list
+ * There could be a \ on the end which we need to
+ * handle at some time
+ */
+ vl = (struct val_spec_list *)smb_xmalloc(sizeof(struct val_spec_list));
+ vl->next = NULL;
+ vl->val = NULL;
+ vl->name = parse_value(cl, &vl->type, &vl->val);
+ if (!vl->name) goto error;
+ if (cmd->val_spec_list == NULL) {
+ cmd->val_spec_list = cmd->val_spec_last = vl;
+ }
+ else {
+ cmd->val_spec_last->next = vl;
+ cmd->val_spec_last = vl;
+ }
+ cmd->val_count++;
+ break;
+
+ default:
+ DEBUG(0, ("Unrecognized line in command file: \n"));
+ print_line(cl);
+ break;
+ }
+ }
+
+ }
+ if (!cmd->cmd) goto error; /* End of file ... */
+
+ return cmd;
+
+ error:
+ if (vl) free(vl);
+ if (cmd) free_cmd(cmd);
+ return NULL;
+}
+
+static int regedit4_exec_cmd(CMD *cmd)
+{
+
+ return 0;
+}
+
+static int editreg_1_0_file_type(int fd)
+{
+ int cur_ofs = 0;
+ char desc[11];
+
+ cur_ofs = lseek(fd, 0, SEEK_CUR); /* Get current offset */
+ if (cur_ofs < 0) {
+ DEBUG(0, ("Unable to get current offset: %s\n", strerror(errno)));
+ exit(1); /* FIXME */
+ }
+
+ if (cur_ofs) {
+ lseek(fd, 0, SEEK_SET);
+ }
+
+ if (read(fd, desc, 10) < 10) {
+ DEBUG(0, ("Unable to read command file format\n"));
+ exit(2); /* FIXME */
+ }
+
+ desc[10] = 0;
+
+ if (strcmp(desc, FMT_STRING_EDITREG1_0) == 0) {
+ lseek(fd, cur_ofs, SEEK_SET);
+ return FMT_REGEDIT4;
+ }
+
+ return FMT_UNREC;
+}
+
+static CMD *editreg_1_0_get_cmd(int fd)
+{
+ return NULL;
+}
+
+static int editreg_1_0_exec_cmd(CMD *cmd)
+{
+
+ return -1;
+}
+
+typedef struct command_ops_s {
+ int type;
+ int (*file_type)(int fd);
+ CMD *(*get_cmd)(int fd);
+ int (*exec_cmd)(CMD *cmd);
+} CMD_OPS;
+
+CMD_OPS default_cmd_ops[] = {
+ {0, regedit4_file_type, regedit4_get_cmd, regedit4_exec_cmd},
+ {1, editreg_1_0_file_type, editreg_1_0_get_cmd, editreg_1_0_exec_cmd},
+ {-1, NULL, NULL, NULL}
+};
+
+typedef struct command_file_s {
+ char *name;
+ int type, fd;
+ CMD_OPS cmd_ops;
+} CMD_FILE;
+
+/*
+ * Create a new command file structure
+ */
+
+static CMD_FILE *cmd_file_create(char *file)
+{
+ CMD_FILE *tmp;
+ struct stat sbuf;
+ int i = 0;
+
+ /*
+ * Let's check if the file exists ...
+ * No use creating the cmd_file structure if the file does not exist
+ */
+
+ if (stat(file, &sbuf) < 0) { /* Not able to access file */
+
+ return NULL;
+ }
+
+ tmp = (CMD_FILE *)smb_xmalloc(sizeof(CMD_FILE));
+
+ /*
+ * Let's fill in some of the fields;
+ */
+
+ tmp->name = strdup(file);
+
+ if ((tmp->fd = open(file, O_RDONLY, 666)) < 0) {
+ free(tmp);
+ return NULL;
+ }
+
+ /*
+ * Now, try to find the format by indexing through the table
+ */
+ while (default_cmd_ops[i].type != -1) {
+ if ((tmp->type = default_cmd_ops[i].file_type(tmp->fd)) >= 0) {
+ tmp->cmd_ops = default_cmd_ops[i];
+ return tmp;
+ }
+ i++;
+ }
+
+ /*
+ * If we got here, return NULL, as we could not figure out the type
+ * of command file.
+ *
+ * What about errors?
+ */
+
+ free(tmp);
+ return NULL;
+}
+
+/*
+ * Extract commands from the command file, and execute them.
+ * We pass a table of command callbacks for that
+ */
+
+//FIXME
+
+/*
+ * Main code from here on ...
+ */
+
+/*
+ * key print function here ...
+ */
+
+/*
+ * Sec Desc print functions
+ */
+
+char *str_type(unsigned char type);
+
+int nt_apply_reg_command_file(REG_HANDLE *regf, const char *cmd_file_name)
+{
+ CMD *cmd;
+ int modified = 0;
+ CMD_FILE *cmd_file = NULL;
+ cmd_file = cmd_file_create(cmd_file_name);
+
+ while ((cmd = cmd_file->cmd_ops.get_cmd(cmd_file->fd)) != NULL) {
+
+ /*
+ * Now, apply the requests to the tree ...
+ */
+ switch (cmd->cmd) {
+ case CMD_ADD_KEY: {
+ REG_KEY *tmp = NULL;
+ tmp = reg_open_key(reg_get_root(regf), cmd->key);
+ /* If we found it, apply the other bits, else create such a key */
+ if (!tmp) {
+ if(reg_key_add_name(reg_get_root(regf), cmd->key)) {
+ tmp = reg_open_key(reg_get_root(regf), cmd->key);
+ }
+ modified = 1;
+ }
+
+ while (cmd->val_count) {
+ VAL_SPEC_LIST *val = cmd->val_spec_list;
+ REG_VAL *reg_val = NULL;
+
+ if (val->type == REG_DELETE) {
+ reg_val = reg_key_get_value_by_name( tmp, val->name);
+ reg_val_del(reg_val);
+ modified = 1;
+ }
+ else {
+ /* FIXME
+ reg_val = nt_add_reg_value(tmp, val->name, val->type,
+ val->val); */
+ modified = 1;
+ }
+
+ cmd->val_spec_list = val->next;
+ free_val_spec_list(val);
+ cmd->val_count--;
+ }
+
+ break;
+ }
+
+ case CMD_DEL_KEY:
+ /*
+ * Any value does not matter ...
+ * Find the key if it exists, and delete it ...
+ */
+
+ reg_key_del_recursive(reg_open_key(reg_get_root(regf), cmd->key));
+ modified = 1;
+ break;
+ }
+ }
+ free_cmd(cmd);
+
+ return modified;
+}
+
+int main (int argc, char **argv)
+{
+ uint32 setparms, checkparms;
+ int opt;
+ poptContext pc;
+ REG_KEY *root;
+ const char *location;
+ const char *patch;
+ char *backend = "dir";
+ REG_HANDLE *h;
+ int fullpath = 0, no_values = 0;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"backend", 'b', POPT_ARG_STRING, &backend, 'b', "backend to use", NULL},
+ POPT_TABLEEND
+ };
+
+ pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0);
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ setup_logging(argv[0], True);
+
+ location = poptGetArg(pc);
+ if(!location) {
+ poptPrintUsage(pc, stderr, 0);
+ return 1;
+ }
+
+ h = reg_open(backend, location, True);
+ if(!h) {
+ fprintf(stderr, "Unable to open '%s' with backend '%s'\n", location, backend);
+ return 1;
+ }
+
+ poptFreeContext(pc);
+
+ patch = poptGetArg(pc);
+ if(!patch) patch = "/dev/stdin";
+
+ nt_apply_reg_command_file(h, patch);
+
+ return 0;
+}
diff --git a/source4/lib/registry/tools/regshell.c b/source4/lib/registry/tools/regshell.c
new file mode 100644
index 0000000000..9074d1c716
--- /dev/null
+++ b/source4/lib/registry/tools/regshell.c
@@ -0,0 +1,243 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple registry frontend
+
+ Copyright (C) Jelmer Vernooij 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ * ck/cd - change key
+ * ls - list values/keys
+ * rmval/rm - remove value
+ * rmkey/rmdir - remove key
+ * mkkey/mkdir - make key
+ * help
+ * exit
+ */
+
+static REG_KEY *cmd_set(REG_KEY *cur, int argc, char **argv)
+{
+ /* FIXME */
+ return NULL;
+}
+
+static REG_KEY *cmd_ck(REG_KEY *cur, int argc, char **argv)
+{
+ REG_KEY *new;
+ if(argc < 2) {
+ new = cur;
+ } else {
+ new = reg_open_key(cur, argv[1]);
+ }
+
+ if(!new) new = cur;
+
+ printf("Current path is: %s\n", reg_key_get_path(new));
+
+ return new;
+}
+
+static REG_KEY *cmd_ls(REG_KEY *cur, int argc, char **argv)
+{
+ int i, num;
+ num = reg_key_num_subkeys(cur);
+ for(i = 0; i < num; i++) {
+ REG_KEY *sub = reg_key_get_subkey_by_index(cur, i);
+ printf("K %s\n", reg_key_name(sub));
+ }
+
+ num = reg_key_num_values(cur);
+ for(i = 0; i < num; i++) {
+ REG_VAL *sub = reg_key_get_value_by_index(cur, i);
+ printf("V %s %s %s\n", reg_val_name(sub), str_regtype(reg_val_type(sub)), reg_val_data_string(sub));
+ }
+
+ return NULL;
+}
+static REG_KEY *cmd_mkkey(REG_KEY *cur, int argc, char **argv)
+{
+ if(argc < 2) {
+ fprintf(stderr, "Usage: mkkey <keyname>\n");
+ return NULL;
+ }
+
+ if(!reg_key_add_name(cur, argv[1])) {
+ fprintf(stderr, "Error adding new subkey '%s'\n", argv[1]);
+ return NULL;
+ }
+
+ fprintf(stderr, "Successfully added new subkey '%s' to '%s'\n", argv[1], reg_key_get_path(cur));
+
+ return NULL;
+}
+
+static REG_KEY *cmd_rmkey(REG_KEY *cur, int argc, char **argv)
+{
+ REG_KEY *key;
+ if(argc < 2) {
+ fprintf(stderr, "Usage: rmkey <name>\n");
+ return NULL;
+ }
+
+ key = reg_open_key(cur, argv[1]);
+ if(!key) {
+ fprintf(stderr, "No such subkey '%s'\n", argv[1]);
+ return NULL;
+ }
+
+ if(!reg_key_del(key)) {
+ fprintf(stderr, "Error deleting '%s'\n", argv[1]);
+ } else {
+ fprintf(stderr, "Successfully deleted '%s'\n", argv[1]);
+ }
+
+ return NULL;
+}
+
+static REG_KEY *cmd_rmval(REG_KEY *cur, int argc, char **argv)
+{
+ REG_VAL *val;
+ if(argc < 2) {
+ fprintf(stderr, "Usage: rmval <valuename>\n");
+ return NULL;
+ }
+
+ val = reg_key_get_value_by_name(cur, argv[1]);
+ if(!val) {
+ fprintf(stderr, "No such value '%s'\n", argv[1]);
+ return NULL;
+ }
+
+ if(!reg_val_del(val)) {
+ fprintf(stderr, "Error deleting value '%s'\n", argv[1]);
+ } else {
+ fprintf(stderr, "Successfully deleted value '%s'\n", argv[1]);
+ }
+
+ return NULL;
+}
+
+static REG_KEY *cmd_exit(REG_KEY *cur, int argc, char **argv)
+{
+ exit(0);
+ return NULL;
+}
+
+static REG_KEY *cmd_help(REG_KEY *, int, char **);
+
+struct {
+ const char *name;
+ const char *alias;
+ const char *help;
+ REG_KEY *(*handle)(REG_KEY *, int argc, char **argv);
+} regshell_cmds[] = {
+ {"ck", "cd", "Change current key", cmd_ck },
+ {"list", "ls", "List values/keys in current key", cmd_ls },
+ {"mkkey", "mkdir", "Make new key", cmd_mkkey },
+ {"rmval", "rm", "Remove value", cmd_rmval },
+ {"rmkey", "rmdir", "Remove key", cmd_rmkey },
+ {"set", "update", "Update value", cmd_set },
+ {"help", "?", "Help", cmd_help },
+ {"exit", "quit", "Exit", cmd_exit },
+ {NULL }
+};
+
+static REG_KEY *cmd_help(REG_KEY *cur, int argc, char **argv)
+{
+ int i;
+ printf("Available commands:\n");
+ for(i = 0; regshell_cmds[i].name; i++) {
+ printf("%s - %s\n", regshell_cmds[i].name, regshell_cmds[i].help);
+ }
+ return NULL;
+}
+
+REG_KEY *process_cmd(REG_KEY *k, char *line)
+{
+ int argc;
+ char **argv = NULL;
+ int ret, i;
+
+ if ((ret = poptParseArgvString(line, &argc, (const char ***) &argv)) != 0) {
+ fprintf(stderr, "regshell: %s\n", poptStrerror(ret));
+ return k;
+ }
+
+ for(i = 0; regshell_cmds[i].name; i++) {
+ if(!strcmp(regshell_cmds[i].name, argv[0]) ||
+ (regshell_cmds[i].alias && !strcmp(regshell_cmds[i].alias, argv[0]))) {
+ return regshell_cmds[i].handle(k, argc, argv);
+ }
+ }
+
+ fprintf(stderr, "No such command '%s'\n", argv[0]);
+
+ return k;
+}
+
+int main (int argc, char **argv)
+{
+ uint32 setparms, checkparms;
+ int opt;
+ char *backend = "dir";
+ REG_KEY *curkey = NULL;;
+ poptContext pc;
+ REG_HANDLE *h;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"backend", 'b', POPT_ARG_STRING, &backend, 0, "backend to use", NULL},
+ POPT_TABLEEND
+ };
+
+ pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0);
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ h = reg_open(backend, poptPeekArg(pc), True);
+ if(!h) {
+ fprintf(stderr, "Unable to open '%s' with backend '%s'\n", poptGetArg(pc), backend);
+ return 1;
+ }
+ poptFreeContext(pc);
+
+ setup_logging("regtree", True);
+
+ curkey = reg_get_root(h);
+
+ if(!curkey) return 1;
+
+ while(True) {
+ char *line, *prompt;
+
+ asprintf(&prompt, "%s> ", reg_key_get_path(curkey));
+
+ line = smb_readline(prompt, NULL, NULL);
+
+ if(!line)
+ break;
+
+ if(line[0] != '\n') {
+ REG_KEY *new = process_cmd(curkey, line);
+ if(new)curkey = new;
+ }
+ }
+
+ return 0;
+}
diff --git a/source4/lib/registry/tools/regtree.c b/source4/lib/registry/tools/regtree.c
new file mode 100644
index 0000000000..80cbccf48f
--- /dev/null
+++ b/source4/lib/registry/tools/regtree.c
@@ -0,0 +1,91 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple registry frontend
+
+ Copyright (C) Jelmer Vernooij 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+void print_tree(int l, REG_KEY *p, int fullpath, int novals)
+{
+ int num_subkeys, i, num_values;
+
+ for(i = 0; i < l; i++) putchar(' ');
+ if(fullpath) printf("%s\n", reg_key_get_path(p));
+ else printf("%s\n", reg_key_name(p));
+
+ num_subkeys = reg_key_num_subkeys(p);
+ for(i = 0; i < num_subkeys; i++) {
+ REG_KEY *subkey = reg_key_get_subkey_by_index(p, i);
+ print_tree(l+1, subkey, fullpath, novals);
+ reg_key_free(subkey);
+ }
+
+ if(!novals) {
+ num_values = reg_key_num_values(p);
+ for(i = 0; i < num_values; i++) {
+ int j;
+ char *desc;
+ REG_VAL *value = reg_key_get_value_by_index(p, i);
+ for(j = 0; j < l+1; j++) putchar(' ');
+ desc = reg_val_description(value);
+ printf("%s\n", desc);
+ free(desc);
+ reg_val_free(value);
+ }
+ }
+}
+
+int main (int argc, char **argv)
+{
+ uint32 setparms, checkparms;
+ int opt;
+ char *backend = "dir";
+ poptContext pc;
+ REG_KEY *root;
+ REG_HANDLE *h;
+ int fullpath = 0, no_values = 0;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"backend", 'b', POPT_ARG_STRING, &backend, 0, "backend to use", NULL},
+ {"fullpath", 'f', POPT_ARG_NONE, &fullpath, 0, "show full paths", NULL},
+ {"no-values", 'V', POPT_ARG_NONE, &no_values, 0, "don't show values", NULL},
+ POPT_TABLEEND
+ };
+
+ pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0);
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ }
+
+ setup_logging("regtree", True);
+
+ h = reg_open(backend, poptPeekArg(pc), True);
+ if(!h) {
+ fprintf(stderr, "Unable to open '%s' with backend '%s'\n", poptGetArg(pc), backend);
+ return 1;
+ }
+ poptFreeContext(pc);
+
+ root = reg_get_root(h);
+ if(!root) return 1;
+
+ print_tree(0, root, fullpath, no_values);
+
+ return 0;
+}