GRASS Programmer's Manual 6.4.1(2011)
user_config.c
Go to the documentation of this file.
00001 
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <assert.h>
00031 #include <unistd.h>
00032 #include <string.h>
00033 #ifndef __MINGW32__
00034 #include <pwd.h>
00035 #endif
00036 #include <sys/types.h>
00037 #include <sys/stat.h>
00038 #include <errno.h>
00039 #include <grass/gis.h>
00040 
00041 
00042 /**************************************************************************
00043  * _make_toplevel(): make user's toplevel config directory if it doesn't
00044  * already exist.  Adjust perms to 1700. Returns the toplevel directory
00045  * path [caller must G_free ()] on success, or NULL on failure
00046  *************************************************************************/
00047 
00048 #ifndef __MINGW32__             /* TODO */
00049 static char *_make_toplevel(void)
00050 {
00051     size_t len;
00052     int status;
00053 
00054 #ifdef __MINGW32__
00055     char *defaulthomedir = "c:";
00056     char *homedir = getenv("HOME");
00057 #else
00058     uid_t me;
00059     struct passwd *my_passwd;
00060 #endif
00061     struct stat buf;
00062     char *path;
00063 
00064     errno = 0;
00065 
00066     /* Query whatever database to get user's home dir */
00067 #ifdef __MINGW32__
00068     if (NULL == homedir) {
00069         homedir = defaulthomedir;
00070     }
00071 
00072     len = strlen(homedir) + 8;  /* + "/.grass\0" */
00073     if (NULL == (path = G_calloc(1, len))) {
00074         return NULL;
00075     }
00076     sprintf(path, "%s%s", homedir, "/.grass");
00077 #else
00078     me = getuid();
00079     my_passwd = getpwuid(me);
00080     if (my_passwd == NULL)
00081         return NULL;
00082 
00083     len = strlen(my_passwd->pw_dir) + 8;        /* + "/.grass\0" */
00084     if (NULL == (path = G_calloc(1, len)))
00085         return NULL;
00086 
00087     sprintf(path, "%s%s", my_passwd->pw_dir, "/.grass");
00088 #endif
00089 
00090     status = G_lstat(path, &buf);
00091 
00092     /* If errno == ENOENT, the directory doesn't exist */
00093     if (status != 0) {
00094         if (errno == ENOENT) {
00095             status = G_mkdir(path);
00096 
00097             if (status != 0) {  /* mkdir failed */
00098                 G_free(path);
00099                 return NULL;
00100             }
00101 
00102             /* override umask settings, if possible */
00103             chmod(path, S_IRWXU);
00104 
00105             /* otherwise mkdir succeeded, we're done here */
00106             return path;
00107         }
00108 
00109         /* other errors should not be defined ??? give up */
00110         G_free(path);
00111         return NULL;
00112     }
00113     /* implicit else */
00114 
00115     /* Examine the stat "buf" */
00116     /* It better be a directory */
00117     if (!S_ISDIR(buf.st_mode)) {        /* File, link, something else */
00118         errno = ENOTDIR;        /* element is not a directory, but should be */
00119         G_free(path);
00120         return NULL;
00121     }
00122 
00123     /* No read/write/execute ??? */
00124     if (!((S_IRUSR & buf.st_mode) &&
00125           (S_IWUSR & buf.st_mode) && (S_IXUSR & buf.st_mode)
00126         )
00127         ) {
00128         errno = EACCES;         /* Permissions error */
00129         G_free(path);
00130         return NULL;
00131     }
00132 
00133     /* We'll assume that if the user grants greater permissions
00134      * than we would, that they know what they're doing
00135      * -- so we're done here...
00136      */
00137 
00138     return path;
00139 }
00140 
00141 
00142 /**************************************************************************
00143  * _elem_count_split: Does a couple things:
00144  * 1) Counts the number of elements in "elems"
00145  * 2) Replaces occurrences of '/' with '\0'
00146  * 3) Checks that no element begins with a '.'
00147  * 4) Checks there are no '//'
00148  *
00149  * Therefore, THE STRING THAT IS PASSED IN IS MODIFIED
00150  * Returns 0 if there are no elements, or an element
00151  * beginning with a '.' or containing a '//' is found.
00152  *************************************************************************/
00153 static int _elem_count_split(char *elems)
00154 {
00155     int i;
00156     size_t len;
00157     char *begin, *end;
00158 
00159     /* Some basic assertions */
00160     assert(elems != NULL);
00161     assert((len = strlen(elems)) > 0);
00162     assert(*elems != '/');
00163 
00164     begin = elems;
00165     for (i = 0; begin != NULL && len > begin - elems; i++) {
00166         /* check '.' condition */
00167         if (*begin == '.')
00168             return 0;
00169         end = strchr(begin, '/');
00170         /* check '//' condition */
00171         if (end != NULL && end == begin)
00172             return 0;
00173         /* okay, change '/' into '\0' */
00174         begin = end;
00175         if (begin != NULL) {
00176             *begin = '\0';      /* begin points at '/', change it */
00177             begin++;            /* increment begin to next char */
00178         }
00179     }
00180 
00181     /* That's it */
00182     return i;
00183 }
00184 
00185 
00186 /**************************************************************************
00187  * _make_sublevels(): creates subelements as necessary from the passed
00188  * "elems" string.  It returns the full path if successful or NULL
00189  * if it fails.  "elems" must not be NULL, zero length, or have any
00190  * elements that begin with a '.' or any occurrences of '//'.
00191  *************************************************************************/
00192 static char *_make_sublevels(const char *elems)
00193 {
00194     int i, status;
00195     char *cp, *path, *top, *ptr;
00196     struct stat buf;
00197 
00198     /* Get top level path */
00199     if (NULL == (top = _make_toplevel()))
00200         return NULL;
00201 
00202     /* Make a copy of elems */
00203     if (NULL == (cp = G_store(elems))) {
00204         G_free(top);
00205         return NULL;
00206     }
00207 
00208     /* Do element count, sanity checking and "splitting" */
00209     if ((i = _elem_count_split(cp)) < 1) {
00210         G_free(cp);
00211         G_free(top);
00212         return NULL;
00213     }
00214 
00215     /* Allocate our path to be large enough */
00216     if ((path = G_calloc(1, strlen(top) + strlen(elems) + 2)) == NULL) {
00217         G_free(top);
00218         G_free(cp);
00219         return NULL;
00220     }
00221 
00222     /* Now loop along adding directories if they don't exist
00223      * make sure the thing is a directory as well.
00224      * If there was a trailing '/' in the original "elem", it doesn't
00225      * make it into the returned path.
00226      */
00227     for (; i > 0; i--) {
00228         sprintf(path, "%s/%s", top, cp);
00229         errno = 0;
00230         status = G_lstat(path, &buf);
00231         if (status != 0) {
00232             /* the element doesn't exist */
00233             status = G_mkdir(path);
00234             if (status != 0) {
00235                 /* Some kind of problem... */
00236                 G_free(top);
00237                 G_free(cp);
00238                 return NULL;
00239             }
00240             /* override umask settings, if possible */
00241             chmod(path, S_IRWXU);
00242         }
00243         else {
00244             /* Examine the stat "buf" */
00245             /* It better be a directory */
00246             if (!S_ISDIR(buf.st_mode)) {        /* File, link, something else */
00247                 errno = ENOTDIR;        /* element is not a directory, but should be */
00248                 G_free(path);
00249                 return NULL;
00250             }
00251 
00252             /* No read/write/execute ??? */
00253             if (!((S_IRUSR & buf.st_mode) &&
00254                   (S_IWUSR & buf.st_mode) && (S_IXUSR & buf.st_mode)
00255                 )
00256                 ) {
00257                 errno = EACCES; /* Permissions error */
00258                 G_free(path);
00259                 return NULL;
00260             }
00261 
00262             /* okay continue ... */
00263         }
00264 
00265         ptr = strchr(cp, '\0');
00266         *ptr = '/';
00267     }
00268 
00269     /* All done, free memory */
00270     G_free(top);
00271     G_free(cp);
00272 
00273     return path;
00274 }
00275 
00276 
00291 char *G_rc_path(const char *element, const char *item)
00292 {
00293     size_t len;
00294     char *path, *ptr;
00295 
00296     assert(!(element == NULL && item == NULL));
00297 
00298     /* Simple item in top-level */
00299     if (element == NULL) {
00300         path = _make_toplevel();
00301     }
00302     else if (item == NULL) {
00303         return _make_sublevels(element);
00304     }
00305     else {
00306         path = _make_sublevels(element);
00307     }
00308 
00309 
00310     assert(*item != '.');
00311     assert(path != NULL);
00312     ptr = strchr(item, '/');    /* should not have slashes */
00313     assert(ptr == NULL);
00314     len = strlen(path) + strlen(item) + 2;
00315     if ((ptr = G_realloc(path, len)) == NULL) {
00316         G_free(path);
00317         return NULL;
00318     }
00319     path = ptr;
00320     ptr = strchr(path, '\0');
00321     sprintf(ptr, "/%s", item);
00322 
00323     return path;
00324 }                               /* G_rc_path */
00325 
00326 
00327 /* vim: set softtabstop=4 shiftwidth=4 expandtab: */
00328 #endif
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines