GRASS 8 Programmer's Manual 8.6.0dev(2026)-ddeab64dbf
Loading...
Searching...
No Matches
user_config.c
Go to the documentation of this file.
1/*!
2 * \file lib/gis/user_config.c
3 *
4 * \brief GIS Library - Routines related to user's GRASS configuration, tmp, and
5 * miscellaneous files.
6 *
7 * Functions related to the user's GRASS configuration, tmp, and
8 * miscellaneous files. Provides a set of routines for creating and
9 * accessing elements within the user's "rc" directory. The
10 * directory is in $HOME/.grass.<br>
11 *
12 * <b>NOTE:</b> As of 2001-03-25 this file is not hooked up. It is
13 * provided as a candidate for handling $HOME/.grass files and
14 * subdirectories. There may be more functionality desired (such as
15 * deletion routines, directory globs).<br>
16 *
17 * (C) 2001-2014 by the GRASS Development Team
18 *
19 * This program is free software under the GNU General Public License
20 * (>=v2). Read the file COPYING that comes with GRASS for details.
21 *
22 * \author Eric G Miller - egm2 at jps net
23 *
24 * \date 2007-04-14
25 */
26
27#include <grass/config.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <assert.h>
31#include <unistd.h>
32#include <string.h>
33#include <stdint.h>
34#include <stddef.h>
35#ifndef _WIN32
36#include <pwd.h>
37#endif
38#include <sys/types.h>
39#include <sys/stat.h>
40#include <errno.h>
41#include <grass/gis.h>
42
43/**************************************************************************
44 * _make_toplevel(): make user's toplevel config directory if it doesn't
45 * already exist. Adjust perms to 1700. Returns the toplevel directory
46 * path [caller must G_free ()] on success, or NULL on failure
47 *************************************************************************/
48
49#ifndef _WIN32 /* TODO */
50static char *_make_toplevel(void)
51{
52 size_t len;
53 int status;
54
55#ifdef __MINGW32__
56 char *defaulthomedir = "c:";
57 char *homedir = getenv("HOME");
58#else
59 uid_t me;
60 struct passwd *my_passwd;
61#endif
62 struct stat buf;
63 char *path;
64
65 errno = 0;
66
67 /* Query whatever database to get user's home dir */
68#ifdef __MINGW32__
69 if (NULL == homedir) {
71 }
72
73 len = strlen(homedir) + 8; /* + "/.grass\0" */
74 if (NULL == (path = G_calloc(1, len))) {
75 return NULL;
76 }
77 snprintf(path, len, "%s%s", homedir, "/.grass");
78#else
79 me = getuid();
81 if (my_passwd == NULL)
82 return NULL;
83
84 len = strlen(my_passwd->pw_dir) + 8; /* + "/.grass\0" */
85 if (NULL == (path = G_calloc(1, len)))
86 return NULL;
87
88 snprintf(path, len, "%s%s", my_passwd->pw_dir, "/.grass");
89#endif
90
91 status = G_lstat(path, &buf);
92
93 /* If errno == ENOENT, the directory doesn't exist */
94 if (status != 0) {
95 if (errno == ENOENT) {
96 status = G_mkdir(path);
97
98 if (status != 0) { /* mkdir failed */
99 G_free(path);
100 return NULL;
101 }
102
103 /* override umask settings, if possible */
105
106 /* otherwise mkdir succeeded, we're done here */
107 return path;
108 }
109
110 /* other errors should not be defined ??? give up */
111 G_free(path);
112 return NULL;
113 }
114 /* implicit else */
115
116 /* Examine the stat "buf" */
117 /* It better be a directory */
118 if (!S_ISDIR(buf.st_mode)) { /* File, link, something else */
119 errno = ENOTDIR; /* element is not a directory, but should be */
120 G_free(path);
121 return NULL;
122 }
123
124 /* No read/write/execute ??? */
125 if (!((S_IRUSR & buf.st_mode) && (S_IWUSR & buf.st_mode) &&
126 (S_IXUSR & buf.st_mode))) {
127 errno = EACCES; /* Permissions error */
128 G_free(path);
129 return NULL;
130 }
131
132 /* We'll assume that if the user grants greater permissions
133 * than we would, that they know what they're doing
134 * -- so we're done here...
135 */
136
137 return path;
138}
139
140/**************************************************************************
141 * _elem_count_split: Does a couple things:
142 * 1) Counts the number of elements in "elems"
143 * 2) Replaces occurrences of '/' with '\0'
144 * 3) Checks that no element begins with a '.'
145 * 4) Checks there are no '//'
146 *
147 * Therefore, THE STRING THAT IS PASSED IN IS MODIFIED
148 * Returns 0 if there are no elements, or an element
149 * beginning with a '.' or containing a '//' is found.
150 *************************************************************************/
151static int _elem_count_split(char *elems)
152{
153 int i;
154 size_t len;
155 char *begin, *end;
156
157 /* Some basic assertions */
158 assert(elems != NULL);
159
160 len = strlen(elems);
161 assert(len > 0);
162 assert(len < PTRDIFF_MAX);
163 assert(*elems != '/');
164
165 begin = elems;
166 for (i = 0; begin != NULL && (ptrdiff_t)len > begin - elems; i++) {
167 /* check '.' condition */
168 if (*begin == '.')
169 return 0;
170 end = strchr(begin, '/');
171 /* check '//' condition */
172 if (end != NULL && end == begin)
173 return 0;
174 /* okay, change '/' into '\0' */
175 begin = end;
176 if (begin != NULL) {
177 *begin = '\0'; /* begin points at '/', change it */
178 begin++; /* increment begin to next char */
179 }
180 }
181
182 /* That's it */
183 return i;
184}
185
186/**************************************************************************
187 * _make_sublevels(): creates subelements as necessary from the passed
188 * "elems" string. It returns the full path if successful or NULL
189 * if it fails. "elems" must not be NULL, zero length, or have any
190 * elements that begin with a '.' or any occurrences of '//'.
191 *************************************************************************/
192static char *_make_sublevels(const char *elems)
193{
194 int i, status;
195 char *cp, *path, *top, *ptr;
196 struct stat buf;
197
198 /* Get top level path */
199 if (NULL == (top = _make_toplevel()))
200 return NULL;
201
202 /* Make a copy of elems */
203 if (NULL == (cp = G_store(elems))) {
204 G_free(top);
205 return NULL;
206 }
207
208 /* Do element count, sanity checking and "splitting" */
209 if ((i = _elem_count_split(cp)) < 1) {
210 G_free(cp);
211 G_free(top);
212 return NULL;
213 }
214
215 /* Allocate our path to be large enough */
216 size_t bufsize = strlen(top) + strlen(elems) + 2;
217 if ((path = G_calloc(1, bufsize)) == NULL) {
218 G_free(top);
219 G_free(cp);
220 return NULL;
221 }
222
223 /* Now loop along adding directories if they don't exist
224 * make sure the thing is a directory as well.
225 * If there was a trailing '/' in the original "elem", it doesn't
226 * make it into the returned path.
227 */
228 for (; i > 0; i--) {
229 snprintf(path, bufsize, "%s/%s", top, cp);
230 errno = 0;
231 status = G_lstat(path, &buf);
232 if (status != 0) {
233 /* the element doesn't exist */
234 status = G_mkdir(path);
235 if (status != 0) {
236 /* Some kind of problem... */
237 G_free(top);
238 G_free(cp);
239 return NULL;
240 }
241 /* override umask settings, if possible */
243 }
244 else {
245 /* Examine the stat "buf" */
246 /* It better be a directory */
247 if (!S_ISDIR(buf.st_mode)) { /* File, link, something else */
248 errno = ENOTDIR; /* element is not a directory, but should be */
249 G_free(path);
250 return NULL;
251 }
252
253 /* No read/write/execute ??? */
254 if (!((S_IRUSR & buf.st_mode) && (S_IWUSR & buf.st_mode) &&
255 (S_IXUSR & buf.st_mode))) {
256 errno = EACCES; /* Permissions error */
257 G_free(path);
258 return NULL;
259 }
260
261 /* okay continue ... */
262 }
263
264 ptr = strchr(cp, '\0');
265 *ptr = '/';
266 }
267
268 /* All done, free memory */
269 G_free(top);
270 G_free(cp);
271
272 return path;
273}
274
275/**
276 * \brief Returns path to <b>element</b> and <b>item</b>.
277 *
278 * Either <b>element</b> or <b>item</b> can be NULL, but not both. If
279 * <b>element</b> is NULL, then the file is assumed to live at the top
280 * level. If file is NULL, then it is assumed the caller is not
281 * interested in the file. If the element or rc dir do not exist, they
282 * are created. However, the file is never checked for.
283 *
284 * \param[in] element
285 * \param[in] item
286 * \return Pointer to string path
287 */
288char *G_rc_path(const char *element, const char *item)
289{
290 size_t len;
291 char *path, *ptr;
292
293 assert(!(element == NULL && item == NULL));
294
295 /* Simple item in top-level */
296 if (element == NULL) {
297 path = _make_toplevel();
298 }
299 else if (item == NULL) {
300 return _make_sublevels(element);
301 }
302 else {
303 path = _make_sublevels(element);
304 }
305
306 assert(*item != '.');
307 assert(path != NULL);
308 ptr = strchr(item, '/'); /* should not have slashes */
309 assert(ptr == NULL);
310 len = strlen(path) + strlen(item) + 2;
311 if ((ptr = G_realloc(path, len)) == NULL) {
312 G_free(path);
313 return NULL;
314 }
315 path = ptr;
316 ptr = strchr(path, '\0');
317 snprintf(ptr, len, "/%s", item);
318
319 return path;
320} /* G_rc_path */
321
322/* vim: set softtabstop=4 shiftwidth=4 expandtab: */
323#endif
#define NULL
Definition ccmath.h:32
char path[BUFSIZ]
Definition ami_stream.h:127
void G_free(void *)
Free allocated memory.
Definition gis/alloc.c:147
#define G_realloc(p, n)
Definition defs/gis.h:141
#define G_calloc(m, n)
Definition defs/gis.h:140
int G_lstat(const char *, struct stat *)
Get file status.
Definition paths.c:145
char * G_store(const char *)
Copy string to allocated memory.
Definition strings.c:87
int G_mkdir(const char *)
Creates a new directory.
Definition paths.c:27
#define assert(condition)
Definition lz4.c:291
#define S_ISDIR(mode)
Definition stat.h:6
#define S_IRUSR
Definition stat.h:8
#define S_IWUSR
Definition stat.h:9
Definition path.h:15
char * G_rc_path(const char *element, const char *item)
Returns path to element and item.