GRASS 8 Programmer's Manual
8.5.0(2026)-8d6ceba290
Toggle main menu visibility
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 */
50
static
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) {
70
homedir = defaulthomedir;
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();
80
my_passwd = getpwuid(me);
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 */
104
chmod(
path
, S_IRWXU);
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
*************************************************************************/
151
static
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
*************************************************************************/
192
static
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 */
242
chmod(
path
, S_IRWXU);
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
*/
288
char
*
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
G_free
void G_free(void *buf)
Free allocated memory.
Definition
alloc.c:147
NULL
#define NULL
Definition
ccmath.h:32
assert
#define assert(condition)
Definition
lz4.c:291
G_mkdir
int G_mkdir(const char *path)
Creates a new directory.
Definition
paths.c:27
G_lstat
int G_lstat(const char *file_name, struct stat *buf)
Get file status.
Definition
paths.c:145
G_store
char * G_store(const char *s)
Copy string to allocated memory.
Definition
strings.c:87
element
Definition
lidar.h:85
path
Definition
path.h:15
G_rc_path
char * G_rc_path(const char *element, const char *item)
Returns path to element and item.
Definition
user_config.c:288
gis
user_config.c
Generated on
for GRASS 8 Programmer's Manual by
1.17.0