3 Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
4 2009, 2010, 2011 Red Hat Inc.
6 This file is part of Cygwin.
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
21 #include <sys/cygwin.h>
22 #include <cygwin/version.h>
25 #define DEFAULT_KEY_SEPARATOR '\\'
29 int value_type
= REG_AUTO
;
31 char key_sep
= DEFAULT_KEY_SEPARATOR
;
33 #define LIST_KEYS 0x01
34 #define LIST_VALS 0x02
35 #define LIST_ALL (LIST_KEYS | LIST_VALS)
37 static char *prog_name
;
39 static struct option longopts
[] =
41 {"binary", no_argument
, NULL
, 'b' },
42 {"dword", no_argument
, NULL
, 'd' },
43 {"dword-be", no_argument
, NULL
, 'D' },
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'},
50 {"none", no_argument
, NULL
, 'n' },
51 {"postfix", no_argument
, NULL
, 'p'},
52 {"quiet", no_argument
, NULL
, 'q'},
53 {"qword", no_argument
, NULL
, 'Q' },
54 {"string", no_argument
, NULL
, 's'},
55 {"verbose", no_argument
, NULL
, 'v'},
56 {"version", no_argument
, NULL
, 'V'},
57 {"wow64", no_argument
, NULL
, 'w'},
58 {"wow32", no_argument
, NULL
, 'W'},
59 {"hex", no_argument
, NULL
, 'x'},
60 {"key-separator", required_argument
, NULL
, 'K'},
64 static char opts
[] = "bdDehiklmnpqQsvVwWxK:";
73 "REG_DWORD_BIG_ENDIAN",
77 "REG_FULL_RESOURCE_DESCRIPTOR",
78 "REG_RESOURCE_REQUIREMENTS_LIST",
94 usage (FILE *where
= stderr
)
97 "Usage: %s [OPTION] ACTION KEY [data...]\n"
99 "View or edit the Win32 registry\n"
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"
118 "Options for 'list' Action:\n"
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"
124 "Options for 'get' Action:\n"
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"
130 "Options for 'set' Action:\n"
132 " -b, --binary set type to REG_BINARY (hex args or '-')\n"
133 " -d, --dword set type to REG_DWORD\n"
134 " -D, --dword-be set type to REG_DWORD_BIG_ENDIAN\n"
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"
142 "Options for 'set' and 'unset' Actions:\n"
144 " -K<c>, --key-separator[=]<c> set key-value separator to <c> instead of '\\'\n"
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"
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"
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");
168 "%s list '/machine/SOFTWARE/Classes/MIME/Database/Content Type/audio\\/wav'\n\n", prog_name
);
172 "ACTION is one of add, check, get, list, remove, set, unset, load, unload, save\n"
174 "Try `%s --help' for more information.\n", prog_name
);
175 exit (where
== stderr
? 1 : 0);
181 printf ("regtool (cygwin) %d.%d.%d\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"
185 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
186 CYGWIN_VERSION_DLL_MAJOR
/ 1000,
187 CYGWIN_VERSION_DLL_MAJOR
% 1000,
188 CYGWIN_VERSION_DLL_MINOR
,
189 strrchr (__DATE__
, ' ') + 1);
198 FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER
199 | FORMAT_MESSAGE_FROM_SYSTEM
,
200 0, rv
, 0, (CHAR
*) & buf
, 0, 0);
201 fprintf (stderr
, "Error (%ld): %s\n", rv
, buf
);
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
},
227 {"HKEY_USERS", HKEY_USERS
},
232 translate (char *key
)
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";
283 c
= (c
<< 3) | tooct (*++s
);
285 c
= (c
<< 3) | tooct (*++s
);
290 if (!isxdigit (s
[1]))
296 c
= (c
<< 4) | tohex (*++s
);
300 default: /* before non-special char: just add the char */
314 find_key (int howmanyparts
, REGSAM access
, int option
= 0)
318 char *n
= argv
[0], *e
, *h
, c
;
327 /* expect host:/key/value format */
328 host
= (char*) malloc (strlen (n
) + 1);
329 host
[0] = host
[1] = '\\';
330 for (e
= n
, h
= host
+ 2; *e
&& *e
!= ':'; e
++, h
++)
337 else if (n
[0] == '\\' && n
[1] == '\\')
339 /* expect //host/key/value format */
340 host
= (char*) malloc (strlen (n
) + 1);
341 host
[0] = host
[1] = '\\';
342 for (e
= n
+ 2, h
= host
+ 2; *e
&& *e
!= '\\'; e
++, h
++)
350 for (e
= n
; *e
&& *e
!= '\\'; e
++);
353 for (i
= 0; wkprefixes
[i
].string
; i
++)
354 if (strcmp (wkprefixes
[i
].string
, n
) == 0)
356 if (!wkprefixes
[i
].string
)
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
);
366 while (*n
&& *n
== '\\')
369 if (howmanyparts
> 1)
371 while (n
< e
&& *e
!= key_sep
)
375 key
= wkprefixes
[i
].key
;
378 len
= mbstowcs (NULL
, n
, 0) + 1;
379 value
= (wchar_t *) malloc (len
* sizeof (wchar_t));
380 mbstowcs (value
, n
, len
);
388 len
= mbstowcs (NULL
, e
+ 1, 0) + 1;
389 value
= (wchar_t *) malloc (len
* sizeof (wchar_t));
390 mbstowcs (value
, e
+ 1, len
);
395 rv
= RegConnectRegistry (host
, wkprefixes
[i
].key
, &base
);
396 if (rv
!= ERROR_SUCCESS
)
401 base
= wkprefixes
[i
].key
;
407 len
= mbstowcs (NULL
, n
, 0) + 1;
409 mbstowcs (name
, n
, len
);
412 rv
= RegOpenKeyExW (base
, name
, 0, access
| wow64
, &key
);
413 if (option
&& (rv
== ERROR_SUCCESS
|| rv
== ERROR_ACCESS_DENIED
))
415 /* reopen with desired option due to missing option support in
417 /* FIXME: may create the key in rare cases (e.g. access denied
420 if (RegCreateKeyExW (base
, name
, 0, NULL
, option
, access
| wow64
,
424 if (rv
== ERROR_SUCCESS
)
430 if (rv
!= ERROR_SUCCESS
)
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
);
439 if (rv
!= ERROR_SUCCESS
)
442 printf ("key %ls loaded from file %ls\n", name
, win32_path
);
446 rv
= RegUnLoadKeyW (base
, name
);
447 if (rv
!= ERROR_SUCCESS
)
450 printf ("key %ls unloaded\n", name
);
459 DWORD num_subkeys
, maxsubkeylen
, num_values
, maxvalnamelen
, maxvaluelen
;
461 wchar_t *subkey_name
, *value_name
, *class_name
, *vd
;
462 unsigned char *value_data
;
466 find_key (1, KEY_READ
);
467 RegQueryInfoKeyW (key
, 0, 0, 0, &num_subkeys
, &maxsubkeylen
, &maxclasslen
,
468 &num_values
, &maxvalnamelen
, &maxvaluelen
, 0, 0);
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));
473 value_data
= (unsigned char *) malloc (maxvaluelen
+ 1);
478 if (listwhat
& LIST_KEYS
)
479 for (i
= 0; i
< num_subkeys
; i
++)
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
);
485 if (postfix
|| verbose
)
486 fputc (key_sep
, stdout
);
489 printf (" (%ls)", class_name
);
494 if (listwhat
& LIST_VALS
)
495 for (i
= 0; i
< num_values
; i
++)
497 m
= (maxvalnamelen
+ 1) * sizeof (wchar_t);
499 RegEnumValueW (key
, i
, value_name
, &m
, 0, &t
, (BYTE
*) value_data
, &n
);
502 printf ("%ls\n", value_name
);
505 printf ("%ls (%s) = ", value_name
, types
[t
]);
510 for (j
= 0; j
< 8 && j
< n
; j
++)
511 printf ("%02x ", value_data
[j
]);
515 printf ("0x%08lx (%lu)\n", *(DWORD
*) value_data
,
516 *(DWORD
*) value_data
);
518 case REG_DWORD_BIG_ENDIAN
:
519 v
= ((value_data
[0] << 24)
520 | (value_data
[1] << 16)
521 | (value_data
[2] << 8)
523 printf ("0x%08x (%d)\n", v
, v
);
526 printf ("0x%016llx (%llu)\n",
527 *(unsigned long long *) value_data
,
528 *(unsigned long long *) value_data
);
533 printf ("\"%ls\"\n", (wchar_t *) value_data
);
536 vd
= (wchar_t *) value_data
;
539 printf ("\"%ls\"", vd
);
540 vd
= vd
+ wcslen (vd
) + 1;
558 find_key (2, KEY_ALL_ACCESS
);
561 int rv
= RegCreateKeyExW (key
, value
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
562 KEY_ALL_ACCESS
| wow64
, 0, &newkey
, &newtype
);
563 if (rv
!= ERROR_SUCCESS
)
568 if (newtype
== REG_OPENED_EXISTING_KEY
)
569 printf ("Key %ls already exists\n", value
);
571 printf ("Key %ls created\n", value
);
577 WINADVAPI LONG
WINAPI (*regDeleteKeyEx
)(HKEY
, LPCWSTR
, REGSAM
, DWORD
);
585 find_key (2, KEY_ALL_ACCESS
);
588 HMODULE mod
= LoadLibrary ("advapi32.dll");
590 regDeleteKeyEx
= (WINADVAPI LONG
WINAPI (*)(HKEY
, LPCWSTR
, REGSAM
, DWORD
)) GetProcAddress (mod
, "RegDeleteKeyExW");
593 rv
= (*regDeleteKeyEx
) (key
, value
, wow64
, 0);
595 rv
= RegDeleteKeyW (key
, value
);
596 if (rv
!= ERROR_SUCCESS
)
599 printf ("subkey %ls deleted\n", value
);
606 find_key (1, KEY_READ
);
608 printf ("key %s exists\n", argv
[0]);
617 unsigned long long llval
;
618 char *a
= argv
[1], *data
= 0;
619 find_key (2, KEY_ALL_ACCESS
);
623 if (value_type
== REG_AUTO
)
626 llval
= strtoull (a
, &e
, 0);
628 value_type
= REG_EXPAND_SZ
;
629 else if (a
[0] && !*e
)
630 value_type
= llval
> 0xffffffffULL
? REG_QWORD
: REG_DWORD
;
632 value_type
= REG_MULTI_SZ
;
641 for (n
= 0; argv
[n
+1]; n
++)
643 if (n
== 1 && strcmp (argv
[1], "-") == 0)
644 { /* read from stdin */
651 data
= (char *) realloc (data
, i
);
653 int r
= fread (data
+n
, 1, i
-n
, stdin
);
660 { /* parse hex from argv */
661 data
= (char *) malloc (n
);
662 for (i
= 0; i
< n
; i
++)
666 v
= strtoul (argv
[i
+1], &e
, 16);
667 if (errno
|| v
> 0xff || *e
)
669 fprintf (stderr
, "Invalid hex constant `%s'\n", argv
[i
+1]);
675 rv
= RegSetValueExW (key
, value
, 0, value_type
, (const BYTE
*) data
, n
);
678 v
= strtoul (a
, 0, 0);
679 rv
= RegSetValueExW (key
, value
, 0, REG_DWORD
, (const BYTE
*) &v
,
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));
688 rv
= RegSetValueExW (key
, value
, 0, REG_DWORD_BIG_ENDIAN
,
689 (const BYTE
*) &v
, sizeof (v
));
692 llval
= strtoul (a
, 0, 0);
693 rv
= RegSetValueExW (key
, value
, 0, REG_QWORD
, (const BYTE
*) &llval
,
699 n
= mbstowcs (NULL
, a
, 0);
701 mbstowcs (w
, a
, n
+ 1);
702 rv
= RegSetValueExW (key
, value
, 0, value_type
,
703 (const BYTE
*) w
, (n
+ 1) * sizeof (wchar_t));
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));
710 for (i
= 1, n
= 0; argv
[i
]; i
++)
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
,
714 (n
+ 1) * sizeof (wchar_t));
720 rv
= ERROR_INVALID_CATEGORY
;
727 if (rv
!= ERROR_SUCCESS
)
736 find_key (2, KEY_ALL_ACCESS
);
737 DWORD rv
= RegDeleteValueW (key
, value
);
738 if (rv
!= ERROR_SUCCESS
)
741 printf ("value %ls deleted\n", value
);
748 find_key (2, KEY_READ
);
749 DWORD vtype
, dsize
, rv
;
753 rv
= RegQueryValueExW (key
, value
, 0, &vtype
, 0, &dsize
);
754 if (rv
!= ERROR_SUCCESS
)
756 data
= (PBYTE
) malloc (dsize
+ 1);
757 rv
= RegQueryValueExW (key
, value
, 0, &vtype
, data
, &dsize
);
758 if (rv
!= ERROR_SUCCESS
)
760 if (value_type
== REG_BINARY
)
762 for (unsigned i
= 0; i
< dsize
; i
++)
763 printf ("%02x%c", (unsigned char)data
[i
],
764 (i
< dsize
-1 ? ' ' : '\n'));
766 else if (value_type
== REG_NONE
)
767 fwrite (data
, dsize
, 1, stdout
);
773 fwrite (data
, dsize
, 1, stdout
);
776 printf (hex
? "0x%08lx\n" : "%lu\n", *(DWORD
*) data
);
778 case REG_DWORD_BIG_ENDIAN
:
779 rv
= ((data
[0] << 24)
783 printf (hex
? "0x%08lx\n" : "%lu\n", rv
);
786 printf (hex
? "0x%016llx\n" : "%llu\n", *(unsigned long long *) data
);
790 printf ("%ls\n", (wchar_t *) data
);
793 if (value_type
== REG_EXPAND_SZ
) // hack
797 bufsize
= ExpandEnvironmentStringsW ((wchar_t *) data
, 0, 0);
798 buf
= (wchar_t *) malloc (bufsize
+ 1);
799 ExpandEnvironmentStringsW ((wchar_t *) data
, buf
, bufsize
+ 1);
803 printf ("%ls\n", (wchar_t *) data
);
806 vd
= (wchar_t *) data
;
809 printf ("%ls\n", vd
);
810 vd
= vd
+ wcslen (vd
) + 1;
842 set_privilege (const char *name
)
845 if (!LookupPrivilegeValue (NULL
, name
, &tp
.Privileges
[0].Luid
))
846 return GetLastError ();
847 tp
.PrivilegeCount
= 1;
848 tp
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
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 ();
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
);
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
);
876 if (rv
!= ERROR_SUCCESS
)
879 printf ("key saved to %ls\n", win32_path
);
891 {"remove", cmd_remove
},
892 {"check", cmd_check
},
894 {"unset", cmd_unset
},
897 {"unload", cmd_unload
},
903 main (int argc
, char **_argv
)
907 setlocale (LC_ALL
, "");
909 prog_name
= program_invocation_short_name
;
911 while ((g
= getopt_long (argc
, _argv
, opts
, longopts
, NULL
)) != EOF
)
915 value_type
= REG_BINARY
;
918 value_type
= REG_DWORD
;
921 value_type
= REG_DWORD_BIG_ENDIAN
;
924 value_type
= REG_EXPAND_SZ
;
927 listwhat
|= LIST_KEYS
;
932 value_type
= REG_DWORD
;
935 listwhat
|= LIST_VALS
;
938 value_type
= REG_MULTI_SZ
;
941 value_type
= REG_NONE
;
950 value_type
= REG_QWORD
;
962 wow64
= KEY_WOW64_64KEY
;
965 wow64
= KEY_WOW64_32KEY
;
974 fprintf (stderr
, "Try `%s --help' for more information.\n",
979 if ((_argv
[optind
] == NULL
) || (_argv
[optind
+1] == NULL
))
982 argv
= _argv
+ optind
;
984 for (i
= 0; commands
[i
].name
; i
++)
985 if (strcmp (commands
[i
].name
, argv
[0]) == 0)
988 return commands
[i
].func ();