]> sourceware.org Git - newlib-cygwin.git/blame - winsup/utils/regtool.cc
Cygwin: add release message for latest pipe changes
[newlib-cygwin.git] / winsup / utils / regtool.cc
CommitLineData
1fd5e000
CF
1/* regtool.cc
2
1fd5e000
CF
3This file is part of Cygwin.
4
5This software is a copyrighted work licensed under the terms of the
6Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7details. */
8
9#include <stdio.h>
10#include <stdlib.h>
17c8ac39 11#include <errno.h>
1fd5e000 12#include <ctype.h>
7077c48e 13#include <wchar.h>
1fd5e000 14#include <getopt.h>
7077c48e 15#include <locale.h>
1fd5e000 16#include <windows.h>
17c8ac39 17#include <sys/cygwin.h>
92b499ac 18#include <cygwin/version.h>
1fd5e000 19
403985a4
CF
20#define DEFAULT_KEY_SEPARATOR '\\'
21
70158caf
CV
22#define REG_AUTO -1
23
24int value_type = REG_AUTO;
1fd5e000 25
403985a4
CF
26char key_sep = DEFAULT_KEY_SEPARATOR;
27
37770e00
CF
28#define LIST_KEYS 0x01
29#define LIST_VALS 0x02
30#define LIST_ALL (LIST_KEYS | LIST_VALS)
31
9bd02410
CF
32static char *prog_name;
33
34static struct option longopts[] =
35{
17c8ac39 36 {"binary", no_argument, NULL, 'b' },
70158caf 37 {"dword", no_argument, NULL, 'd' },
7077c48e 38 {"dword-be", no_argument, NULL, 'D' },
9bd02410 39 {"expand-string", no_argument, NULL, 'e' },
a6791b3b 40 {"force", no_argument, NULL, 'f' },
9bd02410
CF
41 {"help", no_argument, NULL, 'h' },
42 {"integer", no_argument, NULL, 'i' },
43 {"keys", no_argument, NULL, 'k'},
44 {"list", no_argument, NULL, 'l'},
45 {"multi-string", no_argument, NULL, 'm'},
70158caf 46 {"none", no_argument, NULL, 'n' },
9bd02410
CF
47 {"postfix", no_argument, NULL, 'p'},
48 {"quiet", no_argument, NULL, 'q'},
70158caf 49 {"qword", no_argument, NULL, 'Q' },
9bd02410
CF
50 {"string", no_argument, NULL, 's'},
51 {"verbose", no_argument, NULL, 'v'},
52 {"version", no_argument, NULL, 'V'},
40c60b89 53 {"wow64", no_argument, NULL, 'w'},
3c256e38 54 {"wow32", no_argument, NULL, 'W'},
70158caf 55 {"hex", no_argument, NULL, 'x'},
403985a4 56 {"key-separator", required_argument, NULL, 'K'},
9bd02410
CF
57 {NULL, 0, NULL, 0}
58};
59
a6791b3b 60static char opts[] = "bdDefhiklmnpqQsvVwWxK:";
70158caf
CV
61
62const char *types[] =
63{
64 "REG_NONE",
65 "REG_SZ",
66 "REG_EXPAND_SZ",
67 "REG_BINARY",
68 "REG_DWORD",
69 "REG_DWORD_BIG_ENDIAN",
70 "REG_LINK",
71 "REG_MULTI_SZ",
72 "REG_RESOURCE_LIST",
73 "REG_FULL_RESOURCE_DESCRIPTOR",
74 "REG_RESOURCE_REQUIREMENTS_LIST",
75 "REG_QWORD",
76};
9bd02410 77
37770e00
CF
78int listwhat = 0;
79int postfix = 0;
1fd5e000
CF
80int verbose = 0;
81int quiet = 0;
70158caf 82int hex = 0;
40c60b89 83DWORD wow64 = 0;
a6791b3b 84DWORD restore_flags = 0;
1fd5e000
CF
85char **argv;
86
87HKEY key;
7077c48e 88wchar_t *value;
1fd5e000 89
e7fca6f8 90static void __attribute__ ((__noreturn__))
9bd02410
CF
91usage (FILE *where = stderr)
92{
93 fprintf (where, ""
70158caf 94 "Usage: %s [OPTION] ACTION KEY [data...]\n"
92b499ac 95 "\n"
aa275fe0 96 "View or edit the Win32 registry\n"
70158caf 97 "\n", prog_name);
9bd02410 98 if (where == stdout)
dae37d5d 99 {
70158caf
CV
100 fprintf (where, ""
101 "Actions:\n"
92b499ac 102 "\n"
70158caf
CV
103 " add KEY\\SUBKEY add new SUBKEY\n"
104 " check KEY exit 0 if KEY exists, 1 if not\n"
105 " get KEY\\VALUE prints VALUE to stdout\n"
106 " list KEY list SUBKEYs and VALUEs\n"
107 " remove KEY remove KEY\n"
108 " set KEY\\VALUE [data ...] set VALUE\n"
109 " unset KEY\\VALUE removes VALUE from KEY\n"
110 " load KEY\\SUBKEY PATH load hive from PATH into new SUBKEY\n"
111 " unload KEY\\SUBKEY unload hive and remove SUBKEY\n"
a6791b3b
CV
112 " save KEY\\SUBKEY PATH save SUBKEY into new file PATH\n"
113 " restore KEY\\SUBKEY PATH restore SUBKEY from file PATH\n"
70158caf
CV
114 "\n");
115 fprintf (where, ""
a6791b3b 116 "Options for 'list' action:\n"
92b499ac 117 "\n"
70158caf
CV
118 " -k, --keys print only KEYs\n"
119 " -l, --list print only VALUEs\n"
120 " -p, --postfix like ls -p, appends '\\' postfix to KEY names\n"
121 "\n"
a6791b3b 122 "Options for 'get' action:\n"
92b499ac 123 "\n"
70158caf
CV
124 " -b, --binary print data as printable hex bytes\n"
125 " -n, --none print data as stream of bytes as stored in registry\n"
126 " -x, --hex print numerical data as hex numbers\n"
127 "\n"
a6791b3b 128 "Options for 'set' action:\n"
92b499ac 129 "\n"
70158caf
CV
130 " -b, --binary set type to REG_BINARY (hex args or '-')\n"
131 " -d, --dword set type to REG_DWORD\n"
7077c48e 132 " -D, --dword-be set type to REG_DWORD_BIG_ENDIAN\n"
70158caf
CV
133 " -e, --expand-string set type to REG_EXPAND_SZ\n"
134 " -i, --integer set type to REG_DWORD\n"
135 " -m, --multi-string set type to REG_MULTI_SZ\n"
136 " -n, --none set type to REG_NONE\n"
137 " -Q, --qword set type to REG_QWORD\n"
138 " -s, --string set type to REG_SZ\n"
139 "\n"
140 "Options for 'set' and 'unset' Actions:\n"
92b499ac 141 "\n"
70158caf
CV
142 " -K<c>, --key-separator[=]<c> set key-value separator to <c> instead of '\\'\n"
143 "\n"
a6791b3b
CV
144 "Options for 'restore' action:\n"
145 "\n"
146 " -f, --force restore even if open handles exist at or beneath the location\n"
147 " in the registry hierarchy to which KEY\\SUBKEY points\n"
148 "\n"
70158caf 149 "Other Options:\n"
92b499ac 150 "\n"
70158caf
CV
151 " -h, --help output usage information and exit\n"
152 " -q, --quiet no error output, just nonzero return if KEY/VALUE missing\n"
153 " -v, --verbose verbose output, including VALUE contents when applicable\n"
f51e76da
CV
154 " -w, --wow64 access 64 bit registry view\n"
155 " -W, --wow32 access 32 bit registry view\n"
70158caf
CV
156 " -V, --version output version information and exit\n"
157 "\n");
dae37d5d
CV
158 fprintf (where, ""
159 "KEY is in the format [host]\\prefix\\KEY\\KEY\\VALUE, where host is optional\n"
160 "remote host in either \\\\hostname or hostname: format and prefix is any of:\n"
161 " root HKCR HKEY_CLASSES_ROOT (local only)\n"
162 " config HKCC HKEY_CURRENT_CONFIG (local only)\n"
163 " user HKCU HKEY_CURRENT_USER (local only)\n"
164 " machine HKLM HKEY_LOCAL_MACHINE\n"
165 " users HKU HKEY_USERS\n"
166 "\n"
d3110717
BI
167 "You can use forward slash ('/') as a separator instead of backslash, in\n"
168 "that case backslash is treated as an escape character.\n"
169 "You can also supply the registry path prefix /proc/registry{,32,64}/ to\n"
170 "use path completion.\n");
dae37d5d
CV
171 fprintf (where, ""
172 "Example:\n"
d3110717 173 "%s list '/HKLM/SOFTWARE/Classes/MIME/Database/Content Type/audio\\/wav'\n\n", prog_name);
dae37d5d 174 }
9bd02410 175 if (where == stderr)
70158caf
CV
176 fprintf (where,
177 "ACTION is one of add, check, get, list, remove, set, unset, load, unload, save\n"
178 "\n"
92b499ac 179 "Try `%s --help' for more information.\n", prog_name);
9bd02410
CF
180 exit (where == stderr ? 1 : 0);
181}
1fd5e000 182
9bd02410
CF
183static void
184print_version ()
1fd5e000 185{
92b499ac 186 printf ("regtool (cygwin) %d.%d.%d\n"
1b23b30b 187 "Registry tool\n"
6e623e93 188 "Copyright (C) 2000 - %s Cygwin Authors\n"
1b23b30b 189 "This is free software; see the source for copying conditions. There is NO\n"
92b499ac 190 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
1b23b30b
CF
191 CYGWIN_VERSION_DLL_MAJOR / 1000,
192 CYGWIN_VERSION_DLL_MAJOR % 1000,
193 CYGWIN_VERSION_DLL_MINOR,
194 strrchr (__DATE__, ' ') + 1);
1fd5e000
CF
195}
196
197void
61522196 198Fail (unsigned int rv)
1fd5e000 199{
4d336756
FH
200 wchar_t *buf;
201
1fd5e000
CF
202 if (!quiet)
203 {
4d336756
FH
204 FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER
205 | FORMAT_MESSAGE_FROM_SYSTEM,
206 0, rv, 0, (WCHAR *)& buf, 0, 0);
207 fprintf (stderr, "Error (%d): %ls\n", rv, buf);
37770e00 208 LocalFree (buf);
1fd5e000 209 }
b82a7a5e 210 exit (1);
1fd5e000
CF
211}
212
a35d9f1a 213static struct
b82a7a5e 214{
1fd5e000
CF
215 const char *string;
216 HKEY key;
b82a7a5e
CF
217} wkprefixes[] =
218{
219 {"root", HKEY_CLASSES_ROOT},
220 {"HKCR", HKEY_CLASSES_ROOT},
221 {"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT},
222 {"config", HKEY_CURRENT_CONFIG},
223 {"HKCC", HKEY_CURRENT_CONFIG},
224 {"HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG},
225 {"user", HKEY_CURRENT_USER},
226 {"HKCU", HKEY_CURRENT_USER},
227 {"HKEY_CURRENT_USER", HKEY_CURRENT_USER},
228 {"machine", HKEY_LOCAL_MACHINE},
229 {"HKLM", HKEY_LOCAL_MACHINE},
230 {"HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE},
231 {"users", HKEY_USERS},
232 {"HKU", HKEY_USERS},
233 {"HKEY_USERS", HKEY_USERS},
234 {0, 0}
1fd5e000
CF
235};
236
b82a7a5e
CF
237void
238translate (char *key)
1fd5e000
CF
239{
240#define isodigit(c) (strchr("01234567", c))
241#define tooct(c) ((c)-'0')
242#define tohex(c) (strchr(_hs,tolower(c))-_hs)
243 static char _hs[] = "0123456789abcdef";
244
245 char *d = key;
246 char *s = key;
247 char c;
248
249 while (*s)
250 {
251 if (*s == '\\')
b82a7a5e
CF
252 switch (*++s)
253 {
254 case 'a':
255 *d++ = '\007';
256 break;
257 case 'b':
258 *d++ = '\b';
259 break;
260 case 'e':
261 *d++ = '\033';
262 break;
263 case 'f':
264 *d++ = '\f';
265 break;
266 case 'n':
267 *d++ = '\n';
268 break;
269 case 'r':
270 *d++ = '\r';
271 break;
272 case 't':
273 *d++ = '\t';
274 break;
275 case 'v':
276 *d++ = '\v';
277 break;
278 case '0':
279 case '1':
280 case '2':
281 case '3':
282 case '4':
283 case '5':
284 case '6':
285 case '7':
286 c = tooct (*s);
287 if (isodigit (s[1]))
288 {
289 c = (c << 3) | tooct (*++s);
290 if (isodigit (s[1]))
291 c = (c << 3) | tooct (*++s);
292 }
293 *d++ = c;
294 break;
295 case 'x':
296 if (!isxdigit (s[1]))
7adad121 297 c = '0';
b82a7a5e
CF
298 else
299 {
300 c = tohex (*++s);
301 if (isxdigit (s[1]))
302 c = (c << 4) | tohex (*++s);
303 }
304 *d++ = c;
305 break;
306 default: /* before non-special char: just add the char */
307 *d++ = *s;
308 break;
309 }
1fd5e000 310 else if (*s == '/')
b82a7a5e 311 *d++ = '\\';
1fd5e000 312 else
b82a7a5e 313 *d++ = *s;
1fd5e000
CF
314 ++s;
315 }
316 *d = '\0';
317}
318
319void
17c8ac39 320find_key (int howmanyparts, REGSAM access, int option = 0)
1fd5e000 321{
381fb8ba
CV
322 HKEY base;
323 int rv;
324 char *n = argv[0], *e, *h, c;
325 char* host = NULL;
1fd5e000 326 int i;
7077c48e
CV
327 size_t len;
328
1fd5e000 329 if (*n == '/')
b82a7a5e 330 translate (n);
381fb8ba
CV
331 if (*n != '\\')
332 {
333 /* expect host:/key/value format */
334 host = (char*) malloc (strlen (n) + 1);
4bfc614b 335 host[0] = host [1] = '\\';
381fb8ba 336 for (e = n, h = host + 2; *e && *e != ':'; e++, h++)
4bfc614b 337 *h = *e;
381fb8ba
CV
338 *h = 0;
339 n = e + 1;
340 if (*n == '/')
4bfc614b 341 translate (n);
381fb8ba
CV
342 }
343 else if (n[0] == '\\' && n[1] == '\\')
344 {
345 /* expect //host/key/value format */
346 host = (char*) malloc (strlen (n) + 1);
4bfc614b 347 host[0] = host[1] = '\\';
381fb8ba 348 for (e = n + 2, h = host + 2; *e && *e != '\\'; e++, h++)
4bfc614b 349 *h = *e;
381fb8ba
CV
350 *h = 0;
351 n = e;
352 }
d3110717
BI
353 else if (strncmp ("\\proc\\registry", n, strlen ("\\proc\\registry")) == 0)
354 {
355 /* skip /proc/registry{,32,64}/ prefix */
356 n += strlen ("\\proc\\registry");
357 if (strncmp ("64", n, strlen ("64")) == 0)
358 n += strlen ("64");
359 else if (strncmp ("32", n, strlen ("32")) == 0)
360 n += strlen ("32");
361 }
381fb8ba 362 while (*n != '\\')
1fd5e000 363 n++;
381fb8ba 364 *n++ = 0;
288f125e
CF
365 for (e = n; *e && *e != '\\'; e++);
366 c = *e;
1fd5e000 367 *e = 0;
b82a7a5e
CF
368 for (i = 0; wkprefixes[i].string; i++)
369 if (strcmp (wkprefixes[i].string, n) == 0)
1fd5e000
CF
370 break;
371 if (!wkprefixes[i].string)
372 {
b82a7a5e
CF
373 fprintf (stderr, "Unknown key prefix. Valid prefixes are:\n");
374 for (i = 0; wkprefixes[i].string; i++)
375 fprintf (stderr, "\t%s\n", wkprefixes[i].string);
376 exit (1);
1fd5e000
CF
377 }
378
379 n = e;
380 *e = c;
381 while (*n && *n == '\\')
382 n++;
b82a7a5e 383 e = n + strlen (n);
1fd5e000
CF
384 if (howmanyparts > 1)
385 {
403985a4 386 while (n < e && *e != key_sep)
1fd5e000 387 e--;
403985a4 388 if (*e != key_sep)
1fd5e000 389 {
4c61c04c 390 key = wkprefixes[i].key;
7077c48e
CV
391 if (value)
392 free (value);
393 len = mbstowcs (NULL, n, 0) + 1;
708d2a1e 394 value = (wchar_t *) malloc (len * sizeof (wchar_t));
7077c48e 395 mbstowcs (value, n, len);
4c61c04c
CV
396 return;
397 }
398 else
4bfc614b 399 {
4c61c04c 400 *e = 0;
7077c48e
CV
401 if (value)
402 free (value);
403 len = mbstowcs (NULL, e + 1, 0) + 1;
708d2a1e 404 value = (wchar_t *) malloc (len * sizeof (wchar_t));
7077c48e 405 mbstowcs (value, e + 1, len);
1fd5e000 406 }
1fd5e000 407 }
381fb8ba
CV
408 if (host)
409 {
410 rv = RegConnectRegistry (host, wkprefixes[i].key, &base);
411 if (rv != ERROR_SUCCESS)
412 Fail (rv);
413 free (host);
414 }
415 else
416 base = wkprefixes[i].key;
417
1fd5e000 418 if (n[0] == 0)
381fb8ba
CV
419 key = base;
420 else
1fd5e000 421 {
7077c48e
CV
422 len = mbstowcs (NULL, n, 0) + 1;
423 wchar_t name[len];
424 mbstowcs (name, n, len);
17c8ac39
CV
425 if (access)
426 {
7077c48e 427 rv = RegOpenKeyExW (base, name, 0, access | wow64, &key);
17c8ac39
CV
428 if (option && (rv == ERROR_SUCCESS || rv == ERROR_ACCESS_DENIED))
429 {
7077c48e
CV
430 /* reopen with desired option due to missing option support in
431 RegOpenKeyE */
432 /* FIXME: may create the key in rare cases (e.g. access denied
433 in parent) */
17c8ac39 434 HKEY key2;
7077c48e
CV
435 if (RegCreateKeyExW (base, name, 0, NULL, option, access | wow64,
436 NULL, &key2, NULL)
17c8ac39 437 == ERROR_SUCCESS)
1b23b30b 438 {
17c8ac39
CV
439 if (rv == ERROR_SUCCESS)
440 RegCloseKey (key);
441 key = key2;
442 rv = ERROR_SUCCESS;
1b23b30b 443 }
17c8ac39
CV
444 }
445 if (rv != ERROR_SUCCESS)
446 Fail (rv);
447 }
448 else if (argv[1])
1b23b30b 449 {
7077c48e
CV
450 ssize_t len = cygwin_conv_path (CCP_POSIX_TO_WIN_W, argv[1], NULL, 0);
451 wchar_t win32_path[len];
452 cygwin_conv_path (CCP_POSIX_TO_WIN_W, argv[1], win32_path, len);
453 rv = RegLoadKeyW (base, name, win32_path);
17c8ac39
CV
454 if (rv != ERROR_SUCCESS)
455 Fail (rv);
456 if (verbose)
7077c48e 457 printf ("key %ls loaded from file %ls\n", name, win32_path);
17c8ac39
CV
458 }
459 else
1b23b30b 460 {
7077c48e 461 rv = RegUnLoadKeyW (base, name);
17c8ac39
CV
462 if (rv != ERROR_SUCCESS)
463 Fail (rv);
464 if (verbose)
7077c48e 465 printf ("key %ls unloaded\n", name);
17c8ac39 466 }
1fd5e000 467 }
1fd5e000
CF
468}
469
470
471int
b82a7a5e 472cmd_list ()
1fd5e000
CF
473{
474 DWORD num_subkeys, maxsubkeylen, num_values, maxvalnamelen, maxvaluelen;
475 DWORD maxclasslen;
7077c48e
CV
476 wchar_t *subkey_name, *value_name, *class_name, *vd;
477 unsigned char *value_data;
1fd5e000
CF
478 DWORD i, j, m, n, t;
479 int v;
480
b82a7a5e 481 find_key (1, KEY_READ);
7077c48e
CV
482 RegQueryInfoKeyW (key, 0, 0, 0, &num_subkeys, &maxsubkeylen, &maxclasslen,
483 &num_values, &maxvalnamelen, &maxvaluelen, 0, 0);
1fd5e000 484
7077c48e
CV
485 subkey_name = (wchar_t *) malloc ((maxsubkeylen + 1) * sizeof (wchar_t));
486 class_name = (wchar_t *) malloc ((maxclasslen + 1) * sizeof (wchar_t));
487 value_name = (wchar_t *) malloc ((maxvalnamelen + 1) * sizeof (wchar_t));
b82a7a5e 488 value_data = (unsigned char *) malloc (maxvaluelen + 1);
1fd5e000 489
37770e00
CF
490 if (!listwhat)
491 listwhat = LIST_ALL;
1fd5e000 492
37770e00
CF
493 if (listwhat & LIST_KEYS)
494 for (i = 0; i < num_subkeys; i++)
495 {
7077c48e
CV
496 m = (maxsubkeylen + 1) * sizeof (wchar_t);
497 n = (maxclasslen + 1) * sizeof (wchar_t);
498 RegEnumKeyExW (key, i, subkey_name, &m, 0, class_name, &n, 0);
499 printf ("%ls", subkey_name);
70158caf
CV
500 if (postfix || verbose)
501 fputc (key_sep, stdout);
37770e00
CF
502
503 if (verbose)
7077c48e 504 printf (" (%ls)", class_name);
37770e00
CF
505
506 puts ("");
507 }
508
509 if (listwhat & LIST_VALS)
510 for (i = 0; i < num_values; i++)
511 {
7077c48e 512 m = (maxvalnamelen + 1) * sizeof (wchar_t);
37770e00 513 n = maxvaluelen + 1;
7077c48e 514 RegEnumValueW (key, i, value_name, &m, 0, &t, (BYTE *) value_data, &n);
b17b7644 515 value_data[n] = 0;
37770e00 516 if (!verbose)
7077c48e 517 printf ("%ls\n", value_name);
37770e00
CF
518 else
519 {
7077c48e 520 printf ("%ls (%s) = ", value_name, types[t]);
37770e00
CF
521 switch (t)
522 {
70158caf 523 case REG_NONE:
37770e00
CF
524 case REG_BINARY:
525 for (j = 0; j < 8 && j < n; j++)
526 printf ("%02x ", value_data[j]);
527 printf ("\n");
528 break;
529 case REG_DWORD:
61522196
CV
530 printf ("0x%08x (%u)\n", *(unsigned int *) value_data,
531 *(unsigned int *) value_data);
37770e00
CF
532 break;
533 case REG_DWORD_BIG_ENDIAN:
534 v = ((value_data[0] << 24)
535 | (value_data[1] << 16)
70158caf
CV
536 | (value_data[2] << 8)
537 | (value_data[3]));
37770e00
CF
538 printf ("0x%08x (%d)\n", v, v);
539 break;
70158caf
CV
540 case REG_QWORD:
541 printf ("0x%016llx (%llu)\n",
542 *(unsigned long long *) value_data,
543 *(unsigned long long *) value_data);
544 break;
37770e00
CF
545 case REG_EXPAND_SZ:
546 case REG_SZ:
7077c48e
CV
547 case REG_LINK:
548 printf ("\"%ls\"\n", (wchar_t *) value_data);
37770e00
CF
549 break;
550 case REG_MULTI_SZ:
7077c48e 551 vd = (wchar_t *) value_data;
37770e00
CF
552 while (vd && *vd)
553 {
7077c48e
CV
554 printf ("\"%ls\"", vd);
555 vd = vd + wcslen (vd) + 1;
37770e00
CF
556 if (*vd)
557 printf (", ");
558 }
559 printf ("\n");
560 break;
561 default:
70158caf
CV
562 printf ("?\n");
563 break;
37770e00
CF
564 }
565 }
566 }
1fd5e000
CF
567 return 0;
568}
569
570int
b82a7a5e 571cmd_add ()
1fd5e000 572{
b82a7a5e 573 find_key (2, KEY_ALL_ACCESS);
1fd5e000
CF
574 HKEY newkey;
575 DWORD newtype;
7077c48e
CV
576 int rv = RegCreateKeyExW (key, value, 0, NULL, REG_OPTION_NON_VOLATILE,
577 KEY_ALL_ACCESS | wow64, 0, &newkey, &newtype);
1fd5e000 578 if (rv != ERROR_SUCCESS)
b82a7a5e 579 Fail (rv);
1fd5e000
CF
580
581 if (verbose)
582 {
583 if (newtype == REG_OPENED_EXISTING_KEY)
7077c48e 584 printf ("Key %ls already exists\n", value);
1fd5e000 585 else
7077c48e 586 printf ("Key %ls created\n", value);
1fd5e000
CF
587 }
588 return 0;
589}
590
591int
b82a7a5e 592cmd_remove ()
1fd5e000 593{
40c60b89
CV
594 DWORD rv;
595
b82a7a5e 596 find_key (2, KEY_ALL_ACCESS);
40c60b89 597 if (wow64)
f36dd402 598 rv = RegDeleteKeyExW (key, value, wow64, 0);
40c60b89 599 else
7077c48e 600 rv = RegDeleteKeyW (key, value);
1fd5e000 601 if (rv != ERROR_SUCCESS)
b82a7a5e 602 Fail (rv);
1fd5e000 603 if (verbose)
7077c48e 604 printf ("subkey %ls deleted\n", value);
1fd5e000
CF
605 return 0;
606}
607
608int
b82a7a5e 609cmd_check ()
1fd5e000 610{
b82a7a5e 611 find_key (1, KEY_READ);
1fd5e000 612 if (verbose)
b82a7a5e 613 printf ("key %s exists\n", argv[0]);
1fd5e000
CF
614 return 0;
615}
616
617int
b82a7a5e 618cmd_set ()
1fd5e000 619{
7077c48e 620 int i, n, max_n;
1fd5e000 621 DWORD v, rv;
70158caf 622 unsigned long long llval;
17c8ac39 623 char *a = argv[1], *data = 0;
b82a7a5e 624 find_key (2, KEY_ALL_ACCESS);
1fd5e000 625
70158caf
CV
626 if (!a)
627 usage ();
628 if (value_type == REG_AUTO)
1fd5e000
CF
629 {
630 char *e;
70158caf 631 llval = strtoull (a, &e, 0);
1fd5e000 632 if (a[0] == '%')
70158caf 633 value_type = REG_EXPAND_SZ;
1fd5e000 634 else if (a[0] && !*e)
70158caf 635 value_type = llval > 0xffffffffULL ? REG_QWORD : REG_DWORD;
1fd5e000 636 else if (argv[2])
70158caf 637 value_type = REG_MULTI_SZ;
1fd5e000 638 else
70158caf 639 value_type = REG_SZ;
1fd5e000
CF
640 }
641
70158caf 642 switch (value_type)
1fd5e000 643 {
70158caf
CV
644 case REG_NONE:
645 case REG_BINARY:
17c8ac39 646 for (n = 0; argv[n+1]; n++)
1b23b30b 647 ;
17c8ac39
CV
648 if (n == 1 && strcmp (argv[1], "-") == 0)
649 { /* read from stdin */
650 i = n = 0;
651 for (;;)
652 {
653 if (i <= n)
654 {
655 i = n + BUFSIZ;
656 data = (char *) realloc (data, i);
657 }
658 int r = fread (data+n, 1, i-n, stdin);
659 if (r <= 0)
660 break;
661 n += r;
662 }
663 }
664 else if (n > 0)
665 { /* parse hex from argv */
666 data = (char *) malloc (n);
667 for (i = 0; i < n; i++)
668 {
669 char *e;
670 errno = 0;
671 v = strtoul (argv[i+1], &e, 16);
672 if (errno || v > 0xff || *e)
673 {
674 fprintf (stderr, "Invalid hex constant `%s'\n", argv[i+1]);
675 exit (1);
676 }
677 data[i] = (char) v;
678 }
679 }
7077c48e 680 rv = RegSetValueExW (key, value, 0, value_type, (const BYTE *) data, n);
17c8ac39 681 break;
70158caf 682 case REG_DWORD:
b82a7a5e 683 v = strtoul (a, 0, 0);
7077c48e 684 rv = RegSetValueExW (key, value, 0, REG_DWORD, (const BYTE *) &v,
b82a7a5e 685 sizeof (v));
1fd5e000 686 break;
70158caf
CV
687 case REG_DWORD_BIG_ENDIAN:
688 v = strtoul (a, 0, 0);
689 v = (((v & 0xff) << 24)
690 | ((v & 0xff00) << 8)
691 | ((v & 0xff0000) >> 8)
692 | ((v & 0xff000000) >> 24));
7077c48e 693 rv = RegSetValueExW (key, value, 0, REG_DWORD_BIG_ENDIAN,
70158caf
CV
694 (const BYTE *) &v, sizeof (v));
695 break;
696 case REG_QWORD:
697 llval = strtoul (a, 0, 0);
7077c48e 698 rv = RegSetValueExW (key, value, 0, REG_QWORD, (const BYTE *) &llval,
70158caf
CV
699 sizeof (llval));
700 break;
701 case REG_SZ:
70158caf 702 case REG_EXPAND_SZ:
51564c78
CV
703 {
704 n = mbstowcs (NULL, a, 0);
705 wchar_t w[n + 1];
706 mbstowcs (w, a, n + 1);
707 rv = RegSetValueExW (key, value, 0, value_type,
708 (const BYTE *) w, (n + 1) * sizeof (wchar_t));
709 }
1fd5e000 710 break;
70158caf 711 case REG_MULTI_SZ:
7077c48e
CV
712 for (i = 1, max_n = 1; argv[i]; i++)
713 max_n += mbstowcs (NULL, argv[i], 0) + 1;
714 data = (char *) malloc (max_n * sizeof (wchar_t));
b82a7a5e 715 for (i = 1, n = 0; argv[i]; i++)
7077c48e
CV
716 n += mbstowcs ((wchar_t *) data + n, argv[i], max_n - n) + 1;
717 ((wchar_t *)data)[n] = L'\0';
718 rv = RegSetValueExW (key, value, 0, REG_MULTI_SZ, (const BYTE *) data,
41870989 719 (n + 1) * sizeof (wchar_t));
1fd5e000 720 break;
70158caf 721 case REG_AUTO:
b82a7a5e 722 rv = ERROR_SUCCESS;
1fd5e000 723 break;
7adad121
CF
724 default:
725 rv = ERROR_INVALID_CATEGORY;
726 break;
1fd5e000 727 }
1b23b30b 728
17c8ac39
CV
729 if (data)
730 free(data);
1fd5e000
CF
731
732 if (rv != ERROR_SUCCESS)
b82a7a5e 733 Fail (rv);
1fd5e000
CF
734
735 return 0;
736}
737
738int
b82a7a5e 739cmd_unset ()
1fd5e000 740{
b82a7a5e 741 find_key (2, KEY_ALL_ACCESS);
7077c48e 742 DWORD rv = RegDeleteValueW (key, value);
1fd5e000 743 if (rv != ERROR_SUCCESS)
b82a7a5e 744 Fail (rv);
1fd5e000 745 if (verbose)
7077c48e 746 printf ("value %ls deleted\n", value);
1fd5e000
CF
747 return 0;
748}
749
750int
b82a7a5e 751cmd_get ()
1fd5e000 752{
b82a7a5e 753 find_key (2, KEY_READ);
1fd5e000 754 DWORD vtype, dsize, rv;
7077c48e
CV
755 PBYTE data;
756 wchar_t *vd;
757
758 rv = RegQueryValueExW (key, value, 0, &vtype, 0, &dsize);
1fd5e000 759 if (rv != ERROR_SUCCESS)
b82a7a5e 760 Fail (rv);
7077c48e
CV
761 data = (PBYTE) malloc (dsize + 1);
762 rv = RegQueryValueExW (key, value, 0, &vtype, data, &dsize);
1fd5e000 763 if (rv != ERROR_SUCCESS)
b82a7a5e 764 Fail (rv);
70158caf 765 if (value_type == REG_BINARY)
1fd5e000 766 {
70158caf
CV
767 for (unsigned i = 0; i < dsize; i++)
768 printf ("%02x%c", (unsigned char)data[i],
769 (i < dsize-1 ? ' ' : '\n'));
1fd5e000 770 }
70158caf
CV
771 else if (value_type == REG_NONE)
772 fwrite (data, dsize, 1, stdout);
773 else
774 switch (vtype)
775 {
776 case REG_NONE:
777 case REG_BINARY:
70158caf
CV
778 fwrite (data, dsize, 1, stdout);
779 break;
780 case REG_DWORD:
61522196 781 printf (hex ? "0x%08x\n" : "%u\n", *(unsigned int *) data);
70158caf
CV
782 break;
783 case REG_DWORD_BIG_ENDIAN:
784 rv = ((data[0] << 24)
785 | (data[1] << 16)
786 | (data[2] << 8)
787 | (data[3]));
61522196 788 printf (hex ? "0x%08x\n" : "%u\n", (unsigned int) rv);
70158caf
CV
789 break;
790 case REG_QWORD:
791 printf (hex ? "0x%016llx\n" : "%llu\n", *(unsigned long long *) data);
792 break;
793 case REG_SZ:
7077c48e
CV
794 case REG_LINK:
795 printf ("%ls\n", (wchar_t *) data);
70158caf
CV
796 break;
797 case REG_EXPAND_SZ:
798 if (value_type == REG_EXPAND_SZ) // hack
799 {
7077c48e 800 wchar_t *buf;
70158caf 801 DWORD bufsize;
7077c48e
CV
802 bufsize = ExpandEnvironmentStringsW ((wchar_t *) data, 0, 0);
803 buf = (wchar_t *) malloc (bufsize + 1);
804 ExpandEnvironmentStringsW ((wchar_t *) data, buf, bufsize + 1);
70158caf 805 free (data);
7077c48e 806 data = (PBYTE) buf;
70158caf 807 }
7077c48e 808 printf ("%ls\n", (wchar_t *) data);
70158caf
CV
809 break;
810 case REG_MULTI_SZ:
7077c48e 811 vd = (wchar_t *) data;
70158caf
CV
812 while (vd && *vd)
813 {
7077c48e
CV
814 printf ("%ls\n", vd);
815 vd = vd + wcslen (vd) + 1;
70158caf
CV
816 }
817 break;
818 }
1fd5e000
CF
819 return 0;
820}
821
17c8ac39
CV
822int
823cmd_load ()
824{
825 if (!argv[1])
e7fca6f8 826 usage ();
17c8ac39
CV
827 find_key (1, 0);
828 return 0;
829}
830
831int
832cmd_unload ()
833{
834 if (argv[1])
e7fca6f8 835 usage ();
17c8ac39
CV
836 find_key (1, 0);
837 return 0;
838}
839
17c8ac39
CV
840int
841cmd_save ()
842{
843 if (!argv[1])
e7fca6f8 844 usage ();
17c8ac39
CV
845 /* REG_OPTION_BACKUP_RESTORE is necessary to save /HKLM/SECURITY */
846 find_key (1, KEY_QUERY_VALUE, REG_OPTION_BACKUP_RESTORE);
7077c48e
CV
847 ssize_t len = cygwin_conv_path (CCP_POSIX_TO_WIN_W, argv[1], NULL, 0);
848 wchar_t win32_path[len];
849 cygwin_conv_path (CCP_POSIX_TO_WIN_W, argv[1], win32_path, len);
850 DWORD rv = RegSaveKeyW (key, win32_path, NULL);
17c8ac39
CV
851 if (rv != ERROR_SUCCESS)
852 Fail (rv);
853 if (verbose)
7077c48e 854 printf ("key saved to %ls\n", win32_path);
17c8ac39
CV
855 return 0;
856}
857
a6791b3b
CV
858int
859cmd_restore ()
860{
861 if (!argv[1])
e7fca6f8 862 usage ();
a6791b3b
CV
863 /* REG_OPTION_BACKUP_RESTORE is necessary to restore /HKLM/SECURITY */
864 find_key (1, KEY_ALL_ACCESS, REG_OPTION_BACKUP_RESTORE);
865 ssize_t len = cygwin_conv_path (CCP_POSIX_TO_WIN_W, argv[1], NULL, 0);
866 wchar_t win32_path[len];
867 cygwin_conv_path (CCP_POSIX_TO_WIN_W, argv[1], win32_path, len);
868 DWORD rv = RegRestoreKeyW (key, win32_path, restore_flags);
869 if (rv != ERROR_SUCCESS)
870 Fail (rv);
871 if (verbose)
872 printf ("key saved to %ls\n", win32_path);
873 return 0;
874}
875
a35d9f1a 876static struct
b82a7a5e 877{
1fd5e000 878 const char *name;
b82a7a5e
CF
879 int (*func) ();
880} commands[] =
881{
882 {"list", cmd_list},
883 {"add", cmd_add},
884 {"remove", cmd_remove},
885 {"check", cmd_check},
886 {"set", cmd_set},
887 {"unset", cmd_unset},
888 {"get", cmd_get},
17c8ac39
CV
889 {"load", cmd_load},
890 {"unload", cmd_unload},
891 {"save", cmd_save},
a6791b3b 892 {"restore", cmd_restore},
b82a7a5e 893 {0, 0}
1fd5e000
CF
894};
895
896int
b82a7a5e 897main (int argc, char **_argv)
1fd5e000 898{
9bd02410
CF
899 int g;
900
7077c48e 901 setlocale (LC_ALL, "");
92b499ac
CV
902
903 prog_name = program_invocation_short_name;
9bd02410
CF
904
905 while ((g = getopt_long (argc, _argv, opts, longopts, NULL)) != EOF)
906 switch (g)
b82a7a5e 907 {
17c8ac39 908 case 'b':
70158caf
CV
909 value_type = REG_BINARY;
910 break;
911 case 'd':
912 value_type = REG_DWORD;
913 break;
914 case 'D':
915 value_type = REG_DWORD_BIG_ENDIAN;
17c8ac39 916 break;
9bd02410 917 case 'e':
70158caf 918 value_type = REG_EXPAND_SZ;
37770e00 919 break;
a6791b3b
CV
920 case 'f':
921 restore_flags = REG_FORCE_RESTORE;
922 break;
37770e00
CF
923 case 'k':
924 listwhat |= LIST_KEYS;
925 break;
9bd02410
CF
926 case 'h':
927 usage (stdout);
928 case 'i':
70158caf 929 value_type = REG_DWORD;
9bd02410 930 break;
37770e00
CF
931 case 'l':
932 listwhat |= LIST_VALS;
933 break;
9bd02410 934 case 'm':
70158caf
CV
935 value_type = REG_MULTI_SZ;
936 break;
937 case 'n':
938 value_type = REG_NONE;
9bd02410
CF
939 break;
940 case 'p':
941 postfix++;
942 break;
943 case 'q':
944 quiet++;
b82a7a5e 945 break;
70158caf
CV
946 case 'Q':
947 value_type = REG_QWORD;
948 break;
b82a7a5e 949 case 's':
70158caf 950 value_type = REG_SZ;
b82a7a5e 951 break;
9bd02410
CF
952 case 'v':
953 verbose++;
b82a7a5e 954 break;
9bd02410
CF
955 case 'V':
956 print_version ();
957 exit (0);
40c60b89
CV
958 case 'w':
959 wow64 = KEY_WOW64_64KEY;
960 break;
3c256e38
CV
961 case 'W':
962 wow64 = KEY_WOW64_32KEY;
963 break;
70158caf
CV
964 case 'x':
965 hex++;
966 break;
403985a4 967 case 'K':
9dc6005a 968 key_sep = *optarg;
403985a4 969 break;
9bd02410 970 default :
92b499ac
CV
971 fprintf (stderr, "Try `%s --help' for more information.\n",
972 prog_name);
973 return 1;
b82a7a5e 974 }
9bd02410
CF
975
976 if ((_argv[optind] == NULL) || (_argv[optind+1] == NULL))
b82a7a5e 977 usage ();
1fd5e000 978
b82a7a5e 979 argv = _argv + optind;
1fd5e000 980 int i;
b82a7a5e
CF
981 for (i = 0; commands[i].name; i++)
982 if (strcmp (commands[i].name, argv[0]) == 0)
1fd5e000
CF
983 {
984 argv++;
b82a7a5e 985 return commands[i].func ();
1fd5e000 986 }
b82a7a5e 987 usage ();
1fd5e000 988}
This page took 0.490149 seconds and 6 git commands to generate.