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