15c51f124SMoriah Waterland /*
25c51f124SMoriah Waterland  * CDDL HEADER START
35c51f124SMoriah Waterland  *
45c51f124SMoriah Waterland  * The contents of this file are subject to the terms of the
55c51f124SMoriah Waterland  * Common Development and Distribution License (the "License").
65c51f124SMoriah Waterland  * You may not use this file except in compliance with the License.
75c51f124SMoriah Waterland  *
85c51f124SMoriah Waterland  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95c51f124SMoriah Waterland  * or http://www.opensolaris.org/os/licensing.
105c51f124SMoriah Waterland  * See the License for the specific language governing permissions
115c51f124SMoriah Waterland  * and limitations under the License.
125c51f124SMoriah Waterland  *
135c51f124SMoriah Waterland  * When distributing Covered Code, include this CDDL HEADER in each
145c51f124SMoriah Waterland  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155c51f124SMoriah Waterland  * If applicable, add the following below this CDDL HEADER, with the
165c51f124SMoriah Waterland  * fields enclosed by brackets "[]" replaced with your own identifying
175c51f124SMoriah Waterland  * information: Portions Copyright [yyyy] [name of copyright owner]
185c51f124SMoriah Waterland  *
195c51f124SMoriah Waterland  * CDDL HEADER END
205c51f124SMoriah Waterland  */
215c51f124SMoriah Waterland 
225c51f124SMoriah Waterland /*
235c51f124SMoriah Waterland  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
245c51f124SMoriah Waterland  * Use is subject to license terms.
255c51f124SMoriah Waterland  */
265c51f124SMoriah Waterland 
275c51f124SMoriah Waterland /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
285c51f124SMoriah Waterland /* All Rights Reserved */
295c51f124SMoriah Waterland 
305c51f124SMoriah Waterland 
315c51f124SMoriah Waterland #include <stdio.h>
325c51f124SMoriah Waterland #include <errno.h>
335c51f124SMoriah Waterland #include <string.h>
345c51f124SMoriah Waterland #include <limits.h>
355c51f124SMoriah Waterland #include <stdlib.h>
365c51f124SMoriah Waterland #include <unistd.h>
375c51f124SMoriah Waterland #include <sys/types.h>
385c51f124SMoriah Waterland #include <sys/param.h>
395c51f124SMoriah Waterland #include <pkgdev.h>
405c51f124SMoriah Waterland #include <pkgstrct.h>
415c51f124SMoriah Waterland #include <locale.h>
425c51f124SMoriah Waterland #include <libintl.h>
435c51f124SMoriah Waterland #include <pkglib.h>
445c51f124SMoriah Waterland #include <libadm.h>
455c51f124SMoriah Waterland #include <libinst.h>
465c51f124SMoriah Waterland 
475c51f124SMoriah Waterland extern struct pkgdev pkgdev;
485c51f124SMoriah Waterland 
495c51f124SMoriah Waterland #define	MALSIZ	500
505c51f124SMoriah Waterland #define	EFACTOR	128ULL	/* typical size of a single entry in a pkgmap file */
515c51f124SMoriah Waterland 
525c51f124SMoriah Waterland #define	WRN_LIMIT	"WARNING: -l limit (%llu blocks) exceeds device " \
535c51f124SMoriah Waterland 			"capacity (%llu blocks)"
545c51f124SMoriah Waterland #define	ERR_MEMORY	"memory allocation failure, errno=%d"
555c51f124SMoriah Waterland #define	ERR_TOOBIG	"%s (%llu blocks) does not fit on a volume"
565c51f124SMoriah Waterland #define	ERR_INFOFIRST	"information file <%s> must appear on first part"
575c51f124SMoriah Waterland #define	ERR_INFOSPACE	"all install files must appear on first part"
585c51f124SMoriah Waterland #define	ERR_VOLBLKS	"Objects selected for part %d require %llu blocks, " \
595c51f124SMoriah Waterland 			"limit=%llu."
605c51f124SMoriah Waterland #define	ERR_VOLFILES	"Objects selected for part %d require %llu files, " \
615c51f124SMoriah Waterland 			"limit=%llu."
625c51f124SMoriah Waterland #define	ERR_FREE	"package does not fit space currently available in <%s>"
635c51f124SMoriah Waterland 
645c51f124SMoriah Waterland struct data {
655c51f124SMoriah Waterland 	fsblkcnt_t	blks;
665c51f124SMoriah Waterland 	struct cfent *ept;
675c51f124SMoriah Waterland };
685c51f124SMoriah Waterland 
695c51f124SMoriah Waterland struct class_type {
705c51f124SMoriah Waterland 	char *name;
715c51f124SMoriah Waterland 	int first;
725c51f124SMoriah Waterland 	int last;
735c51f124SMoriah Waterland };
745c51f124SMoriah Waterland 
755c51f124SMoriah Waterland static fsblkcnt_t	btotal;	/* blocks stored on current part */
76*014740deSToomas Soome static fsblkcnt_t	bmax;	/* maximum number of blocks on any part */
775c51f124SMoriah Waterland 
785c51f124SMoriah Waterland static fsfilcnt_t	ftotal;	/* files stored on current part */
795c51f124SMoriah Waterland static fsfilcnt_t	fmax;	/* maximum number of files on any part */
80*014740deSToomas Soome static fsblkcnt_t	bpkginfo;	/* blocks used by pkginfo file */
815c51f124SMoriah Waterland static char	**dirlist;
82*014740deSToomas Soome static short	volno;		/* current part */
83*014740deSToomas Soome static int	nparts = -1;	/* total number of parts */
845c51f124SMoriah Waterland static int	nclass;
85*014740deSToomas Soome static fsblkcnt_t	DIRSIZE;
865c51f124SMoriah Waterland static struct	class_type *cl;
875c51f124SMoriah Waterland 
885c51f124SMoriah Waterland static int	nodecount(char *path);
895c51f124SMoriah Waterland static int	store(struct data **, unsigned int, char *, fsblkcnt_t,
905c51f124SMoriah Waterland     fsblkcnt_t);
915c51f124SMoriah Waterland static void	addclass(char *aclass, int vol);
925c51f124SMoriah Waterland static void	allocnode(char *path);
935c51f124SMoriah Waterland static void	newvolume(struct data **, unsigned int, fsblkcnt_t limit,
945c51f124SMoriah Waterland     fsblkcnt_t);
955c51f124SMoriah Waterland static void	sortsize(struct data *f, struct data **sf, unsigned int eptnum);
965c51f124SMoriah Waterland 
975c51f124SMoriah Waterland int
splpkgmap(struct cfent ** eptlist,unsigned int eptnum,char * order[],ulong_t bsize,ulong_t frsize,fsblkcnt_t * plimit,fsfilcnt_t * pilimit,fsblkcnt_t * pllimit)985c51f124SMoriah Waterland splpkgmap(struct cfent **eptlist, unsigned int eptnum, char *order[],
995c51f124SMoriah Waterland     ulong_t bsize, ulong_t frsize, fsblkcnt_t *plimit, fsfilcnt_t *pilimit,
1005c51f124SMoriah Waterland     fsblkcnt_t *pllimit)
1015c51f124SMoriah Waterland {
1025c51f124SMoriah Waterland 	struct data	*f, **sf;
1035c51f124SMoriah Waterland 	struct cfent	*ept;
1045c51f124SMoriah Waterland 	register int	i, j;
1055c51f124SMoriah Waterland 	int		new_vol_set;
1065c51f124SMoriah Waterland 	short		new_vol;
1075c51f124SMoriah Waterland 	int		flag, errflg;
1085c51f124SMoriah Waterland 	fsblkcnt_t	total;
1095c51f124SMoriah Waterland 	fsblkcnt_t	btemp;
1105c51f124SMoriah Waterland 	fsfilcnt_t	ftemp;
1115c51f124SMoriah Waterland 
1125c51f124SMoriah Waterland 	f = (struct data *)calloc(eptnum, sizeof (struct data));
1135c51f124SMoriah Waterland 	if (f == NULL) {
1145c51f124SMoriah Waterland 		progerr(gettext(ERR_MEMORY), errno);
1155c51f124SMoriah Waterland 		quit(99);
1165c51f124SMoriah Waterland 	}
1175c51f124SMoriah Waterland 
1185c51f124SMoriah Waterland 	sf = (struct data **)calloc(eptnum, sizeof (struct data *));
1195c51f124SMoriah Waterland 	if (sf == NULL) {
1205c51f124SMoriah Waterland 		progerr(gettext(ERR_MEMORY), errno);
1215c51f124SMoriah Waterland 		quit(99);
1225c51f124SMoriah Waterland 	}
1235c51f124SMoriah Waterland 
1245c51f124SMoriah Waterland 	nclass = 0;
1255c51f124SMoriah Waterland 	cl = (struct class_type *)calloc(MALSIZ, sizeof (struct class_type));
1265c51f124SMoriah Waterland 	if (cl == NULL) {
1275c51f124SMoriah Waterland 		progerr(gettext(ERR_MEMORY), errno);
1285c51f124SMoriah Waterland 		quit(99);
1295c51f124SMoriah Waterland 	}
1305c51f124SMoriah Waterland 
1315c51f124SMoriah Waterland 	errflg = 0;
1325c51f124SMoriah Waterland 
1335c51f124SMoriah Waterland 	/*
1345c51f124SMoriah Waterland 	 * The next bit of code checks to see if, when creating a package
1355c51f124SMoriah Waterland 	 * on a directory, there are enough free blocks and inodes before
1365c51f124SMoriah Waterland 	 * continuing.
1375c51f124SMoriah Waterland 	 */
1385c51f124SMoriah Waterland 	total = 0;
1395c51f124SMoriah Waterland 	/*
1405c51f124SMoriah Waterland 	 * DIRSIZE takes up 1 logical block, iff we have no frags, else
1415c51f124SMoriah Waterland 	 * it just takes a frag
1425c51f124SMoriah Waterland 	 */
1435c51f124SMoriah Waterland 	DIRSIZE = ((fsblkcnt_t)frsize > 0) ?
1445c51f124SMoriah Waterland 	    howmany(frsize, DEV_BSIZE) :
1455c51f124SMoriah Waterland 	    howmany(bsize, DEV_BSIZE);
1465c51f124SMoriah Waterland 
1475c51f124SMoriah Waterland 	if (!pkgdev.mount) {
1485c51f124SMoriah Waterland 		allocnode(NULL);
1495c51f124SMoriah Waterland 		/*
1505c51f124SMoriah Waterland 		 * If we appear to have a valid value for free inodes
1515c51f124SMoriah Waterland 		 * and there's not enough for the package contents,
1525c51f124SMoriah Waterland 		 * then exit
1535c51f124SMoriah Waterland 		 */
1545c51f124SMoriah Waterland 		if ((*pilimit > 0) && (eptnum+1 > *pilimit)) {
1555c51f124SMoriah Waterland 			progerr(gettext(ERR_FREE), pkgdev.dirname);
1565c51f124SMoriah Waterland 			quit(1);
1575c51f124SMoriah Waterland 		}
1585c51f124SMoriah Waterland 		for (i = 0; i < eptnum; i++) {
1595c51f124SMoriah Waterland 			if (strchr("dxslcbp", eptlist[i]->ftype))
1605c51f124SMoriah Waterland 				continue;
1615c51f124SMoriah Waterland 			else {
1625c51f124SMoriah Waterland 				total +=
1635c51f124SMoriah Waterland 				    (nodecount(eptlist[i]->path) * DIRSIZE);
1645c51f124SMoriah Waterland 				total +=
1655c51f124SMoriah Waterland 				    nblk(eptlist[i]->cinfo.size, bsize, frsize);
1665c51f124SMoriah Waterland 				if (total > *plimit) {
1675c51f124SMoriah Waterland 					progerr(gettext(ERR_FREE),
168*014740deSToomas Soome 					    pkgdev.dirname);
1695c51f124SMoriah Waterland 					quit(1);
1705c51f124SMoriah Waterland 				}
1715c51f124SMoriah Waterland 				allocnode(eptlist[i]->path);
1725c51f124SMoriah Waterland 			}
1735c51f124SMoriah Waterland 		}
1745c51f124SMoriah Waterland 	}
1755c51f124SMoriah Waterland 	/*
1765c51f124SMoriah Waterland 	 * if there is a value in pllimit (-l specified limit), use that for
1775c51f124SMoriah Waterland 	 * the limit from now on.
1785c51f124SMoriah Waterland 	 */
1795c51f124SMoriah Waterland 
1805c51f124SMoriah Waterland 	if (*pllimit != 0) {
1815c51f124SMoriah Waterland 		if (pkgdev.mount && *pllimit > *plimit)
1825c51f124SMoriah Waterland 			logerr(gettext(WRN_LIMIT), *pllimit, *plimit);
1835c51f124SMoriah Waterland 		*plimit = *pllimit;
1845c51f124SMoriah Waterland 	}
1855c51f124SMoriah Waterland 	/*
1865c51f124SMoriah Waterland 	 * calculate number of physical blocks used by each object
1875c51f124SMoriah Waterland 	 */
1885c51f124SMoriah Waterland 	for (i = 0; i < eptnum; i++) {
1895c51f124SMoriah Waterland 		f[i].ept = ept = eptlist[i];
1905c51f124SMoriah Waterland 		if (ept->volno > nparts)
1915c51f124SMoriah Waterland 			nparts = ept->volno;
1925c51f124SMoriah Waterland 		addclass(ept->pkg_class, 0);
1935c51f124SMoriah Waterland 		if (strchr("dxslcbp", ept->ftype))
1945c51f124SMoriah Waterland 			/*
1955c51f124SMoriah Waterland 			 * virtual object (no contents)
1965c51f124SMoriah Waterland 			 */
1975c51f124SMoriah Waterland 			f[i].blks = 0;
1985c51f124SMoriah Waterland 		else
1995c51f124SMoriah Waterland 			/*
2005c51f124SMoriah Waterland 			 * space consumers
2015c51f124SMoriah Waterland 			 *
2025c51f124SMoriah Waterland 			 * (directories are space consumers as well, but they
2035c51f124SMoriah Waterland 			 * get accounted for later).
2045c51f124SMoriah Waterland 			 *
2055c51f124SMoriah Waterland 			 */
2065c51f124SMoriah Waterland 
2075c51f124SMoriah Waterland 			f[i].blks = nblk(ept->cinfo.size, bsize, frsize);
2085c51f124SMoriah Waterland 
2095c51f124SMoriah Waterland 		if (!bpkginfo && (strcmp(f[i].ept->path, "pkginfo") == 0))
2105c51f124SMoriah Waterland 			bpkginfo = f[i].blks;
2115c51f124SMoriah Waterland 	}
2125c51f124SMoriah Waterland 
2135c51f124SMoriah Waterland 	/*
2145c51f124SMoriah Waterland 	 * Make sure that items slated for a given 'part' do not exceed a single
2155c51f124SMoriah Waterland 	 * volume.
2165c51f124SMoriah Waterland 	 */
2175c51f124SMoriah Waterland 	for (i = 1; i <= nparts; i++) {
2185c51f124SMoriah Waterland 		btemp = (bpkginfo + 2LL);
2195c51f124SMoriah Waterland 		ftemp = 2LL;
2205c51f124SMoriah Waterland 		if (i == 1) {
2215c51f124SMoriah Waterland 			/*
2225c51f124SMoriah Waterland 			 * save room for install directory
2235c51f124SMoriah Waterland 			 */
2245c51f124SMoriah Waterland 			ftemp += 2;
2255c51f124SMoriah Waterland 			btemp += nblk(eptnum * EFACTOR, bsize, frsize);
2265c51f124SMoriah Waterland 			btemp += 2;
2275c51f124SMoriah Waterland 		}
2285c51f124SMoriah Waterland 		allocnode(NULL);
2295c51f124SMoriah Waterland 		for (j = 0; j < eptnum; j++) {
2305c51f124SMoriah Waterland 			if (i == 1 && f[j].ept->ftype == 'i' &&
2315c51f124SMoriah Waterland 			    (strcmp(f[j].ept->path, "pkginfo") == 0 ||
2325c51f124SMoriah Waterland 			    strcmp(f[j].ept->path, "pkgmap") == 0))
2335c51f124SMoriah Waterland 				continue;
2345c51f124SMoriah Waterland 			if (f[j].ept->volno == i ||
2355c51f124SMoriah Waterland 			    (f[j].ept->ftype == 'i' && i == 1)) {
2365c51f124SMoriah Waterland 				ftemp += nodecount(f[j].ept->path);
2375c51f124SMoriah Waterland 				btemp += f[j].blks;
2385c51f124SMoriah Waterland 				allocnode(f[j].ept->path);
2395c51f124SMoriah Waterland 			}
2405c51f124SMoriah Waterland 		}
2415c51f124SMoriah Waterland 		btemp += (ftemp * DIRSIZE);
2425c51f124SMoriah Waterland 		if (btemp > *plimit) {
2435c51f124SMoriah Waterland 			progerr(gettext(ERR_VOLBLKS), i, btemp, *plimit);
2445c51f124SMoriah Waterland 			errflg++;
2455c51f124SMoriah Waterland 		/* If we have a valid inode limit, ensure this part will fit */
2465c51f124SMoriah Waterland 		} else if ((*pilimit > 0) && (ftemp+1 > *pilimit)) {
2475c51f124SMoriah Waterland 			progerr(gettext(ERR_VOLFILES), i, ftemp + 1, *pilimit);
2485c51f124SMoriah Waterland 			errflg++;
2495c51f124SMoriah Waterland 		}
2505c51f124SMoriah Waterland 	}
2515c51f124SMoriah Waterland 	if (errflg)
2525c51f124SMoriah Waterland 		quit(1);
2535c51f124SMoriah Waterland 
2545c51f124SMoriah Waterland 	/*
2555c51f124SMoriah Waterland 	 * "sf" - array sorted in decreasing file size order, based on "f".
2565c51f124SMoriah Waterland 	 */
2575c51f124SMoriah Waterland 	sortsize(f, sf, eptnum);
2585c51f124SMoriah Waterland 
2595c51f124SMoriah Waterland 	/*
2605c51f124SMoriah Waterland 	 * initialize first volume
2615c51f124SMoriah Waterland 	 */
2625c51f124SMoriah Waterland 	newvolume(sf, eptnum, *plimit, *pilimit);
2635c51f124SMoriah Waterland 
2645c51f124SMoriah Waterland 	/*
2655c51f124SMoriah Waterland 	 * reserve room on first volume for pkgmap
2665c51f124SMoriah Waterland 	 */
2675c51f124SMoriah Waterland 	btotal += nblk((fsblkcnt_t)(eptnum * EFACTOR), bsize, frsize);
2685c51f124SMoriah Waterland 	ftotal++;
2695c51f124SMoriah Waterland 
2705c51f124SMoriah Waterland 
2715c51f124SMoriah Waterland 	/*
2725c51f124SMoriah Waterland 	 * initialize directory info
2735c51f124SMoriah Waterland 	 */
2745c51f124SMoriah Waterland 	allocnode(NULL);
2755c51f124SMoriah Waterland 
2765c51f124SMoriah Waterland 	/*
2775c51f124SMoriah Waterland 	 * place installation files on first volume!
2785c51f124SMoriah Waterland 	 */
2795c51f124SMoriah Waterland 	flag = 0;
2805c51f124SMoriah Waterland 	for (j = 0; j < eptnum; ++j) {
2815c51f124SMoriah Waterland 		if (f[j].ept->ftype != 'i')
2825c51f124SMoriah Waterland 			continue;
2835c51f124SMoriah Waterland 		else if (!flag++) {
2845c51f124SMoriah Waterland 			/*
2855c51f124SMoriah Waterland 			 * save room for install directory
2865c51f124SMoriah Waterland 			 */
2875c51f124SMoriah Waterland 			ftotal++;
2885c51f124SMoriah Waterland 			btotal += 2ULL;
2895c51f124SMoriah Waterland 		}
2905c51f124SMoriah Waterland 		if (!f[j].ept->volno) {
2915c51f124SMoriah Waterland 			f[j].ept->volno = 1;
2925c51f124SMoriah Waterland 			ftotal++;
2935c51f124SMoriah Waterland 			btotal += f[j].blks;
2945c51f124SMoriah Waterland 		} else if (f[j].ept->volno != 1) {
2955c51f124SMoriah Waterland 			progerr(gettext(ERR_INFOFIRST), f[j].ept->path);
2965c51f124SMoriah Waterland 			errflg++;
2975c51f124SMoriah Waterland 		}
2985c51f124SMoriah Waterland 	}
2995c51f124SMoriah Waterland 
3005c51f124SMoriah Waterland 	if (errflg)
3015c51f124SMoriah Waterland 		quit(1);
3025c51f124SMoriah Waterland 	if (btotal > *plimit) {
3035c51f124SMoriah Waterland 		progerr(gettext(ERR_INFOSPACE));
3045c51f124SMoriah Waterland 		quit(1);
3055c51f124SMoriah Waterland 	}
3065c51f124SMoriah Waterland 
3075c51f124SMoriah Waterland 	/*
3085c51f124SMoriah Waterland 	 * Make sure that any given file will fit on a single volume, this
3095c51f124SMoriah Waterland 	 * calculation has to take into account packaging overhead, otherwise
3105c51f124SMoriah Waterland 	 * the function store() will go into a severe recursive plunge.
3115c51f124SMoriah Waterland 	 */
3125c51f124SMoriah Waterland 	for (j = 0; j < eptnum; ++j) {
3135c51f124SMoriah Waterland 		/*
3145c51f124SMoriah Waterland 		 * directory overhead.
3155c51f124SMoriah Waterland 		 */
3165c51f124SMoriah Waterland 		btemp = nodecount(f[j].ept->path) * DIRSIZE;
3175c51f124SMoriah Waterland 		/*
3185c51f124SMoriah Waterland 		 * packaging overhead.
3195c51f124SMoriah Waterland 		 */
320*014740deSToomas Soome 		btemp += (bpkginfo + 2L);	/* from newvolume() */
3215c51f124SMoriah Waterland 		if ((f[j].blks + btemp) > *plimit) {
3225c51f124SMoriah Waterland 			errflg++;
3235c51f124SMoriah Waterland 			progerr(gettext(ERR_TOOBIG), f[j].ept->path, f[j].blks);
3245c51f124SMoriah Waterland 		}
3255c51f124SMoriah Waterland 	}
3265c51f124SMoriah Waterland 	if (errflg)
3275c51f124SMoriah Waterland 		quit(1);
3285c51f124SMoriah Waterland 
3295c51f124SMoriah Waterland 	/*
3305c51f124SMoriah Waterland 	 * place classes listed on command line
3315c51f124SMoriah Waterland 	 */
3325c51f124SMoriah Waterland 	if (order) {
3335c51f124SMoriah Waterland 		for (i = 0; order[i]; ++i)  {
3345c51f124SMoriah Waterland 			while (store(sf, eptnum, order[i], *plimit, *pilimit))
3355c51f124SMoriah Waterland 				/* stay in loop until store is complete */
3365c51f124SMoriah Waterland 				/* void */;
3375c51f124SMoriah Waterland 		}
3385c51f124SMoriah Waterland 	}
3395c51f124SMoriah Waterland 
3405c51f124SMoriah Waterland 	while (store(sf, eptnum, (char *)0, *plimit, *pilimit))
3415c51f124SMoriah Waterland 		/* stay in loop until store is complete */
3425c51f124SMoriah Waterland 		/* void */;
3435c51f124SMoriah Waterland 
3445c51f124SMoriah Waterland 	/*
3455c51f124SMoriah Waterland 	 * place all virtual objects, e.g. links and spec devices
3465c51f124SMoriah Waterland 	 */
3475c51f124SMoriah Waterland 	for (i = 0; i < nclass; ++i) {
3485c51f124SMoriah Waterland 		/*
3495c51f124SMoriah Waterland 		 * if no objects were associated, attempt to
3505c51f124SMoriah Waterland 		 * distribute in order of class list
3515c51f124SMoriah Waterland 		 */
3525c51f124SMoriah Waterland 		if (cl[i].first == 0)
3535c51f124SMoriah Waterland 			cl[i].last = cl[i].first = (i ? cl[i-1].last : 1);
3545c51f124SMoriah Waterland 		for (j = 0; j < eptnum; j++) {
3555c51f124SMoriah Waterland 			if ((f[j].ept->volno == 0) &&
3565c51f124SMoriah Waterland 			    strcmp(f[j].ept->pkg_class, cl[i].name) == 0) {
3575c51f124SMoriah Waterland 				if (strchr("sl", f[j].ept->ftype))
3585c51f124SMoriah Waterland 					f[j].ept->volno = cl[i].last;
3595c51f124SMoriah Waterland 				else
3605c51f124SMoriah Waterland 					f[j].ept->volno = cl[i].first;
3615c51f124SMoriah Waterland 			}
3625c51f124SMoriah Waterland 		}
3635c51f124SMoriah Waterland 	}
3645c51f124SMoriah Waterland 
3655c51f124SMoriah Waterland 	if (btotal)
3665c51f124SMoriah Waterland 		newvolume(sf, eptnum, *plimit, *pilimit);
3675c51f124SMoriah Waterland 
3685c51f124SMoriah Waterland 	if (nparts > (volno - 1)) {
3695c51f124SMoriah Waterland 		new_vol = volno;
3705c51f124SMoriah Waterland 		for (i = volno; i <= nparts; i++) {
3715c51f124SMoriah Waterland 			new_vol_set = 0;
3725c51f124SMoriah Waterland 			for (j = 0; j < eptnum; j++) {
3735c51f124SMoriah Waterland 				if (f[j].ept->volno == i) {
3745c51f124SMoriah Waterland 					f[j].ept->volno = new_vol;
3755c51f124SMoriah Waterland 					new_vol_set = 1;
3765c51f124SMoriah Waterland 				}
3775c51f124SMoriah Waterland 			}
3785c51f124SMoriah Waterland 			new_vol += new_vol_set;
3795c51f124SMoriah Waterland 		}
3805c51f124SMoriah Waterland 		nparts = new_vol - 1;
3815c51f124SMoriah Waterland 	} else
3825c51f124SMoriah Waterland 		nparts = volno - 1;
3835c51f124SMoriah Waterland 
3845c51f124SMoriah Waterland 	*plimit = bmax;
3855c51f124SMoriah Waterland 	*pilimit = fmax;
3865c51f124SMoriah Waterland 
3875c51f124SMoriah Waterland 	/*
3885c51f124SMoriah Waterland 	 * free up dynamic space used by this module
3895c51f124SMoriah Waterland 	 */
3905c51f124SMoriah Waterland 	free(f);
3915c51f124SMoriah Waterland 	free(sf);
3925c51f124SMoriah Waterland 	for (i = 0; i < nclass; ++i)
3935c51f124SMoriah Waterland 		free(cl[i].name);
3945c51f124SMoriah Waterland 	free(cl);
3955c51f124SMoriah Waterland 	for (i = 0; dirlist[i]; i++)
3965c51f124SMoriah Waterland 		free(dirlist[i]);
3975c51f124SMoriah Waterland 	free(dirlist);
3985c51f124SMoriah Waterland 
3995c51f124SMoriah Waterland 	return (errflg ? -1 : nparts);
4005c51f124SMoriah Waterland }
4015c51f124SMoriah Waterland 
4025c51f124SMoriah Waterland static int
store(struct data ** sf,unsigned int eptnum,char * aclass,fsblkcnt_t limit,fsfilcnt_t ilimit)4035c51f124SMoriah Waterland store(struct data **sf, unsigned int eptnum, char *aclass, fsblkcnt_t limit,
4045c51f124SMoriah Waterland     fsfilcnt_t ilimit)
4055c51f124SMoriah Waterland {
4065c51f124SMoriah Waterland 	int	i, svnodes, choice, select;
4075c51f124SMoriah Waterland 	long	ftemp;
4085c51f124SMoriah Waterland 	fsblkcnt_t	btemp;
4095c51f124SMoriah Waterland 
410*014740deSToomas Soome 	svnodes = 0;
4115c51f124SMoriah Waterland 	select = 0;
4125c51f124SMoriah Waterland 	choice = (-1);
4135c51f124SMoriah Waterland 	for (i = 0; i < eptnum; ++i) {
4145c51f124SMoriah Waterland 		if (sf[i]->ept->volno || strchr("sldxcbp", sf[i]->ept->ftype))
4155c51f124SMoriah Waterland 			continue; /* defer storage until class is selected */
4165c51f124SMoriah Waterland 		if (aclass && strcmp(aclass, sf[i]->ept->pkg_class))
4175c51f124SMoriah Waterland 			continue;
4185c51f124SMoriah Waterland 		select++; /* we need to place at least one object */
4195c51f124SMoriah Waterland 		ftemp = nodecount(sf[i]->ept->path);
4205c51f124SMoriah Waterland 		btemp = sf[i]->blks + (ftemp * DIRSIZE);
4215c51f124SMoriah Waterland 		if (((limit == 0) || ((btotal + btemp) <= limit)) &&
4225c51f124SMoriah Waterland 		    ((ilimit == 0) || ((ftotal + ftemp) < ilimit))) {
4235c51f124SMoriah Waterland 			/* largest object which fits on this volume */
4245c51f124SMoriah Waterland 			choice = i;
4255c51f124SMoriah Waterland 			svnodes = ftemp;
4265c51f124SMoriah Waterland 			break;
4275c51f124SMoriah Waterland 		}
4285c51f124SMoriah Waterland 	}
4295c51f124SMoriah Waterland 	if (!select)
4305c51f124SMoriah Waterland 		return (0); /* no more to objects to place */
4315c51f124SMoriah Waterland 
4325c51f124SMoriah Waterland 	if (choice < 0) {
4335c51f124SMoriah Waterland 		newvolume(sf, eptnum, limit, ilimit);
4345c51f124SMoriah Waterland 		return (store(sf, eptnum, aclass, limit, ilimit));
4355c51f124SMoriah Waterland 	}
4365c51f124SMoriah Waterland 	sf[choice]->ept->volno = (char)volno;
4375c51f124SMoriah Waterland 	ftotal += svnodes + 1;
4385c51f124SMoriah Waterland 	btotal += sf[choice]->blks + (svnodes * DIRSIZE);
4395c51f124SMoriah Waterland 	allocnode(sf[i]->ept->path);
4405c51f124SMoriah Waterland 	addclass(sf[choice]->ept->pkg_class, volno);
4415c51f124SMoriah Waterland 	return (++choice); /* return non-zero if more work to do */
4425c51f124SMoriah Waterland }
4435c51f124SMoriah Waterland 
4445c51f124SMoriah Waterland static void
allocnode(char * path)4455c51f124SMoriah Waterland allocnode(char *path)
4465c51f124SMoriah Waterland {
4475c51f124SMoriah Waterland 	register int i;
4485c51f124SMoriah Waterland 	int	found;
4495c51f124SMoriah Waterland 	char	*pt;
4505c51f124SMoriah Waterland 
4515c51f124SMoriah Waterland 	if (path == NULL) {
4525c51f124SMoriah Waterland 		if (dirlist) {
4535c51f124SMoriah Waterland 			/*
4545c51f124SMoriah Waterland 			 * free everything
4555c51f124SMoriah Waterland 			 */
4565c51f124SMoriah Waterland 			for (i = 0; dirlist[i]; i++)
4575c51f124SMoriah Waterland 				free(dirlist[i]);
4585c51f124SMoriah Waterland 			free(dirlist);
4595c51f124SMoriah Waterland 		}
4605c51f124SMoriah Waterland 		dirlist = (char **)calloc(MALSIZ, sizeof (char *));
4615c51f124SMoriah Waterland 		if (dirlist == NULL) {
4625c51f124SMoriah Waterland 			progerr(gettext(ERR_MEMORY), errno);
4635c51f124SMoriah Waterland 			quit(99);
4645c51f124SMoriah Waterland 		}
4655c51f124SMoriah Waterland 		return;
4665c51f124SMoriah Waterland 	}
4675c51f124SMoriah Waterland 
4685c51f124SMoriah Waterland 	pt = path;
4695c51f124SMoriah Waterland 	if (*pt == '/')
4705c51f124SMoriah Waterland 		pt++;
4715c51f124SMoriah Waterland 	/*
4725c51f124SMoriah Waterland 	 * since the pathname supplied is never just a directory,
4735c51f124SMoriah Waterland 	 * we store only the dirname of of the path.
4745c51f124SMoriah Waterland 	 */
4755c51f124SMoriah Waterland 	while (pt = strchr(pt, '/')) {
4765c51f124SMoriah Waterland 		*pt = '\0';
4775c51f124SMoriah Waterland 		found = 0;
4785c51f124SMoriah Waterland 		for (i = 0; dirlist[i] != NULL; i++) {
4795c51f124SMoriah Waterland 			if (strcmp(path, dirlist[i]) == 0) {
4805c51f124SMoriah Waterland 				found++;
4815c51f124SMoriah Waterland 				break;
4825c51f124SMoriah Waterland 			}
4835c51f124SMoriah Waterland 		}
4845c51f124SMoriah Waterland 		if (!found) {
4855c51f124SMoriah Waterland 			/* insert this path in node list */
4865c51f124SMoriah Waterland 			dirlist[i] = qstrdup(path);
4875c51f124SMoriah Waterland 			if ((++i % MALSIZ) == 0) {
4885c51f124SMoriah Waterland 				dirlist = (char **)realloc(dirlist,
489*014740deSToomas Soome 				    (i+MALSIZ) * sizeof (char *));
4905c51f124SMoriah Waterland 				if (dirlist == NULL) {
4915c51f124SMoriah Waterland 					progerr(gettext(ERR_MEMORY), errno);
4925c51f124SMoriah Waterland 					quit(99);
4935c51f124SMoriah Waterland 				}
4945c51f124SMoriah Waterland 			}
4955c51f124SMoriah Waterland 			dirlist[i] = (char *)NULL;
4965c51f124SMoriah Waterland 		}
4975c51f124SMoriah Waterland 		*pt++ = '/';
4985c51f124SMoriah Waterland 	}
4995c51f124SMoriah Waterland }
5005c51f124SMoriah Waterland 
5015c51f124SMoriah Waterland static int
nodecount(char * path)5025c51f124SMoriah Waterland nodecount(char *path)
5035c51f124SMoriah Waterland {
5045c51f124SMoriah Waterland 	char	*pt;
5055c51f124SMoriah Waterland 	int	i, found, count;
5065c51f124SMoriah Waterland 
5075c51f124SMoriah Waterland 	pt = path;
5085c51f124SMoriah Waterland 	if (*pt == '/')
5095c51f124SMoriah Waterland 		pt++;
5105c51f124SMoriah Waterland 
5115c51f124SMoriah Waterland 	/*
5125c51f124SMoriah Waterland 	 * we want to count the number of path
5135c51f124SMoriah Waterland 	 * segments that need to be created, not
5145c51f124SMoriah Waterland 	 * including the basename of the path;
5155c51f124SMoriah Waterland 	 * this works only since we are never
5165c51f124SMoriah Waterland 	 * passed a pathname which itself is a
5175c51f124SMoriah Waterland 	 * directory
5185c51f124SMoriah Waterland 	 */
5195c51f124SMoriah Waterland 	count = 0;
5205c51f124SMoriah Waterland 	while (pt = strchr(pt, '/')) {
5215c51f124SMoriah Waterland 		*pt = '\0';
5225c51f124SMoriah Waterland 		found = 0;
5235c51f124SMoriah Waterland 		for (i = 0; dirlist[i]; i++) {
5245c51f124SMoriah Waterland 			if (strcmp(path, dirlist[i]) != 0) {
5255c51f124SMoriah Waterland 				found++;
5265c51f124SMoriah Waterland 				break;
5275c51f124SMoriah Waterland 			}
5285c51f124SMoriah Waterland 		}
5295c51f124SMoriah Waterland 		if (!found)
5305c51f124SMoriah Waterland 			count++;
5315c51f124SMoriah Waterland 		*pt++ = '/';
5325c51f124SMoriah Waterland 	}
5335c51f124SMoriah Waterland 	return (count);
5345c51f124SMoriah Waterland }
5355c51f124SMoriah Waterland 
5365c51f124SMoriah Waterland static void
newvolume(struct data ** sf,unsigned int eptnum,fsblkcnt_t limit,fsblkcnt_t ilimit)5375c51f124SMoriah Waterland newvolume(struct data **sf, unsigned int eptnum, fsblkcnt_t limit,
5385c51f124SMoriah Waterland     fsblkcnt_t ilimit)
5395c51f124SMoriah Waterland {
5405c51f124SMoriah Waterland 	register int i;
5415c51f124SMoriah Waterland 	int	newnodes;
5425c51f124SMoriah Waterland 
5435c51f124SMoriah Waterland 	if (volno) {
5445c51f124SMoriah Waterland 		(void) fprintf(stderr,
5455c51f124SMoriah Waterland 		    gettext("part %2d -- %llu blocks, %llu entries\n"),
5465c51f124SMoriah Waterland 		    volno, btotal, ftotal);
5475c51f124SMoriah Waterland 		if (btotal > bmax)
5485c51f124SMoriah Waterland 			bmax = btotal;
5495c51f124SMoriah Waterland 		if (ftotal > fmax)
5505c51f124SMoriah Waterland 			fmax = ftotal;
5515c51f124SMoriah Waterland 		btotal = bpkginfo + 2ULL;
5525c51f124SMoriah Waterland 		ftotal = 2;
5535c51f124SMoriah Waterland 	} else {
5545c51f124SMoriah Waterland 		btotal = 2ULL;
5555c51f124SMoriah Waterland 		ftotal = 1;
5565c51f124SMoriah Waterland 	}
5575c51f124SMoriah Waterland 	volno++;
5585c51f124SMoriah Waterland 
5595c51f124SMoriah Waterland 	/*
5605c51f124SMoriah Waterland 	 * zero out directory storage
5615c51f124SMoriah Waterland 	 */
5625c51f124SMoriah Waterland 	allocnode((char *)0);
5635c51f124SMoriah Waterland 
5645c51f124SMoriah Waterland 	/*
5655c51f124SMoriah Waterland 	 * force storage of files whose volume number has already been assigned
5665c51f124SMoriah Waterland 	 */
5675c51f124SMoriah Waterland 	for (i = 0; i < eptnum; i++) {
5685c51f124SMoriah Waterland 		if (sf[i]->ept->volno == volno) {
5695c51f124SMoriah Waterland 			newnodes = nodecount(sf[i]->ept->path);
5705c51f124SMoriah Waterland 			ftotal += newnodes + 1;
5715c51f124SMoriah Waterland 			btotal += sf[i]->blks + (newnodes * DIRSIZE);
5725c51f124SMoriah Waterland 			if (btotal > limit) {
5735c51f124SMoriah Waterland 				progerr(gettext(ERR_VOLBLKS), volno, btotal,
574*014740deSToomas Soome 				    limit);
5755c51f124SMoriah Waterland 				quit(1);
5765c51f124SMoriah Waterland 			} else if ((ilimit == 0) && (ftotal+1 > ilimit)) {
5775c51f124SMoriah Waterland 				progerr(gettext(ERR_VOLFILES), volno, ftotal+1,
5785c51f124SMoriah Waterland 				    ilimit);
5795c51f124SMoriah Waterland 				quit(1);
5805c51f124SMoriah Waterland 			}
5815c51f124SMoriah Waterland 		}
5825c51f124SMoriah Waterland 	}
5835c51f124SMoriah Waterland }
5845c51f124SMoriah Waterland 
5855c51f124SMoriah Waterland static void
addclass(char * aclass,int vol)5865c51f124SMoriah Waterland addclass(char *aclass, int vol)
5875c51f124SMoriah Waterland {
5885c51f124SMoriah Waterland 	int i;
5895c51f124SMoriah Waterland 
5905c51f124SMoriah Waterland 	for (i = 0; i < nclass; ++i) {
5915c51f124SMoriah Waterland 		if (strcmp(cl[i].name, aclass) == 0) {
5925c51f124SMoriah Waterland 			if (vol <= 0)
5935c51f124SMoriah Waterland 				return;
5945c51f124SMoriah Waterland 			if (!cl[i].first || (vol < cl[i].first))
5955c51f124SMoriah Waterland 				cl[i].first = vol;
5965c51f124SMoriah Waterland 			if (vol > cl[i].last)
5975c51f124SMoriah Waterland 				cl[i].last = vol;
5985c51f124SMoriah Waterland 			return;
5995c51f124SMoriah Waterland 		}
6005c51f124SMoriah Waterland 	}
6015c51f124SMoriah Waterland 	cl[nclass].name = qstrdup(aclass);
6025c51f124SMoriah Waterland 	cl[nclass].first = vol;
6035c51f124SMoriah Waterland 	cl[nclass].last = vol;
6045c51f124SMoriah Waterland 	if ((++nclass % MALSIZ) == 0) {
6055c51f124SMoriah Waterland 		cl = (struct class_type *)realloc((char *)cl,
606*014740deSToomas Soome 		    sizeof (struct class_type) * (nclass+MALSIZ));
6075c51f124SMoriah Waterland 		if (!cl) {
6085c51f124SMoriah Waterland 			progerr(gettext(ERR_MEMORY), errno);
6095c51f124SMoriah Waterland 			quit(99);
6105c51f124SMoriah Waterland 		}
6115c51f124SMoriah Waterland 	}
6125c51f124SMoriah Waterland }
6135c51f124SMoriah Waterland 
6145c51f124SMoriah Waterland static void
sortsize(struct data * f,struct data ** sf,unsigned int eptnum)6155c51f124SMoriah Waterland sortsize(struct data *f, struct data **sf, unsigned int eptnum)
6165c51f124SMoriah Waterland {
6175c51f124SMoriah Waterland 	int	nsf;
6185c51f124SMoriah Waterland 	int	j, k;
6195c51f124SMoriah Waterland 	unsigned int	i;
6205c51f124SMoriah Waterland 
6215c51f124SMoriah Waterland 	nsf = 0;
6225c51f124SMoriah Waterland 	for (i = 0; i < eptnum; i++) {
6235c51f124SMoriah Waterland 		for (j = 0; j < nsf; ++j) {
6245c51f124SMoriah Waterland 			if (f[i].blks > sf[j]->blks) {
6255c51f124SMoriah Waterland 				for (k = nsf; k > j; k--) {
6265c51f124SMoriah Waterland 					sf[k] = sf[k-1];
6275c51f124SMoriah Waterland 				}
6285c51f124SMoriah Waterland 				break;
6295c51f124SMoriah Waterland 			}
6305c51f124SMoriah Waterland 		}
6315c51f124SMoriah Waterland 		sf[j] = &f[i];
6325c51f124SMoriah Waterland 		nsf++;
6335c51f124SMoriah Waterland 	}
6345c51f124SMoriah Waterland }
635