/* * $Id: user_config.c,v 2.5 2006/07/07 10:16:35 paul Exp $ * **************************************************************************** * * LIBRARY: user_config.c -- Routines related to the user's GRASS * configuration, tmp, and miscellaneous files. * * AUTHOR(S): Eric G. Miller * * PURPOSE: Provide a set of routines for creating and accessing * elements within the user's "rc" directory. The directory is * in $HOME/.grass * * COPYRIGHT: (C) 2000 by the GRASS Development Team * * This program is free software under the GNU General Public * License (>=v2). Read the file COPYING that comes with GRASS * for details. * *****************************************************************************/ /* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ * NOTE: As of 2001-03-25 this file is not hooked up. It is provided as a * candidate for handling $HOME/.grass files and subdirectories. There may * be more functionality desired (such as deletion routines, directory globs). * @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ #include #include #include #include #include #ifndef __MINGW32__ #include #endif #include #include #include #include #ifdef __MINGW32__ # define mkdir(name, mode) ((mkdir) (name)) #endif /************************************************************************** * _make_toplevel(): make user's toplevel config directory if it doesn't * already exist. Adjust perms to 1700. Returns the toplevel directory * path [caller must G_free ()] on success, or NULL on failure *************************************************************************/ #ifndef __MINGW32__ /* TODO */ static char * _make_toplevel (void) { size_t len; int status; #ifdef __MINGW32__ char *defaulthomedir = "c:"; char *homedir = getenv ( "HOME" ); #else uid_t me; struct passwd *my_passwd; #endif struct stat buf; char *path; errno = 0; /* Query whatever database to get user's home dir */ #ifdef __MINGW32__ if ( NULL == homedir ) { homedir = defaulthomedir; } len = strlen ( homedir ) + 8; /* + "/.grass\0" */ if ( NULL == ( path = G_calloc ( 1, len ) ) ) { return NULL; } sprintf ( path, "%s%s", homedir, "/.grass" ); #else me = getuid(); my_passwd = getpwuid (me); if (my_passwd == NULL) return NULL; len = strlen (my_passwd->pw_dir) + 8; /* + "/.grass\0" */ if (NULL == (path = G_calloc (1, len))) return NULL; sprintf (path, "%s%s", my_passwd->pw_dir, "/.grass"); #endif status = lstat (path, &buf); /* If errno == ENOENT, the directory doesn't exist */ if (status != 0) { if (errno == ENOENT) { status = mkdir (path, S_IRWXU); /* drwx------ */ if (status != 0) /* mkdir failed */ { G_free (path); return NULL; } /* override umask settings, if possible */ chmod (path, S_IRWXU); /* otherwise mkdir succeeded, we're done here */ return path; } /* other errors should not be defined ??? give up */ G_free (path); return NULL; } /* implicit else */ /* Examine the stat "buf" */ /* It better be a directory */ if (!S_ISDIR(buf.st_mode)) /* File, link, something else */ { errno = ENOTDIR; /* element is not a directory, but should be */ G_free (path); return NULL; } /* No read/write/execute ??? */ if (!( (S_IRUSR & buf.st_mode) && (S_IWUSR & buf.st_mode) && (S_IXUSR & buf.st_mode) ) ) { errno = EACCES; /* Permissions error */ G_free (path); return NULL; } /* We'll assume that if the user grants greater permissions * than we would, that they know what they're doing * -- so we're done here... */ return path; } /************************************************************************** * _elem_count_split: Does a couple things: * 1) Counts the number of elements in "elems" * 2) Replaces occurrences of '/' with '\0' * 3) Checks that no element begins with a '.' * 4) Checks there are no '//' * * Therefore, THE STRING THAT IS PASSED IN IS MODIFIED * Returns 0 if there are no elements, or an element * beginning with a '.' or containing a '//' is found. *************************************************************************/ static int _elem_count_split (char *elems) { int i; size_t len; char *begin, *end; /* Some basic assertions */ assert (elems != NULL); assert ((len = strlen(elems)) > 0); assert (*elems != '/'); begin = elems; for (i = 0; begin != NULL && len > begin - elems; i++) { /* check '.' condition */ if (*begin == '.') return 0; end = strchr (begin, '/'); /* check '//' condition */ if (end != NULL && end == begin) return 0; /* okay, change '/' into '\0' */ begin = end; if (begin != NULL) { *begin = '\0'; /* begin points at '/', change it */ begin++; /* increment begin to next char */ } } /* That's it */ return i; } /************************************************************************** * _make_sublevels(): creates subelements as necessary from the passed * "elems" string. It returns the full path if successful or NULL * if it fails. "elems" must not be NULL, zero length, or have any * elements that begin with a '.' or any occurrences of '//'. *************************************************************************/ static char * _make_sublevels(char *elems) { int i, status; char *cp, *path, *top, *ptr; struct stat buf; /* Get top level path */ if (NULL == (top = _make_toplevel())) return NULL; /* Make a copy of elems */ if (NULL == (cp = G_store (elems))) { G_free (top); return NULL; } /* Do element count, sanity checking and "splitting" */ if ((i = _elem_count_split (cp)) < 1) { G_free (cp); G_free (top); return NULL; } /* Allocate our path to be large enough */ if ((path = G_calloc (1, strlen(top) + strlen(elems) + 2)) == NULL) { G_free (top); G_free (cp); return NULL; } /* Now loop along adding directories if they don't exist * make sure the thing is a directory as well. * If there was a trailing '/' in the original "elem", it doesn't * make it into the returned path. */ for (; i > 0; i--) { sprintf (path, "%s/%s", top, cp); errno = 0; status = lstat (path, &buf); if (status != 0) { /* the element doesn't exist */ status = mkdir (path, S_IRWXU); /* drwx------ */ if (status != 0) { /* Some kind of problem... */ G_free (top); G_free (cp); return NULL; } /* override umask settings, if possible */ chmod (path, S_IRWXU); } else { /* Examine the stat "buf" */ /* It better be a directory */ if (!S_ISDIR(buf.st_mode)) /* File, link, something else */ { errno = ENOTDIR; /* element is not a directory, but should be */ G_free (path); return NULL; } /* No read/write/execute ??? */ if (!( (S_IRUSR & buf.st_mode) && (S_IWUSR & buf.st_mode) && (S_IXUSR & buf.st_mode) ) ) { errno = EACCES; /* Permissions error */ G_free (path); return NULL; } /* okay continue ... */ } ptr = strchr (cp, '\0'); *ptr = '/'; } /* All done, free memory */ G_free (top); G_free (cp); return path; } /*************************************************************************** * G_rc_path: Return the path to "element" and "item". Either can be NULL, * but not both. If "element" is NULL, then the file is assumed to live at * the top level. If file is NULL, then it is assumed the caller is not * interested in the file. If the element or rc dir do not exist, they are * created. However, the file is never checked for. **************************************************************************/ char * G_rc_path (char *element, char *item) { size_t len; char *path, *ptr; assert (!(element == NULL && item == NULL)); /* Simple item in top-level */ if (element == NULL) { path = _make_toplevel(); } else if (item == NULL) { return _make_sublevels (element); } else { path = _make_sublevels (element); } assert (*item != '.'); assert (path != NULL); ptr = strchr (item, '/'); /* should not have slashes */ assert (ptr == NULL); len = strlen(path) + strlen(item) + 2; if ((ptr = G_realloc (path, len)) == NULL) { G_free (path); return NULL; } path = ptr; ptr = strchr (path, '\0'); sprintf (ptr, "/%s", item); return path; } /* G_rc_path */ /* vim: set softtabstop=4 shiftwidth=4 expandtab: */ #endif