OSDN Git Service

* regtool.cc (find_key): Allow '/' as a synonym for '\\'.
[pf3gnuchains/sourceware.git] / winsup / utils / regtool.cc
1 /* regtool.cc
2
3    Copyright 2000 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 enum
18 {
19   KT_AUTO, KT_INT, KT_STRING, KT_EXPAND, KT_MULTI
20 } key_type = KT_AUTO;
21
22 #define LIST_KEYS       0x01
23 #define LIST_VALS       0x02
24 #define LIST_ALL        (LIST_KEYS | LIST_VALS)
25
26 int listwhat = 0;
27 int postfix = 0;
28 int verbose = 0;
29 int quiet = 0;
30 char **argv;
31
32 HKEY key;
33 char *value;
34
35 const char *usage_msg[] = {
36   "Regtool Copyright (c) 2000 Red Hat Inc",
37   " regtool -h  - print this message",
38   " regtool [-v|-p|-k|-l] list [key]  - list subkeys and values",
39   "     -p=postfix, like ls -p, appends / postfix to key names",
40   "     -k=keys, lists only keys",
41   "     -l=values, lists only values",
42   " regtool [-v] add [key\\subkey]  - add new subkey",
43   " regtool [-v] remove [key]  - remove key",
44   " regtool [-v|-q] check [key]  - exit 0 if key exists, 1 if not",
45   " regtool [-i|-s|-e|-m] set [key\\value] [data ...]  - set value",
46   "     -i=integer -s=string -e=expand-string -m=multi-string",
47   " regtool [-v] unset [key\\value]  - removes value from key",
48   " regtool [-q] get [key\\value]  - prints value to stdout",
49   "     -q=quiet, no error msg, just return nonzero exit if key/value missing",
50   " keys are like \\prefix\\key\\key\\key\\value, where prefix is any of:",
51   "   root     HKCR  HKEY_CLASSES_ROOT",
52   "   config   HKCC  HKEY_CURRENT_CONFIG",
53   "   user     HKCU  HKEY_CURRENT_USER",
54   "   machine  HKLM  HKEY_LOCAL_MACHINE",
55   "   users    HKU   HKEY_USERS",
56   " example: \\user\\software\\Microsoft\\Clock\\iFormat",
57   0
58 };
59
60 void
61 usage (void)
62 {
63   int i;
64   for (i = 0; usage_msg[i]; i++)
65     fprintf (stderr, "%s\n", usage_msg[i]);
66   exit (1);
67 }
68
69 void
70 Fail (DWORD rv)
71 {
72   char *buf;
73   if (!quiet)
74     {
75       FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER
76                      | FORMAT_MESSAGE_FROM_SYSTEM,
77                      0, rv, 0, (CHAR *) & buf, 0, 0);
78       fprintf (stderr, "Error: %s\n", buf);
79       LocalFree (buf);
80     }
81   exit (1);
82 }
83
84 struct
85 {
86   const char *string;
87   HKEY key;
88 } wkprefixes[] =
89 {
90   {"root", HKEY_CLASSES_ROOT},
91   {"HKCR", HKEY_CLASSES_ROOT},
92   {"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT},
93   {"config", HKEY_CURRENT_CONFIG},
94   {"HKCC", HKEY_CURRENT_CONFIG},
95   {"HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG},
96   {"user", HKEY_CURRENT_USER},
97   {"HKCU", HKEY_CURRENT_USER},
98   {"HKEY_CURRENT_USER", HKEY_CURRENT_USER},
99   {"machine", HKEY_LOCAL_MACHINE},
100   {"HKLM", HKEY_LOCAL_MACHINE},
101   {"HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE},
102   {"users", HKEY_USERS},
103   {"HKU", HKEY_USERS},
104   {"HKEY_USERS", HKEY_USERS},
105   {0, 0}
106 };
107
108 void
109 translate (char *key)
110 {
111 #define isodigit(c) (strchr("01234567", c))
112 #define tooct(c)    ((c)-'0')
113 #define tohex(c)    (strchr(_hs,tolower(c))-_hs)
114   static char _hs[] = "0123456789abcdef";
115
116   char *d = key;
117   char *s = key;
118   char c;
119
120   while (*s)
121     {
122       if (*s == '\\')
123         switch (*++s)
124           {
125           case 'a':
126             *d++ = '\007';
127             break;
128           case 'b':
129             *d++ = '\b';
130             break;
131           case 'e':
132             *d++ = '\033';
133             break;
134           case 'f':
135             *d++ = '\f';
136             break;
137           case 'n':
138             *d++ = '\n';
139             break;
140           case 'r':
141             *d++ = '\r';
142             break;
143           case 't':
144             *d++ = '\t';
145             break;
146           case 'v':
147             *d++ = '\v';
148             break;
149           case '0':
150           case '1':
151           case '2':
152           case '3':
153           case '4':
154           case '5':
155           case '6':
156           case '7':
157             c = tooct (*s);
158             if (isodigit (s[1]))
159               {
160                 c = (c << 3) | tooct (*++s);
161                 if (isodigit (s[1]))
162                   c = (c << 3) | tooct (*++s);
163               }
164             *d++ = c;
165             break;
166           case 'x':
167             if (!isxdigit (s[1]))
168               c = '0';
169             else
170               {
171                 c = tohex (*++s);
172                 if (isxdigit (s[1]))
173                   c = (c << 4) | tohex (*++s);
174               }
175             *d++ = c;
176             break;
177           default:              /* before non-special char: just add the char */
178             *d++ = *s;
179             break;
180           }
181       else if (*s == '/')
182         *d++ = '\\';
183       else
184         *d++ = *s;
185       ++s;
186     }
187   *d = '\0';
188 }
189
190 void
191 find_key (int howmanyparts, REGSAM access)
192 {
193   char *n = argv[0], *e, c;
194   int i;
195   if (*n == '/')
196     translate (n);
197   while ((*n == '\\') || (*n == '/'))
198     n++;
199   for (e = n; *e && *e != '\\' && *e != '/'; e++);
200   if (*e == '/')
201     c = '\\';
202   else
203     c = *e;
204   *e = 0;
205   for (i = 0; wkprefixes[i].string; i++)
206     if (strcmp (wkprefixes[i].string, n) == 0)
207       break;
208   if (!wkprefixes[i].string)
209     {
210       fprintf (stderr, "Unknown key prefix.  Valid prefixes are:\n");
211       for (i = 0; wkprefixes[i].string; i++)
212         fprintf (stderr, "\t%s\n", wkprefixes[i].string);
213       exit (1);
214     }
215
216   n = e;
217   *e = c;
218   while (*n && *n == '\\')
219     n++;
220   e = n + strlen (n);
221   if (howmanyparts > 1)
222     {
223       while (n < e && *e != '\\')
224         e--;
225       if (*e != '\\')
226         {
227           fprintf (stderr, "Invalid key\n");
228           exit (1);
229         }
230       *e = 0;
231       value = e + 1;
232     }
233   if (n[0] == 0)
234     {
235       key = wkprefixes[i].key;
236       return;
237     }
238   int rv = RegOpenKeyEx (wkprefixes[i].key, n, 0, access, &key);
239   if (rv != ERROR_SUCCESS)
240     Fail (rv);
241   //printf("key `%s' value `%s'\n", n, value);
242 }
243
244
245 int
246 cmd_list ()
247 {
248   DWORD num_subkeys, maxsubkeylen, num_values, maxvalnamelen, maxvaluelen;
249   DWORD maxclasslen;
250   char *subkey_name, *value_name, *class_name;
251   unsigned char *value_data, *vd;
252   DWORD i, j, m, n, t;
253   int v;
254
255   find_key (1, KEY_READ);
256   RegQueryInfoKey (key, 0, 0, 0, &num_subkeys, &maxsubkeylen, &maxclasslen,
257                    &num_values, &maxvalnamelen, &maxvaluelen, 0, 0);
258
259   subkey_name = (char *) malloc (maxsubkeylen + 1);
260   class_name = (char *) malloc (maxclasslen + 1);
261   value_name = (char *) malloc (maxvalnamelen + 1);
262   value_data = (unsigned char *) malloc (maxvaluelen + 1);
263
264   if (!listwhat)
265     listwhat = LIST_ALL;
266
267   if (listwhat & LIST_KEYS)
268     for (i = 0; i < num_subkeys; i++)
269       {
270         m = maxsubkeylen + 1;
271         n = maxclasslen + 1;
272         RegEnumKeyEx (key, i, subkey_name, &m, 0, class_name, &n, 0);
273         printf ("%s%s", subkey_name, (postfix || verbose) ? "\\" : "");
274
275         if (verbose)
276           printf (" (%s)", class_name);
277
278         puts ("");
279       }
280
281   if (listwhat & LIST_VALS)
282     for (i = 0; i < num_values; i++)
283       {
284         m = maxvalnamelen + 1;
285         n = maxvaluelen + 1;
286         RegEnumValue (key, i, value_name, &m, 0, &t, (BYTE *) value_data, &n);
287         if (!verbose)
288           printf ("%s\n", value_name);
289         else
290           {
291             printf ("%s = ", value_name);
292             switch (t)
293               {
294               case REG_BINARY:
295                 for (j = 0; j < 8 && j < n; j++)
296                   printf ("%02x ", value_data[j]);
297                 printf ("\n");
298                 break;
299               case REG_DWORD:
300                 printf ("0x%08lx (%lu)\n", *(DWORD *) value_data,
301                         *(DWORD *) value_data);
302                 break;
303               case REG_DWORD_BIG_ENDIAN:
304                 v = ((value_data[0] << 24)
305                      | (value_data[1] << 16)
306                      | (value_data[2] << 8) | (value_data[3]));
307                 printf ("0x%08x (%d)\n", v, v);
308                 break;
309               case REG_EXPAND_SZ:
310               case REG_SZ:
311                 printf ("\"%s\"\n", value_data);
312                 break;
313               case REG_MULTI_SZ:
314                 vd = value_data;
315                 while (vd && *vd)
316                   {
317                     printf ("\"%s\"", vd);
318                     vd = vd + strlen ((const char *) vd) + 1;
319                     if (*vd)
320                       printf (", ");
321                   }
322                 printf ("\n");
323                 break;
324               default:
325                 printf ("? (type %d)\n", (int) t);
326               }
327           }
328       }
329   return 0;
330 }
331
332 int
333 cmd_add ()
334 {
335   find_key (2, KEY_ALL_ACCESS);
336   HKEY newkey;
337   DWORD newtype;
338   int rv = RegCreateKeyEx (key, value, 0, (char *) "", REG_OPTION_NON_VOLATILE,
339                            KEY_ALL_ACCESS, 0, &newkey, &newtype);
340   if (rv != ERROR_SUCCESS)
341     Fail (rv);
342
343   if (verbose)
344     {
345       if (newtype == REG_OPENED_EXISTING_KEY)
346         printf ("Key %s already exists\n", value);
347       else
348         printf ("Key %s created\n", value);
349     }
350   return 0;
351 }
352
353 int
354 cmd_remove ()
355 {
356   find_key (2, KEY_ALL_ACCESS);
357   DWORD rv = RegDeleteKey (key, value);
358   if (rv != ERROR_SUCCESS)
359     Fail (rv);
360   if (verbose)
361     printf ("subkey %s deleted\n", value);
362   return 0;
363 }
364
365 int
366 cmd_check ()
367 {
368   find_key (1, KEY_READ);
369   if (verbose)
370     printf ("key %s exists\n", argv[0]);
371   return 0;
372 }
373
374 int
375 cmd_set ()
376 {
377   int i, n;
378   DWORD v, rv;
379   char *a = argv[1], *data;
380   find_key (2, KEY_ALL_ACCESS);
381
382   if (key_type == KT_AUTO)
383     {
384       char *e;
385       strtoul (a, &e, 0);
386       if (a[0] == '%')
387         key_type = KT_EXPAND;
388       else if (a[0] && !*e)
389         key_type = KT_INT;
390       else if (argv[2])
391         key_type = KT_MULTI;
392       else
393         key_type = KT_STRING;
394     }
395
396   switch (key_type)
397     {
398     case KT_INT:
399       v = strtoul (a, 0, 0);
400       rv = RegSetValueEx (key, value, 0, REG_DWORD, (const BYTE *) &v,
401                           sizeof (v));
402       break;
403     case KT_STRING:
404       rv = RegSetValueEx (key, value, 0, REG_SZ, (const BYTE *) a, strlen (a));
405       break;
406     case KT_EXPAND:
407       rv = RegSetValueEx (key, value, 0, REG_EXPAND_SZ, (const BYTE *) a,
408                           strlen (a));
409       break;
410     case KT_MULTI:
411       for (i = 1, n = 1; argv[i]; i++)
412         n += strlen (argv[i]) + 1;
413       data = (char *) malloc (n);
414       for (i = 1, n = 0; argv[i]; i++)
415         {
416           strcpy (data + n, argv[i]);
417           n += strlen (argv[i]) + 1;
418         }
419       data[n] = 0;
420       rv = RegSetValueEx (key, value, 0, REG_MULTI_SZ, (const BYTE *) data,
421                           n + 1);
422       break;
423     case KT_AUTO:
424       rv = ERROR_SUCCESS;
425       break;
426     default:
427       rv = ERROR_INVALID_CATEGORY;
428       break;
429     }
430
431   if (rv != ERROR_SUCCESS)
432     Fail (rv);
433
434   return 0;
435 }
436
437 int
438 cmd_unset ()
439 {
440   find_key (2, KEY_ALL_ACCESS);
441   DWORD rv = RegDeleteValue (key, value);
442   if (rv != ERROR_SUCCESS)
443     Fail (rv);
444   if (verbose)
445     printf ("value %s deleted\n", value);
446   return 0;
447 }
448
449 int
450 cmd_get ()
451 {
452   find_key (2, KEY_READ);
453   DWORD vtype, dsize, rv;
454   char *data, *vd;
455   rv = RegQueryValueEx (key, value, 0, &vtype, 0, &dsize);
456   if (rv != ERROR_SUCCESS)
457     Fail (rv);
458   dsize++;
459   data = (char *) malloc (dsize);
460   rv = RegQueryValueEx (key, value, 0, &vtype, (BYTE *) data, &dsize);
461   if (rv != ERROR_SUCCESS)
462     Fail (rv);
463   switch (vtype)
464     {
465     case REG_BINARY:
466       fwrite (data, dsize, 0, stdout);
467       break;
468     case REG_DWORD:
469       printf ("%lu\n", *(DWORD *) data);
470       break;
471     case REG_SZ:
472       printf ("%s\n", data);
473       break;
474     case REG_EXPAND_SZ:
475       if (key_type == KT_EXPAND)        // hack
476         {
477           char *buf;
478           DWORD bufsize;
479           bufsize = ExpandEnvironmentStrings (data, 0, 0);
480           buf = (char *) malloc (bufsize + 1);
481           ExpandEnvironmentStrings (data, buf, bufsize + 1);
482           data = buf;
483         }
484       printf ("%s\n", data);
485       break;
486     case REG_MULTI_SZ:
487       vd = data;
488       while (vd && *vd)
489         {
490           printf ("%s\n", vd);
491           vd = vd + strlen ((const char *) vd) + 1;
492         }
493       break;
494     }
495   return 0;
496 }
497
498 struct
499 {
500   const char *name;
501   int (*func) ();
502 } commands[] =
503 {
504   {"list", cmd_list},
505   {"add", cmd_add},
506   {"remove", cmd_remove},
507   {"check", cmd_check},
508   {"set", cmd_set},
509   {"unset", cmd_unset},
510   {"get", cmd_get},
511   {0, 0}
512 };
513
514 int
515 main (int argc, char **_argv)
516 {
517   while (1)
518     {
519       int g = getopt (argc, _argv, "hvqisempkl");
520       if (g == -1)
521         break;
522       switch (g)
523         {
524         case 'v':
525           verbose++;
526           break;
527         case 'q':
528           quiet++;
529           break;
530         case 'p':
531           postfix++;
532           break;
533         case 'k':
534           listwhat |= LIST_KEYS;
535           break;
536         case 'l':
537           listwhat |= LIST_VALS;
538           break;
539
540         case 'i':
541           key_type = KT_INT;
542           break;
543         case 's':
544           key_type = KT_STRING;
545           break;
546         case 'e':
547           key_type = KT_EXPAND;
548           break;
549         case 'm':
550           key_type = KT_MULTI;
551           break;
552
553         case '?':
554         case 'h':
555           usage ();
556         }
557     }
558   if (_argv[optind] == NULL)
559     usage ();
560
561   argv = _argv + optind;
562   int i;
563   for (i = 0; commands[i].name; i++)
564     if (strcmp (commands[i].name, argv[0]) == 0)
565       {
566         argv++;
567         return commands[i].func ();
568       }
569   usage ();
570
571   return 0;
572 }