/* regtool.cc Copyright 2000 Red Hat Inc. This file is part of Cygwin. This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include #include #include #include #include enum { KT_AUTO, KT_INT, KT_STRING, KT_EXPAND, KT_MULTI } key_type = KT_AUTO; #define LIST_KEYS 0x01 #define LIST_VALS 0x02 #define LIST_ALL (LIST_KEYS | LIST_VALS) int listwhat = 0; int postfix = 0; int verbose = 0; int quiet = 0; char **argv; HKEY key; char *value; const char *usage_msg[] = { "Regtool Copyright (c) 2000 Red Hat Inc", " regtool -h - print this message", " regtool [-v|-p|-k|-l] list [key] - list subkeys and values", " -p=postfix, like ls -p, appends / postfix to key names", " -k=keys, lists only keys", " -l=values, lists only values", " regtool [-v] add [key\\subkey] - add new subkey", " regtool [-v] remove [key] - remove key", " regtool [-v|-q] check [key] - exit 0 if key exists, 1 if not", " regtool [-i|-s|-e|-m] set [key\\value] [data ...] - set value", " -i=integer -s=string -e=expand-string -m=multi-string", " regtool [-v] unset [key\\value] - removes value from key", " regtool [-q] get [key\\value] - prints value to stdout", " -q=quiet, no error msg, just return nonzero exit if key/value missing", " keys are like \\prefix\\key\\key\\key\\value, where prefix is any of:", " root HKCR HKEY_CLASSES_ROOT", " config HKCC HKEY_CURRENT_CONFIG", " user HKCU HKEY_CURRENT_USER", " machine HKLM HKEY_LOCAL_MACHINE", " users HKU HKEY_USERS", " example: \\user\\software\\Microsoft\\Clock\\iFormat", 0 }; void usage (void) { int i; for (i = 0; usage_msg[i]; i++) fprintf (stderr, "%s\n", usage_msg[i]); exit (1); } void Fail (DWORD rv) { char *buf; if (!quiet) { FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, rv, 0, (CHAR *) & buf, 0, 0); fprintf (stderr, "Error: %s\n", buf); LocalFree (buf); } exit (1); } struct { const char *string; HKEY key; } wkprefixes[] = { {"root", HKEY_CLASSES_ROOT}, {"HKCR", HKEY_CLASSES_ROOT}, {"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT}, {"config", HKEY_CURRENT_CONFIG}, {"HKCC", HKEY_CURRENT_CONFIG}, {"HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG}, {"user", HKEY_CURRENT_USER}, {"HKCU", HKEY_CURRENT_USER}, {"HKEY_CURRENT_USER", HKEY_CURRENT_USER}, {"machine", HKEY_LOCAL_MACHINE}, {"HKLM", HKEY_LOCAL_MACHINE}, {"HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE}, {"users", HKEY_USERS}, {"HKU", HKEY_USERS}, {"HKEY_USERS", HKEY_USERS}, {0, 0} }; void translate (char *key) { #define isodigit(c) (strchr("01234567", c)) #define tooct(c) ((c)-'0') #define tohex(c) (strchr(_hs,tolower(c))-_hs) static char _hs[] = "0123456789abcdef"; char *d = key; char *s = key; char c; while (*s) { if (*s == '\\') switch (*++s) { case 'a': *d++ = '\007'; break; case 'b': *d++ = '\b'; break; case 'e': *d++ = '\033'; break; case 'f': *d++ = '\f'; break; case 'n': *d++ = '\n'; break; case 'r': *d++ = '\r'; break; case 't': *d++ = '\t'; break; case 'v': *d++ = '\v'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': c = tooct (*s); if (isodigit (s[1])) { c = (c << 3) | tooct (*++s); if (isodigit (s[1])) c = (c << 3) | tooct (*++s); } *d++ = c; break; case 'x': if (!isxdigit (s[1])) c = '0'; else { c = tohex (*++s); if (isxdigit (s[1])) c = (c << 4) | tohex (*++s); } *d++ = c; break; default: /* before non-special char: just add the char */ *d++ = *s; break; } else if (*s == '/') *d++ = '\\'; else *d++ = *s; ++s; } *d = '\0'; } void find_key (int howmanyparts, REGSAM access) { char *n = argv[0], *e, c; int i; if (*n == '/') translate (n); while ((*n == '\\') || (*n == '/')) n++; for (e = n; *e && *e != '\\' && *e != '/'; e++); if (*e == '/') c = '\\'; else c = *e; *e = 0; for (i = 0; wkprefixes[i].string; i++) if (strcmp (wkprefixes[i].string, n) == 0) break; if (!wkprefixes[i].string) { fprintf (stderr, "Unknown key prefix. Valid prefixes are:\n"); for (i = 0; wkprefixes[i].string; i++) fprintf (stderr, "\t%s\n", wkprefixes[i].string); exit (1); } n = e; *e = c; while (*n && *n == '\\') n++; e = n + strlen (n); if (howmanyparts > 1) { while (n < e && *e != '\\') e--; if (*e != '\\') { fprintf (stderr, "Invalid key\n"); exit (1); } *e = 0; value = e + 1; } if (n[0] == 0) { key = wkprefixes[i].key; return; } int rv = RegOpenKeyEx (wkprefixes[i].key, n, 0, access, &key); if (rv != ERROR_SUCCESS) Fail (rv); //printf("key `%s' value `%s'\n", n, value); } int cmd_list () { DWORD num_subkeys, maxsubkeylen, num_values, maxvalnamelen, maxvaluelen; DWORD maxclasslen; char *subkey_name, *value_name, *class_name; unsigned char *value_data, *vd; DWORD i, j, m, n, t; int v; find_key (1, KEY_READ); RegQueryInfoKey (key, 0, 0, 0, &num_subkeys, &maxsubkeylen, &maxclasslen, &num_values, &maxvalnamelen, &maxvaluelen, 0, 0); subkey_name = (char *) malloc (maxsubkeylen + 1); class_name = (char *) malloc (maxclasslen + 1); value_name = (char *) malloc (maxvalnamelen + 1); value_data = (unsigned char *) malloc (maxvaluelen + 1); if (!listwhat) listwhat = LIST_ALL; if (listwhat & LIST_KEYS) for (i = 0; i < num_subkeys; i++) { m = maxsubkeylen + 1; n = maxclasslen + 1; RegEnumKeyEx (key, i, subkey_name, &m, 0, class_name, &n, 0); printf ("%s%s", subkey_name, (postfix || verbose) ? "\\" : ""); if (verbose) printf (" (%s)", class_name); puts (""); } if (listwhat & LIST_VALS) for (i = 0; i < num_values; i++) { m = maxvalnamelen + 1; n = maxvaluelen + 1; RegEnumValue (key, i, value_name, &m, 0, &t, (BYTE *) value_data, &n); if (!verbose) printf ("%s\n", value_name); else { printf ("%s = ", value_name); switch (t) { case REG_BINARY: for (j = 0; j < 8 && j < n; j++) printf ("%02x ", value_data[j]); printf ("\n"); break; case REG_DWORD: printf ("0x%08lx (%lu)\n", *(DWORD *) value_data, *(DWORD *) value_data); break; case REG_DWORD_BIG_ENDIAN: v = ((value_data[0] << 24) | (value_data[1] << 16) | (value_data[2] << 8) | (value_data[3])); printf ("0x%08x (%d)\n", v, v); break; case REG_EXPAND_SZ: case REG_SZ: printf ("\"%s\"\n", value_data); break; case REG_MULTI_SZ: vd = value_data; while (vd && *vd) { printf ("\"%s\"", vd); vd = vd + strlen ((const char *) vd) + 1; if (*vd) printf (", "); } printf ("\n"); break; default: printf ("? (type %d)\n", (int) t); } } } return 0; } int cmd_add () { find_key (2, KEY_ALL_ACCESS); HKEY newkey; DWORD newtype; int rv = RegCreateKeyEx (key, value, 0, (char *) "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &newkey, &newtype); if (rv != ERROR_SUCCESS) Fail (rv); if (verbose) { if (newtype == REG_OPENED_EXISTING_KEY) printf ("Key %s already exists\n", value); else printf ("Key %s created\n", value); } return 0; } int cmd_remove () { find_key (2, KEY_ALL_ACCESS); DWORD rv = RegDeleteKey (key, value); if (rv != ERROR_SUCCESS) Fail (rv); if (verbose) printf ("subkey %s deleted\n", value); return 0; } int cmd_check () { find_key (1, KEY_READ); if (verbose) printf ("key %s exists\n", argv[0]); return 0; } int cmd_set () { int i, n; DWORD v, rv; char *a = argv[1], *data; find_key (2, KEY_ALL_ACCESS); if (key_type == KT_AUTO) { char *e; strtoul (a, &e, 0); if (a[0] == '%') key_type = KT_EXPAND; else if (a[0] && !*e) key_type = KT_INT; else if (argv[2]) key_type = KT_MULTI; else key_type = KT_STRING; } switch (key_type) { case KT_INT: v = strtoul (a, 0, 0); rv = RegSetValueEx (key, value, 0, REG_DWORD, (const BYTE *) &v, sizeof (v)); break; case KT_STRING: rv = RegSetValueEx (key, value, 0, REG_SZ, (const BYTE *) a, strlen (a)); break; case KT_EXPAND: rv = RegSetValueEx (key, value, 0, REG_EXPAND_SZ, (const BYTE *) a, strlen (a)); break; case KT_MULTI: for (i = 1, n = 1; argv[i]; i++) n += strlen (argv[i]) + 1; data = (char *) malloc (n); for (i = 1, n = 0; argv[i]; i++) { strcpy (data + n, argv[i]); n += strlen (argv[i]) + 1; } data[n] = 0; rv = RegSetValueEx (key, value, 0, REG_MULTI_SZ, (const BYTE *) data, n + 1); break; case KT_AUTO: rv = ERROR_SUCCESS; break; default: rv = ERROR_INVALID_CATEGORY; break; } if (rv != ERROR_SUCCESS) Fail (rv); return 0; } int cmd_unset () { find_key (2, KEY_ALL_ACCESS); DWORD rv = RegDeleteValue (key, value); if (rv != ERROR_SUCCESS) Fail (rv); if (verbose) printf ("value %s deleted\n", value); return 0; } int cmd_get () { find_key (2, KEY_READ); DWORD vtype, dsize, rv; char *data, *vd; rv = RegQueryValueEx (key, value, 0, &vtype, 0, &dsize); if (rv != ERROR_SUCCESS) Fail (rv); dsize++; data = (char *) malloc (dsize); rv = RegQueryValueEx (key, value, 0, &vtype, (BYTE *) data, &dsize); if (rv != ERROR_SUCCESS) Fail (rv); switch (vtype) { case REG_BINARY: fwrite (data, dsize, 0, stdout); break; case REG_DWORD: printf ("%lu\n", *(DWORD *) data); break; case REG_SZ: printf ("%s\n", data); break; case REG_EXPAND_SZ: if (key_type == KT_EXPAND) // hack { char *buf; DWORD bufsize; bufsize = ExpandEnvironmentStrings (data, 0, 0); buf = (char *) malloc (bufsize + 1); ExpandEnvironmentStrings (data, buf, bufsize + 1); data = buf; } printf ("%s\n", data); break; case REG_MULTI_SZ: vd = data; while (vd && *vd) { printf ("%s\n", vd); vd = vd + strlen ((const char *) vd) + 1; } break; } return 0; } struct { const char *name; int (*func) (); } commands[] = { {"list", cmd_list}, {"add", cmd_add}, {"remove", cmd_remove}, {"check", cmd_check}, {"set", cmd_set}, {"unset", cmd_unset}, {"get", cmd_get}, {0, 0} }; int main (int argc, char **_argv) { while (1) { int g = getopt (argc, _argv, "hvqisempkl"); if (g == -1) break; switch (g) { case 'v': verbose++; break; case 'q': quiet++; break; case 'p': postfix++; break; case 'k': listwhat |= LIST_KEYS; break; case 'l': listwhat |= LIST_VALS; break; case 'i': key_type = KT_INT; break; case 's': key_type = KT_STRING; break; case 'e': key_type = KT_EXPAND; break; case 'm': key_type = KT_MULTI; break; case '?': case 'h': usage (); } } if (_argv[optind] == NULL) usage (); argv = _argv + optind; int i; for (i = 0; commands[i].name; i++) if (strcmp (commands[i].name, argv[0]) == 0) { argv++; return commands[i].func (); } usage (); return 0; }