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 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #include <stdio.h> 32 #include <limits.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <errno.h> 36 #include <string.h> 37 #include <sys/types.h> 38 #include <pkgstrct.h> 39 #include <locale.h> 40 #include <libintl.h> 41 #include <pkglib.h> 42 #include <install.h> 43 #include <libinst.h> 44 45 #define ERR_MEMORY "memory allocation failure" 46 #define ERR_DUPPATH "duplicate pathname <%s>" 47 48 /* libpkg/gpkgmap */ 49 extern int getmapmode(void); 50 51 #define EPTMALLOC 512 52 53 static struct cfent **eptlist; 54 55 static int eptnum; 56 static int errflg; 57 static int nparts; 58 static int space = -1; 59 60 static void procinit(void); 61 static int procassign(struct cfent *ept, char **server_local, 62 char **client_local, char **server_path, 63 char **client_path, char **map_path, int mapflag, 64 int nc); 65 66 static int ckdup(struct cfent *ept1, struct cfent *ept2); 67 static int sortentry(int index); 68 69 static void 70 procinit(void) 71 { 72 errflg = nparts = eptnum = 0; 73 74 if (space != -1) { 75 ar_free(space); 76 space = -1; 77 } 78 79 /* 80 * initialize dynamic memory used to store 81 * path information which is read in 82 */ 83 (void) pathdup((char *)0); 84 } 85 86 /* 87 * This function assigns appropriate values based upon the pkgmap entry 88 * in the cfent structure. 89 */ 90 static int 91 procassign(struct cfent *ept, char **server_local, char **client_local, 92 char **server_path, char **client_path, char **map_path, int mapflag, 93 int nc) 94 { 95 int path_duped = 0; 96 int local_duped = 0; 97 char source[PATH_MAX+1]; 98 99 if (nc >= 0 && ept->ftype != 'i') 100 if ((ept->pkg_class_idx = cl_idx(ept->pkg_class)) == -1) 101 return (1); 102 103 if (ept->volno > nparts) 104 nparts++; 105 106 /* 107 * Generate local (delivered source) paths for files 108 * which need them so that the install routine will know 109 * where to get the file from the package. Note that we 110 * do not resolve path environment variables here since 111 * they won't be resolved in the reloc directory. 112 */ 113 if ((mapflag > 1) && strchr("fve", ept->ftype)) { 114 if (ept->ainfo.local == NULL) { 115 source[0] = '~'; 116 (void) strcpy(&source[1], ept->path); 117 ept->ainfo.local = pathdup(source); 118 *server_local = ept->ainfo.local; 119 *client_local = ept->ainfo.local; 120 121 local_duped = 1; 122 } 123 } 124 125 /* 126 * Evaluate the destination path based upon available 127 * environment, then produce a client-relative and 128 * server-relative canonized path. 129 */ 130 if (mapflag && (ept->ftype != 'i')) { 131 mappath(getmapmode(), ept->path); /* evaluate variables */ 132 canonize(ept->path); /* Fix path as necessary. */ 133 134 (void) eval_path(server_path, 135 client_path, 136 map_path, 137 ept->path); 138 path_duped = 1; /* eval_path dup's it */ 139 ept->path = *server_path; /* default */ 140 } 141 142 /* 143 * Deal with source for hard and soft links. 144 */ 145 if (strchr("sl", ept->ftype)) { 146 if (mapflag) { 147 mappath(getmapmode(), ept->ainfo.local); 148 if (!RELATIVE(ept->ainfo.local)) { 149 canonize(ept->ainfo.local); 150 151 /* check for hard link */ 152 if (ept->ftype == 'l') { 153 (void) eval_path( 154 server_local, 155 client_local, 156 NULL, 157 ept->ainfo.local); 158 local_duped = 1; 159 160 /* Default to server. */ 161 ept->ainfo.local = *server_local; 162 } 163 } 164 } 165 } 166 167 /* 168 * For the paths (both source and target) that were too mundane to 169 * have been copied into dup space yet, do that. 170 */ 171 if (!path_duped) { 172 *server_path = pathdup(ept->path); 173 *client_path = *server_path; 174 ept->path = *server_path; 175 176 path_duped = 1; 177 } 178 if (ept->ainfo.local != NULL) 179 if (!local_duped) { 180 *server_local = pathdup(ept->ainfo.local); 181 ept->ainfo.local = *server_local; 182 *client_local = ept->ainfo.local; 183 184 local_duped = 1; 185 } 186 187 return (0); 188 } 189 190 /* 191 * This function reads the prototype file and returns a pointer to a list of 192 * struct cfent representing the contents of that file. 193 */ 194 /*ARGSUSED*/ 195 struct cfent ** 196 procmap(VFP_T *vfp, int mapflag, char *ir) 197 { 198 struct cfent *ept = (struct cfent *)NULL; 199 struct cfent map_entry; 200 struct cfent **ept_ptr; 201 int i; 202 int n; 203 int nc; 204 static char *server_local, *client_local; 205 static char *server_path, *client_path, *map_path; 206 207 procinit(); 208 209 space = ar_create(EPTMALLOC, (unsigned)sizeof (struct cfent), 210 "prototype object"); 211 if (space == -1) { 212 progerr(gettext(ERR_MEMORY)); 213 return (NULL); 214 } 215 216 nc = cl_getn(); 217 for (;;) { 218 /* Clear the buffer. */ 219 (void) memset(&map_entry, '\000', sizeof (struct cfent)); 220 221 n = gpkgmapvfp(&map_entry, vfp); 222 223 if (n == 0) 224 break; /* no more entries in pkgmap */ 225 else if (n < 0) { 226 char *errstr = getErrstr(); 227 progerr(gettext("bad entry read in pkgmap")); 228 logerr(gettext("pathname=%s"), 229 (ept && ept->path && *ept->path) ? 230 ept->path : "Unknown"); 231 logerr(gettext("problem=%s"), 232 (errstr && *errstr) ? errstr : "Unknown"); 233 return (NULL); 234 } 235 236 /* 237 * A valid entry was found in the map, so allocate an 238 * official record. 239 */ 240 ept_ptr = (struct cfent **)ar_next_avail(space); 241 if (ept_ptr == NULL || *ept_ptr == NULL) { 242 progerr(gettext(ERR_MEMORY)); 243 return (NULL); 244 } 245 246 ept = *ept_ptr; 247 248 /* Transfer what we just read in. */ 249 (void) memcpy(ept, &map_entry, sizeof (struct cfent)); 250 251 if (procassign(ept, &server_local, &client_local, 252 &server_path, &client_path, &map_path, 253 mapflag, nc)) { 254 /* It didn't take. */ 255 (void) ar_delete(space, eptnum); 256 continue; 257 } 258 259 eptnum++; 260 } 261 262 /* setup a pointer array to point to malloc'd entries space */ 263 eptlist = (struct cfent **)ar_get_head(space); 264 if (eptlist == NULL) { 265 progerr(gettext(ERR_MEMORY)); 266 return (NULL); 267 } 268 269 (void) sortentry(-1); 270 for (i = 0; i < eptnum; /* void */) { 271 if (!sortentry(i)) 272 i++; 273 } 274 return (errflg ? NULL : eptlist); 275 } 276 277 /* 278 * This function sorts the final list of cfent entries. If index = -1, the 279 * function is initialized. index = 0 doesn't get us anywhere because this 280 * sorts against index-1. Positive natural index values are compared and 281 * sorted into the array appropriately. Yes, it does seem we should use a 282 * quicksort on the whole array or something. The apparent reason for taking 283 * this approach is that there are enough special considerations to be 284 * applied to each package object that inserting them one-by-one doesn't cost 285 * that much. 286 */ 287 static int 288 sortentry(int index) 289 { 290 struct cfent *ept, *ept_i; 291 static int last = 0; 292 int i, n, j; 293 int upper, lower; 294 295 if (index == 0) 296 return (0); 297 else if (index < 0) { 298 last = 0; 299 return (0); 300 } 301 302 /* 303 * Based on the index, this is the package object we're going to 304 * review. It may stay where it is or it may be repositioned in the 305 * array. 306 */ 307 ept = eptlist[index]; 308 309 /* quick comparison optimization for pre-sorted arrays */ 310 if (strcmp(ept->path, eptlist[index-1]->path) > 0) { 311 /* do nothing */ 312 last = index-1; 313 return (0); 314 } 315 316 lower = 0; /* lower bound of the unsorted elements */ 317 upper = index; /* upper bound */ 318 i = last; 319 do { 320 /* 321 * NOTE: This does a binary sort on path. There are lots of 322 * other worthy items in the array, but path is the key into 323 * the package database. 324 */ 325 ept_i = eptlist[i]; 326 327 n = strcmp(ept->path, ept_i->path); 328 if (n == 0) { 329 if (!ckdup(ept, ept_i)) { 330 progerr(gettext(ERR_DUPPATH), 331 ept->path); 332 errflg++; 333 } 334 /* remove the entry at index */ 335 (void) ar_delete(space, index); 336 337 eptnum--; 338 return (1); /* Use this index again. */ 339 } else if (n < 0) { 340 /* 341 * The path of interest is smaller than the path 342 * under test. Move down array using the method of 343 * division 344 */ 345 upper = i; 346 i = lower + (upper-lower)/2; 347 } else { 348 /* Move up array */ 349 lower = i+1; 350 i = upper - (upper-lower)/2 - 1; 351 } 352 } while (upper != lower); 353 last = i = upper; 354 355 /* expand to insert at i */ 356 for (j = index; j > i; j--) 357 eptlist[j] = eptlist[j-1]; 358 359 eptlist[i] = ept; 360 361 return (0); 362 } 363 364 /* 365 * Check duplicate entries in the package object list. If it's a directory, 366 * this just merges them, if not, it returns a 0 to force further processing. 367 */ 368 static int 369 ckdup(struct cfent *ept1, struct cfent *ept2) 370 { 371 /* ept2 will be modified to contain "merged" entries */ 372 373 if (!strchr("?dx", ept1->ftype)) 374 return (0); 375 376 if (!strchr("?dx", ept2->ftype)) 377 return (0); 378 379 if (ept2->ainfo.mode == BADMODE) 380 ept2->ainfo.mode = ept1->ainfo.mode; 381 if ((ept1->ainfo.mode != ept2->ainfo.mode) && 382 (ept1->ainfo.mode != BADMODE)) 383 return (0); 384 385 if (strcmp(ept2->ainfo.owner, "?") == 0) 386 (void) strcpy(ept2->ainfo.owner, ept1->ainfo.owner); 387 if (strcmp(ept1->ainfo.owner, ept2->ainfo.owner) && 388 strcmp(ept1->ainfo.owner, "?")) 389 return (0); 390 391 if (strcmp(ept2->ainfo.group, "?") == 0) 392 (void) strcpy(ept2->ainfo.group, ept1->ainfo.group); 393 if (strcmp(ept1->ainfo.group, ept2->ainfo.group) && 394 strcmp(ept1->ainfo.group, "?")) 395 return (0); 396 397 if (ept1->pinfo) { 398 ept2->npkgs = ept1->npkgs; 399 ept2->pinfo = ept1->pinfo; 400 } 401 402 return (1); 403 } 404