BSD 4_4 release
[unix-history] / usr / src / usr.sbin / config.new / pack.c
CommitLineData
5073ce2e 1/*
ad787160
C
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5073ce2e
CT
4 *
5 * This software was developed by the Computer Systems Engineering group
6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
7 * contributed to Berkeley.
8 *
9 * All advertising materials mentioning features or use of this software
10 * must display the following acknowledgement:
11 * This product includes software developed by the University of
12 * California, Lawrence Berkeley Laboratories.
13 *
ad787160
C
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. All advertising materials mentioning features or use of this software
23 * must display the following acknowledgement:
24 * This product includes software developed by the University of
25 * California, Berkeley and its contributors.
26 * 4. Neither the name of the University nor the names of its contributors
27 * may be used to endorse or promote products derived from this software
28 * without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * SUCH DAMAGE.
5073ce2e 41 *
ad787160 42 * @(#)pack.c 8.1 (Berkeley) 6/6/93
5073ce2e
CT
43 */
44
45#include <sys/param.h>
46#include <stdlib.h>
47#include <string.h>
48#include "config.h"
49
50/*
51 * Packing. We have three separate kinds of packing here.
52 *
53 * First, we pack device instances, to collapse things like
54 *
55 * uba0 at sbi0 nexus ?
56 * uba0 at bi0 nexus ?
57 *
58 * into a single instance that is "at sbi0 or bi0".
59 *
60 * Second, we pack locators. Given something like
61 *
62 * hp0 at mba0 drive 0
63 * hp* at mba* drive ?
64 * ht0 at mba0 drive 0
65 * tu0 at ht0 slave 0
66 * ht* at mba* drive ?
67 * tu* at ht* slave ?
68 *
69 * (where the default drive and slave numbers are -1), we have three
70 * locators whose value is 0 and three whose value is -1. Rather than
71 * emitting six integers, we emit just two.
72 *
73 * Finally, we pack parent vectors. This is very much like packing
74 * locators. Unlike locators, however, parent vectors are always
75 * terminated by -1 (rather like the way C strings always end with
76 * a NUL).
77 *
78 * When packing locators, we would like to find sequences such as
79 * {1 2 3} {2 3 4} {3} {4 5}
80 * and turn this into the flat sequence {1 2 3 4 5}, with each subsequence
81 * given by the appropriate offset (here 0, 1, 2, and 3 respectively).
82 * When we pack parent vectors, overlap of this sort is impossible.
83 * Non-overlapping packing is much easier, and so we use that here
84 * and miss out on the chance to squeeze the locator sequence optimally.
85 * (So it goes.)
86 */
87
88typedef int (*vec_cmp_func) __P((const void *, int, int));
89
90#define TAILHSIZE 128
91#define PVHASH(i) ((i) & (TAILHSIZE - 1))
92#define LOCHASH(l) (((int)(l) >> 2) & (TAILHSIZE - 1))
93struct tails {
94 struct tails *t_next;
95 int t_ends_at;
96};
97
98static struct tails *tails[TAILHSIZE];
99static int locspace;
100static int pvecspace;
101static int longest_pvec;
102
103static void packdevi __P((void));
104static void packlocs __P((void));
105static void packpvec __P((void));
106
107static void addparents __P((struct devi *src, struct devi *dst));
108static int nparents __P((struct devi **, struct devbase *, int));
109static int sameas __P((struct devi *, struct devi *));
110static int findvec __P((const void *, int, int, vec_cmp_func, int));
111static int samelocs __P((const void *, int, int));
112static int addlocs __P((const char **, int));
113static int loclencmp __P((const void *, const void *));
114static int samepv __P((const void *, int, int));
115static int addpv __P((short *, int));
116static int pvlencmp __P((const void *, const void *));
117static void resettails __P((void));
118
119void
120pack()
121{
122 register struct devi *i;
123 register int n;
124
125 /* Pack instances and make parent vectors. */
126 packdevi();
127
128 /*
129 * Now that we know what we have, find upper limits on space
130 * needed for the loc[] and pv[] tables, and find the longest
131 * single pvec. The loc and pv table sizes are bounded by
132 * what we would get if no packing occurred.
133 */
134 locspace = pvecspace = 0;
135 for (i = alldevi; i != NULL; i = i->i_next) {
136 if (i->i_collapsed)
137 continue;
138 locspace += i->i_atattr->a_loclen;
139 n = i->i_pvlen + 1;
140 if (n > longest_pvec)
141 longest_pvec = n;
142 pvecspace += n;
143 }
144
145 /* Allocate and pack loc[]. */
146 locators.vec = emalloc(locspace * sizeof(*locators.vec));
147 locators.used = 0;
148 packlocs();
149
150 /* Allocate and pack pv[]. */
151 parents.vec = emalloc(pvecspace * sizeof(*parents.vec));
152 parents.used = 0;
153 packpvec();
154}
155
156/*
157 * Pack instances together wherever possible. When everything is
158 * packed, go back and set up the parents for each. We must do this
159 * on a second pass because during the first one, we do not know which,
160 * if any, of the parents will collapse during packing.
161 */
162void
163packdevi()
164{
165 register struct devi *i, *l, *p;
166 register struct devbase *d;
167 register int j, m, n;
168
169 packed = emalloc((ndevi + 1) * sizeof *packed);
170 n = 0;
171 for (d = allbases; d != NULL; d = d->d_next) {
172 /*
173 * For each instance of each device, add or collapse
174 * all its aliases.
175 */
176 for (i = d->d_ihead; i != NULL; i = i->i_bsame) {
177 m = n;
178 for (l = i; l != NULL; l = l->i_alias) {
179 l->i_pvlen = 0;
180 l->i_pvoff = -1;
181 l->i_locoff = -1;
182 l->i_ivoff = -1;
183 /* try to find an equivalent for l */
184 for (j = m; j < n; j++) {
185 p = packed[j];
186 if (sameas(l, p)) {
187 l->i_collapsed = 1;
188 l->i_cfindex = p->i_cfindex;
189 goto nextalias;
190 }
191 }
192 /* could not find a suitable alias */
193 l->i_collapsed = 0;
194 l->i_cfindex = n;
195 l->i_parents = emalloc(sizeof(*l->i_parents));
196 l->i_parents[0] = NULL;
197 packed[n++] = l;
198 nextalias:;
199 }
200 }
201 }
202 npacked = n;
203 packed[n] = NULL;
204 for (i = alldevi; i != NULL; i = i->i_next)
205 addparents(i, packed[i->i_cfindex]);
206}
207
208/*
209 * Return true if two aliases are "the same". In this case, they need
210 * to have the same config flags and the same locators.
211 */
212static int
213sameas(i1, i2)
214 register struct devi *i1, *i2;
215{
216 register const char **p1, **p2;
217
218 if (i1->i_cfflags != i2->i_cfflags)
219 return (0);
220 for (p1 = i1->i_locs, p2 = i2->i_locs; *p1 == *p2; p2++)
221 if (*p1++ == 0)
222 return (1);
223 return 0;
224}
225
226/*
227 * Add the parents associated with "src" to the (presumably uncollapsed)
228 * instance "dst".
229 */
230static void
231addparents(src, dst)
232 register struct devi *src, *dst;
233{
234 register struct nvlist *nv;
235 register struct devi *i, **p, **q;
236 register int j, n, old, new, ndup;
237
238 if (dst->i_collapsed)
239 panic("addparents() i_collapsed");
240
241 /* Collect up list of parents to add. */
242 if (src->i_at == NULL) /* none, 'cuz "at root" */
243 return;
244 if (src->i_atdev != NULL) {
245 n = nparents(NULL, src->i_atdev, src->i_atunit);
246 p = emalloc(n * sizeof *p);
247 if (n == 0)
248 return;
249 (void)nparents(p, src->i_atdev, src->i_atunit);
250 } else {
251 n = 0;
252 for (nv = src->i_atattr->a_refs; nv != NULL; nv = nv->nv_next)
253 n += nparents(NULL, nv->nv_ptr, src->i_atunit);
254 if (n == 0)
255 return;
256 p = emalloc(n * sizeof *p);
257 n = 0;
258 for (nv = src->i_atattr->a_refs; nv != NULL; nv = nv->nv_next)
259 n += nparents(p + n, nv->nv_ptr, src->i_atunit);
260 }
261 /* Now elide duplicates. */
262 ndup = 0;
263 for (j = 0; j < n; j++) {
264 i = p[j];
265 for (q = dst->i_parents; *q != NULL; q++) {
266 if (*q == i) {
267 ndup++;
268 p[j] = NULL;
269 break;
270 }
271 }
272 }
273 /* Finally, add all the non-duplicates. */
274 old = dst->i_pvlen;
275 new = old + (n - ndup);
276 if (old > new)
277 panic("addparents() old > new");
278 if (old == new) {
279 free(p);
280 return;
281 }
282 dst->i_parents = q = erealloc(dst->i_parents, (new + 1) * sizeof(*q));
283 dst->i_pvlen = new;
284 q[new] = NULL;
285 q += old;
286 for (j = 0; j < n; j++)
287 if (p[j] != NULL)
288 *q++ = p[j];
289 free(p);
290}
291
292/*
293 * Count up parents, and optionally store pointers to each.
294 */
295static int
296nparents(p, dev, unit)
297 register struct devi **p;
298 register struct devbase *dev;
299 register int unit;
300{
301 register struct devi *i, *l;
302 register int n;
303
304 n = 0;
305 /* for each instance ... */
306 for (i = dev->d_ihead; i != NULL; i = i->i_bsame) {
307 /* ... take each un-collapsed alias */
308 for (l = i; l != NULL; l = l->i_alias) {
309 if (!l->i_collapsed &&
310 (unit == WILD || unit == l->i_unit)) {
311 if (p != NULL)
312 *p++ = l;
313 n++;
314 }
315 }
316 }
317 return (n);
318}
319
320static void
321packlocs()
322{
323 register struct devi **p, *i;
324 register int l, o;
325
326 qsort(packed, npacked, sizeof *packed, loclencmp);
327 for (p = packed; (i = *p) != NULL; p++) {
328 if ((l = i->i_atattr->a_loclen) > 0) {
329 o = findvec(i->i_locs, LOCHASH(i->i_locs[l - 1]), l,
330 samelocs, locators.used);
331 i->i_locoff = o < 0 ? addlocs(i->i_locs, l) : o;
332 } else
333 i->i_locoff = -1;
334 }
335 resettails();
336}
337
338static void
339packpvec()
340{
341 register struct devi **p, *i, **par;
342 register int l, v, o;
343 register short *vec;
344
345 vec = emalloc(longest_pvec * sizeof(*vec));
346 qsort(packed, npacked, sizeof *packed, pvlencmp);
347 for (p = packed; (i = *p) != NULL; p++) {
348 l = i->i_pvlen;
349if (l > longest_pvec) panic("packpvec");
350 par = i->i_parents;
351 for (v = 0; v < l; v++)
352 vec[v] = par[v]->i_cfindex;
353 if (l == 0 ||
354 (o = findvec(vec, PVHASH(vec[l - 1]), l,
355 samepv, parents.used)) < 0)
356 o = addpv(vec, l);
357 i->i_pvoff = o;
358 }
359 free(vec);
360 resettails();
361}
362
363/*
364 * Return the index at which the given vector already exists, or -1
365 * if it is not anywhere in the current set. If we return -1, we assume
366 * our caller will add it at the end of the current set, and we make
367 * sure that next time, we will find it there.
368 */
369static int
370findvec(ptr, hash, len, cmp, nextplace)
371 const void *ptr;
372 int hash, len;
373 vec_cmp_func cmp;
374 int nextplace;
375{
376 register struct tails *t, **hp;
377 register int off;
378
379 hp = &tails[hash];
380 for (t = *hp; t != NULL; t = t->t_next) {
381 off = t->t_ends_at - len;
382 if (off >= 0 && (*cmp)(ptr, off, len))
383 return (off);
384 }
385 t = emalloc(sizeof(*t));
386 t->t_next = *hp;
387 *hp = t;
388 t->t_ends_at = nextplace + len;
389 return (-1);
390}
391
392/*
393 * Comparison function for locators.
394 */
395static int
396samelocs(ptr, off, len)
397 const void *ptr;
398 int off;
399 register int len;
400{
401 register const char **p, **q;
402
403 for (p = &locators.vec[off], q = (const char **)ptr; --len >= 0;)
404 if (*p++ != *q++)
405 return (0); /* different */
406 return (1); /* same */
407}
408
409/*
410 * Add the given locators at the end of the global loc[] table.
411 */
412static int
413addlocs(locs, len)
414 register const char **locs;
415 register int len;
416{
417 register const char **p;
418 register int ret;
419
420 ret = locators.used;
421 if ((locators.used = ret + len) > locspace)
422 panic("addlocs: overrun");
423 for (p = &locators.vec[ret]; --len >= 0;)
424 *p++ = *locs++;
425 return (ret);
426}
427
428/*
429 * Comparison function for qsort-by-locator-length, longest first.
430 * We rashly assume that subtraction of these lengths does not overflow.
431 */
432static int
433loclencmp(a, b)
434 const void *a, *b;
435{
436 register int l1, l2;
437
438 l1 = (*(struct devi **)a)->i_atattr->a_loclen;
439 l2 = (*(struct devi **)b)->i_atattr->a_loclen;
440 return (l2 - l1);
441}
442
443/*
444 * Comparison function for parent vectors.
445 */
446static int
447samepv(ptr, off, len)
448 const void *ptr;
449 int off;
450 register int len;
451{
452 register short *p, *q;
453
454 for (p = &parents.vec[off], q = (short *)ptr; --len >= 0;)
455 if (*p++ != *q++)
456 return (0); /* different */
457 return (1); /* same */
458}
459
460/*
461 * Add the given parent vectors at the end of the global pv[] table.
462 */
463static int
464addpv(pv, len)
465 register short *pv;
466 register int len;
467{
468 register short *p;
469 register int ret;
470 static int firstend = -1;
471
472 /*
473 * If the vector is empty, reuse the first -1. It will be
474 * there if there are any nonempty vectors at all, since we
475 * do the longest first. If there are no nonempty vectors,
476 * something is probably wrong, but we will ignore that here.
477 */
478 if (len == 0 && firstend >= 0)
479 return (firstend);
480 len++; /* account for trailing -1 */
481 ret = parents.used;
482 if ((parents.used = ret + len) > pvecspace)
483 panic("addpv: overrun");
484 for (p = &parents.vec[ret]; --len > 0;)
485 *p++ = *pv++;
486 *p = -1;
487 if (firstend < 0)
488 firstend = parents.used - 1;
489 return (ret);
490}
491
492/*
493 * Comparison function for qsort-by-parent-vector-length, longest first.
494 * We rashly assume that subtraction of these lengths does not overflow.
495 */
496static int
497pvlencmp(a, b)
498 const void *a, *b;
499{
500 register int l1, l2;
501
502 l1 = (*(struct devi **)a)->i_pvlen;
503 l2 = (*(struct devi **)b)->i_pvlen;
504 return (l2 - l1);
505}
506
507static void
508resettails()
509{
510 register struct tails **p, *t, *next;
511 register int i;
512
513 for (p = tails, i = TAILHSIZE; --i >= 0; p++) {
514 for (t = *p; t != NULL; t = next) {
515 next = t->t_next;
516 free(t);
517 }
518 *p = NULL;
519 }
520}