user_config.c 8.1 KB

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