]> sourceware.org Git - newlib-cygwin.git/blob - winsup/utils/regtool.cc
* regtool.cc (opts): The argument to 'K' is not optional.
[newlib-cygwin.git] / winsup / utils / regtool.cc
1 /* regtool.cc
2
3 Copyright 2000, 2001, 2002, 2003, 2004 Red Hat Inc.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <ctype.h>
14 #include <getopt.h>
15 #include <windows.h>
16
17 #define DEFAULT_KEY_SEPARATOR '\\'
18
19 enum
20 {
21 KT_AUTO, KT_INT, KT_STRING, KT_EXPAND, KT_MULTI
22 } key_type = KT_AUTO;
23
24 char key_sep = DEFAULT_KEY_SEPARATOR;
25
26 #define LIST_KEYS 0x01
27 #define LIST_VALS 0x02
28 #define LIST_ALL (LIST_KEYS | LIST_VALS)
29
30 static const char version[] = "$Revision$";
31 static char *prog_name;
32
33 static struct option longopts[] =
34 {
35 {"expand-string", no_argument, NULL, 'e' },
36 {"help", no_argument, NULL, 'h' },
37 {"integer", no_argument, NULL, 'i' },
38 {"keys", no_argument, NULL, 'k'},
39 {"list", no_argument, NULL, 'l'},
40 {"multi-string", no_argument, NULL, 'm'},
41 {"postfix", no_argument, NULL, 'p'},
42 {"quiet", no_argument, NULL, 'q'},
43 {"string", no_argument, NULL, 's'},
44 {"verbose", no_argument, NULL, 'v'},
45 {"version", no_argument, NULL, 'V'},
46 {"key-separator", required_argument, NULL, 'K'},
47 {NULL, 0, NULL, 0}
48 };
49
50 static char opts[] = "ehiklmpqsvVK:";
51
52 int listwhat = 0;
53 int postfix = 0;
54 int verbose = 0;
55 int quiet = 0;
56 char **argv;
57
58 HKEY key;
59 char *value;
60
61 static void
62 usage (FILE *where = stderr)
63 {
64 fprintf (where, ""
65 "Usage: %s [OPTION] (add | check | get | list | remove | unset) KEY\n"
66 "View or edit the Win32 registry\n"
67 "\n"
68 "", prog_name);
69 if (where == stdout)
70 fprintf (where, ""
71 "Actions:\n"
72 " add KEY\\SUBKEY add new SUBKEY\n"
73 " check KEY exit 0 if KEY exists, 1 if not\n"
74 " get KEY\\VALUE prints VALUE to stdout\n"
75 " list KEY list SUBKEYs and VALUEs\n"
76 " remove KEY remove KEY\n"
77 " set KEY\\VALUE [data ...] set VALUE\n"
78 " unset KEY\\VALUE removes VALUE from KEY\n"
79 "\n");
80 fprintf (where, ""
81 "Options for 'list' Action:\n"
82 " -k, --keys print only KEYs\n"
83 " -l, --list print only VALUEs\n"
84 " -p, --postfix like ls -p, appends '\\' postfix to KEY names\n"
85 "\n"
86 "Options for 'set' Action:\n"
87 " -e, --expand-string set type to REG_EXPAND_SZ\n"
88 " -i, --integer set type to REG_DWORD\n"
89 " -m, --multi-string set type to REG_MULTI_SZ\n"
90 " -s, --string set type to REG_SZ\n"
91 "\n"
92 "Options for 'set' and 'unset' Actions:\n"
93 " -K<c>, --key-separator[=]<c> set key separator to <c> instead of '\\'\n"
94 "\n"
95 "Other Options:\n"
96 " -h, --help output usage information and exit\n"
97 " -q, --quiet no error output, just nonzero return if KEY/VALUE missing\n"
98 " -v, --verbose verbose output, including VALUE contents when applicable\n"
99 " -V, --version output version information and exit\n"
100 "\n");
101 if (where == stdout)
102 {
103 fprintf (where, ""
104 "KEY is in the format [host]\\prefix\\KEY\\KEY\\VALUE, where host is optional\n"
105 "remote host in either \\\\hostname or hostname: format and prefix is any of:\n"
106 " root HKCR HKEY_CLASSES_ROOT (local only)\n"
107 " config HKCC HKEY_CURRENT_CONFIG (local only)\n"
108 " user HKCU HKEY_CURRENT_USER (local only)\n"
109 " machine HKLM HKEY_LOCAL_MACHINE\n"
110 " users HKU HKEY_USERS\n"
111 "\n"
112 "If the keyname starts with a forward slash ('/'), the forward slash is used\n"
113 "as separator and the backslash can be used as escape character.\n");
114 fprintf (where, ""
115 "Example:\n"
116 "%s list '/machine/SOFTWARE/Classes/MIME/Database/Content Type/audio\\/wav'\n", prog_name);
117 }
118 if (where == stderr)
119 fprintf (where, "Try '%s --help' for more information.\n", prog_name);
120 exit (where == stderr ? 1 : 0);
121 }
122
123 static void
124 print_version ()
125 {
126 const char *v = strchr (version, ':');
127 int len;
128 if (!v)
129 {
130 v = "?";
131 len = 1;
132 }
133 else
134 {
135 v += 2;
136 len = strchr (v, ' ') - v;
137 }
138 printf ("\
139 %s (cygwin) %.*s\n\
140 Registry Tool\n\
141 Copyright 2000, 2001, 2002 Red Hat, Inc.\n\
142 Compiled on %s\n\
143 ", prog_name, len, v, __DATE__);
144 }
145
146 void
147 Fail (DWORD rv)
148 {
149 char *buf;
150 if (!quiet)
151 {
152 FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER
153 | FORMAT_MESSAGE_FROM_SYSTEM,
154 0, rv, 0, (CHAR *) & buf, 0, 0);
155 fprintf (stderr, "Error (%ld): %s\n", rv, buf);
156 LocalFree (buf);
157 }
158 exit (1);
159 }
160
161 struct
162 {
163 const char *string;
164 HKEY key;
165 } wkprefixes[] =
166 {
167 {"root", HKEY_CLASSES_ROOT},
168 {"HKCR", HKEY_CLASSES_ROOT},
169 {"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT},
170 {"config", HKEY_CURRENT_CONFIG},
171 {"HKCC", HKEY_CURRENT_CONFIG},
172 {"HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG},
173 {"user", HKEY_CURRENT_USER},
174 {"HKCU", HKEY_CURRENT_USER},
175 {"HKEY_CURRENT_USER", HKEY_CURRENT_USER},
176 {"machine", HKEY_LOCAL_MACHINE},
177 {"HKLM", HKEY_LOCAL_MACHINE},
178 {"HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE},
179 {"users", HKEY_USERS},
180 {"HKU", HKEY_USERS},
181 {"HKEY_USERS", HKEY_USERS},
182 {0, 0}
183 };
184
185 void
186 translate (char *key)
187 {
188 #define isodigit(c) (strchr("01234567", c))
189 #define tooct(c) ((c)-'0')
190 #define tohex(c) (strchr(_hs,tolower(c))-_hs)
191 static char _hs[] = "0123456789abcdef";
192
193 char *d = key;
194 char *s = key;
195 char c;
196
197 while (*s)
198 {
199 if (*s == '\\')
200 switch (*++s)
201 {
202 case 'a':
203 *d++ = '\007';
204 break;
205 case 'b':
206 *d++ = '\b';
207 break;
208 case 'e':
209 *d++ = '\033';
210 break;
211 case 'f':
212 *d++ = '\f';
213 break;
214 case 'n':
215 *d++ = '\n';
216 break;
217 case 'r':
218 *d++ = '\r';
219 break;
220 case 't':
221 *d++ = '\t';
222 break;
223 case 'v':
224 *d++ = '\v';
225 break;
226 case '0':
227 case '1':
228 case '2':
229 case '3':
230 case '4':
231 case '5':
232 case '6':
233 case '7':
234 c = tooct (*s);
235 if (isodigit (s[1]))
236 {
237 c = (c << 3) | tooct (*++s);
238 if (isodigit (s[1]))
239 c = (c << 3) | tooct (*++s);
240 }
241 *d++ = c;
242 break;
243 case 'x':
244 if (!isxdigit (s[1]))
245 c = '0';
246 else
247 {
248 c = tohex (*++s);
249 if (isxdigit (s[1]))
250 c = (c << 4) | tohex (*++s);
251 }
252 *d++ = c;
253 break;
254 default: /* before non-special char: just add the char */
255 *d++ = *s;
256 break;
257 }
258 else if (*s == '/')
259 *d++ = '\\';
260 else
261 *d++ = *s;
262 ++s;
263 }
264 *d = '\0';
265 }
266
267 void
268 find_key (int howmanyparts, REGSAM access)
269 {
270 HKEY base;
271 int rv;
272 char *n = argv[0], *e, *h, c;
273 char* host = NULL;
274 int i;
275 if (*n == '/')
276 translate (n);
277 if (*n != '\\')
278 {
279 /* expect host:/key/value format */
280 host = (char*) malloc (strlen (n) + 1);
281 host[0] = host [1] = '\\';
282 for (e = n, h = host + 2; *e && *e != ':'; e++, h++)
283 *h = *e;
284 *h = 0;
285 n = e + 1;
286 if (*n == '/')
287 translate (n);
288 }
289 else if (n[0] == '\\' && n[1] == '\\')
290 {
291 /* expect //host/key/value format */
292 host = (char*) malloc (strlen (n) + 1);
293 host[0] = host[1] = '\\';
294 for (e = n + 2, h = host + 2; *e && *e != '\\'; e++, h++)
295 *h = *e;
296 *h = 0;
297 n = e;
298 }
299 while (*n != '\\')
300 n++;
301 *n++ = 0;
302 for (e = n; *e && *e != '\\'; e++);
303 c = *e;
304 *e = 0;
305 for (i = 0; wkprefixes[i].string; i++)
306 if (strcmp (wkprefixes[i].string, n) == 0)
307 break;
308 if (!wkprefixes[i].string)
309 {
310 fprintf (stderr, "Unknown key prefix. Valid prefixes are:\n");
311 for (i = 0; wkprefixes[i].string; i++)
312 fprintf (stderr, "\t%s\n", wkprefixes[i].string);
313 exit (1);
314 }
315
316 n = e;
317 *e = c;
318 while (*n && *n == '\\')
319 n++;
320 e = n + strlen (n);
321 if (howmanyparts > 1)
322 {
323 while (n < e && *e != key_sep)
324 e--;
325 if (*e != key_sep)
326 {
327 key = wkprefixes[i].key;
328 value = n;
329 return;
330 }
331 else
332 {
333 *e = 0;
334 value = e + 1;
335 }
336 }
337 if (host)
338 {
339 rv = RegConnectRegistry (host, wkprefixes[i].key, &base);
340 if (rv != ERROR_SUCCESS)
341 Fail (rv);
342 free (host);
343 }
344 else
345 base = wkprefixes[i].key;
346
347 if (n[0] == 0)
348 key = base;
349 else
350 {
351 rv = RegOpenKeyEx (base, n, 0, access, &key);
352 if (rv != ERROR_SUCCESS)
353 Fail (rv);
354 }
355 //printf("key `%s' value `%s'\n", n, value);
356 }
357
358
359 int
360 cmd_list ()
361 {
362 DWORD num_subkeys, maxsubkeylen, num_values, maxvalnamelen, maxvaluelen;
363 DWORD maxclasslen;
364 char *subkey_name, *value_name, *class_name;
365 unsigned char *value_data, *vd;
366 DWORD i, j, m, n, t;
367 int v;
368
369 find_key (1, KEY_READ);
370 RegQueryInfoKey (key, 0, 0, 0, &num_subkeys, &maxsubkeylen, &maxclasslen,
371 &num_values, &maxvalnamelen, &maxvaluelen, 0, 0);
372
373 subkey_name = (char *) malloc (maxsubkeylen + 1);
374 class_name = (char *) malloc (maxclasslen + 1);
375 value_name = (char *) malloc (maxvalnamelen + 1);
376 value_data = (unsigned char *) malloc (maxvaluelen + 1);
377
378 if (!listwhat)
379 listwhat = LIST_ALL;
380
381 if (listwhat & LIST_KEYS)
382 for (i = 0; i < num_subkeys; i++)
383 {
384 m = maxsubkeylen + 1;
385 n = maxclasslen + 1;
386 RegEnumKeyEx (key, i, subkey_name, &m, 0, class_name, &n, 0);
387 printf ("%s%s", subkey_name, (postfix || verbose) ? "\\" : "");
388
389 if (verbose)
390 printf (" (%s)", class_name);
391
392 puts ("");
393 }
394
395 if (listwhat & LIST_VALS)
396 for (i = 0; i < num_values; i++)
397 {
398 m = maxvalnamelen + 1;
399 n = maxvaluelen + 1;
400 RegEnumValue (key, i, value_name, &m, 0, &t, (BYTE *) value_data, &n);
401 if (!verbose)
402 printf ("%s\n", value_name);
403 else
404 {
405 printf ("%s = ", value_name);
406 switch (t)
407 {
408 case REG_BINARY:
409 for (j = 0; j < 8 && j < n; j++)
410 printf ("%02x ", value_data[j]);
411 printf ("\n");
412 break;
413 case REG_DWORD:
414 printf ("0x%08lx (%lu)\n", *(DWORD *) value_data,
415 *(DWORD *) value_data);
416 break;
417 case REG_DWORD_BIG_ENDIAN:
418 v = ((value_data[0] << 24)
419 | (value_data[1] << 16)
420 | (value_data[2] << 8) | (value_data[3]));
421 printf ("0x%08x (%d)\n", v, v);
422 break;
423 case REG_EXPAND_SZ:
424 case REG_SZ:
425 printf ("\"%s\"\n", value_data);
426 break;
427 case REG_MULTI_SZ:
428 vd = value_data;
429 while (vd && *vd)
430 {
431 printf ("\"%s\"", vd);
432 vd = vd + strlen ((const char *) vd) + 1;
433 if (*vd)
434 printf (", ");
435 }
436 printf ("\n");
437 break;
438 default:
439 printf ("? (type %d)\n", (int) t);
440 }
441 }
442 }
443 return 0;
444 }
445
446 int
447 cmd_add ()
448 {
449 find_key (2, KEY_ALL_ACCESS);
450 HKEY newkey;
451 DWORD newtype;
452 int rv = RegCreateKeyEx (key, value, 0, (char *) "", REG_OPTION_NON_VOLATILE,
453 KEY_ALL_ACCESS, 0, &newkey, &newtype);
454 if (rv != ERROR_SUCCESS)
455 Fail (rv);
456
457 if (verbose)
458 {
459 if (newtype == REG_OPENED_EXISTING_KEY)
460 printf ("Key %s already exists\n", value);
461 else
462 printf ("Key %s created\n", value);
463 }
464 return 0;
465 }
466
467 int
468 cmd_remove ()
469 {
470 find_key (2, KEY_ALL_ACCESS);
471 DWORD rv = RegDeleteKey (key, value);
472 if (rv != ERROR_SUCCESS)
473 Fail (rv);
474 if (verbose)
475 printf ("subkey %s deleted\n", value);
476 return 0;
477 }
478
479 int
480 cmd_check ()
481 {
482 find_key (1, KEY_READ);
483 if (verbose)
484 printf ("key %s exists\n", argv[0]);
485 return 0;
486 }
487
488 int
489 cmd_set ()
490 {
491 int i, n;
492 DWORD v, rv;
493 char *a = argv[1], *data;
494 find_key (2, KEY_ALL_ACCESS);
495
496 if (key_type == KT_AUTO)
497 {
498 char *e;
499 strtoul (a, &e, 0);
500 if (a[0] == '%')
501 key_type = KT_EXPAND;
502 else if (a[0] && !*e)
503 key_type = KT_INT;
504 else if (argv[2])
505 key_type = KT_MULTI;
506 else
507 key_type = KT_STRING;
508 }
509
510 switch (key_type)
511 {
512 case KT_INT:
513 v = strtoul (a, 0, 0);
514 rv = RegSetValueEx (key, value, 0, REG_DWORD, (const BYTE *) &v,
515 sizeof (v));
516 break;
517 case KT_STRING:
518 rv = RegSetValueEx (key, value, 0, REG_SZ, (const BYTE *) a, strlen (a));
519 break;
520 case KT_EXPAND:
521 rv = RegSetValueEx (key, value, 0, REG_EXPAND_SZ, (const BYTE *) a,
522 strlen (a));
523 break;
524 case KT_MULTI:
525 for (i = 1, n = 1; argv[i]; i++)
526 n += strlen (argv[i]) + 1;
527 data = (char *) malloc (n);
528 for (i = 1, n = 0; argv[i]; i++)
529 {
530 strcpy (data + n, argv[i]);
531 n += strlen (argv[i]) + 1;
532 }
533 data[n] = 0;
534 rv = RegSetValueEx (key, value, 0, REG_MULTI_SZ, (const BYTE *) data,
535 n + 1);
536 break;
537 case KT_AUTO:
538 rv = ERROR_SUCCESS;
539 break;
540 default:
541 rv = ERROR_INVALID_CATEGORY;
542 break;
543 }
544
545 if (rv != ERROR_SUCCESS)
546 Fail (rv);
547
548 return 0;
549 }
550
551 int
552 cmd_unset ()
553 {
554 find_key (2, KEY_ALL_ACCESS);
555 DWORD rv = RegDeleteValue (key, value);
556 if (rv != ERROR_SUCCESS)
557 Fail (rv);
558 if (verbose)
559 printf ("value %s deleted\n", value);
560 return 0;
561 }
562
563 int
564 cmd_get ()
565 {
566 find_key (2, KEY_READ);
567 DWORD vtype, dsize, rv;
568 char *data, *vd;
569 rv = RegQueryValueEx (key, value, 0, &vtype, 0, &dsize);
570 if (rv != ERROR_SUCCESS)
571 Fail (rv);
572 dsize++;
573 data = (char *) malloc (dsize);
574 rv = RegQueryValueEx (key, value, 0, &vtype, (BYTE *) data, &dsize);
575 if (rv != ERROR_SUCCESS)
576 Fail (rv);
577 switch (vtype)
578 {
579 case REG_BINARY:
580 fwrite (data, dsize, 0, stdout);
581 break;
582 case REG_DWORD:
583 printf ("%lu\n", *(DWORD *) data);
584 break;
585 case REG_SZ:
586 printf ("%s\n", data);
587 break;
588 case REG_EXPAND_SZ:
589 if (key_type == KT_EXPAND) // hack
590 {
591 char *buf;
592 DWORD bufsize;
593 bufsize = ExpandEnvironmentStrings (data, 0, 0);
594 buf = (char *) malloc (bufsize + 1);
595 ExpandEnvironmentStrings (data, buf, bufsize + 1);
596 data = buf;
597 }
598 printf ("%s\n", data);
599 break;
600 case REG_MULTI_SZ:
601 vd = data;
602 while (vd && *vd)
603 {
604 printf ("%s\n", vd);
605 vd = vd + strlen ((const char *) vd) + 1;
606 }
607 break;
608 }
609 return 0;
610 }
611
612 struct
613 {
614 const char *name;
615 int (*func) ();
616 } commands[] =
617 {
618 {"list", cmd_list},
619 {"add", cmd_add},
620 {"remove", cmd_remove},
621 {"check", cmd_check},
622 {"set", cmd_set},
623 {"unset", cmd_unset},
624 {"get", cmd_get},
625 {0, 0}
626 };
627
628 int
629 main (int argc, char **_argv)
630 {
631 int g;
632
633 prog_name = strrchr (_argv[0], '/');
634 if (prog_name == NULL)
635 prog_name = strrchr (_argv[0], '\\');
636 if (prog_name == NULL)
637 prog_name = _argv[0];
638 else
639 prog_name++;
640
641 while ((g = getopt_long (argc, _argv, opts, longopts, NULL)) != EOF)
642 switch (g)
643 {
644 case 'e':
645 key_type = KT_EXPAND;
646 break;
647 case 'k':
648 listwhat |= LIST_KEYS;
649 break;
650 case 'h':
651 usage (stdout);
652 case 'i':
653 key_type = KT_INT;
654 break;
655 case 'l':
656 listwhat |= LIST_VALS;
657 break;
658 case 'm':
659 key_type = KT_MULTI;
660 break;
661 case 'p':
662 postfix++;
663 break;
664 case 'q':
665 quiet++;
666 break;
667 case 's':
668 key_type = KT_STRING;
669 break;
670 case 'v':
671 verbose++;
672 break;
673 case 'V':
674 print_version ();
675 exit (0);
676 case 'K':
677 key_sep = *optarg;
678 break;
679 default :
680 usage ();
681 }
682
683 if ((_argv[optind] == NULL) || (_argv[optind+1] == NULL))
684 usage ();
685
686 argv = _argv + optind;
687 int i;
688 for (i = 0; commands[i].name; i++)
689 if (strcmp (commands[i].name, argv[0]) == 0)
690 {
691 argv++;
692 return commands[i].func ();
693 }
694 usage ();
695
696 return 0;
697 }
This page took 0.066873 seconds and 6 git commands to generate.