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