3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
18 #include <sys/cygwin.h>
19 #include <cygwin/version.h>
22 #define DEFAULT_KEY_SEPARATOR '\\'
26 int value_type
= REG_AUTO
;
28 char key_sep
= DEFAULT_KEY_SEPARATOR
;
30 #define LIST_KEYS 0x01
31 #define LIST_VALS 0x02
32 #define LIST_ALL (LIST_KEYS | LIST_VALS)
34 static char *prog_name
;
36 static struct option longopts
[] =
38 {"binary", no_argument
, NULL
, 'b' },
39 {"dword", no_argument
, NULL
, 'd' },
40 {"dword-be", no_argument
, NULL
, 'D' },
41 {"expand-string", no_argument
, NULL
, 'e' },
42 {"force", no_argument
, NULL
, 'f' },
43 {"help", no_argument
, NULL
, 'h' },
44 {"integer", no_argument
, NULL
, 'i' },
45 {"keys", no_argument
, NULL
, 'k'},
46 {"list", no_argument
, NULL
, 'l'},
47 {"multi-string", no_argument
, NULL
, 'm'},
48 {"none", no_argument
, NULL
, 'n' },
49 {"postfix", no_argument
, NULL
, 'p'},
50 {"quiet", no_argument
, NULL
, 'q'},
51 {"qword", no_argument
, NULL
, 'Q' },
52 {"string", no_argument
, NULL
, 's'},
53 {"verbose", no_argument
, NULL
, 'v'},
54 {"version", no_argument
, NULL
, 'V'},
55 {"wow64", no_argument
, NULL
, 'w'},
56 {"wow32", no_argument
, NULL
, 'W'},
57 {"hex", no_argument
, NULL
, 'x'},
58 {"key-separator", required_argument
, NULL
, 'K'},
62 static char opts
[] = "bdDefhiklmnpqQsvVwWxK:";
71 "REG_DWORD_BIG_ENDIAN",
75 "REG_FULL_RESOURCE_DESCRIPTOR",
76 "REG_RESOURCE_REQUIREMENTS_LIST",
86 DWORD restore_flags
= 0;
93 usage (FILE *where
= stderr
)
96 "Usage: %s [OPTION] ACTION KEY [data...]\n"
98 "View or edit the Win32 registry\n"
105 " add KEY\\SUBKEY add new SUBKEY\n"
106 " check KEY exit 0 if KEY exists, 1 if not\n"
107 " get KEY\\VALUE prints VALUE to stdout\n"
108 " list KEY list SUBKEYs and VALUEs\n"
109 " remove KEY remove KEY\n"
110 " set KEY\\VALUE [data ...] set VALUE\n"
111 " unset KEY\\VALUE removes VALUE from KEY\n"
112 " load KEY\\SUBKEY PATH load hive from PATH into new SUBKEY\n"
113 " unload KEY\\SUBKEY unload hive and remove SUBKEY\n"
114 " save KEY\\SUBKEY PATH save SUBKEY into new file PATH\n"
115 " restore KEY\\SUBKEY PATH restore SUBKEY from file 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"
146 "Options for 'restore' action:\n"
148 " -f, --force restore even if open handles exist at or beneath the location\n"
149 " in the registry hierarchy to which KEY\\SUBKEY points\n"
153 " -h, --help output usage information and exit\n"
154 " -q, --quiet no error output, just nonzero return if KEY/VALUE missing\n"
155 " -v, --verbose verbose output, including VALUE contents when applicable\n"
156 " -w, --wow64 access 64 bit registry view (ignored on 32 bit Windows)\n"
157 " -W, --wow32 access 32 bit registry view (ignored on 32 bit Windows)\n"
158 " -V, --version output version information and exit\n"
161 "KEY is in the format [host]\\prefix\\KEY\\KEY\\VALUE, where host is optional\n"
162 "remote host in either \\\\hostname or hostname: format and prefix is any of:\n"
163 " root HKCR HKEY_CLASSES_ROOT (local only)\n"
164 " config HKCC HKEY_CURRENT_CONFIG (local only)\n"
165 " user HKCU HKEY_CURRENT_USER (local only)\n"
166 " machine HKLM HKEY_LOCAL_MACHINE\n"
167 " users HKU HKEY_USERS\n"
169 "If the keyname starts with a forward slash ('/'), the forward slash is used\n"
170 "as separator and the backslash can be used as escape character.\n");
173 "%s list '/machine/SOFTWARE/Classes/MIME/Database/Content Type/audio\\/wav'\n\n", prog_name
);
177 "ACTION is one of add, check, get, list, remove, set, unset, load, unload, save\n"
179 "Try `%s --help' for more information.\n", prog_name
);
180 exit (where
== stderr
? 1 : 0);
186 printf ("regtool (cygwin) %d.%d.%d\n"
188 "Copyright (C) 2000 - %s Cygwin Authors\n"
189 "This is free software; see the source for copying conditions. There is NO\n"
190 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
191 CYGWIN_VERSION_DLL_MAJOR
/ 1000,
192 CYGWIN_VERSION_DLL_MAJOR
% 1000,
193 CYGWIN_VERSION_DLL_MINOR
,
194 strrchr (__DATE__
, ' ') + 1);
198 Fail (unsigned int rv
)
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
);
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
},
233 {"HKEY_USERS", HKEY_USERS
},
238 translate (char *key
)
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";
289 c
= (c
<< 3) | tooct (*++s
);
291 c
= (c
<< 3) | tooct (*++s
);
296 if (!isxdigit (s
[1]))
302 c
= (c
<< 4) | tohex (*++s
);
306 default: /* before non-special char: just add the char */
320 find_key (int howmanyparts
, REGSAM access
, int option
= 0)
324 char *n
= argv
[0], *e
, *h
, c
;
333 /* expect host:/key/value format */
334 host
= (char*) malloc (strlen (n
) + 1);
335 host
[0] = host
[1] = '\\';
336 for (e
= n
, h
= host
+ 2; *e
&& *e
!= ':'; e
++, h
++)
343 else if (n
[0] == '\\' && n
[1] == '\\')
345 /* expect //host/key/value format */
346 host
= (char*) malloc (strlen (n
) + 1);
347 host
[0] = host
[1] = '\\';
348 for (e
= n
+ 2, h
= host
+ 2; *e
&& *e
!= '\\'; e
++, h
++)
356 for (e
= n
; *e
&& *e
!= '\\'; e
++);
359 for (i
= 0; wkprefixes
[i
].string
; i
++)
360 if (strcmp (wkprefixes
[i
].string
, n
) == 0)
362 if (!wkprefixes
[i
].string
)
364 fprintf (stderr
, "Unknown key prefix. Valid prefixes are:\n");
365 for (i
= 0; wkprefixes
[i
].string
; i
++)
366 fprintf (stderr
, "\t%s\n", wkprefixes
[i
].string
);
372 while (*n
&& *n
== '\\')
375 if (howmanyparts
> 1)
377 while (n
< e
&& *e
!= key_sep
)
381 key
= wkprefixes
[i
].key
;
384 len
= mbstowcs (NULL
, n
, 0) + 1;
385 value
= (wchar_t *) malloc (len
* sizeof (wchar_t));
386 mbstowcs (value
, n
, len
);
394 len
= mbstowcs (NULL
, e
+ 1, 0) + 1;
395 value
= (wchar_t *) malloc (len
* sizeof (wchar_t));
396 mbstowcs (value
, e
+ 1, len
);
401 rv
= RegConnectRegistry (host
, wkprefixes
[i
].key
, &base
);
402 if (rv
!= ERROR_SUCCESS
)
407 base
= wkprefixes
[i
].key
;
413 len
= mbstowcs (NULL
, n
, 0) + 1;
415 mbstowcs (name
, n
, len
);
418 rv
= RegOpenKeyExW (base
, name
, 0, access
| wow64
, &key
);
419 if (option
&& (rv
== ERROR_SUCCESS
|| rv
== ERROR_ACCESS_DENIED
))
421 /* reopen with desired option due to missing option support in
423 /* FIXME: may create the key in rare cases (e.g. access denied
426 if (RegCreateKeyExW (base
, name
, 0, NULL
, option
, access
| wow64
,
430 if (rv
== ERROR_SUCCESS
)
436 if (rv
!= ERROR_SUCCESS
)
441 ssize_t len
= cygwin_conv_path (CCP_POSIX_TO_WIN_W
, argv
[1], NULL
, 0);
442 wchar_t win32_path
[len
];
443 cygwin_conv_path (CCP_POSIX_TO_WIN_W
, argv
[1], win32_path
, len
);
444 rv
= RegLoadKeyW (base
, name
, win32_path
);
445 if (rv
!= ERROR_SUCCESS
)
448 printf ("key %ls loaded from file %ls\n", name
, win32_path
);
452 rv
= RegUnLoadKeyW (base
, name
);
453 if (rv
!= ERROR_SUCCESS
)
456 printf ("key %ls unloaded\n", name
);
465 DWORD num_subkeys
, maxsubkeylen
, num_values
, maxvalnamelen
, maxvaluelen
;
467 wchar_t *subkey_name
, *value_name
, *class_name
, *vd
;
468 unsigned char *value_data
;
472 find_key (1, KEY_READ
);
473 RegQueryInfoKeyW (key
, 0, 0, 0, &num_subkeys
, &maxsubkeylen
, &maxclasslen
,
474 &num_values
, &maxvalnamelen
, &maxvaluelen
, 0, 0);
476 subkey_name
= (wchar_t *) malloc ((maxsubkeylen
+ 1) * sizeof (wchar_t));
477 class_name
= (wchar_t *) malloc ((maxclasslen
+ 1) * sizeof (wchar_t));
478 value_name
= (wchar_t *) malloc ((maxvalnamelen
+ 1) * sizeof (wchar_t));
479 value_data
= (unsigned char *) malloc (maxvaluelen
+ 1);
484 if (listwhat
& LIST_KEYS
)
485 for (i
= 0; i
< num_subkeys
; i
++)
487 m
= (maxsubkeylen
+ 1) * sizeof (wchar_t);
488 n
= (maxclasslen
+ 1) * sizeof (wchar_t);
489 RegEnumKeyExW (key
, i
, subkey_name
, &m
, 0, class_name
, &n
, 0);
490 printf ("%ls", subkey_name
);
491 if (postfix
|| verbose
)
492 fputc (key_sep
, stdout
);
495 printf (" (%ls)", class_name
);
500 if (listwhat
& LIST_VALS
)
501 for (i
= 0; i
< num_values
; i
++)
503 m
= (maxvalnamelen
+ 1) * sizeof (wchar_t);
505 RegEnumValueW (key
, i
, value_name
, &m
, 0, &t
, (BYTE
*) value_data
, &n
);
508 printf ("%ls\n", value_name
);
511 printf ("%ls (%s) = ", value_name
, types
[t
]);
516 for (j
= 0; j
< 8 && j
< n
; j
++)
517 printf ("%02x ", value_data
[j
]);
521 printf ("0x%08x (%u)\n", *(unsigned int *) value_data
,
522 *(unsigned int *) value_data
);
524 case REG_DWORD_BIG_ENDIAN
:
525 v
= ((value_data
[0] << 24)
526 | (value_data
[1] << 16)
527 | (value_data
[2] << 8)
529 printf ("0x%08x (%d)\n", v
, v
);
532 printf ("0x%016llx (%llu)\n",
533 *(unsigned long long *) value_data
,
534 *(unsigned long long *) value_data
);
539 printf ("\"%ls\"\n", (wchar_t *) value_data
);
542 vd
= (wchar_t *) value_data
;
545 printf ("\"%ls\"", vd
);
546 vd
= vd
+ wcslen (vd
) + 1;
564 find_key (2, KEY_ALL_ACCESS
);
567 int rv
= RegCreateKeyExW (key
, value
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
568 KEY_ALL_ACCESS
| wow64
, 0, &newkey
, &newtype
);
569 if (rv
!= ERROR_SUCCESS
)
574 if (newtype
== REG_OPENED_EXISTING_KEY
)
575 printf ("Key %ls already exists\n", value
);
577 printf ("Key %ls created\n", value
);
583 LONG
WINAPI (*regDeleteKeyEx
)(HKEY
, LPCWSTR
, REGSAM
, DWORD
);
591 find_key (2, KEY_ALL_ACCESS
);
594 HMODULE mod
= LoadLibrary ("advapi32.dll");
596 regDeleteKeyEx
= (LONG
WINAPI (*)(HKEY
, LPCWSTR
, REGSAM
, DWORD
)) GetProcAddress (mod
, "RegDeleteKeyExW");
599 rv
= (*regDeleteKeyEx
) (key
, value
, wow64
, 0);
601 rv
= RegDeleteKeyW (key
, value
);
602 if (rv
!= ERROR_SUCCESS
)
605 printf ("subkey %ls deleted\n", value
);
612 find_key (1, KEY_READ
);
614 printf ("key %s exists\n", argv
[0]);
623 unsigned long long llval
;
624 char *a
= argv
[1], *data
= 0;
625 find_key (2, KEY_ALL_ACCESS
);
629 if (value_type
== REG_AUTO
)
632 llval
= strtoull (a
, &e
, 0);
634 value_type
= REG_EXPAND_SZ
;
635 else if (a
[0] && !*e
)
636 value_type
= llval
> 0xffffffffULL
? REG_QWORD
: REG_DWORD
;
638 value_type
= REG_MULTI_SZ
;
647 for (n
= 0; argv
[n
+1]; n
++)
649 if (n
== 1 && strcmp (argv
[1], "-") == 0)
650 { /* read from stdin */
657 data
= (char *) realloc (data
, i
);
659 int r
= fread (data
+n
, 1, i
-n
, stdin
);
666 { /* parse hex from argv */
667 data
= (char *) malloc (n
);
668 for (i
= 0; i
< n
; i
++)
672 v
= strtoul (argv
[i
+1], &e
, 16);
673 if (errno
|| v
> 0xff || *e
)
675 fprintf (stderr
, "Invalid hex constant `%s'\n", argv
[i
+1]);
681 rv
= RegSetValueExW (key
, value
, 0, value_type
, (const BYTE
*) data
, n
);
684 v
= strtoul (a
, 0, 0);
685 rv
= RegSetValueExW (key
, value
, 0, REG_DWORD
, (const BYTE
*) &v
,
688 case REG_DWORD_BIG_ENDIAN
:
689 v
= strtoul (a
, 0, 0);
690 v
= (((v
& 0xff) << 24)
691 | ((v
& 0xff00) << 8)
692 | ((v
& 0xff0000) >> 8)
693 | ((v
& 0xff000000) >> 24));
694 rv
= RegSetValueExW (key
, value
, 0, REG_DWORD_BIG_ENDIAN
,
695 (const BYTE
*) &v
, sizeof (v
));
698 llval
= strtoul (a
, 0, 0);
699 rv
= RegSetValueExW (key
, value
, 0, REG_QWORD
, (const BYTE
*) &llval
,
705 n
= mbstowcs (NULL
, a
, 0);
707 mbstowcs (w
, a
, n
+ 1);
708 rv
= RegSetValueExW (key
, value
, 0, value_type
,
709 (const BYTE
*) w
, (n
+ 1) * sizeof (wchar_t));
713 for (i
= 1, max_n
= 1; argv
[i
]; i
++)
714 max_n
+= mbstowcs (NULL
, argv
[i
], 0) + 1;
715 data
= (char *) malloc (max_n
* sizeof (wchar_t));
716 for (i
= 1, n
= 0; argv
[i
]; i
++)
717 n
+= mbstowcs ((wchar_t *) data
+ n
, argv
[i
], max_n
- n
) + 1;
718 ((wchar_t *)data
)[n
] = L
'\0';
719 rv
= RegSetValueExW (key
, value
, 0, REG_MULTI_SZ
, (const BYTE
*) data
,
720 (n
+ 1) * sizeof (wchar_t));
726 rv
= ERROR_INVALID_CATEGORY
;
733 if (rv
!= ERROR_SUCCESS
)
742 find_key (2, KEY_ALL_ACCESS
);
743 DWORD rv
= RegDeleteValueW (key
, value
);
744 if (rv
!= ERROR_SUCCESS
)
747 printf ("value %ls deleted\n", value
);
754 find_key (2, KEY_READ
);
755 DWORD vtype
, dsize
, rv
;
759 rv
= RegQueryValueExW (key
, value
, 0, &vtype
, 0, &dsize
);
760 if (rv
!= ERROR_SUCCESS
)
762 data
= (PBYTE
) malloc (dsize
+ 1);
763 rv
= RegQueryValueExW (key
, value
, 0, &vtype
, data
, &dsize
);
764 if (rv
!= ERROR_SUCCESS
)
766 if (value_type
== REG_BINARY
)
768 for (unsigned i
= 0; i
< dsize
; i
++)
769 printf ("%02x%c", (unsigned char)data
[i
],
770 (i
< dsize
-1 ? ' ' : '\n'));
772 else if (value_type
== REG_NONE
)
773 fwrite (data
, dsize
, 1, stdout
);
779 fwrite (data
, dsize
, 1, stdout
);
782 printf (hex
? "0x%08x\n" : "%u\n", *(unsigned int *) data
);
784 case REG_DWORD_BIG_ENDIAN
:
785 rv
= ((data
[0] << 24)
789 printf (hex
? "0x%08x\n" : "%u\n", (unsigned int) rv
);
792 printf (hex
? "0x%016llx\n" : "%llu\n", *(unsigned long long *) data
);
796 printf ("%ls\n", (wchar_t *) data
);
799 if (value_type
== REG_EXPAND_SZ
) // hack
803 bufsize
= ExpandEnvironmentStringsW ((wchar_t *) data
, 0, 0);
804 buf
= (wchar_t *) malloc (bufsize
+ 1);
805 ExpandEnvironmentStringsW ((wchar_t *) data
, buf
, bufsize
+ 1);
809 printf ("%ls\n", (wchar_t *) data
);
812 vd
= (wchar_t *) data
;
815 printf ("%ls\n", vd
);
816 vd
= vd
+ wcslen (vd
) + 1;
855 /* REG_OPTION_BACKUP_RESTORE is necessary to save /HKLM/SECURITY */
856 find_key (1, KEY_QUERY_VALUE
, REG_OPTION_BACKUP_RESTORE
);
857 ssize_t len
= cygwin_conv_path (CCP_POSIX_TO_WIN_W
, argv
[1], NULL
, 0);
858 wchar_t win32_path
[len
];
859 cygwin_conv_path (CCP_POSIX_TO_WIN_W
, argv
[1], win32_path
, len
);
860 DWORD rv
= RegSaveKeyW (key
, win32_path
, NULL
);
861 if (rv
!= ERROR_SUCCESS
)
864 printf ("key saved to %ls\n", win32_path
);
876 /* REG_OPTION_BACKUP_RESTORE is necessary to restore /HKLM/SECURITY */
877 find_key (1, KEY_ALL_ACCESS
, REG_OPTION_BACKUP_RESTORE
);
878 ssize_t len
= cygwin_conv_path (CCP_POSIX_TO_WIN_W
, argv
[1], NULL
, 0);
879 wchar_t win32_path
[len
];
880 cygwin_conv_path (CCP_POSIX_TO_WIN_W
, argv
[1], win32_path
, len
);
881 DWORD rv
= RegRestoreKeyW (key
, win32_path
, restore_flags
);
882 if (rv
!= ERROR_SUCCESS
)
885 printf ("key saved to %ls\n", win32_path
);
897 {"remove", cmd_remove
},
898 {"check", cmd_check
},
900 {"unset", cmd_unset
},
903 {"unload", cmd_unload
},
905 {"restore", cmd_restore
},
910 main (int argc
, char **_argv
)
914 setlocale (LC_ALL
, "");
916 prog_name
= program_invocation_short_name
;
918 while ((g
= getopt_long (argc
, _argv
, opts
, longopts
, NULL
)) != EOF
)
922 value_type
= REG_BINARY
;
925 value_type
= REG_DWORD
;
928 value_type
= REG_DWORD_BIG_ENDIAN
;
931 value_type
= REG_EXPAND_SZ
;
934 restore_flags
= REG_FORCE_RESTORE
;
937 listwhat
|= LIST_KEYS
;
942 value_type
= REG_DWORD
;
945 listwhat
|= LIST_VALS
;
948 value_type
= REG_MULTI_SZ
;
951 value_type
= REG_NONE
;
960 value_type
= REG_QWORD
;
972 wow64
= KEY_WOW64_64KEY
;
975 wow64
= KEY_WOW64_32KEY
;
984 fprintf (stderr
, "Try `%s --help' for more information.\n",
989 if ((_argv
[optind
] == NULL
) || (_argv
[optind
+1] == NULL
))
992 argv
= _argv
+ optind
;
994 for (i
= 0; commands
[i
].name
; i
++)
995 if (strcmp (commands
[i
].name
, argv
[0]) == 0)
998 return commands
[i
].func ();