mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-01-20 05:19:21 +08:00
f36dd40275
Link directly with RegDeleteKeyExW(), available since Vista. (It's unclear the LoadLibrary wrapper was ever doing anything useful here, as (i) DLL lookup in PATH was avoided as advapi32 is already loaded into the process, and (ii) advapi32 is a 'known DLL' which is only ever loaded from system directory)
989 lines
23 KiB
C++
989 lines
23 KiB
C++
/* regtool.cc
|
|
|
|
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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <ctype.h>
|
|
#include <wchar.h>
|
|
#include <getopt.h>
|
|
#include <locale.h>
|
|
#include <windows.h>
|
|
#include <sys/cygwin.h>
|
|
#include <cygwin/version.h>
|
|
|
|
#define DEFAULT_KEY_SEPARATOR '\\'
|
|
|
|
#define REG_AUTO -1
|
|
|
|
int value_type = REG_AUTO;
|
|
|
|
char key_sep = DEFAULT_KEY_SEPARATOR;
|
|
|
|
#define LIST_KEYS 0x01
|
|
#define LIST_VALS 0x02
|
|
#define LIST_ALL (LIST_KEYS | LIST_VALS)
|
|
|
|
static char *prog_name;
|
|
|
|
static struct option longopts[] =
|
|
{
|
|
{"binary", no_argument, NULL, 'b' },
|
|
{"dword", no_argument, NULL, 'd' },
|
|
{"dword-be", no_argument, NULL, 'D' },
|
|
{"expand-string", no_argument, NULL, 'e' },
|
|
{"force", no_argument, NULL, 'f' },
|
|
{"help", no_argument, NULL, 'h' },
|
|
{"integer", no_argument, NULL, 'i' },
|
|
{"keys", no_argument, NULL, 'k'},
|
|
{"list", no_argument, NULL, 'l'},
|
|
{"multi-string", no_argument, NULL, 'm'},
|
|
{"none", no_argument, NULL, 'n' },
|
|
{"postfix", no_argument, NULL, 'p'},
|
|
{"quiet", no_argument, NULL, 'q'},
|
|
{"qword", no_argument, NULL, 'Q' },
|
|
{"string", no_argument, NULL, 's'},
|
|
{"verbose", no_argument, NULL, 'v'},
|
|
{"version", no_argument, NULL, 'V'},
|
|
{"wow64", no_argument, NULL, 'w'},
|
|
{"wow32", no_argument, NULL, 'W'},
|
|
{"hex", no_argument, NULL, 'x'},
|
|
{"key-separator", required_argument, NULL, 'K'},
|
|
{NULL, 0, NULL, 0}
|
|
};
|
|
|
|
static char opts[] = "bdDefhiklmnpqQsvVwWxK:";
|
|
|
|
const char *types[] =
|
|
{
|
|
"REG_NONE",
|
|
"REG_SZ",
|
|
"REG_EXPAND_SZ",
|
|
"REG_BINARY",
|
|
"REG_DWORD",
|
|
"REG_DWORD_BIG_ENDIAN",
|
|
"REG_LINK",
|
|
"REG_MULTI_SZ",
|
|
"REG_RESOURCE_LIST",
|
|
"REG_FULL_RESOURCE_DESCRIPTOR",
|
|
"REG_RESOURCE_REQUIREMENTS_LIST",
|
|
"REG_QWORD",
|
|
};
|
|
|
|
int listwhat = 0;
|
|
int postfix = 0;
|
|
int verbose = 0;
|
|
int quiet = 0;
|
|
int hex = 0;
|
|
DWORD wow64 = 0;
|
|
DWORD restore_flags = 0;
|
|
char **argv;
|
|
|
|
HKEY key;
|
|
wchar_t *value;
|
|
|
|
static void __attribute__ ((__noreturn__))
|
|
usage (FILE *where = stderr)
|
|
{
|
|
fprintf (where, ""
|
|
"Usage: %s [OPTION] ACTION KEY [data...]\n"
|
|
"\n"
|
|
"View or edit the Win32 registry\n"
|
|
"\n", prog_name);
|
|
if (where == stdout)
|
|
{
|
|
fprintf (where, ""
|
|
"Actions:\n"
|
|
"\n"
|
|
" add KEY\\SUBKEY add new SUBKEY\n"
|
|
" check KEY exit 0 if KEY exists, 1 if not\n"
|
|
" get KEY\\VALUE prints VALUE to stdout\n"
|
|
" list KEY list SUBKEYs and VALUEs\n"
|
|
" remove KEY remove KEY\n"
|
|
" set KEY\\VALUE [data ...] set VALUE\n"
|
|
" unset KEY\\VALUE removes VALUE from KEY\n"
|
|
" load KEY\\SUBKEY PATH load hive from PATH into new SUBKEY\n"
|
|
" unload KEY\\SUBKEY unload hive and remove SUBKEY\n"
|
|
" save KEY\\SUBKEY PATH save SUBKEY into new file PATH\n"
|
|
" restore KEY\\SUBKEY PATH restore SUBKEY from file PATH\n"
|
|
"\n");
|
|
fprintf (where, ""
|
|
"Options for 'list' action:\n"
|
|
"\n"
|
|
" -k, --keys print only KEYs\n"
|
|
" -l, --list print only VALUEs\n"
|
|
" -p, --postfix like ls -p, appends '\\' postfix to KEY names\n"
|
|
"\n"
|
|
"Options for 'get' action:\n"
|
|
"\n"
|
|
" -b, --binary print data as printable hex bytes\n"
|
|
" -n, --none print data as stream of bytes as stored in registry\n"
|
|
" -x, --hex print numerical data as hex numbers\n"
|
|
"\n"
|
|
"Options for 'set' action:\n"
|
|
"\n"
|
|
" -b, --binary set type to REG_BINARY (hex args or '-')\n"
|
|
" -d, --dword set type to REG_DWORD\n"
|
|
" -D, --dword-be set type to REG_DWORD_BIG_ENDIAN\n"
|
|
" -e, --expand-string set type to REG_EXPAND_SZ\n"
|
|
" -i, --integer set type to REG_DWORD\n"
|
|
" -m, --multi-string set type to REG_MULTI_SZ\n"
|
|
" -n, --none set type to REG_NONE\n"
|
|
" -Q, --qword set type to REG_QWORD\n"
|
|
" -s, --string set type to REG_SZ\n"
|
|
"\n"
|
|
"Options for 'set' and 'unset' Actions:\n"
|
|
"\n"
|
|
" -K<c>, --key-separator[=]<c> set key-value separator to <c> instead of '\\'\n"
|
|
"\n"
|
|
"Options for 'restore' action:\n"
|
|
"\n"
|
|
" -f, --force restore even if open handles exist at or beneath the location\n"
|
|
" in the registry hierarchy to which KEY\\SUBKEY points\n"
|
|
"\n"
|
|
"Other Options:\n"
|
|
"\n"
|
|
" -h, --help output usage information and exit\n"
|
|
" -q, --quiet no error output, just nonzero return if KEY/VALUE missing\n"
|
|
" -v, --verbose verbose output, including VALUE contents when applicable\n"
|
|
" -w, --wow64 access 64 bit registry view (ignored on 32 bit Windows)\n"
|
|
" -W, --wow32 access 32 bit registry view (ignored on 32 bit Windows)\n"
|
|
" -V, --version output version information and exit\n"
|
|
"\n");
|
|
fprintf (where, ""
|
|
"KEY is in the format [host]\\prefix\\KEY\\KEY\\VALUE, where host is optional\n"
|
|
"remote host in either \\\\hostname or hostname: format and prefix is any of:\n"
|
|
" root HKCR HKEY_CLASSES_ROOT (local only)\n"
|
|
" config HKCC HKEY_CURRENT_CONFIG (local only)\n"
|
|
" user HKCU HKEY_CURRENT_USER (local only)\n"
|
|
" machine HKLM HKEY_LOCAL_MACHINE\n"
|
|
" users HKU HKEY_USERS\n"
|
|
"\n"
|
|
"You can use forward slash ('/') as a separator instead of backslash, in\n"
|
|
"that case backslash is treated as an escape character.\n"
|
|
"You can also supply the registry path prefix /proc/registry{,32,64}/ to\n"
|
|
"use path completion.\n");
|
|
fprintf (where, ""
|
|
"Example:\n"
|
|
"%s list '/HKLM/SOFTWARE/Classes/MIME/Database/Content Type/audio\\/wav'\n\n", prog_name);
|
|
}
|
|
if (where == stderr)
|
|
fprintf (where,
|
|
"ACTION is one of add, check, get, list, remove, set, unset, load, unload, save\n"
|
|
"\n"
|
|
"Try `%s --help' for more information.\n", prog_name);
|
|
exit (where == stderr ? 1 : 0);
|
|
}
|
|
|
|
static void
|
|
print_version ()
|
|
{
|
|
printf ("regtool (cygwin) %d.%d.%d\n"
|
|
"Registry tool\n"
|
|
"Copyright (C) 2000 - %s Cygwin Authors\n"
|
|
"This is free software; see the source for copying conditions. There is NO\n"
|
|
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
|
|
CYGWIN_VERSION_DLL_MAJOR / 1000,
|
|
CYGWIN_VERSION_DLL_MAJOR % 1000,
|
|
CYGWIN_VERSION_DLL_MINOR,
|
|
strrchr (__DATE__, ' ') + 1);
|
|
}
|
|
|
|
void
|
|
Fail (unsigned int rv)
|
|
{
|
|
wchar_t *buf;
|
|
|
|
if (!quiet)
|
|
{
|
|
FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER
|
|
| FORMAT_MESSAGE_FROM_SYSTEM,
|
|
0, rv, 0, (WCHAR *)& buf, 0, 0);
|
|
fprintf (stderr, "Error (%d): %ls\n", rv, buf);
|
|
LocalFree (buf);
|
|
}
|
|
exit (1);
|
|
}
|
|
|
|
static 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, int option = 0)
|
|
{
|
|
HKEY base;
|
|
int rv;
|
|
char *n = argv[0], *e, *h, c;
|
|
char* host = NULL;
|
|
int i;
|
|
size_t len;
|
|
|
|
if (*n == '/')
|
|
translate (n);
|
|
if (*n != '\\')
|
|
{
|
|
/* expect host:/key/value format */
|
|
host = (char*) malloc (strlen (n) + 1);
|
|
host[0] = host [1] = '\\';
|
|
for (e = n, h = host + 2; *e && *e != ':'; e++, h++)
|
|
*h = *e;
|
|
*h = 0;
|
|
n = e + 1;
|
|
if (*n == '/')
|
|
translate (n);
|
|
}
|
|
else if (n[0] == '\\' && n[1] == '\\')
|
|
{
|
|
/* expect //host/key/value format */
|
|
host = (char*) malloc (strlen (n) + 1);
|
|
host[0] = host[1] = '\\';
|
|
for (e = n + 2, h = host + 2; *e && *e != '\\'; e++, h++)
|
|
*h = *e;
|
|
*h = 0;
|
|
n = e;
|
|
}
|
|
else if (strncmp ("\\proc\\registry", n, strlen ("\\proc\\registry")) == 0)
|
|
{
|
|
/* skip /proc/registry{,32,64}/ prefix */
|
|
n += strlen ("\\proc\\registry");
|
|
if (strncmp ("64", n, strlen ("64")) == 0)
|
|
n += strlen ("64");
|
|
else if (strncmp ("32", n, strlen ("32")) == 0)
|
|
n += strlen ("32");
|
|
}
|
|
while (*n != '\\')
|
|
n++;
|
|
*n++ = 0;
|
|
for (e = n; *e && *e != '\\'; e++);
|
|
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 != key_sep)
|
|
e--;
|
|
if (*e != key_sep)
|
|
{
|
|
key = wkprefixes[i].key;
|
|
if (value)
|
|
free (value);
|
|
len = mbstowcs (NULL, n, 0) + 1;
|
|
value = (wchar_t *) malloc (len * sizeof (wchar_t));
|
|
mbstowcs (value, n, len);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
*e = 0;
|
|
if (value)
|
|
free (value);
|
|
len = mbstowcs (NULL, e + 1, 0) + 1;
|
|
value = (wchar_t *) malloc (len * sizeof (wchar_t));
|
|
mbstowcs (value, e + 1, len);
|
|
}
|
|
}
|
|
if (host)
|
|
{
|
|
rv = RegConnectRegistry (host, wkprefixes[i].key, &base);
|
|
if (rv != ERROR_SUCCESS)
|
|
Fail (rv);
|
|
free (host);
|
|
}
|
|
else
|
|
base = wkprefixes[i].key;
|
|
|
|
if (n[0] == 0)
|
|
key = base;
|
|
else
|
|
{
|
|
len = mbstowcs (NULL, n, 0) + 1;
|
|
wchar_t name[len];
|
|
mbstowcs (name, n, len);
|
|
if (access)
|
|
{
|
|
rv = RegOpenKeyExW (base, name, 0, access | wow64, &key);
|
|
if (option && (rv == ERROR_SUCCESS || rv == ERROR_ACCESS_DENIED))
|
|
{
|
|
/* reopen with desired option due to missing option support in
|
|
RegOpenKeyE */
|
|
/* FIXME: may create the key in rare cases (e.g. access denied
|
|
in parent) */
|
|
HKEY key2;
|
|
if (RegCreateKeyExW (base, name, 0, NULL, option, access | wow64,
|
|
NULL, &key2, NULL)
|
|
== ERROR_SUCCESS)
|
|
{
|
|
if (rv == ERROR_SUCCESS)
|
|
RegCloseKey (key);
|
|
key = key2;
|
|
rv = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
if (rv != ERROR_SUCCESS)
|
|
Fail (rv);
|
|
}
|
|
else if (argv[1])
|
|
{
|
|
ssize_t len = cygwin_conv_path (CCP_POSIX_TO_WIN_W, argv[1], NULL, 0);
|
|
wchar_t win32_path[len];
|
|
cygwin_conv_path (CCP_POSIX_TO_WIN_W, argv[1], win32_path, len);
|
|
rv = RegLoadKeyW (base, name, win32_path);
|
|
if (rv != ERROR_SUCCESS)
|
|
Fail (rv);
|
|
if (verbose)
|
|
printf ("key %ls loaded from file %ls\n", name, win32_path);
|
|
}
|
|
else
|
|
{
|
|
rv = RegUnLoadKeyW (base, name);
|
|
if (rv != ERROR_SUCCESS)
|
|
Fail (rv);
|
|
if (verbose)
|
|
printf ("key %ls unloaded\n", name);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
cmd_list ()
|
|
{
|
|
DWORD num_subkeys, maxsubkeylen, num_values, maxvalnamelen, maxvaluelen;
|
|
DWORD maxclasslen;
|
|
wchar_t *subkey_name, *value_name, *class_name, *vd;
|
|
unsigned char *value_data;
|
|
DWORD i, j, m, n, t;
|
|
int v;
|
|
|
|
find_key (1, KEY_READ);
|
|
RegQueryInfoKeyW (key, 0, 0, 0, &num_subkeys, &maxsubkeylen, &maxclasslen,
|
|
&num_values, &maxvalnamelen, &maxvaluelen, 0, 0);
|
|
|
|
subkey_name = (wchar_t *) malloc ((maxsubkeylen + 1) * sizeof (wchar_t));
|
|
class_name = (wchar_t *) malloc ((maxclasslen + 1) * sizeof (wchar_t));
|
|
value_name = (wchar_t *) malloc ((maxvalnamelen + 1) * sizeof (wchar_t));
|
|
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) * sizeof (wchar_t);
|
|
n = (maxclasslen + 1) * sizeof (wchar_t);
|
|
RegEnumKeyExW (key, i, subkey_name, &m, 0, class_name, &n, 0);
|
|
printf ("%ls", subkey_name);
|
|
if (postfix || verbose)
|
|
fputc (key_sep, stdout);
|
|
|
|
if (verbose)
|
|
printf (" (%ls)", class_name);
|
|
|
|
puts ("");
|
|
}
|
|
|
|
if (listwhat & LIST_VALS)
|
|
for (i = 0; i < num_values; i++)
|
|
{
|
|
m = (maxvalnamelen + 1) * sizeof (wchar_t);
|
|
n = maxvaluelen + 1;
|
|
RegEnumValueW (key, i, value_name, &m, 0, &t, (BYTE *) value_data, &n);
|
|
value_data[n] = 0;
|
|
if (!verbose)
|
|
printf ("%ls\n", value_name);
|
|
else
|
|
{
|
|
printf ("%ls (%s) = ", value_name, types[t]);
|
|
switch (t)
|
|
{
|
|
case REG_NONE:
|
|
case REG_BINARY:
|
|
for (j = 0; j < 8 && j < n; j++)
|
|
printf ("%02x ", value_data[j]);
|
|
printf ("\n");
|
|
break;
|
|
case REG_DWORD:
|
|
printf ("0x%08x (%u)\n", *(unsigned int *) value_data,
|
|
*(unsigned int *) 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_QWORD:
|
|
printf ("0x%016llx (%llu)\n",
|
|
*(unsigned long long *) value_data,
|
|
*(unsigned long long *) value_data);
|
|
break;
|
|
case REG_EXPAND_SZ:
|
|
case REG_SZ:
|
|
case REG_LINK:
|
|
printf ("\"%ls\"\n", (wchar_t *) value_data);
|
|
break;
|
|
case REG_MULTI_SZ:
|
|
vd = (wchar_t *) value_data;
|
|
while (vd && *vd)
|
|
{
|
|
printf ("\"%ls\"", vd);
|
|
vd = vd + wcslen (vd) + 1;
|
|
if (*vd)
|
|
printf (", ");
|
|
}
|
|
printf ("\n");
|
|
break;
|
|
default:
|
|
printf ("?\n");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
cmd_add ()
|
|
{
|
|
find_key (2, KEY_ALL_ACCESS);
|
|
HKEY newkey;
|
|
DWORD newtype;
|
|
int rv = RegCreateKeyExW (key, value, 0, NULL, REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS | wow64, 0, &newkey, &newtype);
|
|
if (rv != ERROR_SUCCESS)
|
|
Fail (rv);
|
|
|
|
if (verbose)
|
|
{
|
|
if (newtype == REG_OPENED_EXISTING_KEY)
|
|
printf ("Key %ls already exists\n", value);
|
|
else
|
|
printf ("Key %ls created\n", value);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
cmd_remove ()
|
|
{
|
|
DWORD rv;
|
|
|
|
find_key (2, KEY_ALL_ACCESS);
|
|
if (wow64)
|
|
rv = RegDeleteKeyExW (key, value, wow64, 0);
|
|
else
|
|
rv = RegDeleteKeyW (key, value);
|
|
if (rv != ERROR_SUCCESS)
|
|
Fail (rv);
|
|
if (verbose)
|
|
printf ("subkey %ls 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, max_n;
|
|
DWORD v, rv;
|
|
unsigned long long llval;
|
|
char *a = argv[1], *data = 0;
|
|
find_key (2, KEY_ALL_ACCESS);
|
|
|
|
if (!a)
|
|
usage ();
|
|
if (value_type == REG_AUTO)
|
|
{
|
|
char *e;
|
|
llval = strtoull (a, &e, 0);
|
|
if (a[0] == '%')
|
|
value_type = REG_EXPAND_SZ;
|
|
else if (a[0] && !*e)
|
|
value_type = llval > 0xffffffffULL ? REG_QWORD : REG_DWORD;
|
|
else if (argv[2])
|
|
value_type = REG_MULTI_SZ;
|
|
else
|
|
value_type = REG_SZ;
|
|
}
|
|
|
|
switch (value_type)
|
|
{
|
|
case REG_NONE:
|
|
case REG_BINARY:
|
|
for (n = 0; argv[n+1]; n++)
|
|
;
|
|
if (n == 1 && strcmp (argv[1], "-") == 0)
|
|
{ /* read from stdin */
|
|
i = n = 0;
|
|
for (;;)
|
|
{
|
|
if (i <= n)
|
|
{
|
|
i = n + BUFSIZ;
|
|
data = (char *) realloc (data, i);
|
|
}
|
|
int r = fread (data+n, 1, i-n, stdin);
|
|
if (r <= 0)
|
|
break;
|
|
n += r;
|
|
}
|
|
}
|
|
else if (n > 0)
|
|
{ /* parse hex from argv */
|
|
data = (char *) malloc (n);
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
char *e;
|
|
errno = 0;
|
|
v = strtoul (argv[i+1], &e, 16);
|
|
if (errno || v > 0xff || *e)
|
|
{
|
|
fprintf (stderr, "Invalid hex constant `%s'\n", argv[i+1]);
|
|
exit (1);
|
|
}
|
|
data[i] = (char) v;
|
|
}
|
|
}
|
|
rv = RegSetValueExW (key, value, 0, value_type, (const BYTE *) data, n);
|
|
break;
|
|
case REG_DWORD:
|
|
v = strtoul (a, 0, 0);
|
|
rv = RegSetValueExW (key, value, 0, REG_DWORD, (const BYTE *) &v,
|
|
sizeof (v));
|
|
break;
|
|
case REG_DWORD_BIG_ENDIAN:
|
|
v = strtoul (a, 0, 0);
|
|
v = (((v & 0xff) << 24)
|
|
| ((v & 0xff00) << 8)
|
|
| ((v & 0xff0000) >> 8)
|
|
| ((v & 0xff000000) >> 24));
|
|
rv = RegSetValueExW (key, value, 0, REG_DWORD_BIG_ENDIAN,
|
|
(const BYTE *) &v, sizeof (v));
|
|
break;
|
|
case REG_QWORD:
|
|
llval = strtoul (a, 0, 0);
|
|
rv = RegSetValueExW (key, value, 0, REG_QWORD, (const BYTE *) &llval,
|
|
sizeof (llval));
|
|
break;
|
|
case REG_SZ:
|
|
case REG_EXPAND_SZ:
|
|
{
|
|
n = mbstowcs (NULL, a, 0);
|
|
wchar_t w[n + 1];
|
|
mbstowcs (w, a, n + 1);
|
|
rv = RegSetValueExW (key, value, 0, value_type,
|
|
(const BYTE *) w, (n + 1) * sizeof (wchar_t));
|
|
}
|
|
break;
|
|
case REG_MULTI_SZ:
|
|
for (i = 1, max_n = 1; argv[i]; i++)
|
|
max_n += mbstowcs (NULL, argv[i], 0) + 1;
|
|
data = (char *) malloc (max_n * sizeof (wchar_t));
|
|
for (i = 1, n = 0; argv[i]; i++)
|
|
n += mbstowcs ((wchar_t *) data + n, argv[i], max_n - n) + 1;
|
|
((wchar_t *)data)[n] = L'\0';
|
|
rv = RegSetValueExW (key, value, 0, REG_MULTI_SZ, (const BYTE *) data,
|
|
(n + 1) * sizeof (wchar_t));
|
|
break;
|
|
case REG_AUTO:
|
|
rv = ERROR_SUCCESS;
|
|
break;
|
|
default:
|
|
rv = ERROR_INVALID_CATEGORY;
|
|
break;
|
|
}
|
|
|
|
if (data)
|
|
free(data);
|
|
|
|
if (rv != ERROR_SUCCESS)
|
|
Fail (rv);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
cmd_unset ()
|
|
{
|
|
find_key (2, KEY_ALL_ACCESS);
|
|
DWORD rv = RegDeleteValueW (key, value);
|
|
if (rv != ERROR_SUCCESS)
|
|
Fail (rv);
|
|
if (verbose)
|
|
printf ("value %ls deleted\n", value);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
cmd_get ()
|
|
{
|
|
find_key (2, KEY_READ);
|
|
DWORD vtype, dsize, rv;
|
|
PBYTE data;
|
|
wchar_t *vd;
|
|
|
|
rv = RegQueryValueExW (key, value, 0, &vtype, 0, &dsize);
|
|
if (rv != ERROR_SUCCESS)
|
|
Fail (rv);
|
|
data = (PBYTE) malloc (dsize + 1);
|
|
rv = RegQueryValueExW (key, value, 0, &vtype, data, &dsize);
|
|
if (rv != ERROR_SUCCESS)
|
|
Fail (rv);
|
|
if (value_type == REG_BINARY)
|
|
{
|
|
for (unsigned i = 0; i < dsize; i++)
|
|
printf ("%02x%c", (unsigned char)data[i],
|
|
(i < dsize-1 ? ' ' : '\n'));
|
|
}
|
|
else if (value_type == REG_NONE)
|
|
fwrite (data, dsize, 1, stdout);
|
|
else
|
|
switch (vtype)
|
|
{
|
|
case REG_NONE:
|
|
case REG_BINARY:
|
|
fwrite (data, dsize, 1, stdout);
|
|
break;
|
|
case REG_DWORD:
|
|
printf (hex ? "0x%08x\n" : "%u\n", *(unsigned int *) data);
|
|
break;
|
|
case REG_DWORD_BIG_ENDIAN:
|
|
rv = ((data[0] << 24)
|
|
| (data[1] << 16)
|
|
| (data[2] << 8)
|
|
| (data[3]));
|
|
printf (hex ? "0x%08x\n" : "%u\n", (unsigned int) rv);
|
|
break;
|
|
case REG_QWORD:
|
|
printf (hex ? "0x%016llx\n" : "%llu\n", *(unsigned long long *) data);
|
|
break;
|
|
case REG_SZ:
|
|
case REG_LINK:
|
|
printf ("%ls\n", (wchar_t *) data);
|
|
break;
|
|
case REG_EXPAND_SZ:
|
|
if (value_type == REG_EXPAND_SZ) // hack
|
|
{
|
|
wchar_t *buf;
|
|
DWORD bufsize;
|
|
bufsize = ExpandEnvironmentStringsW ((wchar_t *) data, 0, 0);
|
|
buf = (wchar_t *) malloc (bufsize + 1);
|
|
ExpandEnvironmentStringsW ((wchar_t *) data, buf, bufsize + 1);
|
|
free (data);
|
|
data = (PBYTE) buf;
|
|
}
|
|
printf ("%ls\n", (wchar_t *) data);
|
|
break;
|
|
case REG_MULTI_SZ:
|
|
vd = (wchar_t *) data;
|
|
while (vd && *vd)
|
|
{
|
|
printf ("%ls\n", vd);
|
|
vd = vd + wcslen (vd) + 1;
|
|
}
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
cmd_load ()
|
|
{
|
|
if (!argv[1])
|
|
usage ();
|
|
find_key (1, 0);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
cmd_unload ()
|
|
{
|
|
if (argv[1])
|
|
usage ();
|
|
find_key (1, 0);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
cmd_save ()
|
|
{
|
|
if (!argv[1])
|
|
usage ();
|
|
/* REG_OPTION_BACKUP_RESTORE is necessary to save /HKLM/SECURITY */
|
|
find_key (1, KEY_QUERY_VALUE, REG_OPTION_BACKUP_RESTORE);
|
|
ssize_t len = cygwin_conv_path (CCP_POSIX_TO_WIN_W, argv[1], NULL, 0);
|
|
wchar_t win32_path[len];
|
|
cygwin_conv_path (CCP_POSIX_TO_WIN_W, argv[1], win32_path, len);
|
|
DWORD rv = RegSaveKeyW (key, win32_path, NULL);
|
|
if (rv != ERROR_SUCCESS)
|
|
Fail (rv);
|
|
if (verbose)
|
|
printf ("key saved to %ls\n", win32_path);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
cmd_restore ()
|
|
{
|
|
if (!argv[1])
|
|
usage ();
|
|
/* REG_OPTION_BACKUP_RESTORE is necessary to restore /HKLM/SECURITY */
|
|
find_key (1, KEY_ALL_ACCESS, REG_OPTION_BACKUP_RESTORE);
|
|
ssize_t len = cygwin_conv_path (CCP_POSIX_TO_WIN_W, argv[1], NULL, 0);
|
|
wchar_t win32_path[len];
|
|
cygwin_conv_path (CCP_POSIX_TO_WIN_W, argv[1], win32_path, len);
|
|
DWORD rv = RegRestoreKeyW (key, win32_path, restore_flags);
|
|
if (rv != ERROR_SUCCESS)
|
|
Fail (rv);
|
|
if (verbose)
|
|
printf ("key saved to %ls\n", win32_path);
|
|
return 0;
|
|
}
|
|
|
|
static 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},
|
|
{"load", cmd_load},
|
|
{"unload", cmd_unload},
|
|
{"save", cmd_save},
|
|
{"restore", cmd_restore},
|
|
{0, 0}
|
|
};
|
|
|
|
int
|
|
main (int argc, char **_argv)
|
|
{
|
|
int g;
|
|
|
|
setlocale (LC_ALL, "");
|
|
|
|
prog_name = program_invocation_short_name;
|
|
|
|
while ((g = getopt_long (argc, _argv, opts, longopts, NULL)) != EOF)
|
|
switch (g)
|
|
{
|
|
case 'b':
|
|
value_type = REG_BINARY;
|
|
break;
|
|
case 'd':
|
|
value_type = REG_DWORD;
|
|
break;
|
|
case 'D':
|
|
value_type = REG_DWORD_BIG_ENDIAN;
|
|
break;
|
|
case 'e':
|
|
value_type = REG_EXPAND_SZ;
|
|
break;
|
|
case 'f':
|
|
restore_flags = REG_FORCE_RESTORE;
|
|
break;
|
|
case 'k':
|
|
listwhat |= LIST_KEYS;
|
|
break;
|
|
case 'h':
|
|
usage (stdout);
|
|
case 'i':
|
|
value_type = REG_DWORD;
|
|
break;
|
|
case 'l':
|
|
listwhat |= LIST_VALS;
|
|
break;
|
|
case 'm':
|
|
value_type = REG_MULTI_SZ;
|
|
break;
|
|
case 'n':
|
|
value_type = REG_NONE;
|
|
break;
|
|
case 'p':
|
|
postfix++;
|
|
break;
|
|
case 'q':
|
|
quiet++;
|
|
break;
|
|
case 'Q':
|
|
value_type = REG_QWORD;
|
|
break;
|
|
case 's':
|
|
value_type = REG_SZ;
|
|
break;
|
|
case 'v':
|
|
verbose++;
|
|
break;
|
|
case 'V':
|
|
print_version ();
|
|
exit (0);
|
|
case 'w':
|
|
wow64 = KEY_WOW64_64KEY;
|
|
break;
|
|
case 'W':
|
|
wow64 = KEY_WOW64_32KEY;
|
|
break;
|
|
case 'x':
|
|
hex++;
|
|
break;
|
|
case 'K':
|
|
key_sep = *optarg;
|
|
break;
|
|
default :
|
|
fprintf (stderr, "Try `%s --help' for more information.\n",
|
|
prog_name);
|
|
return 1;
|
|
}
|
|
|
|
if ((_argv[optind] == NULL) || (_argv[optind+1] == 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 ();
|
|
}
|