3 Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
4 2009, 2010 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>
24 #define DEFAULT_KEY_SEPARATOR '\\'
28 int value_type = REG_AUTO;
30 char key_sep = DEFAULT_KEY_SEPARATOR;
32 #define LIST_KEYS 0x01
33 #define LIST_VALS 0x02
34 #define LIST_ALL (LIST_KEYS | LIST_VALS)
36 static const char version[] = "$Revision: 1.8 $";
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"
98 "View or edit the Win32 registry\n"
104 " add KEY\\SUBKEY add new SUBKEY\n"
105 " check KEY exit 0 if KEY exists, 1 if not\n"
106 " get KEY\\VALUE prints VALUE to stdout\n"
107 " list KEY list SUBKEYs and VALUEs\n"
108 " remove KEY remove KEY\n"
109 " set KEY\\VALUE [data ...] set VALUE\n"
110 " unset KEY\\VALUE removes VALUE from KEY\n"
111 " load KEY\\SUBKEY PATH load hive from PATH into new SUBKEY\n"
112 " unload KEY\\SUBKEY unload hive and remove SUBKEY\n"
113 " save KEY\\SUBKEY PATH save SUBKEY into new hive PATH\n"
116 "Options for 'list' Action:\n"
117 " -k, --keys print only KEYs\n"
118 " -l, --list print only VALUEs\n"
119 " -p, --postfix like ls -p, appends '\\' postfix to KEY names\n"
121 "Options for 'get' Action:\n"
122 " -b, --binary print data as printable hex bytes\n"
123 " -n, --none print data as stream of bytes as stored in registry\n"
124 " -x, --hex print numerical data as hex numbers\n"
126 "Options for 'set' Action:\n"
127 " -b, --binary set type to REG_BINARY (hex args or '-')\n"
128 " -d, --dword set type to REG_DWORD\n"
129 " -D, --dword-be set type to REG_DWORD_BIG_ENDIAN\n"
130 " -e, --expand-string set type to REG_EXPAND_SZ\n"
131 " -i, --integer set type to REG_DWORD\n"
132 " -m, --multi-string set type to REG_MULTI_SZ\n"
133 " -n, --none set type to REG_NONE\n"
134 " -Q, --qword set type to REG_QWORD\n"
135 " -s, --string set type to REG_SZ\n"
137 "Options for 'set' and 'unset' Actions:\n"
138 " -K<c>, --key-separator[=]<c> set key-value separator to <c> instead of '\\'\n"
141 " -h, --help output usage information and exit\n"
142 " -q, --quiet no error output, just nonzero return if KEY/VALUE missing\n"
143 " -v, --verbose verbose output, including VALUE contents when applicable\n"
144 " -w, --wow64 access 64 bit registry view (ignored on 32 bit Windows)\n"
145 " -W, --wow32 access 32 bit registry view (ignored on 32 bit Windows)\n"
146 " -V, --version output version information and exit\n"
149 "KEY is in the format [host]\\prefix\\KEY\\KEY\\VALUE, where host is optional\n"
150 "remote host in either \\\\hostname or hostname: format and prefix is any of:\n"
151 " root HKCR HKEY_CLASSES_ROOT (local only)\n"
152 " config HKCC HKEY_CURRENT_CONFIG (local only)\n"
153 " user HKCU HKEY_CURRENT_USER (local only)\n"
154 " machine HKLM HKEY_LOCAL_MACHINE\n"
155 " users HKU HKEY_USERS\n"
157 "If the keyname starts with a forward slash ('/'), the forward slash is used\n"
158 "as separator and the backslash can be used as escape character.\n");
161 "%s list '/machine/SOFTWARE/Classes/MIME/Database/Content Type/audio\\/wav'\n", prog_name);
165 "ACTION is one of add, check, get, list, remove, set, unset, load, unload, save\n"
167 "Try '%s --help' for more information.\n", prog_name);
168 exit (where == stderr ? 1 : 0);
174 const char *v = strchr (version, ':');
184 len = strchr (v, ' ') - v;
189 Copyright 2000-2009 Red Hat, Inc.\n\
191 ", prog_name, len, v, __DATE__);
200 FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER
201 | FORMAT_MESSAGE_FROM_SYSTEM,
202 0, rv, 0, (CHAR *) & buf, 0, 0);
203 fprintf (stderr, "Error (%ld): %s\n", rv, buf);
215 {"root", HKEY_CLASSES_ROOT},
216 {"HKCR", HKEY_CLASSES_ROOT},
217 {"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT},
218 {"config", HKEY_CURRENT_CONFIG},
219 {"HKCC", HKEY_CURRENT_CONFIG},
220 {"HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG},
221 {"user", HKEY_CURRENT_USER},
222 {"HKCU", HKEY_CURRENT_USER},
223 {"HKEY_CURRENT_USER", HKEY_CURRENT_USER},
224 {"machine", HKEY_LOCAL_MACHINE},
225 {"HKLM", HKEY_LOCAL_MACHINE},
226 {"HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE},
227 {"users", HKEY_USERS},
229 {"HKEY_USERS", HKEY_USERS},
234 translate (char *key)
236 #define isodigit(c) (strchr("01234567", c))
237 #define tooct(c) ((c)-'0')
238 #define tohex(c) (strchr(_hs,tolower(c))-_hs)
239 static char _hs[] = "0123456789abcdef";
285 c = (c << 3) | tooct (*++s);
287 c = (c << 3) | tooct (*++s);
292 if (!isxdigit (s[1]))
298 c = (c << 4) | tohex (*++s);
302 default: /* before non-special char: just add the char */
316 find_key (int howmanyparts, REGSAM access, int option = 0)
320 char *n = argv[0], *e, *h, c;
329 /* expect host:/key/value format */
330 host = (char*) malloc (strlen (n) + 1);
331 host[0] = host [1] = '\\';
332 for (e = n, h = host + 2; *e && *e != ':'; e++, h++)
339 else if (n[0] == '\\' && n[1] == '\\')
341 /* expect //host/key/value format */
342 host = (char*) malloc (strlen (n) + 1);
343 host[0] = host[1] = '\\';
344 for (e = n + 2, h = host + 2; *e && *e != '\\'; e++, h++)
352 for (e = n; *e && *e != '\\'; e++);
355 for (i = 0; wkprefixes[i].string; i++)
356 if (strcmp (wkprefixes[i].string, n) == 0)
358 if (!wkprefixes[i].string)
360 fprintf (stderr, "Unknown key prefix. Valid prefixes are:\n");
361 for (i = 0; wkprefixes[i].string; i++)
362 fprintf (stderr, "\t%s\n", wkprefixes[i].string);
368 while (*n && *n == '\\')
371 if (howmanyparts > 1)
373 while (n < e && *e != key_sep)
377 key = wkprefixes[i].key;
380 len = mbstowcs (NULL, n, 0) + 1;
381 value = (wchar_t *) malloc (len * sizeof (wchar_t));
382 mbstowcs (value, n, len);
390 len = mbstowcs (NULL, e + 1, 0) + 1;
391 value = (wchar_t *) malloc (len * sizeof (wchar_t));
392 mbstowcs (value, e + 1, len);
397 rv = RegConnectRegistry (host, wkprefixes[i].key, &base);
398 if (rv != ERROR_SUCCESS)
403 base = wkprefixes[i].key;
409 len = mbstowcs (NULL, n, 0) + 1;
411 mbstowcs (name, n, len);
414 rv = RegOpenKeyExW (base, name, 0, access | wow64, &key);
415 if (option && (rv == ERROR_SUCCESS || rv == ERROR_ACCESS_DENIED))
417 /* reopen with desired option due to missing option support in
419 /* FIXME: may create the key in rare cases (e.g. access denied
422 if (RegCreateKeyExW (base, name, 0, NULL, option, access | wow64,
426 if (rv == ERROR_SUCCESS)
432 if (rv != ERROR_SUCCESS)
437 ssize_t len = cygwin_conv_path (CCP_POSIX_TO_WIN_W, argv[1], NULL, 0);
438 wchar_t win32_path[len];
439 cygwin_conv_path (CCP_POSIX_TO_WIN_W, argv[1], win32_path, len);
440 rv = RegLoadKeyW (base, name, win32_path);
441 if (rv != ERROR_SUCCESS)
444 printf ("key %ls loaded from file %ls\n", name, win32_path);
448 rv = RegUnLoadKeyW (base, name);
449 if (rv != ERROR_SUCCESS)
452 printf ("key %ls unloaded\n", name);
461 DWORD num_subkeys, maxsubkeylen, num_values, maxvalnamelen, maxvaluelen;
463 wchar_t *subkey_name, *value_name, *class_name, *vd;
464 unsigned char *value_data;
468 find_key (1, KEY_READ);
469 RegQueryInfoKeyW (key, 0, 0, 0, &num_subkeys, &maxsubkeylen, &maxclasslen,
470 &num_values, &maxvalnamelen, &maxvaluelen, 0, 0);
472 subkey_name = (wchar_t *) malloc ((maxsubkeylen + 1) * sizeof (wchar_t));
473 class_name = (wchar_t *) malloc ((maxclasslen + 1) * sizeof (wchar_t));
474 value_name = (wchar_t *) malloc ((maxvalnamelen + 1) * sizeof (wchar_t));
475 value_data = (unsigned char *) malloc (maxvaluelen + 1);
480 if (listwhat & LIST_KEYS)
481 for (i = 0; i < num_subkeys; i++)
483 m = (maxsubkeylen + 1) * sizeof (wchar_t);
484 n = (maxclasslen + 1) * sizeof (wchar_t);
485 RegEnumKeyExW (key, i, subkey_name, &m, 0, class_name, &n, 0);
486 printf ("%ls", subkey_name);
487 if (postfix || verbose)
488 fputc (key_sep, stdout);
491 printf (" (%ls)", class_name);
496 if (listwhat & LIST_VALS)
497 for (i = 0; i < num_values; i++)
499 m = (maxvalnamelen + 1) * sizeof (wchar_t);
501 RegEnumValueW (key, i, value_name, &m, 0, &t, (BYTE *) value_data, &n);
504 printf ("%ls\n", value_name);
507 printf ("%ls (%s) = ", value_name, types[t]);
512 for (j = 0; j < 8 && j < n; j++)
513 printf ("%02x ", value_data[j]);
517 printf ("0x%08lx (%lu)\n", *(DWORD *) value_data,
518 *(DWORD *) value_data);
520 case REG_DWORD_BIG_ENDIAN:
521 v = ((value_data[0] << 24)
522 | (value_data[1] << 16)
523 | (value_data[2] << 8)
525 printf ("0x%08x (%d)\n", v, v);
528 printf ("0x%016llx (%llu)\n",
529 *(unsigned long long *) value_data,
530 *(unsigned long long *) value_data);
535 printf ("\"%ls\"\n", (wchar_t *) value_data);
538 vd = (wchar_t *) value_data;
541 printf ("\"%ls\"", vd);
542 vd = vd + wcslen (vd) + 1;
560 find_key (2, KEY_ALL_ACCESS);
563 int rv = RegCreateKeyExW (key, value, 0, NULL, REG_OPTION_NON_VOLATILE,
564 KEY_ALL_ACCESS | wow64, 0, &newkey, &newtype);
565 if (rv != ERROR_SUCCESS)
570 if (newtype == REG_OPENED_EXISTING_KEY)
571 printf ("Key %ls already exists\n", value);
573 printf ("Key %ls created\n", value);
579 WINADVAPI LONG WINAPI (*regDeleteKeyEx)(HKEY, LPCWSTR, REGSAM, DWORD);
587 find_key (2, KEY_ALL_ACCESS);
590 HMODULE mod = LoadLibrary ("advapi32.dll");
592 regDeleteKeyEx = (WINADVAPI LONG WINAPI (*)(HKEY, LPCWSTR, REGSAM, DWORD)) GetProcAddress (mod, "RegDeleteKeyExW");
595 rv = (*regDeleteKeyEx) (key, value, wow64, 0);
597 rv = RegDeleteKeyW (key, value);
598 if (rv != ERROR_SUCCESS)
601 printf ("subkey %ls deleted\n", value);
608 find_key (1, KEY_READ);
610 printf ("key %s exists\n", argv[0]);
619 unsigned long long llval;
620 char *a = argv[1], *data = 0;
621 find_key (2, KEY_ALL_ACCESS);
625 if (value_type == REG_AUTO)
628 llval = strtoull (a, &e, 0);
630 value_type = REG_EXPAND_SZ;
631 else if (a[0] && !*e)
632 value_type = llval > 0xffffffffULL ? REG_QWORD : REG_DWORD;
634 value_type = REG_MULTI_SZ;
643 for (n = 0; argv[n+1]; n++)
645 if (n == 1 && strcmp (argv[1], "-") == 0)
646 { /* read from stdin */
653 data = (char *) realloc (data, i);
655 int r = fread (data+n, 1, i-n, stdin);
662 { /* parse hex from argv */
663 data = (char *) malloc (n);
664 for (i = 0; i < n; i++)
668 v = strtoul (argv[i+1], &e, 16);
669 if (errno || v > 0xff || *e)
671 fprintf (stderr, "Invalid hex constant `%s'\n", argv[i+1]);
677 rv = RegSetValueExW (key, value, 0, value_type, (const BYTE *) data, n);
680 v = strtoul (a, 0, 0);
681 rv = RegSetValueExW (key, value, 0, REG_DWORD, (const BYTE *) &v,
684 case REG_DWORD_BIG_ENDIAN:
685 v = strtoul (a, 0, 0);
686 v = (((v & 0xff) << 24)
687 | ((v & 0xff00) << 8)
688 | ((v & 0xff0000) >> 8)
689 | ((v & 0xff000000) >> 24));
690 rv = RegSetValueExW (key, value, 0, REG_DWORD_BIG_ENDIAN,
691 (const BYTE *) &v, sizeof (v));
694 llval = strtoul (a, 0, 0);
695 rv = RegSetValueExW (key, value, 0, REG_QWORD, (const BYTE *) &llval,
700 n = mbstowcs (NULL, a, 0);
702 mbstowcs (w, a, n + 1);
703 rv = RegSetValueExW (key, value, 0, value_type,
704 (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 (max_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, "");
908 prog_name = strrchr (_argv[0], '/');
909 if (prog_name == NULL)
910 prog_name = strrchr (_argv[0], '\\');
911 if (prog_name == NULL)
912 prog_name = _argv[0];
916 while ((g = getopt_long (argc, _argv, opts, longopts, NULL)) != EOF)
920 value_type = REG_BINARY;
923 value_type = REG_DWORD;
926 value_type = REG_DWORD_BIG_ENDIAN;
929 value_type = REG_EXPAND_SZ;
932 listwhat |= LIST_KEYS;
937 value_type = REG_DWORD;
940 listwhat |= LIST_VALS;
943 value_type = REG_MULTI_SZ;
946 value_type = REG_NONE;
955 value_type = REG_QWORD;
967 wow64 = KEY_WOW64_64KEY;
970 wow64 = KEY_WOW64_32KEY;
982 if ((_argv[optind] == NULL) || (_argv[optind+1] == NULL))
985 argv = _argv + optind;
987 for (i = 0; commands[i].name; i++)
988 if (strcmp (commands[i].name, argv[0]) == 0)
991 return commands[i].func ();