core: Fix condition-always-true warning in trace macro.
[gpgme.git] / src / dirinfo.c
1 /* dirinfo.c - Get directory information
2  * Copyright (C) 2009, 2013 g10 Code GmbH
3  *
4  * This file is part of GPGME.
5  *
6  * GPGME is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * GPGME is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "gpgme.h"
28 #include "util.h"
29 #include "priv-io.h"
30 #include "debug.h"
31 #include "sema.h"
32 #include "sys-util.h"
33
34 DEFINE_STATIC_LOCK (dirinfo_lock);
35
36 /* Constants used internally to select the data.  */
37 enum
38   {
39     WANT_HOMEDIR,
40     WANT_SYSCONFDIR,
41     WANT_BINDIR,
42     WANT_LIBEXECDIR,
43     WANT_LIBDIR,
44     WANT_DATADIR,
45     WANT_LOCALEDIR,
46     WANT_AGENT_SOCKET,
47     WANT_AGENT_SSH_SOCKET,
48     WANT_DIRMNGR_SOCKET,
49     WANT_UISRV_SOCKET,
50     WANT_GPGCONF_NAME,
51     WANT_GPG_NAME,
52     WANT_GPGSM_NAME,
53     WANT_G13_NAME,
54     WANT_GPG_ONE_MODE
55   };
56
57 /* Values retrieved via gpgconf and cached here.  */
58 static struct {
59   int  valid;         /* Cached information is valid.  */
60   int  disable_gpgconf;
61   char *homedir;
62   char *sysconfdir;
63   char *bindir;
64   char *libexecdir;
65   char *libdir;
66   char *datadir;
67   char *localedir;
68   char *agent_socket;
69   char *agent_ssh_socket;
70   char *dirmngr_socket;
71   char *uisrv_socket;
72   char *gpgconf_name;
73   char *gpg_name;
74   char *gpgsm_name;
75   char *g13_name;
76   int  gpg_one_mode;  /* System is in gpg1 mode.  */
77 } dirinfo;
78
79
80 \f
81 /* Helper function to be used only by gpgme_set_global_flag.  */
82 void
83 _gpgme_dirinfo_disable_gpgconf (void)
84 {
85   dirinfo.disable_gpgconf = 1;
86 }
87
88
89 /* Return the length of the directory part including the trailing
90  * slash of NAME.  */
91 static size_t
92 dirname_len (const char *name)
93 {
94   return _gpgme_get_basename (name) - name;
95 }
96
97
98 /* Parse the output of "gpgconf --list-dirs".  This function expects
99    that DIRINFO_LOCK is held by the caller.  If COMPONENTS is set, the
100    output of --list-components is expected. */
101 static void
102 parse_output (char *line, int components)
103 {
104   char *value, *p;
105   size_t n;
106
107   value = strchr (line, ':');
108   if (!value)
109     return;
110   *value++ = 0;
111   if (components)
112     {
113       /* Skip the second field.  */
114       value = strchr (value, ':');
115       if (!value)
116         return;
117       *value++ = 0;
118     }
119   p = strchr (value, ':');
120   if (p)
121     *p = 0;
122   if (_gpgme_decode_percent_string (value, &value, strlen (value)+1, 0))
123     return;
124   if (!*value)
125     return;
126
127   if (components)
128     {
129       if (!strcmp (line, "gpg") && !dirinfo.gpg_name)
130         dirinfo.gpg_name = strdup (value);
131       else if (!strcmp (line, "gpgsm") && !dirinfo.gpgsm_name)
132         dirinfo.gpgsm_name = strdup (value);
133       else if (!strcmp (line, "g13") && !dirinfo.g13_name)
134         dirinfo.g13_name = strdup (value);
135     }
136   else
137     {
138       if (!strcmp (line, "homedir") && !dirinfo.homedir)
139         dirinfo.homedir = strdup (value);
140       else if (!strcmp (line, "sysconfdir") && !dirinfo.sysconfdir)
141         dirinfo.sysconfdir = strdup (value);
142       else if (!strcmp (line, "bindir") && !dirinfo.bindir)
143         dirinfo.bindir = strdup (value);
144       else if (!strcmp (line, "libexecdir") && !dirinfo.libexecdir)
145         dirinfo.libexecdir = strdup (value);
146       else if (!strcmp (line, "libdir") && !dirinfo.libdir)
147         dirinfo.libdir = strdup (value);
148       else if (!strcmp (line, "datadir") && !dirinfo.datadir)
149         dirinfo.datadir = strdup (value);
150       else if (!strcmp (line, "localedir") && !dirinfo.localedir)
151         dirinfo.localedir = strdup (value);
152       else if (!strcmp (line, "agent-socket") && !dirinfo.agent_socket)
153         {
154           const char name[] = "S.uiserver";
155           char *buffer;
156
157           dirinfo.agent_socket = strdup (value);
158           if (dirinfo.agent_socket)
159             {
160               n = dirname_len (dirinfo.agent_socket);
161               buffer = malloc (n + strlen (name) + 1);
162               if (buffer)
163                 {
164                   strncpy (buffer, dirinfo.agent_socket, n);
165                   strcpy (buffer + n, name);
166                   dirinfo.uisrv_socket = buffer;
167                 }
168             }
169         }
170       else if (!strcmp (line, "dirmngr-socket") && !dirinfo.dirmngr_socket)
171         dirinfo.dirmngr_socket = strdup (value);
172       else if (!strcmp (line, "agent-ssh-socket") && !dirinfo.agent_ssh_socket)
173         dirinfo.agent_ssh_socket = strdup (value);
174     }
175 }
176
177
178 /* Read the directory information from gpgconf.  This function expects
179    that DIRINFO_LOCK is held by the caller.  PGNAME is the name of the
180    gpgconf binary. If COMPONENTS is set, not the directories bit the
181    name of the componeNts are read. */
182 static void
183 read_gpgconf_dirs (const char *pgmname, int components)
184 {
185   char linebuf[1024] = {0};
186   int linelen = 0;
187   char * argv[3];
188   int rp[2];
189   struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
190                                    {-1, -1} };
191   int status;
192   int nread;
193   char *mark = NULL;
194
195   argv[0] = (char *)pgmname;
196   argv[1] = components? "--list-components" : "--list-dirs";
197   argv[2] = NULL;
198
199   if (_gpgme_io_pipe (rp, 1) < 0)
200     return;
201
202   cfd[0].fd = rp[1];
203
204   status = _gpgme_io_spawn (pgmname, argv, IOSPAWN_FLAG_DETACHED,
205                             cfd, NULL, NULL, NULL);
206   if (status < 0)
207     {
208       _gpgme_io_close (rp[0]);
209       _gpgme_io_close (rp[1]);
210       return;
211     }
212
213   do
214     {
215       nread = _gpgme_io_read (rp[0],
216                               linebuf + linelen,
217                               sizeof linebuf - linelen - 1);
218       if (nread > 0)
219         {
220           char *line;
221           const char *lastmark = NULL;
222           size_t nused;
223
224           linelen += nread;
225           linebuf[linelen] = '\0';
226
227           for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
228             {
229               lastmark = mark;
230               if (mark > line && mark[-1] == '\r')
231                 mark[-1] = '\0';
232               else
233                 mark[0] = '\0';
234
235               parse_output (line, components);
236             }
237
238           nused = lastmark? (lastmark + 1 - linebuf) : 0;
239           memmove (linebuf, linebuf + nused, linelen - nused);
240           linelen -= nused;
241         }
242     }
243   while (nread > 0 && linelen < sizeof linebuf - 1);
244
245   _gpgme_io_close (rp[0]);
246 }
247
248
249 static const char *
250 get_gpgconf_item (int what)
251 {
252   const char *result = NULL;
253
254   LOCK (dirinfo_lock);
255   if (!dirinfo.valid)
256     {
257       char *pgmname;
258
259       pgmname = dirinfo.disable_gpgconf? NULL : _gpgme_get_gpgconf_path ();
260       if (pgmname && access (pgmname, F_OK))
261         {
262           _gpgme_debug (DEBUG_INIT,
263                         "gpgme-dinfo: gpgconf='%s' [not installed]\n", pgmname);
264           free (pgmname);
265           pgmname = NULL; /* Not available.  */
266         }
267       else
268         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: gpgconf='%s'\n",
269                       pgmname? pgmname : "[null]");
270       if (!pgmname)
271         {
272           /* Probably gpgconf is not installed.  Assume we are using
273              GnuPG-1.  */
274           dirinfo.gpg_one_mode = 1;
275           pgmname = _gpgme_get_gpg_path ();
276           if (pgmname)
277             dirinfo.gpg_name = pgmname;
278         }
279       else
280         {
281           dirinfo.gpg_one_mode = 0;
282           read_gpgconf_dirs (pgmname, 0);
283           read_gpgconf_dirs (pgmname, 1);
284           dirinfo.gpgconf_name = pgmname;
285         }
286       /* Even if the reading of the directories failed (e.g. due to an
287          too old version gpgconf or no gpgconf at all), we need to
288          mark the entries as valid so that we won't try over and over
289          to read them.  Note further that we are not able to change
290          the read values later because they are practically statically
291          allocated.  */
292       dirinfo.valid = 1;
293       if (dirinfo.gpg_name)
294         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:     gpg='%s'\n",
295                       dirinfo.gpg_name);
296       if (dirinfo.g13_name)
297         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:     g13='%s'\n",
298                       dirinfo.g13_name);
299       if (dirinfo.gpgsm_name)
300         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:   gpgsm='%s'\n",
301                       dirinfo.gpgsm_name);
302       if (dirinfo.homedir)
303         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: homedir='%s'\n",
304                       dirinfo.homedir);
305       if (dirinfo.agent_socket)
306         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:   agent='%s'\n",
307                       dirinfo.agent_socket);
308       if (dirinfo.agent_ssh_socket)
309         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:     ssh='%s'\n",
310                       dirinfo.agent_ssh_socket);
311       if (dirinfo.dirmngr_socket)
312         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: dirmngr='%s'\n",
313                       dirinfo.dirmngr_socket);
314       if (dirinfo.uisrv_socket)
315         _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:   uisrv='%s'\n",
316                       dirinfo.uisrv_socket);
317     }
318   switch (what)
319     {
320     case WANT_HOMEDIR:    result = dirinfo.homedir; break;
321     case WANT_SYSCONFDIR: result = dirinfo.sysconfdir; break;
322     case WANT_BINDIR:     result = dirinfo.bindir; break;
323     case WANT_LIBEXECDIR: result = dirinfo.libexecdir; break;
324     case WANT_LIBDIR:     result = dirinfo.libdir; break;
325     case WANT_DATADIR:    result = dirinfo.datadir; break;
326     case WANT_LOCALEDIR:  result = dirinfo.localedir; break;
327     case WANT_AGENT_SOCKET: result = dirinfo.agent_socket; break;
328     case WANT_AGENT_SSH_SOCKET: result = dirinfo.agent_ssh_socket; break;
329     case WANT_DIRMNGR_SOCKET: result = dirinfo.dirmngr_socket; break;
330     case WANT_GPGCONF_NAME: result = dirinfo.gpgconf_name; break;
331     case WANT_GPG_NAME:   result = dirinfo.gpg_name; break;
332     case WANT_GPGSM_NAME: result = dirinfo.gpgsm_name; break;
333     case WANT_G13_NAME:   result = dirinfo.g13_name; break;
334     case WANT_UISRV_SOCKET:  result = dirinfo.uisrv_socket; break;
335     case WANT_GPG_ONE_MODE: result = dirinfo.gpg_one_mode? "1":NULL; break;
336     }
337   UNLOCK (dirinfo_lock);
338   return result;
339 }
340
341
342 /* Return the default home directory.   Returns NULL if not known.  */
343 const char *
344 _gpgme_get_default_homedir (void)
345 {
346   return get_gpgconf_item (WANT_HOMEDIR);
347 }
348
349 /* Return the default gpg-agent socket name.  Returns NULL if not known.  */
350 const char *
351 _gpgme_get_default_agent_socket (void)
352 {
353   return get_gpgconf_item (WANT_AGENT_SOCKET);
354 }
355
356 /* Return the default gpg file name.  Returns NULL if not known.  */
357 const char *
358 _gpgme_get_default_gpg_name (void)
359 {
360   return get_gpgconf_item (WANT_GPG_NAME);
361 }
362
363 /* Return the default gpgsm file name.  Returns NULL if not known.  */
364 const char *
365 _gpgme_get_default_gpgsm_name (void)
366 {
367   return get_gpgconf_item (WANT_GPGSM_NAME);
368 }
369
370 /* Return the default g13 file name.  Returns NULL if not known.  */
371 const char *
372 _gpgme_get_default_g13_name (void)
373 {
374   return get_gpgconf_item (WANT_G13_NAME);
375 }
376
377 /* Return the default gpgconf file name.  Returns NULL if not known.  */
378 const char *
379 _gpgme_get_default_gpgconf_name (void)
380 {
381   return get_gpgconf_item (WANT_GPGCONF_NAME);
382 }
383
384 /* Return the default UI-server socket name.  Returns NULL if not
385    known.  */
386 const char *
387 _gpgme_get_default_uisrv_socket (void)
388 {
389   return get_gpgconf_item (WANT_UISRV_SOCKET);
390 }
391
392 /* Return true if we are in GnuPG-1 mode - ie. no gpgconf and agent
393    being optional.  */
394 int
395 _gpgme_in_gpg_one_mode (void)
396 {
397   return !!get_gpgconf_item (WANT_GPG_ONE_MODE);
398 }
399
400
401
402 /* Helper function to return the basename of the passed filename.  */
403 const char *
404 _gpgme_get_basename (const char *name)
405 {
406   const char *s;
407
408   if (!name || !*name)
409     return name;
410   for (s = name + strlen (name) -1; s >= name; s--)
411     if (*s == '/'
412 #ifdef HAVE_W32_SYSTEM
413         || *s == '\\' || *s == ':'
414 #endif
415         )
416       return s+1;
417   return name;
418 }
419
420
421 /* Return default values for various directories and file names.  */
422 const char *
423 gpgme_get_dirinfo (const char *what)
424 {
425   if (!what)
426     return NULL;
427   else if (!strcmp (what, "homedir"))
428     return get_gpgconf_item (WANT_HOMEDIR);
429   else if (!strcmp (what, "agent-socket"))
430     return get_gpgconf_item (WANT_AGENT_SOCKET);
431   else if (!strcmp (what, "uiserver-socket"))
432     return get_gpgconf_item (WANT_UISRV_SOCKET);
433   else if (!strcmp (what, "gpgconf-name"))
434     return get_gpgconf_item (WANT_GPGCONF_NAME);
435   else if (!strcmp (what, "gpg-name"))
436     return get_gpgconf_item (WANT_GPG_NAME);
437   else if (!strcmp (what, "gpgsm-name"))
438     return get_gpgconf_item (WANT_GPGSM_NAME);
439   else if (!strcmp (what, "g13-name"))
440     return get_gpgconf_item (WANT_G13_NAME);
441   else if (!strcmp (what, "agent-ssh-socket"))
442     return get_gpgconf_item (WANT_AGENT_SSH_SOCKET);
443   else if (!strcmp (what, "dirmngr-socket"))
444     return get_gpgconf_item (WANT_DIRMNGR_SOCKET);
445   else if (!strcmp (what, "sysconfdir"))
446     return get_gpgconf_item (WANT_SYSCONFDIR);
447   else if (!strcmp (what, "bindir"))
448     return get_gpgconf_item (WANT_BINDIR);
449   else if (!strcmp (what, "libexecdir"))
450     return get_gpgconf_item (WANT_LIBEXECDIR);
451   else if (!strcmp (what, "libdir"))
452     return get_gpgconf_item (WANT_LIBDIR);
453   else if (!strcmp (what, "datadir"))
454     return get_gpgconf_item (WANT_DATADIR);
455   else if (!strcmp (what, "localedir"))
456     return get_gpgconf_item (WANT_LOCALEDIR);
457   else
458     return NULL;
459 }