xdg.c
Go to the documentation of this file.
1 /* ========================================================================== */
2 /*! \file
3  * \brief Implementation of XDG Base Directory Specification
4  *
5  * Copyright (c) 2020 by the developers. See the LICENSE file for details.
6  *
7  * This is used by different modules that should not depend on CORE module.
8  */
9 
10 
11 /* ========================================================================== */
12 /* Include headers */
13 
14 #include "posix.h" /* Include this first because of feature test macros */
15 
16 #include <string.h>
17 
18 #include "fileutils.h"
19 #include "main.h"
20 #include "xdg.h"
21 
22 
23 /* ========================================================================== */
24 /*! \defgroup XDG XDG: Freedesktop.org Base Directory Specification
25  *
26  * Implementation of XDG Base Directory Specification (version 0.7).
27  */
28 /*! @{ */
29 
30 
31 /* ========================================================================== */
32 /* Constants */
33 
34 /*! \brief Message prefix for XDG module */
35 #define MAIN_ERR_PREFIX "XDG: "
36 
37 
38 /* ========================================================================== */
39 /*! \brief Append path component to buffer
40  *
41  * \param[in] buf Pointer to buffer pointer
42  * \param[in] newcomp New path component to append
43  *
44  * First a slash "/" is appended to the content of buf.
45  * Then, if \e newcomp is not \c NULL , it is appended after the slash.
46  * Additional memory is automatically allocated.
47  *
48  * \attention Dereferenced \e buf must be usable for \c realloc() .
49  *
50  * \return
51  * - Zero on success
52  * - Negative value on error
53  */
54 
55 int xdg_append_to_path(const char** buf, const char* newcomp)
56 {
57  int res = 0;
58  char* tmp;
59  size_t len_buf = 0;
60  size_t len_new = 0;
61 
62  if(NULL != *buf)
63  {
64  len_buf = strlen(*buf);
65  }
66  if(NULL != newcomp)
67  {
68  len_new = strlen(newcomp);
69  }
70 
71  /* Allocate 2 additional bytes for "/" separator and string termination */
72  tmp = (char*) posix_realloc((void*) *buf, len_buf + len_new + (size_t) 2);
73  if(NULL == tmp)
74  {
75  PRINT_ERROR("Cannot allocate memory for path or pathname");
76  res = -1;
77  }
78  else
79  {
80  tmp[len_buf++] = '/'; /* Increment length for slash */
81  if(NULL != newcomp)
82  {
83  memcpy((void*) &tmp[len_buf], (void*) newcomp, len_new);
84  }
85  /* Terminate new string */
86  tmp[len_buf + len_new] = 0;
87  *buf = tmp;
88  }
89 
90  return(res);
91 }
92 
93 
94 /* ========================================================================== */
95 /*! \brief Get configuration directory
96  *
97  * \param[in] progname Program name
98  *
99  * If \e progname is \c NULL then \c $XDG_CONFIG_HOME is returned. Otherwise
100  * \e progname is appended as subdirectory and $XDG_CONFIG_HOME/progname is
101  * returned.
102  *
103  * If \c XDG_CONFIG_HOME is not defined, the default \c $HOME/.config is used
104  * (it is treated as error if \c HOME is not defined in this case).
105  *
106  * \note
107  * On success, the caller is responsible to free the memory allocated for the
108  * result.
109  *
110  * \return
111  * - Pointer to result on success
112  * - \c NULL on error
113  */
114 
115 const char* xdg_get_confdir(const char* progname)
116 {
117  static int confpath_msg_printed = 0;
118  size_t len;
119  char* tmp;
120  const char* buf = NULL;
121 
122  /* User specified path has higher precedence than XDG_CONFIG_HOME */
123  if(NULL != main_confprefix)
124  {
125  if('/' != main_confprefix[0])
126  {
127  PRINT_ERROR("No absolute path specified for configuration directory");
128  goto error;
129  }
130 
131  /* Use path specified by user */
132  len = strlen(main_confprefix);
133  tmp = (char*) posix_malloc(++len);
134  if(NULL == tmp)
135  {
136  goto error;
137  }
138  strncpy(tmp, main_confprefix, len);
139  buf = tmp;
140  }
141  else
142  {
143  /* Use path specified by XDG */
144  if(0 == ts_getenv("XDG_CONFIG_HOME", &buf))
145  {
146  /* XDG_CONFIG_HOME must contain an absolute path */
147  if('/' != buf[0])
148  {
149  PRINT_ERROR("XDG_CONFIG_HOME present, but not an absolute path");
150  goto error;
151  }
152  }
153  else
154  {
155  /* "XDG_CONFIG_HOME" not defined => Use default "$HOME/.config" */
156  if(0 != ts_getenv("HOME", &buf))
157  {
158  /* Treat missing "HOME" as error */
159  PRINT_ERROR("Environment variable HOME is not defined");
160  goto error;
161  }
162  else
163  {
164  if(0 != xdg_append_to_path(&buf, ".config"))
165  {
166  goto error;
167  }
168  }
169  }
170 
171  /* Append program name, if specified */
172  if(NULL != progname)
173  {
174  if(0 != xdg_append_to_path(&buf, progname))
175  {
176  goto error;
177  }
178  }
179  }
180 
181  /* Check path for unsupported characters */
182  if(0 != fu_check_path(buf))
183  {
184  goto error;
185  }
186 
187  /* Create configuration path, if it doesn't exist */
188  if(0 != fu_create_path(buf, (posix_mode_t) POSIX_S_IRWXU))
189  {
190  goto error;
191  }
192 
193  if(main_debug)
194  {
195  /* Print debug message only once */
196  if(!confpath_msg_printed)
197  {
198  fprintf(stderr, "%s: %sConfiguration path: %s\n",
199  CFG_NAME, MAIN_ERR_PREFIX, buf);
200  confpath_msg_printed = 1;
201  }
202  }
203 
204 exit:
205  return(buf);
206 
207 error:
208  posix_free((void*) buf);
209  buf = NULL;
210  goto exit;
211 }
212 
213 
214 /*! @} */
215 
216 /* EOF */
MAIN_ERR_PREFIX
#define MAIN_ERR_PREFIX
Message prefix for XDG module.
Definition: xdg.c:35
fu_create_path
int fu_create_path(const char *path, posix_mode_t perm)
Create path.
Definition: fileutils.c:119
main_debug
int main_debug
Enable additional debug output if nonzero.
Definition: main.cxx:64
PRINT_ERROR
#define PRINT_ERROR(s)
Prepend module prefix and print error message.
Definition: main.h:19
ts_getenv
int ts_getenv(const char *, const char **)
Thread safe replacement for getenv()
Definition: ts_functions.c:136
main_confprefix
const char * main_confprefix
Configuration directory path from command line option or NULL otherwise.
Definition: main.cxx:67
xdg_get_confdir
const char * xdg_get_confdir(const char *progname)
Get configuration directory.
Definition: xdg.c:115
xdg_append_to_path
int xdg_append_to_path(const char **buf, const char *newcomp)
Append path component to buffer.
Definition: xdg.c:55
fu_check_path
int fu_check_path(const char *path)
Check path.
Definition: fileutils.c:73

Generated at 2024-04-27 using  doxygen