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 #include <avo/intl.h>     /* for NOCATGETS */
  38 
  39 typedef struct {
  40         short           init;
  41         pathpt          vector;
  42         const char      *env_var;
  43 } vroot_patht;
  44 
  45 typedef struct {
  46         vroot_patht     vroot;
  47         vroot_patht     path;
  48         char            full_path[MAXPATHLEN+1];
  49         char            *vroot_start;
  50         char            *path_start;
  51         char            *filename_start;
  52         int             scan_vroot_first;
  53         int             cpp_style_path;
  54 } vroot_datat, *vroot_datapt;
  55 
  56 static vroot_datat      vroot_data= {
  57         { 0, NULL, NOCATGETS("VIRTUAL_ROOT")},
  58         { 0, NULL, NOCATGETS("PATH")},
  59         "", NULL, NULL, NULL, 0, 1};
  60 
  61 void
  62 add_dir_to_path(const char *path, register pathpt *pointer, register int position)
  63 {
  64         register int            size= 0;
  65         register int            length;
  66         register char           *name;
  67         register pathcellpt     p;
  68         pathpt                  new_path;
  69 
  70         if (*pointer != NULL) {
  71                 for (p= &((*pointer)[0]); p->path != NULL; p++, size++);
  72                 if (position < 0)
  73                         position= size;}
  74         else
  75                 if (position < 0)
  76                         position= 0;
  77         if (position >= size) {
  78                 new_path= (pathpt)calloc((unsigned)(position+2), sizeof(pathcellt));
  79                 if (*pointer != NULL) {
  80                         memcpy((char *)new_path,(char *)(*pointer),  size*sizeof(pathcellt));
  81                         free((char *)(*pointer));};
  82                 *pointer= new_path;};
  83         length= strlen(path);
  84         name= (char *)malloc((unsigned)(length+1));
  85         (void)strcpy(name, path);
  86         if ((*pointer)[position].path != NULL)
  87                 free((*pointer)[position].path);
  88         (*pointer)[position].path= name;
  89         (*pointer)[position].length= length;
  90 }
  91 
  92 pathpt
  93 parse_path_string(register char *string, register int remove_slash)
  94 {
  95         register char           *p;
  96         pathpt                  result= NULL;
  97 
  98         if (string != NULL)
  99                 for (; 1; string= p+1) {
 100                         if (p= strchr(string, ':')) *p= 0;
 101                         if ((remove_slash == 1) && !strcmp(string, "/"))
 102                                 add_dir_to_path("", &result, -1);
 103                         else
 104                                 add_dir_to_path(string, &result, -1);
 105                         if (p) *p= ':';
 106                         else return(result);};
 107         return((pathpt)NULL);
 108 }
 109 
 110 const char *
 111 get_vroot_name(void)
 112 {
 113         return(vroot_data.vroot.env_var);
 114 }
 115 
 116 const char *
 117 get_path_name(void)
 118 {
 119         return(vroot_data.path.env_var);
 120 }
 121 
 122 void
 123 flush_path_cache(void)
 124 {
 125         vroot_data.path.init= 0;
 126 }
 127 
 128 void
 129 flush_vroot_cache(void)
 130 {
 131         vroot_data.vroot.init= 0;
 132 }
 133 
 134 void
 135 scan_path_first(void)
 136 {
 137         vroot_data.scan_vroot_first= 0;
 138 }
 139 
 140 void
 141 scan_vroot_first(void)
 142 {
 143         vroot_data.scan_vroot_first= 1;
 144 }
 145 
 146 void
 147 set_path_style(int style)
 148 {
 149         vroot_data.cpp_style_path= style;
 150 }
 151 
 152 char *
 153 get_vroot_path(register char **vroot, register char **path, register char **filename)
 154 {
 155         if (vroot != NULL) {
 156                 if ((*vroot= vroot_data.vroot_start) == NULL)
 157                 if ((*vroot= vroot_data.path_start) == NULL)
 158                 *vroot= vroot_data.filename_start;};
 159         if (path != NULL) {
 160                 if ((*path= vroot_data.path_start) == NULL)
 161                 *path= vroot_data.filename_start;};
 162         if (filename != NULL)
 163                 *filename= vroot_data.filename_start;
 164         return(vroot_data.full_path);
 165 }
 166 
 167 void
 168 translate_with_thunk(register char *filename, int (*thunk) (char *), pathpt path_vector, pathpt vroot_vector, rwt rw)
 169 {
 170         register pathcellt      *vp;
 171         pathcellt               *pp;
 172         register pathcellt      *pp1;
 173         register char           *p;
 174         int                     flags[256];
 175 
 176 /* Setup path to use */
 177         if (rw == rw_write)
 178                 pp1= NULL;              /* Do not use path when writing */
 179         else {
 180                 if (path_vector == VROOT_DEFAULT) {
 181                         if (!vroot_data.path.init) {
 182                                 vroot_data.path.init= 1;
 183                                 vroot_data.path.vector= parse_path_string(getenv(vroot_data.path.env_var), 0);};
 184                         path_vector= vroot_data.path.vector;};
 185                 pp1= path_vector == NULL ? NULL : &(path_vector)[0];};
 186 
 187 /* Setup vroot to use */
 188         if (vroot_vector == VROOT_DEFAULT) {
 189                 if (!vroot_data.vroot.init) {
 190                         vroot_data.vroot.init= 1;
 191                         vroot_data.vroot.vector= parse_path_string(getenv(vroot_data.vroot.env_var), 1);};
 192                 vroot_vector= vroot_data.vroot.vector;};
 193         vp= vroot_vector == NULL ? NULL : &(vroot_vector)[0];
 194 
 195 /* Setup to remember pieces */
 196         vroot_data.vroot_start= NULL;
 197         vroot_data.path_start= NULL;
 198         vroot_data.filename_start= NULL;
 199 
 200         int flen = strlen(filename);
 201         if(flen >= MAXPATHLEN) {
 202                 errno = ENAMETOOLONG;
 203                 return;
 204         }
 205 
 206         switch ((vp ?1:0) + (pp1 ? 2:0)) {
 207             case 0:     /* No path. No vroot. */
 208             use_name:
 209                 (void)strcpy(vroot_data.full_path, filename);
 210                 vroot_data.filename_start= vroot_data.full_path;
 211                 (void)(*thunk)(vroot_data.full_path);
 212                 return;
 213             case 1:     /* No path. Vroot */
 214                 if (filename[0] != '/') goto use_name;
 215                 for (; vp->path != NULL; vp++) {
 216                         if((1 + flen + vp->length) >= MAXPATHLEN) {
 217                                 errno = ENAMETOOLONG;
 218                                 continue;
 219                         }
 220                         p= vroot_data.full_path;
 221                         (void)strcpy(vroot_data.vroot_start= p, vp->path);
 222                         p+= vp->length;
 223                         (void)strcpy(vroot_data.filename_start= p, filename);
 224                         if ((*thunk)(vroot_data.full_path)) return;};
 225                 (void)strcpy(vroot_data.full_path, filename);
 226                 return;
 227             case 2:     /* Path. No vroot. */
 228                 if (vroot_data.cpp_style_path) {
 229                         if (filename[0] == '/') goto use_name;
 230                 } else {
 231                         if (strchr(filename, '/') != NULL) goto use_name;
 232                 };
 233                 for (; pp1->path != NULL; pp1++) {
 234                         p= vroot_data.full_path;
 235                         if((1 + flen + pp1->length) >= MAXPATHLEN) {
 236                                 errno = ENAMETOOLONG;
 237                                 continue;
 238                         }
 239                         if (vroot_data.cpp_style_path) {
 240                                 (void)strcpy(vroot_data.path_start= p, pp1->path);
 241                                 p+= pp1->length;
 242                                 *p++= '/';
 243                         } else {
 244                                 if (pp1->length != 0) {
 245                                         (void)strcpy(vroot_data.path_start= p,
 246                                             pp1->path);
 247                                         p+= pp1->length;
 248                                         *p++= '/';
 249                                 };
 250                         };
 251                         (void)strcpy(vroot_data.filename_start= p, filename);
 252                         if ((*thunk)(vroot_data.full_path)) return;};
 253                 (void)strcpy(vroot_data.full_path, filename);
 254                 return;
 255             case 3: {   /* Path. Vroot. */
 256                         int *rel_path, path_len= 1;
 257                 if (vroot_data.scan_vroot_first == 0) {
 258                         for (pp= pp1; pp->path != NULL; pp++) path_len++;
 259                         rel_path= flags;
 260                         for (path_len-= 2; path_len >= 0; path_len--) rel_path[path_len]= 0;
 261                         for (; vp->path != NULL; vp++)
 262                                 for (pp= pp1, path_len= 0; pp->path != NULL; pp++, path_len++) {
 263                                         int len = 0;
 264                                         if (rel_path[path_len] == 1) continue;
 265                                         if (pp->path[0] != '/') rel_path[path_len]= 1;
 266                                         p= vroot_data.full_path;
 267                                         if ((filename[0] == '/') || (pp->path[0] == '/')) {
 268                                                 if(vp->length >= MAXPATHLEN) {
 269                                                         errno = ENAMETOOLONG;
 270                                                         continue;
 271                                                 }
 272                                                 (void)strcpy(vroot_data.vroot_start= p, vp->path); p+= vp->length;
 273                                                 len += vp->length;
 274                                         };
 275                                         if (vroot_data.cpp_style_path) {
 276                                                 if (filename[0] != '/') {
 277                                                         if(1 + len + pp->length >= MAXPATHLEN) {
 278                                                                 errno = ENAMETOOLONG;
 279                                                                 continue;
 280                                                         }
 281                                                         (void)strcpy(vroot_data.path_start= p, pp->path); p+= pp->length;
 282                                                         *p++= '/';
 283                                                         len += 1 + pp->length;
 284                                                 };
 285                                         } else {
 286                                                 if (strchr(filename, '/') == NULL) {
 287                                                         if (pp->length != 0) {
 288                                                                 if(1 + len + pp->length >= MAXPATHLEN) {
 289                                                                         errno = ENAMETOOLONG;
 290                                                                         continue;
 291                                                                 }
 292                                                                 (void)strcpy(vroot_data.path_start= p,
 293                                                                     pp->path);
 294                                                                 p+= pp->length;
 295                                                                 *p++= '/';
 296                                                                 len += 1 + pp->length;
 297                                                         }
 298                                                 }
 299                                         };
 300                                         (void)strcpy(vroot_data.filename_start= p, filename);
 301                                         if ((*thunk)(vroot_data.full_path)) return;};}
 302                 else { pathcellt *vp1= vp;
 303                         for (pp= pp1, path_len= 0; pp->path != NULL; pp++, path_len++)
 304                                 for (vp= vp1; vp->path != NULL; vp++) {
 305                                         int len = 0;
 306                                         p= vroot_data.full_path;
 307                                         if ((filename[0] == '/') || (pp->path[0] == '/')) {
 308                                                 if(vp->length >= MAXPATHLEN) {
 309                                                         errno = ENAMETOOLONG;
 310                                                         continue;
 311                                                 }
 312                                                 (void)strcpy(vroot_data.vroot_start= p, vp->path); p+= vp->length;
 313                                                 len += vp->length;
 314                                         }
 315                                         if (vroot_data.cpp_style_path) {
 316                                                 if (filename[0] != '/') {
 317                                                         if(1 + len + pp->length >= MAXPATHLEN) {
 318                                                                 errno = ENAMETOOLONG;
 319                                                                 continue;
 320                                                         }
 321                                                         (void)strcpy(vroot_data.path_start= p, pp->path); p+= pp->length;
 322                                                         *p++= '/';
 323                                                         len += 1 + pp->length;
 324                                                 }
 325                                         } else {
 326                                                 if (strchr(filename, '/') == NULL) {
 327                                                         if(1 + len + pp->length >= MAXPATHLEN) {
 328                                                                 errno = ENAMETOOLONG;
 329                                                                 continue;
 330                                                         }
 331                                                         (void)strcpy(vroot_data.path_start= p, pp->path); p+= pp->length;
 332                                                         *p++= '/';
 333                                                         len += 1 + pp->length;
 334                                                 }
 335                                         }
 336                                         (void)strcpy(vroot_data.filename_start= p, filename);
 337                                         if ((*thunk)(vroot_data.full_path)) return;};};
 338                 (void)strcpy(vroot_data.full_path, filename);
 339                 return;};};
 340 }