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