user_config.c

Go to the documentation of this file.
00001 /*
00002 * $Id: user_config.c,v 2.0 2004/11/09 12:23:01 bernhard Exp $
00003 *
00004 ****************************************************************************
00005 *
00006 * LIBRARY:      user_config.c  -- Routines related to the user's GRASS 
00007 *               configuration, tmp, and miscellaneous files.
00008 *
00009 * AUTHOR(S):    Eric G. Miller <egm2@jps.net>
00010 *
00011 * PURPOSE:      Provide a set of routines for creating and accessing
00012 *               elements within the user's "rc" directory.  The directory is
00013 *               in $HOME/.grass
00014 *
00015 * COPYRIGHT:    (C) 2000 by the GRASS Development Team
00016 *
00017 *               This program is free software under the GNU General Public
00018 *               License (>=v2). Read the file COPYING that comes with GRASS
00019 *               for details.
00020 *
00021 *****************************************************************************/
00022 
00023 /* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
00024  * NOTE: As of 2001-03-25 this file is not hooked up.  It is provided as a
00025  * candidate for handling $HOME/.grass files and subdirectories.  There may
00026  * be more functionality desired (such as deletion routines, directory globs).
00027  * @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
00028 
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <assert.h>
00032 #include <unistd.h>
00033 #include <string.h>
00034 #include <pwd.h>
00035 #include <sys/types.h>
00036 #include <sys/stat.h>
00037 #include <errno.h>
00038 #include "gis.h"
00039 
00040 
00041 /**************************************************************************
00042  * _make_toplevel(): make user's toplevel config directory if it doesn't
00043  * already exist.  Adjust perms to 1700. Returns the toplevel directory
00044  * path [caller must free()] on success, or NULL on failure
00045  *************************************************************************/
00046 static char *
00047 _make_toplevel (void)
00048 {
00049     size_t len;
00050     int status;
00051 #ifdef __MINGW32__
00052     char *defaulthomedir = "c:";
00053     char *homedir = getenv ( "HOME" );
00054 #else    
00055     uid_t me;
00056     struct passwd *my_passwd;
00057 #endif    
00058     struct stat buf;
00059     char *path;
00060 
00061     errno = 0;
00062 
00063     /* Query whatever database to get user's home dir */
00064 #ifdef __MINGW32__
00065     if ( NULL == homedir ) {
00066         homedir = defaulthomedir;
00067     }
00068     
00069     len = strlen ( homedir ) + 8; /* + "/.grass\0" */
00070     if ( NULL == ( path = G_calloc ( 1, len ) ) ) {
00071         return NULL;
00072     }
00073     snprintf ( path, len, "%s%s", homedir, "/.grass" );
00074 #else
00075     me = getuid();
00076     my_passwd = getpwuid (me);
00077     if (my_passwd == NULL)
00078         return NULL;
00079 
00080     len = strlen (my_passwd->pw_dir) + 8; /* + "/.grass\0" */
00081     if (NULL == (path = G_calloc (1, len)))
00082         return NULL;
00083 
00084     snprintf (path, len, "%s%s", my_passwd->pw_dir, "/.grass");
00085 #endif
00086 
00087     status = lstat (path, &buf);
00088 
00089     /* If errno == ENOENT, the directory doesn't exist */
00090     if (status != 0)
00091     {
00092         if (errno == ENOENT)
00093         {
00094             status = mkdir (path, S_IRWXU); /* drwx------ */ 
00095     
00096             if (status != 0)  /* mkdir failed */
00097             {
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     {
00119         errno = ENOTDIR; /* element is not a directory, but should be */
00120         G_free (path);
00121         return NULL;
00122     }
00123 
00124     /* No read/write/execute ??? */
00125     if (!(
00126           (S_IRUSR & buf.st_mode) &&
00127           (S_IWUSR & buf.st_mode) &&
00128           (S_IXUSR & buf.st_mode)
00129          )
00130        )
00131     {
00132         errno = EACCES;  /* Permissions error */
00133         G_free (path);
00134         return NULL;
00135     }
00136 
00137     /* We'll assume that if the user grants greater permissions
00138      * than we would, that they know what they're doing
00139      * -- so we're done here...
00140      */
00141 
00142     return path;
00143 }
00144 
00145 
00146 /**************************************************************************
00147  * _elem_count_split: Does a couple things:
00148  * 1) Counts the number of elements in "elems"
00149  * 2) Replaces occurrences of '/' with '\0'
00150  * 3) Checks that no element begins with a '.'
00151  * 4) Checks there are no '//'
00152  *
00153  * Therefore, THE STRING THAT IS PASSED IN IS MODIFIED
00154  * Returns 0 if there are no elements, or an element
00155  * beginning with a '.' or containing a '//' is found.
00156  *************************************************************************/
00157 static int
00158 _elem_count_split (char *elems)
00159 {
00160     int i;
00161     size_t len;
00162     char *begin, *end;
00163     
00164     /* Some basic assertions */
00165     assert (elems != NULL);
00166     assert ((len = strlen(elems)) > 0);
00167     assert (*elems != '/');
00168     
00169     begin = elems;
00170     for (i = 0; begin != NULL && len > begin - elems; i++)
00171     {
00172         /* check '.' condition */
00173         if (*begin == '.')
00174             return 0;
00175         end = strchr (begin, '/');
00176         /* check '//' condition */
00177         if (end != NULL && end == begin)
00178             return 0;
00179         /* okay, change '/' into '\0' */
00180         begin = end;
00181         if (begin != NULL)
00182         {
00183             *begin = '\0';  /* begin points at '/', change it */
00184             begin++;        /* increment begin to next char */
00185         }
00186     }
00187 
00188     /* That's it */
00189     return i;
00190 }
00191     
00192 
00193 /**************************************************************************
00194  * _make_sublevels(): creates subelements as necessary from the passed
00195  * "elems" string.  It returns the full path if successful or NULL
00196  * if it fails.  "elems" must not be NULL, zero length, or have any
00197  * elements that begin with a '.' or any occurrences of '//'.
00198  *************************************************************************/
00199 static char *
00200 _make_sublevels(char *elems)
00201 {
00202     int i, status;
00203     char *cp, *path, *top, *ptr;
00204     struct stat buf;
00205 
00206     /* Get top level path */
00207     if (NULL == (top = _make_toplevel()))
00208         return NULL;
00209 
00210     /* Make a copy of elems */
00211     if (NULL == (cp = G_store (elems)))
00212     {
00213         G_free (top);
00214         return NULL;
00215     }
00216     
00217     /* Do element count, sanity checking and "splitting" */
00218     if ((i = _elem_count_split (cp)) < 1)
00219     {
00220         G_free (cp);
00221         G_free (top);
00222         return NULL;
00223     }
00224 
00225     /* Allocate our path to be large enough */
00226     if ((path = G_calloc (1, strlen(top) + strlen(elems) + 2)) == NULL)
00227     {
00228         G_free (top);
00229         G_free (cp);
00230         return NULL;
00231     }
00232     
00233     /* Now loop along adding directories if they don't exist
00234      * make sure the thing is a directory as well.
00235      * If there was a trailing '/' in the original "elem", it doesn't
00236      * make it into the returned path.
00237      */
00238     for (; i > 0; i--)
00239     {
00240         sprintf (path, "%s/%s", top, cp);
00241         errno = 0;
00242         status = lstat (path, &buf);
00243         if (status != 0)
00244         {
00245             /* the element doesn't exist */
00246             status = mkdir (path, S_IRWXU); /* drwx------ */
00247             if (status != 0)
00248             {
00249                 /* Some kind of problem... */
00250                 G_free (top);
00251                 G_free (cp);
00252                 return NULL;
00253             }
00254             /* override umask settings, if possible */
00255             chmod (path, S_IRWXU);
00256         }
00257         else
00258         {
00259             /* Examine the stat "buf" */
00260             /* It better be a directory */
00261             if (!S_ISDIR(buf.st_mode)) /* File, link, something else */
00262             {
00263                 errno = ENOTDIR; /* element is not a directory, but should be */
00264                 G_free (path);
00265                 return NULL;
00266             }
00267 
00268             /* No read/write/execute ??? */
00269             if (!(
00270                   (S_IRUSR & buf.st_mode) &&
00271                   (S_IWUSR & buf.st_mode) &&
00272                   (S_IXUSR & buf.st_mode)
00273                  )
00274                )
00275             {
00276                 errno = EACCES;  /* Permissions error */
00277                 G_free (path);
00278                 return NULL;
00279             }
00280 
00281             /* okay continue ... */
00282         }
00283 
00284         ptr = strchr (cp, '\0');
00285         *ptr = '/';
00286     }
00287 
00288     /* All done, free memory */
00289     G_free (top);
00290     G_free (cp);
00291 
00292     return path;
00293 }
00294 
00295     
00296 /***************************************************************************
00297  * G_rc_path:  Return the path to "element" and "item". Either can be NULL,
00298  * but not both.  If "element" is NULL, then the file is assumed to live at
00299  * the top level.  If file is NULL, then it is assumed the caller is not
00300  * interested in the file.  If the element or rc dir do not exist, they are
00301  * created.  However, the file is never checked for.
00302  **************************************************************************/
00303 char *
00304 G_rc_path (char *element, char *item)
00305 {
00306     size_t len;
00307     char *path, *ptr;
00308 
00309     assert (!(element == NULL && item == NULL));
00310 
00311     /* Simple item in top-level */
00312     if (element == NULL)
00313     {
00314         path = _make_toplevel();
00315     }
00316     else if (item == NULL)
00317     {
00318         return _make_sublevels (element);
00319     }
00320     else
00321     {
00322         path = _make_sublevels (element);
00323     }
00324    
00325 
00326     assert (*item != '.');
00327     assert (path != NULL);
00328     ptr = strchr (item, '/'); /* should not have slashes */
00329     assert (ptr == NULL);
00330     len = strlen(path) + strlen(item) + 2;
00331     if ((ptr = G_realloc (path, len)) == NULL)
00332     {
00333         G_free (path);
00334         return NULL;
00335     }
00336     path = ptr;
00337     ptr = strchr (path, '\0');
00338     sprintf (ptr, "/%s", item);
00339 
00340     return path;
00341 } /* G_rc_path */
00342        
00343 
00344 
00345 /* vim: set softtabstop=4 shiftwidth=4 expandtab: */

Generated on Sat Jul 22 22:06:15 2006 for GRASS by  doxygen 1.4.7