gpgconf: Add limited support for -0.
[gnupg.git] / tools / gpgconf.c
1 /* gpgconf.c - Configuration utility for GnuPG
2  * Copyright (C) 2003, 2007, 2009, 2011 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include "gpgconf.h"
28 #include "i18n.h"
29 #include "sysutils.h"
30 #include "../common/init.h"
31
32
33 /* Constants to identify the commands and options. */
34 enum cmd_and_opt_values
35   {
36     aNull = 0,
37     oDryRun     = 'n',
38     oOutput     = 'o',
39     oQuiet      = 'q',
40     oVerbose    = 'v',
41     oRuntime    = 'r',
42     oComponent  = 'c',
43     oNull       = '0',
44     oNoVerbose  = 500,
45     oHomedir,
46
47     aListComponents,
48     aCheckPrograms,
49     aListOptions,
50     aChangeOptions,
51     aCheckOptions,
52     aApplyDefaults,
53     aListConfig,
54     aCheckConfig,
55     aListDirs,
56     aLaunch,
57     aKill,
58     aCreateSocketDir,
59     aRemoveSocketDir,
60     aReload
61   };
62
63
64 /* The list of commands and options. */
65 static ARGPARSE_OPTS opts[] =
66   {
67     { 300, NULL, 0, N_("@Commands:\n ") },
68
69     { aListComponents, "list-components", 256, N_("list all components") },
70     { aCheckPrograms, "check-programs", 256, N_("check all programs") },
71     { aListOptions, "list-options", 256, N_("|COMPONENT|list options") },
72     { aChangeOptions, "change-options", 256, N_("|COMPONENT|change options") },
73     { aCheckOptions, "check-options", 256, N_("|COMPONENT|check options") },
74     { aApplyDefaults, "apply-defaults", 256,
75       N_("apply global default values") },
76     { aListDirs, "list-dirs", 256,
77       N_("get the configuration directories for @GPGCONF@") },
78     { aListConfig,   "list-config", 256,
79       N_("list global configuration file") },
80     { aCheckConfig,   "check-config", 256,
81       N_("check global configuration file") },
82     { aReload,        "reload", 256, N_("reload all or a given component")},
83     { aLaunch,        "launch", 256, N_("launch a given component")},
84     { aKill,          "kill", 256,   N_("kill a given component")},
85     { aCreateSocketDir, "create-socketdir", 256, "@"},
86     { aRemoveSocketDir, "remove-socketdir", 256, "@"},
87
88     { 301, NULL, 0, N_("@\nOptions:\n ") },
89
90     { oOutput, "output",    2, N_("use as output file") },
91     { oVerbose, "verbose",  0, N_("verbose") },
92     { oQuiet, "quiet",      0, N_("quiet") },
93     { oDryRun, "dry-run",   0, N_("do not make any changes") },
94     { oRuntime, "runtime",  0, N_("activate changes at runtime, if possible") },
95     /* hidden options */
96     { oHomedir, "homedir", 2, "@" },
97     { oNull, "null", 0, "@" },
98     { oNoVerbose, "no-verbose",  0, "@"},
99     {0}
100   };
101
102
103 /* Print usage information and and provide strings for help. */
104 static const char *
105 my_strusage( int level )
106 {
107   const char *p;
108
109   switch (level)
110     {
111     case 11: p = "@GPGCONF@ (@GNUPG@)";
112       break;
113     case 13: p = VERSION; break;
114     case 17: p = PRINTABLE_OS_NAME; break;
115     case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
116
117     case 1:
118     case 40: p = _("Usage: @GPGCONF@ [options] (-h for help)");
119       break;
120     case 41:
121       p = _("Syntax: @GPGCONF@ [options]\n"
122             "Manage configuration options for tools of the @GNUPG@ system\n");
123       break;
124
125     default: p = NULL; break;
126     }
127   return p;
128 }
129
130
131 /* Return the fp for the output.  This is usually stdout unless
132    --output has been used.  In the latter case this function opens
133    that file.  */
134 static estream_t
135 get_outfp (estream_t *fp)
136 {
137   if (!*fp)
138     {
139       if (opt.outfile)
140         {
141           *fp = es_fopen (opt.outfile, "w");
142           if (!*fp)
143             gc_error (1, errno, "can not open '%s'", opt.outfile);
144         }
145       else
146         *fp = es_stdout;
147     }
148   return *fp;
149 }
150
151
152 static void
153 list_dirs (estream_t fp, char **names)
154 {
155   static struct {
156     const char *name;
157     const char *(*fnc)(void);
158     const char *extra;
159     int special;
160   } list[] = {
161     { "sysconfdir",         gnupg_sysconfdir, NULL },
162     { "bindir",             gnupg_bindir,     NULL },
163     { "libexecdir",         gnupg_libexecdir, NULL },
164     { "libdir",             gnupg_libdir,     NULL },
165     { "datadir",            gnupg_datadir,    NULL },
166     { "localedir",          gnupg_localedir,  NULL },
167     { "dirmngr-socket",     dirmngr_user_socket_name, NULL, 1 },
168     { "dirmngr-socket",     dirmngr_sys_socket_name,  NULL, 2 },
169     { "dirmngr-sys-socket", dirmngr_sys_socket_name,  NULL, 1 },
170     { "agent-ssh-socket",   gnupg_socketdir,  GPG_AGENT_SSH_SOCK_NAME },
171     { "agent-socket",       gnupg_socketdir,  GPG_AGENT_SOCK_NAME },
172     { "homedir",            gnupg_homedir,    NULL }
173   };
174   int idx, j;
175   char *tmp;
176   const char *s;
177
178
179   for (idx = 0; idx < DIM (list); idx++)
180     {
181       if (list[idx].special == 1 && dirmngr_user_socket_name ())
182         ;
183       else if (list[idx].special == 2 && !dirmngr_user_socket_name ())
184         ;
185       else if (list[idx].special == 1 || list[idx].special == 2)
186         continue;
187
188       s = list[idx].fnc ();
189       if (list[idx].extra)
190         {
191           tmp = make_filename (s, list[idx].extra, NULL);
192           s = tmp;
193         }
194       else
195         tmp = NULL;
196       if (!names)
197         es_fprintf (fp, "%s:%s\n", list[idx].name, gc_percent_escape (s));
198       else
199         {
200           for (j=0; names[j]; j++)
201             if (!strcmp (names[j], list[idx].name))
202               {
203                 es_fputs (s, fp);
204                 es_putc (opt.null? '\0':'\n', fp);
205               }
206         }
207
208       xfree (tmp);
209     }
210 }
211
212
213 /* gpgconf main. */
214 int
215 main (int argc, char **argv)
216 {
217   ARGPARSE_ARGS pargs;
218   const char *fname;
219   int no_more_options = 0;
220   enum cmd_and_opt_values cmd = 0;
221   estream_t outfp = NULL;
222
223   early_system_init ();
224   gnupg_reopen_std (GPGCONF_NAME);
225   set_strusage (my_strusage);
226   log_set_prefix (GPGCONF_NAME, 1);
227
228   /* Make sure that our subsystems are ready.  */
229   i18n_init();
230   init_common_subsystems (&argc, &argv);
231
232   /* Parse the command line. */
233   pargs.argc  = &argc;
234   pargs.argv  = &argv;
235   pargs.flags =  1;  /* Do not remove the args.  */
236   while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts))
237     {
238       switch (pargs.r_opt)
239         {
240         case oOutput:    opt.outfile = pargs.r.ret_str; break;
241         case oQuiet:     opt.quiet = 1; break;
242         case oDryRun:    opt.dry_run = 1; break;
243         case oRuntime:
244           opt.runtime = 1;
245           break;
246         case oVerbose:   opt.verbose++; break;
247         case oNoVerbose: opt.verbose = 0; break;
248         case oHomedir:   gnupg_set_homedir (pargs.r.ret_str); break;
249         case oNull:      opt.null = 1; break;
250
251         case aListDirs:
252         case aListComponents:
253         case aCheckPrograms:
254         case aListOptions:
255         case aChangeOptions:
256         case aCheckOptions:
257         case aApplyDefaults:
258         case aListConfig:
259         case aCheckConfig:
260         case aReload:
261         case aLaunch:
262         case aKill:
263         case aCreateSocketDir:
264         case aRemoveSocketDir:
265           cmd = pargs.r_opt;
266           break;
267
268         default: pargs.err = 2; break;
269         }
270     }
271
272   if (log_get_errorcount (0))
273     exit (2);
274
275   /* Print a warning if an argument looks like an option.  */
276   if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
277     {
278       int i;
279
280       for (i=0; i < argc; i++)
281         if (argv[i][0] == '-' && argv[i][1] == '-')
282           log_info (_("Note: '%s' is not considered an option\n"), argv[i]);
283     }
284
285   fname = argc ? *argv : NULL;
286
287   switch (cmd)
288     {
289     case aListComponents:
290     default:
291       /* List all components. */
292       gc_component_list_components (get_outfp (&outfp));
293       break;
294
295     case aCheckPrograms:
296       /* Check all programs. */
297       gc_check_programs (get_outfp (&outfp));
298       break;
299
300     case aListOptions:
301     case aChangeOptions:
302     case aCheckOptions:
303       if (!fname)
304         {
305           es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME);
306           es_putc ('\n', es_stderr);
307           es_fputs (_("Need one component argument"), es_stderr);
308           es_putc ('\n', es_stderr);
309           exit (2);
310         }
311       else
312         {
313           int idx = gc_component_find (fname);
314           if (idx < 0)
315             {
316               es_fputs (_("Component not found"), es_stderr);
317               es_putc ('\n', es_stderr);
318               exit (1);
319             }
320           if (cmd == aCheckOptions)
321             gc_component_check_options (idx, get_outfp (&outfp), NULL);
322           else
323             {
324               gc_component_retrieve_options (idx);
325               if (gc_process_gpgconf_conf (NULL, 1, 0, NULL))
326                 exit (1);
327               if (cmd == aListOptions)
328                 gc_component_list_options (idx, get_outfp (&outfp));
329               else if (cmd == aChangeOptions)
330                 gc_component_change_options (idx, es_stdin, get_outfp (&outfp));
331             }
332         }
333       break;
334
335     case aLaunch:
336     case aKill:
337       if (!fname)
338         {
339           es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME);
340           es_putc ('\n', es_stderr);
341           es_fputs (_("Need one component argument"), es_stderr);
342           es_putc ('\n', es_stderr);
343           exit (2);
344         }
345       else
346         {
347           /* Launch/Kill a given component.  */
348           int idx;
349
350           idx = gc_component_find (fname);
351           if (idx < 0)
352             {
353               es_fputs (_("Component not found"), es_stderr);
354               es_putc ('\n', es_stderr);
355               exit (1);
356             }
357           else if (cmd == aLaunch)
358             {
359               if (gc_component_launch (idx))
360                 exit (1);
361             }
362           else
363             {
364               /* We don't error out if the kill failed because this
365                  command should do nothing if the component is not
366                  running.  */
367               gc_component_kill (idx);
368             }
369         }
370       break;
371
372     case aReload:
373       if (!fname)
374         {
375           /* Reload all.  */
376           gc_component_reload (-1);
377         }
378       else
379         {
380           /* Reload given component.  */
381           int idx;
382
383           idx = gc_component_find (fname);
384           if (idx < 0)
385             {
386               es_fputs (_("Component not found"), es_stderr);
387               es_putc ('\n', es_stderr);
388               exit (1);
389             }
390           else
391             {
392               gc_component_reload (idx);
393             }
394         }
395       break;
396
397     case aListConfig:
398       if (gc_process_gpgconf_conf (fname, 0, 0, get_outfp (&outfp)))
399         exit (1);
400       break;
401
402     case aCheckConfig:
403       if (gc_process_gpgconf_conf (fname, 0, 0, NULL))
404         exit (1);
405       break;
406
407     case aApplyDefaults:
408       if (fname)
409         {
410           es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME);
411           es_putc ('\n', es_stderr);
412           es_fputs (_("No argument allowed"), es_stderr);
413           es_putc ('\n', es_stderr);
414           exit (2);
415         }
416       gc_component_retrieve_options (-1);
417       if (gc_process_gpgconf_conf (NULL, 1, 1, NULL))
418         exit (1);
419       break;
420
421     case aListDirs:
422       /* Show the system configuration directories for gpgconf.  */
423       get_outfp (&outfp);
424       list_dirs (outfp, argc? argv : NULL);
425       break;
426
427     case aCreateSocketDir:
428       {
429         char *socketdir;
430         unsigned int flags;
431
432         /* Make sure that the top /run/user/UID/gnupg dir has been
433          * created.  */
434         gnupg_socketdir ();
435
436         /* Check the /var/run dir.  */
437         socketdir = _gnupg_socketdir_internal (1, &flags);
438         if ((flags & 64) && !opt.dry_run)
439           {
440             /* No sub dir - create it. */
441             if (gnupg_mkdir (socketdir, "-rwx"))
442               gc_error (1, errno, "error creating '%s'", socketdir);
443             /* Try again.  */
444             socketdir = _gnupg_socketdir_internal (1, &flags);
445           }
446
447         /* Give some info.  */
448         if ( (flags & ~32) || opt.verbose || opt.dry_run)
449           {
450             log_info ("socketdir is '%s'\n", socketdir);
451             if ((flags &   1)) log_info ("\tgeneral error\n");
452             if ((flags &   2)) log_info ("\tno /run/user dir\n");
453             if ((flags &   4)) log_info ("\tbad permissions\n");
454             if ((flags &   8)) log_info ("\tbad permissions (subdir)\n");
455             if ((flags &  16)) log_info ("\tmkdir failed\n");
456             if ((flags &  32)) log_info ("\tnon-default homedir\n");
457             if ((flags &  64)) log_info ("\tno such subdir\n");
458             if ((flags & 128)) log_info ("\tusing homedir as fallback\n");
459           }
460
461         if ((flags & ~32) && !opt.dry_run)
462           gc_error (1, 0, "error creating socket directory");
463
464         xfree (socketdir);
465       }
466       break;
467
468     case aRemoveSocketDir:
469       {
470         char *socketdir;
471         unsigned int flags;
472
473         /* Check the /var/run dir.  */
474         socketdir = _gnupg_socketdir_internal (1, &flags);
475         if ((flags & 128))
476           log_info ("ignoring request to remove non /run/user socket dir\n");
477         else if (opt.dry_run)
478           ;
479         else if (rmdir (socketdir))
480           gc_error (1, errno, "error removing '%s'", socketdir);
481
482         xfree (socketdir);
483       }
484       break;
485
486     }
487
488   if (outfp != es_stdout)
489     if (es_fclose (outfp))
490       gc_error (1, errno, "error closing '%s'", opt.outfile);
491
492   return 0;
493 }