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.
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.
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]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
37 #include <sys/types.h>
38 #include <sys/param.h>
47 extern struct pkgdev pkgdev
;
50 #define EFACTOR 128ULL /* typical size of a single entry in a pkgmap file */
52 #define WRN_LIMIT "WARNING: -l limit (%llu blocks) exceeds device " \
53 "capacity (%llu blocks)"
54 #define ERR_MEMORY "memory allocation failure, errno=%d"
55 #define ERR_TOOBIG "%s (%llu blocks) does not fit on a volume"
56 #define ERR_INFOFIRST "information file <%s> must appear on first part"
57 #define ERR_INFOSPACE "all install files must appear on first part"
58 #define ERR_VOLBLKS "Objects selected for part %d require %llu blocks, " \
60 #define ERR_VOLFILES "Objects selected for part %d require %llu files, " \
62 #define ERR_FREE "package does not fit space currently available in <%s>"
75 static fsblkcnt_t btotal
; /* blocks stored on current part */
76 static fsblkcnt_t bmax
; /* maximum number of blocks on any part */
78 static fsfilcnt_t ftotal
; /* files stored on current part */
79 static fsfilcnt_t fmax
; /* maximum number of files on any part */
80 static fsblkcnt_t bpkginfo
; /* blocks used by pkginfo file */
81 static char **dirlist
;
82 static short volno
; /* current part */
83 static int nparts
= -1; /* total number of parts */
85 static fsblkcnt_t DIRSIZE
;
86 static struct class_type
*cl
;
88 static int nodecount(char *path
);
89 static int store(struct data
**, unsigned int, char *, fsblkcnt_t
,
91 static void addclass(char *aclass
, int vol
);
92 static void allocnode(char *path
);
93 static void newvolume(struct data
**, unsigned int, fsblkcnt_t limit
,
95 static void sortsize(struct data
*f
, struct data
**sf
, unsigned int eptnum
);
98 splpkgmap(struct cfent
**eptlist
, unsigned int eptnum
, char *order
[],
99 ulong_t bsize
, ulong_t frsize
, fsblkcnt_t
*plimit
, fsfilcnt_t
*pilimit
,
102 struct data
*f
, **sf
;
112 f
= (struct data
*)calloc(eptnum
, sizeof (struct data
));
114 progerr(gettext(ERR_MEMORY
), errno
);
118 sf
= (struct data
**)calloc(eptnum
, sizeof (struct data
*));
120 progerr(gettext(ERR_MEMORY
), errno
);
125 cl
= (struct class_type
*)calloc(MALSIZ
, sizeof (struct class_type
));
127 progerr(gettext(ERR_MEMORY
), errno
);
134 * The next bit of code checks to see if, when creating a package
135 * on a directory, there are enough free blocks and inodes before
140 * DIRSIZE takes up 1 logical block, iff we have no frags, else
141 * it just takes a frag
143 DIRSIZE
= ((fsblkcnt_t
)frsize
> 0) ?
144 howmany(frsize
, DEV_BSIZE
) :
145 howmany(bsize
, DEV_BSIZE
);
150 * If we appear to have a valid value for free inodes
151 * and there's not enough for the package contents,
154 if ((*pilimit
> 0) && (eptnum
+1 > *pilimit
)) {
155 progerr(gettext(ERR_FREE
), pkgdev
.dirname
);
158 for (i
= 0; i
< eptnum
; i
++) {
159 if (strchr("dxslcbp", eptlist
[i
]->ftype
))
163 (nodecount(eptlist
[i
]->path
) * DIRSIZE
);
165 nblk(eptlist
[i
]->cinfo
.size
, bsize
, frsize
);
166 if (total
> *plimit
) {
167 progerr(gettext(ERR_FREE
),
171 allocnode(eptlist
[i
]->path
);
176 * if there is a value in pllimit (-l specified limit), use that for
177 * the limit from now on.
181 if (pkgdev
.mount
&& *pllimit
> *plimit
)
182 logerr(gettext(WRN_LIMIT
), *pllimit
, *plimit
);
186 * calculate number of physical blocks used by each object
188 for (i
= 0; i
< eptnum
; i
++) {
189 f
[i
].ept
= ept
= eptlist
[i
];
190 if (ept
->volno
> nparts
)
192 addclass(ept
->pkg_class
, 0);
193 if (strchr("dxslcbp", ept
->ftype
))
195 * virtual object (no contents)
202 * (directories are space consumers as well, but they
203 * get accounted for later).
207 f
[i
].blks
= nblk(ept
->cinfo
.size
, bsize
, frsize
);
209 if (!bpkginfo
&& (strcmp(f
[i
].ept
->path
, "pkginfo") == 0))
210 bpkginfo
= f
[i
].blks
;
214 * Make sure that items slated for a given 'part' do not exceed a single
217 for (i
= 1; i
<= nparts
; i
++) {
218 btemp
= (bpkginfo
+ 2LL);
222 * save room for install directory
225 btemp
+= nblk(eptnum
* EFACTOR
, bsize
, frsize
);
229 for (j
= 0; j
< eptnum
; j
++) {
230 if (i
== 1 && f
[j
].ept
->ftype
== 'i' &&
231 (strcmp(f
[j
].ept
->path
, "pkginfo") == 0 ||
232 strcmp(f
[j
].ept
->path
, "pkgmap") == 0))
234 if (f
[j
].ept
->volno
== i
||
235 (f
[j
].ept
->ftype
== 'i' && i
== 1)) {
236 ftemp
+= nodecount(f
[j
].ept
->path
);
238 allocnode(f
[j
].ept
->path
);
241 btemp
+= (ftemp
* DIRSIZE
);
242 if (btemp
> *plimit
) {
243 progerr(gettext(ERR_VOLBLKS
), i
, btemp
, *plimit
);
245 /* If we have a valid inode limit, ensure this part will fit */
246 } else if ((*pilimit
> 0) && (ftemp
+1 > *pilimit
)) {
247 progerr(gettext(ERR_VOLFILES
), i
, ftemp
+ 1, *pilimit
);
255 * "sf" - array sorted in decreasing file size order, based on "f".
257 sortsize(f
, sf
, eptnum
);
260 * initialize first volume
262 newvolume(sf
, eptnum
, *plimit
, *pilimit
);
265 * reserve room on first volume for pkgmap
267 btotal
+= nblk((fsblkcnt_t
)(eptnum
* EFACTOR
), bsize
, frsize
);
272 * initialize directory info
277 * place installation files on first volume!
280 for (j
= 0; j
< eptnum
; ++j
) {
281 if (f
[j
].ept
->ftype
!= 'i')
285 * save room for install directory
290 if (!f
[j
].ept
->volno
) {
294 } else if (f
[j
].ept
->volno
!= 1) {
295 progerr(gettext(ERR_INFOFIRST
), f
[j
].ept
->path
);
302 if (btotal
> *plimit
) {
303 progerr(gettext(ERR_INFOSPACE
));
308 * Make sure that any given file will fit on a single volume, this
309 * calculation has to take into account packaging overhead, otherwise
310 * the function store() will go into a severe recursive plunge.
312 for (j
= 0; j
< eptnum
; ++j
) {
314 * directory overhead.
316 btemp
= nodecount(f
[j
].ept
->path
) * DIRSIZE
;
318 * packaging overhead.
320 btemp
+= (bpkginfo
+ 2L); /* from newvolume() */
321 if ((f
[j
].blks
+ btemp
) > *plimit
) {
323 progerr(gettext(ERR_TOOBIG
), f
[j
].ept
->path
, f
[j
].blks
);
330 * place classes listed on command line
333 for (i
= 0; order
[i
]; ++i
) {
334 while (store(sf
, eptnum
, order
[i
], *plimit
, *pilimit
))
335 /* stay in loop until store is complete */
340 while (store(sf
, eptnum
, (char *)0, *plimit
, *pilimit
))
341 /* stay in loop until store is complete */
345 * place all virtual objects, e.g. links and spec devices
347 for (i
= 0; i
< nclass
; ++i
) {
349 * if no objects were associated, attempt to
350 * distribute in order of class list
352 if (cl
[i
].first
== 0)
353 cl
[i
].last
= cl
[i
].first
= (i
? cl
[i
-1].last
: 1);
354 for (j
= 0; j
< eptnum
; j
++) {
355 if ((f
[j
].ept
->volno
== 0) &&
356 strcmp(f
[j
].ept
->pkg_class
, cl
[i
].name
) == 0) {
357 if (strchr("sl", f
[j
].ept
->ftype
))
358 f
[j
].ept
->volno
= cl
[i
].last
;
360 f
[j
].ept
->volno
= cl
[i
].first
;
366 newvolume(sf
, eptnum
, *plimit
, *pilimit
);
368 if (nparts
> (volno
- 1)) {
370 for (i
= volno
; i
<= nparts
; i
++) {
372 for (j
= 0; j
< eptnum
; j
++) {
373 if (f
[j
].ept
->volno
== i
) {
374 f
[j
].ept
->volno
= new_vol
;
378 new_vol
+= new_vol_set
;
380 nparts
= new_vol
- 1;
388 * free up dynamic space used by this module
392 for (i
= 0; i
< nclass
; ++i
)
395 for (i
= 0; dirlist
[i
]; i
++)
399 return (errflg
? -1 : nparts
);
403 store(struct data
**sf
, unsigned int eptnum
, char *aclass
, fsblkcnt_t limit
,
406 int i
, svnodes
, choice
, select
;
412 for (i
= 0; i
< eptnum
; ++i
) {
413 if (sf
[i
]->ept
->volno
|| strchr("sldxcbp", sf
[i
]->ept
->ftype
))
414 continue; /* defer storage until class is selected */
415 if (aclass
&& strcmp(aclass
, sf
[i
]->ept
->pkg_class
))
417 select
++; /* we need to place at least one object */
418 ftemp
= nodecount(sf
[i
]->ept
->path
);
419 btemp
= sf
[i
]->blks
+ (ftemp
* DIRSIZE
);
420 if (((limit
== 0) || ((btotal
+ btemp
) <= limit
)) &&
421 ((ilimit
== 0) || ((ftotal
+ ftemp
) < ilimit
))) {
422 /* largest object which fits on this volume */
429 return (0); /* no more to objects to place */
432 newvolume(sf
, eptnum
, limit
, ilimit
);
433 return (store(sf
, eptnum
, aclass
, limit
, ilimit
));
435 sf
[choice
]->ept
->volno
= (char)volno
;
436 ftotal
+= svnodes
+ 1;
437 btotal
+= sf
[choice
]->blks
+ (svnodes
* DIRSIZE
);
438 allocnode(sf
[i
]->ept
->path
);
439 addclass(sf
[choice
]->ept
->pkg_class
, volno
);
440 return (++choice
); /* return non-zero if more work to do */
444 allocnode(char *path
)
455 for (i
= 0; dirlist
[i
]; i
++)
459 dirlist
= (char **)calloc(MALSIZ
, sizeof (char *));
460 if (dirlist
== NULL
) {
461 progerr(gettext(ERR_MEMORY
), errno
);
471 * since the pathname supplied is never just a directory,
472 * we store only the dirname of of the path.
474 while (pt
= strchr(pt
, '/')) {
477 for (i
= 0; dirlist
[i
] != NULL
; i
++) {
478 if (strcmp(path
, dirlist
[i
]) == 0) {
484 /* insert this path in node list */
485 dirlist
[i
] = qstrdup(path
);
486 if ((++i
% MALSIZ
) == 0) {
487 dirlist
= (char **)realloc(dirlist
,
488 (i
+MALSIZ
) * sizeof (char *));
489 if (dirlist
== NULL
) {
490 progerr(gettext(ERR_MEMORY
), errno
);
494 dirlist
[i
] = (char *)NULL
;
501 nodecount(char *path
)
511 * we want to count the number of path
512 * segments that need to be created, not
513 * including the basename of the path;
514 * this works only since we are never
515 * passed a pathname which itself is a
519 while (pt
= strchr(pt
, '/')) {
522 for (i
= 0; dirlist
[i
]; i
++) {
523 if (strcmp(path
, dirlist
[i
]) != 0) {
536 newvolume(struct data
**sf
, unsigned int eptnum
, fsblkcnt_t limit
,
543 (void) fprintf(stderr
,
544 gettext("part %2d -- %llu blocks, %llu entries\n"),
545 volno
, btotal
, ftotal
);
550 btotal
= bpkginfo
+ 2ULL;
559 * zero out directory storage
561 allocnode((char *)0);
564 * force storage of files whose volume number has already been assigned
566 for (i
= 0; i
< eptnum
; i
++) {
567 if (sf
[i
]->ept
->volno
== volno
) {
568 newnodes
= nodecount(sf
[i
]->ept
->path
);
569 ftotal
+= newnodes
+ 1;
570 btotal
+= sf
[i
]->blks
+ (newnodes
* DIRSIZE
);
571 if (btotal
> limit
) {
572 progerr(gettext(ERR_VOLBLKS
), volno
, btotal
,
575 } else if ((ilimit
== 0) && (ftotal
+1 > ilimit
)) {
576 progerr(gettext(ERR_VOLFILES
), volno
, ftotal
+1,
585 addclass(char *aclass
, int vol
)
589 for (i
= 0; i
< nclass
; ++i
) {
590 if (strcmp(cl
[i
].name
, aclass
) == 0) {
593 if (!cl
[i
].first
|| (vol
< cl
[i
].first
))
595 if (vol
> cl
[i
].last
)
600 cl
[nclass
].name
= qstrdup(aclass
);
601 cl
[nclass
].first
= vol
;
602 cl
[nclass
].last
= vol
;
603 if ((++nclass
% MALSIZ
) == 0) {
604 cl
= (struct class_type
*)realloc((char *)cl
,
605 sizeof (struct class_type
) * (nclass
+MALSIZ
));
607 progerr(gettext(ERR_MEMORY
), errno
);
614 sortsize(struct data
*f
, struct data
**sf
, unsigned int eptnum
)
621 for (i
= 0; i
< eptnum
; i
++) {
622 for (j
= 0; j
< nsf
; ++j
) {
623 if (f
[i
].blks
> sf
[j
]->blks
) {
624 for (k
= nsf
; k
> j
; k
--) {