1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 
  27 #include <stdlib.h>
  28 #include <string.h>
  29 
  30 #include <vroot/vroot.h>
  31 #include <vroot/args.h>
  32 
  33 #include <string.h>
  34 #include <sys/param.h>
  35 #include <sys/file.h>
  36 
  37 typedef struct {
  38         short           init;
  39         pathpt          vector;
  40         const char      *env_var;
  41 } vroot_patht;
  42 
  43 typedef struct {
  44         vroot_patht     vroot;
  45         vroot_patht     path;
  46         char            full_path[MAXPATHLEN+1];
  47         char            *vroot_start;
  48         char            *path_start;
  49         char            *filename_start;
  50         int             scan_vroot_first;
  51         int             cpp_style_path;
  52 } vroot_datat, *vroot_datapt;
  53 
  54 static vroot_datat      vroot_data= {
  55         { 0, NULL, "VIRTUAL_ROOT"},
  56         { 0, NULL, "PATH"},
  57         "", NULL, NULL, NULL, 0, 1};
  58 
  59 void
  60 add_dir_to_path(const char *path, register pathpt *pointer, register int position)
  61 {
  62         register int            size= 0;
  63         register int            length;
  64         register char           *name;
  65         register pathcellpt     p;
  66         pathpt                  new_path;
  67 
  68         if (*pointer != NULL) {
  69                 for (p= &((*pointer)[0]); p->path != NULL; p++, size++);
  70                 if (position < 0)
  71                         position= size;}
  72         else
  73                 if (position < 0)
  74                         position= 0;
  75         if (position >= size) {
  76                 new_path= (pathpt)calloc((unsigned)(position+2), sizeof(pathcellt));
  77                 if (*pointer != NULL) {
  78                         memcpy((char *)new_path,(char *)(*pointer),  size*sizeof(pathcellt));
  79                         free((char *)(*pointer));};
  80                 *pointer= new_path;};
  81         length= strlen(path);
  82         name= (char *)malloc((unsigned)(length+1));
  83         (void)strcpy(name, path);
  84         if ((*pointer)[position].path != NULL)
  85                 free((*pointer)[position].path);
  86         (*pointer)[position].path= name;
  87         (*pointer)[position].length= length;
  88 }
  89 
  90 pathpt
  91 parse_path_string(register char *string, register int remove_slash)
  92 {
  93         register char           *p;
  94         pathpt                  result= NULL;
  95 
  96         if (string != NULL)
  97                 for (; 1; string= p+1) {
  98                         if (p= strchr(string, ':')) *p= 0;
  99                         if ((remove_slash == 1) && !strcmp(string, "/"))
 100                                 add_dir_to_path("", &result, -1);
 101                         else
 102                                 add_dir_to_path(string, &result, -1);
 103                         if (p) *p= ':';
 104                         else return(result);};
 105         return((pathpt)NULL);
 106 }
 107 
 108 const char *
 109 get_vroot_name(void)
 110 {
 111         return(vroot_data.vroot.env_var);
 112 }
 113 
 114 const char *
 115 get_path_name(void)
 116 {
 117         return(vroot_data.path.env_var);
 118 }
 119 
 120 void
 121 flush_path_cache(void)
 122 {
 123         vroot_data.path.init= 0;
 124 }
 125 
 126 void
 127 flush_vroot_cache(void)
 128 {
 129         vroot_data.vroot.init= 0;
 130 }
 131 
 132 void
 133 scan_path_first(void)
 134 {
 135         vroot_data.scan_vroot_first= 0;
 136 }
 137 
 138 void
 139 scan_vroot_first(void)
 140 {
 141         vroot_data.scan_vroot_first= 1;
 142 }
 143 
 144 void
 145 set_path_style(int style)
 146 {
 147         vroot_data.cpp_style_path= style;
 148 }
 149 
 150 char *
 151 get_vroot_path(register char **vroot, register char **path, register char **filename)
 152 {
 153         if (vroot != NULL) {
 154                 if ((*vroot= vroot_data.vroot_start) == NULL)
 155                 if ((*vroot= vroot_data.path_start) == NULL)
 156                 *vroot= vroot_data.filename_start;};
 157         if (path != NULL) {
 158                 if ((*path= vroot_data.path_start) == NULL)
 159                 *path= vroot_data.filename_start;};
 160         if (filename != NULL)
 161                 *filename= vroot_data.filename_start;
 162         return(vroot_data.full_path);
 163 }
 164 
 165 void
 166 translate_with_thunk(register char *filename, int (*thunk) (char *), pathpt path_vector, pathpt vroot_vector, rwt rw)
 167 {
 168         register pathcellt      *vp;
 169         pathcellt               *pp;
 170         register pathcellt      *pp1;
 171         register char           *p;
 172         int                     flags[256];
 173 
 174 /* Setup path to use */
 175         if (rw == rw_write)
 176                 pp1= NULL;              /* Do not use path when writing */
 177         else {
 178                 if (path_vector == VROOT_DEFAULT) {
 179                         if (!vroot_data.path.init) {
 180                                 vroot_data.path.init= 1;
 181                                 vroot_data.path.vector= parse_path_string(getenv(vroot_data.path.env_var), 0);};
 182                         path_vector= vroot_data.path.vector;};
 183                 pp1= path_vector == NULL ? NULL : &(path_vector)[0];};
 184 
 185 /* Setup vroot to use */
 186         if (vroot_vector == VROOT_DEFAULT) {
 187                 if (!vroot_data.vroot.init) {
 188                         vroot_data.vroot.init= 1;
 189                         vroot_data.vroot.vector= parse_path_string(getenv(vroot_data.vroot.env_var), 1);};
 190                 vroot_vector= vroot_data.vroot.vector;};
 191         vp= vroot_vector == NULL ? NULL : &(vroot_vector)[0];
 192 
 193 /* Setup to remember pieces */
 194         vroot_data.vroot_start= NULL;
 195         vroot_data.path_start= NULL;
 196         vroot_data.filename_start= NULL;
 197 
 198         int flen = strlen(filename);
 199         if(flen >= MAXPATHLEN) {
 200                 errno = ENAMETOOLONG;
 201                 return;
 202         }
 203 
 204         switch ((vp ?1:0) + (pp1 ? 2:0)) {
 205             case 0:     /* No path. No vroot. */
 206             use_name:
 207                 (void)strcpy(vroot_data.full_path, filename);
 208                 vroot_data.filename_start= vroot_data.full_path;
 209                 (void)(*thunk)(vroot_data.full_path);
 210                 return;
 211             case 1:     /* No path. Vroot */
 212                 if (filename[0] != '/') goto use_name;
 213                 for (; vp->path != NULL; vp++) {
 214                         if((1 + flen + vp->length) >= MAXPATHLEN) {
 215                                 errno = ENAMETOOLONG;
 216                                 continue;
 217                         }
 218                         p= vroot_data.full_path;
 219                         (void)strcpy(vroot_data.vroot_start= p, vp->path);
 220                         p+= vp->length;
 221                         (void)strcpy(vroot_data.filename_start= p, filename);
 222                         if ((*thunk)(vroot_data.full_path)) return;};
 223                 (void)strcpy(vroot_data.full_path, filename);
 224                 return;
 225             case 2:     /* Path. No vroot. */
 226                 if (vroot_data.cpp_style_path) {
 227                         if (filename[0] == '/') goto use_name;
 228                 } else {
 229                         if (strchr(filename, '/') != NULL) goto use_name;
 230                 };
 231                 for (; pp1->path != NULL; pp1++) {
 232                         p= vroot_data.full_path;
 233                         if((1 + flen + pp1->length) >= MAXPATHLEN) {
 234                                 errno = ENAMETOOLONG;
 235                                 continue;
 236                         }
 237                         if (vroot_data.cpp_style_path) {
 238                                 (void)strcpy(vroot_data.path_start= p, pp1->path);
 239                                 p+= pp1->length;
 240                                 *p++= '/';
 241                         } else {
 242                                 if (pp1->length != 0) {
 243                                         (void)strcpy(vroot_data.path_start= p,
 244                                             pp1->path);
 245                                         p+= pp1->length;
 246                                         *p++= '/';
 247                                 };
 248                         };
 249                         (void)strcpy(vroot_data.filename_start= p, filename);
 250                         if ((*thunk)(vroot_data.full_path)) return;};
 251                 (void)strcpy(vroot_data.full_path, filename);
 252                 return;
 253             case 3: {   /* Path. Vroot. */
 254                         int *rel_path, path_len= 1;
 255                 if (vroot_data.scan_vroot_first == 0) {
 256                         for (pp= pp1; pp->path != NULL; pp++) path_len++;
 257                         rel_path= flags;
 258                         for (path_len-= 2; path_len >= 0; path_len--) rel_path[path_len]= 0;
 259                         for (; vp->path != NULL; vp++)
 260                                 for (pp= pp1, path_len= 0; pp->path != NULL; pp++, path_len++) {
 261                                         int len = 0;
 262                                         if (rel_path[path_len] == 1) continue;
 263                                         if (pp->path[0] != '/') rel_path[path_len]= 1;
 264                                         p= vroot_data.full_path;
 265                                         if ((filename[0] == '/') || (pp->path[0] == '/')) {
 266                                                 if(vp->length >= MAXPATHLEN) {
 267                                                         errno = ENAMETOOLONG;
 268                                                         continue;
 269                                                 }
 270                                                 (void)strcpy(vroot_data.vroot_start= p, vp->path); p+= vp->length;
 271                                                 len += vp->length;
 272                                         };
 273                                         if (vroot_data.cpp_style_path) {
 274                                                 if (filename[0] != '/') {
 275                                                         if(1 + len + pp->length >= MAXPATHLEN) {
 276                                                                 errno = ENAMETOOLONG;
 277                                                                 continue;
 278                                                         }
 279                                                         (void)strcpy(vroot_data.path_start= p, pp->path); p+= pp->length;
 280                                                         *p++= '/';
 281                                                         len += 1 + pp->length;
 282                                                 };
 283                                         } else {
 284                                                 if (strchr(filename, '/') == NULL) {
 285                                                         if (pp->length != 0) {
 286                                                                 if(1 + len + pp->length >= MAXPATHLEN) {
 287                                                                         errno = ENAMETOOLONG;
 288                                                                         continue;
 289                                                                 }
 290                                                                 (void)strcpy(vroot_data.path_start= p,
 291                                                                     pp->path);
 292                                                                 p+= pp->length;
 293                                                                 *p++= '/';
 294                                                                 len += 1 + pp->length;
 295                                                         }
 296                                                 }
 297                                         };
 298                                         (void)strcpy(vroot_data.filename_start= p, filename);
 299                                         if ((*thunk)(vroot_data.full_path)) return;};}
 300                 else { pathcellt *vp1= vp;
 301                         for (pp= pp1, path_len= 0; pp->path != NULL; pp++, path_len++)
 302                                 for (vp= vp1; vp->path != NULL; vp++) {
 303                                         int len = 0;
 304                                         p= vroot_data.full_path;
 305                                         if ((filename[0] == '/') || (pp->path[0] == '/')) {
 306                                                 if(vp->length >= MAXPATHLEN) {
 307                                                         errno = ENAMETOOLONG;
 308                                                         continue;
 309                                                 }
 310                                                 (void)strcpy(vroot_data.vroot_start= p, vp->path); p+= vp->length;
 311                                                 len += vp->length;
 312                                         }
 313                                         if (vroot_data.cpp_style_path) {
 314                                                 if (filename[0] != '/') {
 315                                                         if(1 + len + pp->length >= MAXPATHLEN) {
 316                                                                 errno = ENAMETOOLONG;
 317                                                                 continue;
 318                                                         }
 319                                                         (void)strcpy(vroot_data.path_start= p, pp->path); p+= pp->length;
 320                                                         *p++= '/';
 321                                                         len += 1 + pp->length;
 322                                                 }
 323                                         } else {
 324                                                 if (strchr(filename, '/') == NULL) {
 325                                                         if(1 + len + pp->length >= MAXPATHLEN) {
 326                                                                 errno = ENAMETOOLONG;
 327                                                                 continue;
 328                                                         }
 329                                                         (void)strcpy(vroot_data.path_start= p, pp->path); p+= pp->length;
 330                                                         *p++= '/';
 331                                                         len += 1 + pp->length;
 332                                                 }
 333                                         }
 334                                         (void)strcpy(vroot_data.filename_start= p, filename);
 335                                         if ((*thunk)(vroot_data.full_path)) return;};};
 336                 (void)strcpy(vroot_data.full_path, filename);
 337                 return;};};
 338 }