3 Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006 Red Hat Inc.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
18 #include <sys/cygwin.h>
20 #define DEFAULT_KEY_SEPARATOR '\\'
24 int value_type = REG_AUTO;
26 char key_sep = DEFAULT_KEY_SEPARATOR;
28 #define LIST_KEYS 0x01
29 #define LIST_VALS 0x02
30 #define LIST_ALL (LIST_KEYS | LIST_VALS)
32 static const char version[] = "$Revision$";
33 static char *prog_name;
35 static struct option longopts[] =
37 {"binary", no_argument, NULL, 'b' },
38 {"dword", no_argument, NULL, 'd' },
39 {"dword-le", no_argument, NULL, 'D' },
40 {"expand-string", no_argument, NULL, 'e' },
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'},
46 {"none", no_argument, NULL, 'n' },
47 {"postfix", no_argument, NULL, 'p'},
48 {"quiet", no_argument, NULL, 'q'},
49 {"qword", no_argument, NULL, 'Q' },
50 {"string", no_argument, NULL, 's'},
51 {"verbose", no_argument, NULL, 'v'},
52 {"version", no_argument, NULL, 'V'},
53 {"wow64", no_argument, NULL, 'w'},
54 {"wow32", no_argument, NULL, 'W'},
55 {"hex", no_argument, NULL, 'x'},
56 {"key-separator", required_argument, NULL, 'K'},
60 static char opts[] = "bdDehiklmnpqQsvVwWxK:";
69 "REG_DWORD_BIG_ENDIAN",
73 "REG_FULL_RESOURCE_DESCRIPTOR",
74 "REG_RESOURCE_REQUIREMENTS_LIST",
90 usage (FILE *where = stderr)
93 "Usage: %s [OPTION] ACTION KEY [data...]\n"
94 "View or edit the Win32 registry\n"
100 " add KEY\\SUBKEY add new SUBKEY\n"
101 " check KEY exit 0 if KEY exists, 1 if not\n"
102 " get KEY\\VALUE prints VALUE to stdout\n"
103 " list KEY list SUBKEYs and VALUEs\n"
104 " remove KEY remove KEY\n"
105 " set KEY\\VALUE [data ...] set VALUE\n"
106 " unset KEY\\VALUE removes VALUE from KEY\n"
107 " load KEY\\SUBKEY PATH load hive from PATH into new SUBKEY\n"
108 " unload KEY\\SUBKEY unload hive and remove SUBKEY\n"
109 " save KEY\\SUBKEY PATH save SUBKEY into new hive PATH\n"
112 "Options for 'list' Action:\n"
113 " -k, --keys print only KEYs\n"
114 " -l, --list print only VALUEs\n"
115 " -p, --postfix like ls -p, appends '\\' postfix to KEY names\n"
117 "Options for 'get' Action:\n"
118 " -b, --binary print data as printable hex bytes\n"
119 " -n, --none print data as stream of bytes as stored in registry\n"
120 " -x, --hex print numerical data as hex numbers\n"
122 "Options for 'set' Action:\n"
123 " -b, --binary set type to REG_BINARY (hex args or '-')\n"
124 " -d, --dword set type to REG_DWORD\n"
125 " -D, --dword-le set type to REG_DWORD_LITTLE_ENDIAN\n"
126 " -e, --expand-string set type to REG_EXPAND_SZ\n"
127 " -i, --integer set type to REG_DWORD\n"
128 " -m, --multi-string set type to REG_MULTI_SZ\n"
129 " -n, --none set type to REG_NONE\n"
130 " -Q, --qword set type to REG_QWORD\n"
131 " -s, --string set type to REG_SZ\n"
133 "Options for 'set' and 'unset' Actions:\n"
134 " -K<c>, --key-separator[=]<c> set key-value separator to <c> instead of '\\'\n"
137 " -h, --help output usage information and exit\n"
138 " -q, --quiet no error output, just nonzero return if KEY/VALUE missing\n"
139 " -v, --verbose verbose output, including VALUE contents when applicable\n"
140 " -w, --wow64 access 64 bit registry view (ignored on 32 bit Windows)\n"
141 " -W, --wow32 access 32 bit registry view (ignored on 32 bit Windows)\n"
142 " -V, --version output version information and exit\n"
145 "KEY is in the format [host]\\prefix\\KEY\\KEY\\VALUE, where host is optional\n"
146 "remote host in either \\\\hostname or hostname: format and prefix is any of:\n"
147 " root HKCR HKEY_CLASSES_ROOT (local only)\n"
148 " config HKCC HKEY_CURRENT_CONFIG (local only)\n"
149 " user HKCU HKEY_CURRENT_USER (local only)\n"
150 " machine HKLM HKEY_LOCAL_MACHINE\n"
151 " users HKU HKEY_USERS\n"
153 "If the keyname starts with a forward slash ('/'), the forward slash is used\n"
154 "as separator and the backslash can be used as escape character.\n");
157 "%s list '/machine/SOFTWARE/Classes/MIME/Database/Content Type/audio\\/wav'\n", prog_name);
161 "ACTION is one of add, check, get, list, remove, set, unset, load, unload, save\n"
163 "Try '%s --help' for more information.\n", prog_name);
164 exit (where == stderr ? 1 : 0);
170 const char *v = strchr (version, ':');
180 len = strchr (v, ' ') - v;
185 Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.\n\
187 ", prog_name, len, v, __DATE__);
196 FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER
197 | FORMAT_MESSAGE_FROM_SYSTEM,
198 0, rv, 0, (CHAR *) & buf, 0, 0);
199 fprintf (stderr, "Error (%ld): %s\n", rv, buf);
211 {"root", HKEY_CLASSES_ROOT},
212 {"HKCR", HKEY_CLASSES_ROOT},
213 {"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT},
214 {"config", HKEY_CURRENT_CONFIG},
215 {"HKCC", HKEY_CURRENT_CONFIG},
216 {"HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG},
217 {"user", HKEY_CURRENT_USER},
218 {"HKCU", HKEY_CURRENT_USER},
219 {"HKEY_CURRENT_USER", HKEY_CURRENT_USER},
220 {"machine", HKEY_LOCAL_MACHINE},
221 {"HKLM", HKEY_LOCAL_MACHINE},
222 {"HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE},
223 {"users", HKEY_USERS},
225 {"HKEY_USERS", HKEY_USERS},
230 translate (char *key)
232 #define isodigit(c) (strchr("01234567", c))
233 #define tooct(c) ((c)-'0')
234 #define tohex(c) (strchr(_hs,tolower(c))-_hs)
235 static char _hs[] = "0123456789abcdef";
281 c = (c << 3) | tooct (*++s);
283 c = (c << 3) | tooct (*++s);
288 if (!isxdigit (s[1]))
294 c = (c << 4) | tohex (*++s);
298 default: /* before non-special char: just add the char */
312 find_key (int howmanyparts, REGSAM access, int option = 0)
316 char *n = argv[0], *e, *h, c;
323 /* expect host:/key/value format */
324 host = (char*) malloc (strlen (n) + 1);
325 host[0] = host [1] = '\\';
326 for (e = n, h = host + 2; *e && *e != ':'; e++, h++)
333 else if (n[0] == '\\' && n[1] == '\\')
335 /* expect //host/key/value format */
336 host = (char*) malloc (strlen (n) + 1);
337 host[0] = host[1] = '\\';
338 for (e = n + 2, h = host + 2; *e && *e != '\\'; e++, h++)
346 for (e = n; *e && *e != '\\'; e++);
349 for (i = 0; wkprefixes[i].string; i++)
350 if (strcmp (wkprefixes[i].string, n) == 0)
352 if (!wkprefixes[i].string)
354 fprintf (stderr, "Unknown key prefix. Valid prefixes are:\n");
355 for (i = 0; wkprefixes[i].string; i++)
356 fprintf (stderr, "\t%s\n", wkprefixes[i].string);
362 while (*n && *n == '\\')
365 if (howmanyparts > 1)
367 while (n < e && *e != key_sep)
371 key = wkprefixes[i].key;
383 rv = RegConnectRegistry (host, wkprefixes[i].key, &base);
384 if (rv != ERROR_SUCCESS)
389 base = wkprefixes[i].key;
397 rv = RegOpenKeyEx (base, n, 0, access | wow64, &key);
398 if (option && (rv == ERROR_SUCCESS || rv == ERROR_ACCESS_DENIED))
400 /* reopen with desired option due to missing option support in RegOpenKeyE */
401 /* FIXME: may create the key in rare cases (e.g. access denied in parent) */
403 if (RegCreateKeyEx (base, n, 0, NULL, option, access | wow64, NULL, &key2, NULL)
406 if (rv == ERROR_SUCCESS)
412 if (rv != ERROR_SUCCESS)
417 ssize_t len = cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_RELATIVE,
419 char win32_path[len];
420 cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, argv[1],
422 rv = RegLoadKey (base, n, win32_path);
423 if (rv != ERROR_SUCCESS)
426 printf ("key %s loaded from file %s\n", n, win32_path);
430 rv = RegUnLoadKey (base, n);
431 if (rv != ERROR_SUCCESS)
434 printf ("key %s unloaded\n", n);
437 //printf("key `%s' value `%s'\n", n, value);
444 DWORD num_subkeys, maxsubkeylen, num_values, maxvalnamelen, maxvaluelen;
446 char *subkey_name, *value_name, *class_name;
447 unsigned char *value_data, *vd;
451 find_key (1, KEY_READ);
452 RegQueryInfoKey (key, 0, 0, 0, &num_subkeys, &maxsubkeylen, &maxclasslen,
453 &num_values, &maxvalnamelen, &maxvaluelen, 0, 0);
455 subkey_name = (char *) malloc (maxsubkeylen + 1);
456 class_name = (char *) malloc (maxclasslen + 1);
457 value_name = (char *) malloc (maxvalnamelen + 1);
458 value_data = (unsigned char *) malloc (maxvaluelen + 1);
463 if (listwhat & LIST_KEYS)
464 for (i = 0; i < num_subkeys; i++)
466 m = maxsubkeylen + 1;
468 RegEnumKeyEx (key, i, subkey_name, &m, 0, class_name, &n, 0);
469 fputs (subkey_name, stdout);
470 if (postfix || verbose)
471 fputc (key_sep, stdout);
474 printf (" (%s)", class_name);
479 if (listwhat & LIST_VALS)
480 for (i = 0; i < num_values; i++)
482 m = maxvalnamelen + 1;
484 RegEnumValue (key, i, value_name, &m, 0, &t, (BYTE *) value_data, &n);
487 printf ("%s\n", value_name);
490 printf ("%s (%s) = ", value_name, types[t]);
496 for (j = 0; j < 8 && j < n; j++)
497 printf ("%02x ", value_data[j]);
501 printf ("0x%08lx (%lu)\n", *(DWORD *) value_data,
502 *(DWORD *) value_data);
504 case REG_DWORD_BIG_ENDIAN:
505 v = ((value_data[0] << 24)
506 | (value_data[1] << 16)
507 | (value_data[2] << 8)
509 printf ("0x%08x (%d)\n", v, v);
512 printf ("0x%016llx (%llu)\n",
513 *(unsigned long long *) value_data,
514 *(unsigned long long *) value_data);
518 printf ("\"%s\"\n", value_data);
524 printf ("\"%s\"", vd);
525 vd = vd + strlen ((const char *) vd) + 1;
543 find_key (2, KEY_ALL_ACCESS);
546 int rv = RegCreateKeyEx (key, value, 0, (char *) "", REG_OPTION_NON_VOLATILE,
547 KEY_ALL_ACCESS | wow64, 0, &newkey, &newtype);
548 if (rv != ERROR_SUCCESS)
553 if (newtype == REG_OPENED_EXISTING_KEY)
554 printf ("Key %s already exists\n", value);
556 printf ("Key %s created\n", value);
562 WINADVAPI LONG WINAPI (*regDeleteKeyEx)(HKEY, LPCSTR, REGSAM, DWORD);
570 find_key (2, KEY_ALL_ACCESS);
573 HMODULE mod = LoadLibrary ("advapi32.dll");
575 regDeleteKeyEx = (WINADVAPI LONG WINAPI (*)(HKEY, LPCSTR, REGSAM, DWORD)) GetProcAddress (mod, "RegDeleteKeyExA");
578 rv = (*regDeleteKeyEx) (key, value, wow64, 0);
580 rv = RegDeleteKey (key, value);
581 if (rv != ERROR_SUCCESS)
584 printf ("subkey %s deleted\n", value);
591 find_key (1, KEY_READ);
593 printf ("key %s exists\n", argv[0]);
602 unsigned long long llval;
603 char *a = argv[1], *data = 0;
604 find_key (2, KEY_ALL_ACCESS);
608 if (value_type == REG_AUTO)
611 llval = strtoull (a, &e, 0);
613 value_type = REG_EXPAND_SZ;
614 else if (a[0] && !*e)
615 value_type = llval > 0xffffffffULL ? REG_QWORD : REG_DWORD;
617 value_type = REG_MULTI_SZ;
626 for (n = 0; argv[n+1]; n++)
628 if (n == 1 && strcmp (argv[1], "-") == 0)
629 { /* read from stdin */
636 data = (char *) realloc (data, i);
638 int r = fread (data+n, 1, i-n, stdin);
645 { /* parse hex from argv */
646 data = (char *) malloc (n);
647 for (i = 0; i < n; i++)
651 v = strtoul (argv[i+1], &e, 16);
652 if (errno || v > 0xff || *e)
654 fprintf (stderr, "Invalid hex constant `%s'\n", argv[i+1]);
660 rv = RegSetValueEx (key, value, 0, value_type, (const BYTE *) data, n);
663 v = strtoul (a, 0, 0);
664 rv = RegSetValueEx (key, value, 0, REG_DWORD, (const BYTE *) &v,
667 case REG_DWORD_BIG_ENDIAN:
668 v = strtoul (a, 0, 0);
669 v = (((v & 0xff) << 24)
670 | ((v & 0xff00) << 8)
671 | ((v & 0xff0000) >> 8)
672 | ((v & 0xff000000) >> 24));
673 rv = RegSetValueEx (key, value, 0, REG_DWORD_BIG_ENDIAN,
674 (const BYTE *) &v, sizeof (v));
677 llval = strtoul (a, 0, 0);
678 rv = RegSetValueEx (key, value, 0, REG_QWORD, (const BYTE *) &llval,
682 rv = RegSetValueEx (key, value, 0, REG_SZ, (const BYTE *) a, strlen (a) + 1);
685 rv = RegSetValueEx (key, value, 0, REG_EXPAND_SZ, (const BYTE *) a,
689 for (i = 1, n = 1; argv[i]; i++)
690 n += strlen (argv[i]) + 1;
691 data = (char *) malloc (n);
692 for (i = 1, n = 0; argv[i]; i++)
694 strcpy (data + n, argv[i]);
695 n += strlen (argv[i]) + 1;
698 rv = RegSetValueEx (key, value, 0, REG_MULTI_SZ, (const BYTE *) data,
705 rv = ERROR_INVALID_CATEGORY;
712 if (rv != ERROR_SUCCESS)
721 find_key (2, KEY_ALL_ACCESS);
722 DWORD rv = RegDeleteValue (key, value);
723 if (rv != ERROR_SUCCESS)
726 printf ("value %s deleted\n", value);
733 find_key (2, KEY_READ);
734 DWORD vtype, dsize, rv;
736 rv = RegQueryValueEx (key, value, 0, &vtype, 0, &dsize);
737 if (rv != ERROR_SUCCESS)
739 data = (char *) malloc (dsize + 1);
740 rv = RegQueryValueEx (key, value, 0, &vtype, (BYTE *) data, &dsize);
741 if (rv != ERROR_SUCCESS)
743 if (value_type == REG_BINARY)
745 for (unsigned i = 0; i < dsize; i++)
746 printf ("%02x%c", (unsigned char)data[i],
747 (i < dsize-1 ? ' ' : '\n'));
749 else if (value_type == REG_NONE)
750 fwrite (data, dsize, 1, stdout);
757 fwrite (data, dsize, 1, stdout);
760 printf (hex ? "0x%08lx\n" : "%lu\n", *(DWORD *) data);
762 case REG_DWORD_BIG_ENDIAN:
763 rv = ((data[0] << 24)
767 printf (hex ? "0x%08lx\n" : "%lu\n", rv);
770 printf (hex ? "0x%016llx\n" : "%llu\n", *(unsigned long long *) data);
773 printf ("%s\n", data);
776 if (value_type == REG_EXPAND_SZ) // hack
780 bufsize = ExpandEnvironmentStrings (data, 0, 0);
781 buf = (char *) malloc (bufsize + 1);
782 ExpandEnvironmentStrings (data, buf, bufsize + 1);
786 printf ("%s\n", data);
793 vd = vd + strlen ((const char *) vd) + 1;
825 set_privilege (const char * name)
828 if (!LookupPrivilegeValue (NULL, name, &tp.Privileges[0].Luid))
829 return GetLastError ();
830 tp.PrivilegeCount = 1;
831 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
833 /* OpenProcessToken does not work here, because main thread has its own
834 impersonation token */
835 if (!OpenThreadToken (GetCurrentThread (), TOKEN_ADJUST_PRIVILEGES, FALSE, &t))
836 return GetLastError ();
837 AdjustTokenPrivileges (t, FALSE, &tp, 0, NULL, NULL);
838 DWORD rv = GetLastError ();
851 /* try to set SeBackupPrivilege, let RegSaveKey report the error */
852 set_privilege (SE_BACKUP_NAME);
853 /* REG_OPTION_BACKUP_RESTORE is necessary to save /HKLM/SECURITY */
854 find_key (1, KEY_QUERY_VALUE, REG_OPTION_BACKUP_RESTORE);
855 ssize_t len = cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_RELATIVE,
857 char win32_path[len];
858 cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, argv[1],
860 DWORD rv = RegSaveKey (key, win32_path, NULL);
861 if (rv != ERROR_SUCCESS)
864 printf ("key saved to %s\n", win32_path);
876 {"remove", cmd_remove},
877 {"check", cmd_check},
879 {"unset", cmd_unset},
882 {"unload", cmd_unload},
888 main (int argc, char **_argv)
892 prog_name = strrchr (_argv[0], '/');
893 if (prog_name == NULL)
894 prog_name = strrchr (_argv[0], '\\');
895 if (prog_name == NULL)
896 prog_name = _argv[0];
900 while ((g = getopt_long (argc, _argv, opts, longopts, NULL)) != EOF)
904 value_type = REG_BINARY;
907 value_type = REG_DWORD;
910 value_type = REG_DWORD_BIG_ENDIAN;
913 value_type = REG_EXPAND_SZ;
916 listwhat |= LIST_KEYS;
921 value_type = REG_DWORD;
924 listwhat |= LIST_VALS;
927 value_type = REG_MULTI_SZ;
930 value_type = REG_NONE;
939 value_type = REG_QWORD;
951 wow64 = KEY_WOW64_64KEY;
954 wow64 = KEY_WOW64_32KEY;
966 if ((_argv[optind] == NULL) || (_argv[optind+1] == NULL))
969 argv = _argv + optind;
971 for (i = 0; commands[i].name; i++)
972 if (strcmp (commands[i].name, argv[0]) == 0)
975 return commands[i].func ();