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 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 
28 #include <stdio.h>
29 #include <limits.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <sys/types.h>
35 #include <pkgstrct.h>
36 #include <locale.h>
37 #include <libintl.h>
38 #include <pkglib.h>
39 #include <install.h>
40 #include <libinst.h>
41 
42 #define	WRN_NOPKGOBJ	"WARNING: no package objects found"
43 
44 #define	ERR_MEMORY	"memory allocation failure"
45 #define	ERR_DUPPATH	"duplicate pathname <%s>"
46 
47 /* libpkg/gpkgmap */
48 extern int	getmapmode(void);
49 
50 #define	EPTMALLOC	512
51 
52 static struct cfextra **extlist;
53 
54 int	eptnum;
55 static int	array_preloaded = 0;
56 static int	errflg;
57 static int	nparts;
58 static int	xspace = -1;
59 
60 void	pkgobjinit(void);
61 static int	pkgobjassign(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 static int	dup_merg(struct cfextra *ext1, struct cfextra *ext2);
69 
70 void
pkgobjinit(void)71 pkgobjinit(void)
72 {
73 	if (array_preloaded)	/* Already done. */
74 		return;
75 
76 	errflg = nparts = eptnum = 0;
77 
78 	if (xspace != -1) {
79 		ar_free(xspace);
80 		xspace = -1;
81 	}
82 
83 	/*
84 	 * initialize dynamic memory used to store
85 	 * path information which is read in
86 	 */
87 	(void) pathdup((char *)0);
88 }
89 
90 /*
91  * This function assigns appropriate values based upon the pkgmap entry
92  * in the cfent structure.
93  */
94 static int
pkgobjassign(struct cfent * ept,char ** server_local,char ** client_local,char ** server_path,char ** client_path,char ** map_path,int mapflag,int nc)95 pkgobjassign(struct cfent *ept, char **server_local, char **client_local,
96     char **server_path, char **client_path, char **map_path, int mapflag,
97     int nc)
98 {
99 	int	path_duped = 0;
100 	int	local_duped = 0;
101 	char	source[PATH_MAX+1];
102 
103 	if (nc >= 0 && ept->ftype != 'i')
104 		if ((ept->pkg_class_idx = cl_idx(ept->pkg_class)) == -1)
105 			return (1);
106 
107 	if (ept->volno > nparts)
108 		nparts++;
109 
110 	/*
111 	 * Generate local (delivered source) paths for files
112 	 * which need them so that the install routine will know
113 	 * where to get the file from the package. Note that we
114 	 * do not resolve path environment variables here since
115 	 * they won't be resolved in the reloc directory.
116 	 */
117 	if ((mapflag > 1) && strchr("fve", ept->ftype)) {
118 		if (ept->ainfo.local == NULL) {
119 			source[0] = '~';
120 			(void) strlcpy(&source[1], ept->path,
121 						sizeof (source)-1);
122 			ept->ainfo.local = pathdup(source);
123 			*server_local = ept->ainfo.local;
124 			*client_local = ept->ainfo.local;
125 
126 			local_duped = 1;
127 		}
128 	}
129 
130 	/*
131 	 * Evaluate the destination path based upon available
132 	 * environment, then produce a client-relative and
133 	 * server-relative canonized path.
134 	 */
135 	if (mapflag && (ept->ftype != 'i')) {
136 		mappath(getmapmode(), ept->path); /* evaluate variables */
137 		canonize(ept->path);	/* Fix path as necessary. */
138 
139 		(void) eval_path(server_path,
140 		    client_path,
141 		    map_path,
142 		    ept->path);
143 		path_duped = 1;	/* eval_path dup's it */
144 		ept->path = *server_path;	/* default */
145 	}
146 
147 	/*
148 	 * Deal with source for hard and soft links.
149 	 */
150 	if (strchr("sl", ept->ftype)) {
151 		if (mapflag) {
152 			mappath(getmapmode(), ept->ainfo.local);
153 			if (!RELATIVE(ept->ainfo.local)) {
154 				canonize(ept->ainfo.local);
155 
156 				/* check for hard link */
157 				if (ept->ftype == 'l') {
158 					(void) eval_path(
159 					    server_local,
160 					    client_local,
161 					    NULL,
162 					    ept->ainfo.local);
163 					local_duped = 1;
164 
165 					/* Default to server. */
166 					ept->ainfo.local = *server_local;
167 				}
168 			}
169 		}
170 	}
171 
172 	/*
173 	 * For the paths (both source and target) that were too mundane to
174 	 * have been copied into dup space yet, do that.
175 	 */
176 	if (!path_duped) {
177 		*server_path = pathdup(ept->path);
178 		*client_path = *server_path;
179 		ept->path = *server_path;
180 
181 		path_duped = 1;
182 	}
183 	if (ept->ainfo.local != NULL)
184 		if (!local_duped) {
185 			*server_local = pathdup(ept->ainfo.local);
186 			ept->ainfo.local = *server_local;
187 			*client_local = ept->ainfo.local;
188 
189 		local_duped = 1;
190 	}
191 
192 	return (0);
193 }
194 
195 /* This initializes the package object array. */
196 int
init_pkgobjspace(void)197 init_pkgobjspace(void)
198 {
199 	if (array_preloaded)	/* Already done. */
200 		return (1);
201 
202 	if (xspace == -1) {
203 		xspace = ar_create(EPTMALLOC, sizeof (struct cfextra),
204 		    "package object");
205 		if (xspace == -1) {
206 			progerr(gettext(ERR_MEMORY));
207 			return (0);
208 		}
209 	}
210 
211 	return (1);
212 }
213 
214 int
seed_pkgobjmap(struct cfextra * ext_entry,char * path,char * local)215 seed_pkgobjmap(struct cfextra *ext_entry, char *path, char *local)
216 {
217 	struct cfextra *ext, **ext_ptr;
218 
219 	/* offsets for the various path images. */
220 	int client_path_os;
221 	int server_path_os;
222 	int map_path_os;
223 	int client_local_os;
224 	int server_local_os;
225 
226 	ext_ptr = (struct cfextra **)ar_next_avail(xspace);
227 
228 	if (ext_ptr == NULL || *ext_ptr == NULL) {
229 		progerr(gettext(ERR_MEMORY));
230 		return (0);
231 	}
232 
233 	ext = *ext_ptr;
234 
235 	(void) memcpy(ext, ext_entry, sizeof (struct cfextra));
236 
237 	/* Figure out all of the offsets. */
238 	client_path_os = ((ptrdiff_t)ext->client_path -
239 			(ptrdiff_t)ext->cf_ent.path);
240 	server_path_os = ((ptrdiff_t)ext->server_path -
241 			(ptrdiff_t)ext->cf_ent.path);
242 	map_path_os = ((ptrdiff_t)ext->map_path -
243 			(ptrdiff_t)ext->cf_ent.path);
244 	client_local_os = ((ptrdiff_t)ext->client_local -
245 			(ptrdiff_t)ext->cf_ent.ainfo.local);
246 	server_local_os = ((ptrdiff_t)ext->server_local -
247 			(ptrdiff_t)ext->cf_ent.ainfo.local);
248 
249 	/* Allocate and store the path name. */
250 	ext->cf_ent.path = pathdup(path);
251 
252 	/* Assign the path substring pointers. */
253 	ext->client_path = (ext->cf_ent.path + client_path_os);
254 	ext->server_path = (ext->cf_ent.path + server_path_os);
255 	ext->map_path = (ext->cf_ent.path + map_path_os);
256 
257 	/* If there's a local entry, allocate and store it as well. */
258 	if (local) {
259 		ext->cf_ent.ainfo.local = pathdup(local);
260 
261 		ext->client_local = (ext->cf_ent.ainfo.local + client_local_os);
262 		ext->server_local = (ext->cf_ent.ainfo.local + server_local_os);
263 	} else {
264 		ext->cf_ent.ainfo.local = NULL;
265 		ext->client_local = NULL;
266 		ext->server_local = NULL;
267 	}
268 
269 	eptnum++;
270 	array_preloaded = 1;
271 
272 	return (0);
273 }
274 
275 /*
276  * This function reads the pkgmap (or any file similarly formatted) and
277  * returns a pointer to a list of struct cfextra (each of which
278  * contains a struct cfent) representing the contents of that file.
279  */
280 
281 /* ARGSUSED ir in pkgobjmap */
282 struct cfextra **
pkgobjmap(VFP_T * vfp,int mapflag,char * ir)283 pkgobjmap(VFP_T *vfp, int mapflag, char *ir)
284 {
285 	struct	cfextra *ext, **ext_ptr;
286 	struct	cfent *ept, map_entry;
287 	int	i;
288 	int	n;
289 	int	nc;
290 
291 	pkgobjinit();
292 	if (!init_pkgobjspace())
293 		quit(99);
294 
295 	nc = cl_getn();
296 	for (;;) {
297 		/* Clear the buffer. */
298 		(void) memset(&map_entry, '\000', sizeof (struct cfent));
299 
300 		/*
301 		 * Fill in a cfent structure in a very preliminary fashion.
302 		 * ept->path and ept->ainfo.local point to static memory
303 		 * areas of size PATH_MAX. These are manipulated and
304 		 * then provided their own allocations later in this function.
305 		 */
306 		n = gpkgmapvfp(&map_entry, vfp);
307 
308 		if (n == 0)
309 			break; /* no more entries in pkgmap */
310 		else if (n < 0) {
311 			char	*errstr = getErrstr();
312 			progerr(gettext("bad entry read in pkgmap"));
313 			logerr(gettext("pathname=%s"),
314 			    (map_entry.path && *map_entry.path) ?
315 			    map_entry.path : "Unknown");
316 			logerr(gettext("problem=%s"),
317 			    (errstr && *errstr) ? errstr : "Unknown");
318 			return (NULL);
319 		}
320 
321 		/*
322 		 * A valid entry was found in the map, so allocate an
323 		 * official record.
324 		 */
325 		ext_ptr = (struct cfextra **)ar_next_avail(xspace);
326 		if (ext_ptr == NULL || *ext_ptr == NULL) {
327 			progerr(gettext(ERR_MEMORY));
328 			return (NULL);
329 		}
330 
331 		ext = *ext_ptr;
332 		ept = &(ext->cf_ent);
333 
334 		/* Transfer what we just read in. */
335 		(void) memcpy(ept, &map_entry, sizeof (struct cfent));
336 
337 		/* And process it into the cfextra structure. */
338 		if (pkgobjassign(ept,
339 		    &(ext->server_local),
340 		    &(ext->client_local),
341 		    &(ext->server_path),
342 		    &(ext->client_path),
343 		    &(ext->map_path),
344 		    mapflag, nc)) {
345 			/* It didn't take. */
346 			(void) ar_delete(xspace, eptnum);
347 			continue;
348 		}
349 
350 		eptnum++;
351 		ext->fsys_value = BADFSYS;	/* No file system data yet */
352 		ext->fsys_base = BADFSYS;
353 	}
354 
355 	if (eptnum == 0) {
356 		logerr(gettext(WRN_NOPKGOBJ));
357 		return (NULL);
358 	}
359 
360 	/* setup a pointer array to point to malloc'd entries space */
361 	extlist = (struct cfextra **)ar_get_head(xspace);
362 	if (extlist == NULL) {
363 		progerr(gettext(ERR_MEMORY));
364 		return (NULL);
365 	}
366 
367 	(void) sortentry(-1);
368 	for (i = 0; i < eptnum; /* void */) {
369 		if (!sortentry(i))
370 			i++;
371 	}
372 
373 	return (errflg ? NULL : extlist);
374 }
375 
376 /*
377  * This function sorts the final list of cfextra entries. If index = -1, the
378  * function is initialized. index = 0 doesn't get us anywhere because this
379  * sorts against index-1. Positive natural index values are compared and
380  * sorted into the array appropriately. Yes, it does seem we should use a
381  * quicksort on the whole array or something. The apparent reason for taking
382  * this approach is that there are enough special considerations to be
383  * applied to each package object that inserting them one-by-one doesn't cost
384  * that much.
385  */
386 static int
sortentry(int index)387 sortentry(int index)
388 {
389 	struct cfextra *ext;
390 	struct cfent *ept, *ept_i;
391 	static int last = 0;
392 	int	i, n, j;
393 	int	upper, lower;
394 
395 	if (index == 0)
396 		return (0);
397 	else if (index < 0) {
398 		last = 0;
399 		return (0);
400 	}
401 
402 	/*
403 	 * Based on the index, this is the package object we're going to
404 	 * review. It may stay where it is or it may be repositioned in the
405 	 * array.
406 	 */
407 	ext = extlist[index];
408 	ept = &(ext->cf_ent);
409 
410 	/* quick comparison optimization for pre-sorted arrays */
411 	if (strcmp(ept->path, extlist[index-1]->cf_ent.path) > 0) {
412 		/* do nothing */
413 		last = index-1;
414 		return (0);
415 	}
416 
417 	lower = 0;		/* lower bound of the unsorted elements */
418 	upper = index;		/* upper bound */
419 	i = last;
420 	do {
421 		/*
422 		 * NOTE: This does a binary sort on path. There are lots of
423 		 * other worthy items in the array, but path is the key into
424 		 * the package database.
425 		 */
426 		ept_i = &(extlist[i]->cf_ent);
427 
428 		n = strcmp(ept->path, ept_i->path);
429 		if (n == 0) {
430 			if (!ckdup(ept, ept_i)) {
431 				/*
432 				 * If the array was seeded then there are
433 				 * bound to be occasional duplicates.
434 				 * Otherwise, duplicates are definitely a
435 				 * sign of major damage.
436 				 */
437 				if (array_preloaded) {
438 					if (!dup_merg(ext, extlist[i])) {
439 						progerr(gettext(ERR_DUPPATH),
440 						    ept->path);
441 						errflg++;
442 					}
443 				} else {
444 					progerr(gettext(ERR_DUPPATH),
445 					    ept->path);
446 					errflg++;
447 				}
448 			}
449 			/* remove the entry at index */
450 			(void) ar_delete(xspace, index);
451 
452 			eptnum--;
453 			return (1);	/* Use this index again. */
454 		} else if (n < 0) {
455 			/*
456 			 * The path of interest is smaller than the path
457 			 * under test. Move down array using the method of
458 			 * division
459 			 */
460 			upper = i;
461 			i = lower + (upper-lower)/2;
462 		} else {
463 			/* Move up array */
464 			lower = i+1;
465 			i = upper - (upper-lower)/2 - 1;
466 		}
467 	} while (upper != lower);
468 	last = i = upper;
469 
470 	/* expand to insert at i */
471 	for (j = index; j > i; j--)
472 		extlist[j] = extlist[j-1];
473 
474 	extlist[i] = ext;
475 
476 	return (0);
477 }
478 
479 /* Return the number of blocks required by the package object provided. */
480 static fsblkcnt_t
nblks(short fsys_entry,struct cfextra * ext)481 nblks(short fsys_entry, struct cfextra *ext)
482 {
483 	fsblkcnt_t blk;
484 	ulong_t block_size;
485 	ulong_t frag_size;
486 
487 	block_size = (ulong_t)get_blk_size_n(fsys_entry);
488 	frag_size = (ulong_t)get_frag_size_n(fsys_entry);
489 
490 	if (strchr("dxs", ext->cf_ent.ftype))
491 		blk =
492 		    nblk(block_size, block_size, frag_size);
493 	else if (ext->cf_ent.cinfo.size != BADCONT)
494 		blk = nblk(ext->cf_ent.cinfo.size, block_size,
495 		    frag_size);
496 	else
497 		blk = 0;
498 
499 	return (blk);
500 }
501 
502 /* Remove ext1 from the filesystem size calculations and add ext2. */
503 static void
size_xchng(struct cfextra * ext1,struct cfextra * ext2)504 size_xchng(struct cfextra *ext1, struct cfextra *ext2)
505 {
506 	fsblkcnt_t bused;
507 	ulong_t block_size;
508 	ulong_t frag_size;
509 	fsblkcnt_t	blks1, blks2;
510 	short	fsys_entry;
511 
512 	/*
513 	 * Since these are on the same filesystem, either one will yield the
514 	 * correct block and fragment size.
515 	 */
516 	fsys_entry = ext1->fsys_base;
517 	block_size = (ulong_t)get_blk_size_n(fsys_entry);
518 	frag_size = (ulong_t)get_frag_size_n(fsys_entry);
519 
520 	blks1 = nblk(ext1->cf_ent.cinfo.size, block_size, frag_size);
521 	blks2 = nblk(ext2->cf_ent.cinfo.size, block_size, frag_size);
522 
523 	if (blks1 != blks2) {
524 		/* First, lose the old size, then add the new size. */
525 		bused = get_blk_used_n(fsys_entry);
526 		bused -= nblks(fsys_entry, ext1);
527 		bused += nblks(fsys_entry, ext2);
528 
529 		set_blk_used_n(fsys_entry, bused);
530 	}
531 }
532 
533 /*
534  * This function merges duplicate non-directory entries resulting from a
535  * dryrun or other procedure which preloads the extlist. It uses an odd
536  * heuristic to determine which package object is newest: only package
537  * objects from the dryrun file will have pinfo pointers. Therefore, the
538  * object with a pinfo pointer is from the dryrun file and it will be
539  * overwritten by the object being installed by this package.
540  *
541  * Assumptions:
542  *	1. The newer object will be overwriting the older object.
543  *	2. The two objects are close enough to the same size that
544  *	   the sizing is still OK.
545  *
546  * The calling routine will overwrite ept1, so this must return ept2 with
547  * the correct data to keep. There being only one logical outcome of a
548  * failure, this returns 1 for OK and 0 for FAIL.
549  */
550 static int
dup_merg(struct cfextra * ext1,struct cfextra * ext2)551 dup_merg(struct cfextra *ext1, struct cfextra *ext2)
552 {
553 	struct cfent *ept1, *ept2;
554 
555 	ept1 = &(ext1->cf_ent);
556 	ept2 = &(ext2->cf_ent);
557 
558 	if (strchr("?dx", ept1->ftype))
559 		return (0);
560 
561 	if (strchr("?dx", ept2->ftype))
562 		return (0);
563 
564 	/* First, which is the eldest? */
565 	if (ext2->mstat.preloaded) {
566 		/*
567 		 * While ept2 has the correct pinfo list (it was preloaded into
568 		 * the array before the pkgmap was read), ept1 has everything
569 		 * else. Here we copy the guts of ept1 into ept2.
570 		 *
571 		 * Start by grabbing the pointers to the ext2 items that we
572 		 * need to either restore or free.
573 		 */
574 		/* to free() */
575 		char *path = ept2->path;
576 		char *local = ept2->ainfo.local;
577 
578 		/* to preserve */
579 		short npkgs = ept2->npkgs;
580 		struct pinfo *pinfo = ept2->pinfo;
581 
582 		/* Copy everything from the new entry to the old */
583 		(void) memcpy(ept2, ept1, sizeof (struct cfent));
584 
585 		/* Now restore the original stuff.. */
586 		ept2->path = path;
587 		ept2->ainfo.local = local;
588 		ept2->npkgs = npkgs;
589 		ept2->pinfo = pinfo;
590 
591 		size_xchng(ext2, ext1);
592 	} else if (ext1->mstat.preloaded) {
593 		/*
594 		 * ept2 is already the one we will keep. All we have to do is
595 		 * copy over the pinfo pointer.
596 		 */
597 		ept2->pinfo = ept1->pinfo;
598 		size_xchng(ext1, ext2);
599 	} else
600 		return (0);
601 
602 	return (1);
603 }
604 
605 /*
606  * Check duplicate entries in the package object list. If it's a directory,
607  * this just merges them, if not, it returns a 0 to force further processing.
608  */
609 static int
ckdup(struct cfent * ept1,struct cfent * ept2)610 ckdup(struct cfent *ept1, struct cfent *ept2)
611 {
612 	/* ept2 will be modified to contain "merged" entries */
613 
614 	if (!strchr("?dx", ept1->ftype))
615 		return (0);
616 
617 	if (!strchr("?dx", ept2->ftype))
618 		return (0);
619 
620 	if (ept2->ainfo.mode == BADMODE)
621 		ept2->ainfo.mode = ept1->ainfo.mode;
622 	if ((ept1->ainfo.mode != ept2->ainfo.mode) &&
623 	    (ept1->ainfo.mode != BADMODE))
624 		return (0);
625 
626 	if (strcmp(ept2->ainfo.owner, "?") == 0)
627 		(void) strlcpy(ept2->ainfo.owner, ept1->ainfo.owner,
628 			sizeof (ept2->ainfo.owner));
629 	if (strcmp(ept1->ainfo.owner, ept2->ainfo.owner) &&
630 	    strcmp(ept1->ainfo.owner, "?"))
631 		return (0);
632 
633 	if (strcmp(ept2->ainfo.group, "?") == 0)
634 		(void) strlcpy(ept2->ainfo.group, ept1->ainfo.group,
635 			sizeof (ept2->ainfo.group));
636 	if (strcmp(ept1->ainfo.group, ept2->ainfo.group) &&
637 	    strcmp(ept1->ainfo.group, "?"))
638 		return (0);
639 
640 	if (ept1->pinfo) {
641 		ept2->npkgs = ept1->npkgs;
642 		ept2->pinfo = ept1->pinfo;
643 	}
644 
645 	return (1);
646 }
647 
648 /*
649  * Replace the old package database entry with the new one preserving the
650  * data which remains constant across the replacement.
651  *	copied directly:
652  *		ftype, pkg_class
653  *
654  *	preserved from old:
655  *		path, npkgs, pinfo
656  */
657 void
repl_cfent(struct cfent * new,struct cfent * old)658 repl_cfent(struct cfent *new, struct cfent *old)
659 {
660 	char *path = old->path;
661 	short npkgs = old->npkgs;
662 	struct pinfo *pinfo = old->pinfo;
663 
664 	/* Copy everything from the new entry over */
665 	(void) memcpy(old, new, sizeof (struct cfent));
666 
667 	if (strchr("sl", new->ftype) == NULL)
668 		old->ainfo.local = NULL;
669 
670 	old->path = path;
671 	old->npkgs = npkgs;
672 	old->pinfo = pinfo;
673 
674 	old->volno = 0;
675 }
676 
677 /*
678  * Copy critical portions of cf_ent (from the package database) and el_ent
679  * (constructed from the pkgmap) into a merged cfent structure, tp. Then copy
680  * that to the el_ent structure. The approach we take here is to copy over
681  * everything from the package database entry, condition the paths based upon
682  * the currently installed path and then insert the following entries from
683  * the new structure :
684  *	cfent.volno
685  *	pkg_class
686  *	pkg_class_idx
687  *
688  * The pinfo list is then copied from the cfent list. While
689  * fsys_value is also copied over, it hasn't been set yet. This function
690  * copies over whatever the default value is from the new structure.
691  *
692  * The copied entry is returned in the el_ent argument and the function
693  * value is 1 on success, 0 on failure. There is no recovery plan for
694  * failure.
695  */
696 int
cp_cfent(struct cfent * cf_ent,struct cfextra * el_ent)697 cp_cfent(struct cfent *cf_ent, struct cfextra *el_ent)
698 {
699 	struct cfextra	*tp;
700 
701 	/* Allocate space for cfent copy */
702 	if ((tp = (struct cfextra *)calloc(1,
703 	    sizeof (struct cfextra))) == NULL) {
704 		progerr(gettext("cp_cfent: memory allocation error"));
705 		return (0);
706 	}
707 
708 	/* Copy everything from the package database over */
709 	(void) memcpy(&(tp->cf_ent), cf_ent, sizeof (struct cfent));
710 
711 	/* Now overlay new items from the pkgmap */
712 	tp->fsys_value = el_ent->fsys_value;
713 	tp->cf_ent.volno = el_ent->cf_ent.volno;
714 	(void) strlcpy(tp->cf_ent.pkg_class, el_ent->cf_ent.pkg_class,
715 			sizeof (tp->cf_ent.pkg_class));
716 	tp->cf_ent.pkg_class_idx = el_ent->cf_ent.pkg_class_idx;
717 	tp->cf_ent.pinfo = cf_ent->pinfo;
718 
719 	/*
720 	 * The paths are identical, so we get them from the new entry.  These
721 	 * are pointing to a malloc'd section of memory containing a string
722 	 * that we aren't moving in this operation, so everybody points to
723 	 * the same thing during these transfers.
724 	 */
725 	tp->cf_ent.path = el_ent->client_path;
726 	tp->server_path = el_ent->server_path;
727 	tp->client_path = el_ent->client_path;
728 	tp->map_path = el_ent->map_path;
729 
730 	/*
731 	 * Since instvol() expects to work with the *original* mstat data,
732 	 * mstat is just copied here. NOTE: mstat looks like a structure, but
733 	 * it's really a short bit array.
734 	 */
735 	tp->mstat = el_ent->mstat;
736 
737 	/* Copy everything from the temporary structure to the new entry */
738 	(void) memcpy(el_ent, tp, sizeof (struct cfextra));
739 	free(tp);
740 
741 	return (1);
742 }
743