user_config.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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. #include <grass/config.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <assert.h>
  30. #include <unistd.h>
  31. #include <string.h>
  32. #ifndef __MINGW32__
  33. #include <pwd.h>
  34. #endif
  35. #include <sys/types.h>
  36. #include <sys/stat.h>
  37. #include <errno.h>
  38. #include <grass/gis.h>
  39. /**************************************************************************
  40. * _make_toplevel(): make user's toplevel config directory if it doesn't
  41. * already exist. Adjust perms to 1700. Returns the toplevel directory
  42. * path [caller must G_free ()] on success, or NULL on failure
  43. *************************************************************************/
  44. #ifndef __MINGW32__ /* TODO */
  45. static char *_make_toplevel(void)
  46. {
  47. size_t len;
  48. int status;
  49. #ifdef __MINGW32__
  50. char *defaulthomedir = "c:";
  51. char *homedir = getenv("HOME");
  52. #else
  53. uid_t me;
  54. struct passwd *my_passwd;
  55. #endif
  56. struct stat buf;
  57. char *path;
  58. errno = 0;
  59. /* Query whatever database to get user's home dir */
  60. #ifdef __MINGW32__
  61. if (NULL == homedir) {
  62. homedir = defaulthomedir;
  63. }
  64. len = strlen(homedir) + 8; /* + "/.grass\0" */
  65. if (NULL == (path = G_calloc(1, len))) {
  66. return NULL;
  67. }
  68. sprintf(path, "%s%s", homedir, "/.grass");
  69. #else
  70. me = getuid();
  71. my_passwd = getpwuid(me);
  72. if (my_passwd == NULL)
  73. return NULL;
  74. len = strlen(my_passwd->pw_dir) + 8; /* + "/.grass\0" */
  75. if (NULL == (path = G_calloc(1, len)))
  76. return NULL;
  77. sprintf(path, "%s%s", my_passwd->pw_dir, "/.grass");
  78. #endif
  79. status = G_lstat(path, &buf);
  80. /* If errno == ENOENT, the directory doesn't exist */
  81. if (status != 0) {
  82. if (errno == ENOENT) {
  83. status = G_mkdir(path);
  84. if (status != 0) { /* mkdir failed */
  85. G_free(path);
  86. return NULL;
  87. }
  88. /* override umask settings, if possible */
  89. chmod(path, S_IRWXU);
  90. /* otherwise mkdir succeeded, we're done here */
  91. return path;
  92. }
  93. /* other errors should not be defined ??? give up */
  94. G_free(path);
  95. return NULL;
  96. }
  97. /* implicit else */
  98. /* Examine the stat "buf" */
  99. /* It better be a directory */
  100. if (!S_ISDIR(buf.st_mode)) { /* File, link, something else */
  101. errno = ENOTDIR; /* element is not a directory, but should be */
  102. G_free(path);
  103. return NULL;
  104. }
  105. /* No read/write/execute ??? */
  106. if (!((S_IRUSR & buf.st_mode) &&
  107. (S_IWUSR & buf.st_mode) && (S_IXUSR & buf.st_mode)
  108. )
  109. ) {
  110. errno = EACCES; /* Permissions error */
  111. G_free(path);
  112. return NULL;
  113. }
  114. /* We'll assume that if the user grants greater permissions
  115. * than we would, that they know what they're doing
  116. * -- so we're done here...
  117. */
  118. return path;
  119. }
  120. /**************************************************************************
  121. * _elem_count_split: Does a couple things:
  122. * 1) Counts the number of elements in "elems"
  123. * 2) Replaces occurrences of '/' with '\0'
  124. * 3) Checks that no element begins with a '.'
  125. * 4) Checks there are no '//'
  126. *
  127. * Therefore, THE STRING THAT IS PASSED IN IS MODIFIED
  128. * Returns 0 if there are no elements, or an element
  129. * beginning with a '.' or containing a '//' is found.
  130. *************************************************************************/
  131. static int _elem_count_split(char *elems)
  132. {
  133. int i;
  134. size_t len;
  135. char *begin, *end;
  136. /* Some basic assertions */
  137. assert(elems != NULL);
  138. assert((len = strlen(elems)) > 0);
  139. assert(*elems != '/');
  140. begin = elems;
  141. for (i = 0; begin != NULL && len > begin - elems; i++) {
  142. /* check '.' condition */
  143. if (*begin == '.')
  144. return 0;
  145. end = strchr(begin, '/');
  146. /* check '//' condition */
  147. if (end != NULL && end == begin)
  148. return 0;
  149. /* okay, change '/' into '\0' */
  150. begin = end;
  151. if (begin != NULL) {
  152. *begin = '\0'; /* begin points at '/', change it */
  153. begin++; /* increment begin to next char */
  154. }
  155. }
  156. /* That's it */
  157. return i;
  158. }
  159. /**************************************************************************
  160. * _make_sublevels(): creates subelements as necessary from the passed
  161. * "elems" string. It returns the full path if successful or NULL
  162. * if it fails. "elems" must not be NULL, zero length, or have any
  163. * elements that begin with a '.' or any occurrences of '//'.
  164. *************************************************************************/
  165. static char *_make_sublevels(const char *elems)
  166. {
  167. int i, status;
  168. char *cp, *path, *top, *ptr;
  169. struct stat buf;
  170. /* Get top level path */
  171. if (NULL == (top = _make_toplevel()))
  172. return NULL;
  173. /* Make a copy of elems */
  174. if (NULL == (cp = G_store(elems))) {
  175. G_free(top);
  176. return NULL;
  177. }
  178. /* Do element count, sanity checking and "splitting" */
  179. if ((i = _elem_count_split(cp)) < 1) {
  180. G_free(cp);
  181. G_free(top);
  182. return NULL;
  183. }
  184. /* Allocate our path to be large enough */
  185. if ((path = G_calloc(1, strlen(top) + strlen(elems) + 2)) == NULL) {
  186. G_free(top);
  187. G_free(cp);
  188. return NULL;
  189. }
  190. /* Now loop along adding directories if they don't exist
  191. * make sure the thing is a directory as well.
  192. * If there was a trailing '/' in the original "elem", it doesn't
  193. * make it into the returned path.
  194. */
  195. for (; i > 0; i--) {
  196. sprintf(path, "%s/%s", top, cp);
  197. errno = 0;
  198. status = G_lstat(path, &buf);
  199. if (status != 0) {
  200. /* the element doesn't exist */
  201. status = G_mkdir(path);
  202. if (status != 0) {
  203. /* Some kind of problem... */
  204. G_free(top);
  205. G_free(cp);
  206. return NULL;
  207. }
  208. /* override umask settings, if possible */
  209. chmod(path, S_IRWXU);
  210. }
  211. else {
  212. /* Examine the stat "buf" */
  213. /* It better be a directory */
  214. if (!S_ISDIR(buf.st_mode)) { /* File, link, something else */
  215. errno = ENOTDIR; /* element is not a directory, but should be */
  216. G_free(path);
  217. return NULL;
  218. }
  219. /* No read/write/execute ??? */
  220. if (!((S_IRUSR & buf.st_mode) &&
  221. (S_IWUSR & buf.st_mode) && (S_IXUSR & buf.st_mode)
  222. )
  223. ) {
  224. errno = EACCES; /* Permissions error */
  225. G_free(path);
  226. return NULL;
  227. }
  228. /* okay continue ... */
  229. }
  230. ptr = strchr(cp, '\0');
  231. *ptr = '/';
  232. }
  233. /* All done, free memory */
  234. G_free(top);
  235. G_free(cp);
  236. return path;
  237. }
  238. /**
  239. * \brief Returns path to <b>element</b> and <b>item</b>.
  240. *
  241. * Either <b>element</b> or <b>item</b> can be NULL, but not both. If
  242. * <b>element</b> is NULL, then the file is assumed to live at the top
  243. * level. If file is NULL, then it is assumed the caller is not
  244. * interested in the file. If the element or rc dir do not exist, they
  245. * are created. However, the file is never checked for.
  246. *
  247. * \param[in] element
  248. * \param[in] item
  249. * \return Pointer to string path
  250. */
  251. char *G_rc_path(const char *element, const char *item)
  252. {
  253. size_t len;
  254. char *path, *ptr;
  255. assert(!(element == NULL && item == NULL));
  256. /* Simple item in top-level */
  257. if (element == NULL) {
  258. path = _make_toplevel();
  259. }
  260. else if (item == NULL) {
  261. return _make_sublevels(element);
  262. }
  263. else {
  264. path = _make_sublevels(element);
  265. }
  266. assert(*item != '.');
  267. assert(path != NULL);
  268. ptr = strchr(item, '/'); /* should not have slashes */
  269. assert(ptr == NULL);
  270. len = strlen(path) + strlen(item) + 2;
  271. if ((ptr = G_realloc(path, len)) == NULL) {
  272. G_free(path);
  273. return NULL;
  274. }
  275. path = ptr;
  276. ptr = strchr(path, '\0');
  277. sprintf(ptr, "/%s", item);
  278. return path;
  279. } /* G_rc_path */
  280. /* vim: set softtabstop=4 shiftwidth=4 expandtab: */
  281. #endif