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.
28 * 4.x ld.so directory caching: run-time link-editor specific functions.
37 #include "cache_a.out.h"
45 static int extract_name();
48 static struct link_object
*get_lo();
49 static struct dbd
*new_dbd();
50 static struct db
*find_so();
52 #define SKIP_DOT(str) ((*str == '.') ? ++str : str)
53 #define EMPTY(str) ((str == NULL) || (*str == '\0'))
54 #define isdigit(c) (((c) >= '0') && ((c) <= '9') ? 1:0)
56 static struct dbd
*dbd_head
= NULL
; /* head of data bases */
60 * Given a db - find the highest shared versioned object. The
61 * highest versioned object is the .so with a matching major number
62 * but the highest minor number
76 struct link_object
*tlop
;
80 if ((liblen
= extract_name(&n
)) == -1)
82 if ((libname
= malloc(liblen
+ 1)) == 0)
84 (void) strncpy(libname
, n
, liblen
);
85 libname
[liblen
] = NULL
;
87 if (strncmp(MSG_ORIG(MSG_FIL_DOTSODOT
), (n
+ liblen
),
88 MSG_FIL_DOTSODOT_SIZE
))
91 mnp
= mjp
= ((char *)file
+ MSG_FIL_LIB_SIZE
+ liblen
+
92 MSG_FIL_DOTSODOT_SIZE
);
93 if (!(stol(mjp
, '.', &mnp
, &major
) && (*mnp
== '.') &&
96 to_min
= mnp
- file
+ 1;
99 * Search appropriate hash bucket for a matching entry.
101 index
= hash(libname
, liblen
, major
);
102 for (ep
= (struct dbe
*)&(dbp
->db_hash
[index
]); (ep
&& ep
->dbe_lop
);
103 ep
= ep
->dbe_next
== 0 ? NULL
:
105 (struct dbe
*)&AP(dbp
)[ep
->dbe_next
]) {
107 tlop
= (struct link_object
*)&AP(dbp
)[ep
->dbe_lop
];
108 if (tlop
->lo_major
== major
)
109 if (strcmp((char *)&AP(dbp
)[tlop
->lo_name
],
115 * If no entry was found, we've lost.
117 if (!(ep
&& ep
->dbe_lop
))
119 if (verscmp(file
+ to_min
,
120 &AP(dbp
)[ep
->dbe_name
] + tlop
->lo_minor
) > 0)
121 eprintf(&lml_main
, ERR_WARNING
, MSG_INTL(MSG_GEN_OLDREV
),
122 &AP(dbp
)[ep
->dbe_name
], file
+ to_min
);
123 return (&AP(dbp
)[ep
->dbe_name
]);
127 * Given a directory name - give back a data base. The data base may have
128 * orginated from the mmapped file or temporarily created
131 lo_cache(const char *ds
)
133 struct db
*dbp
; /* database pointer */
134 struct dbd
*dbdp
; /* working database descriptor */
135 struct dbd
**dbdpp
; /* insertion pointer */
138 for (dbdp
= dbd_head
; dbdp
; dbdp
= dbdp
->dbd_next
) {
139 if (strcmp(ds
, &AP(dbdp
->dbd_db
)[dbdp
->dbd_db
->db_name
]) == 0)
140 return (dbdp
->dbd_db
);
141 dbdpp
= &dbdp
->dbd_next
;
143 if (dbp
= find_so(ds
)) {
144 (void) new_dbd(dbdpp
, dbp
);
150 * Build a database for the directory "ds".
153 find_so(const char *ds
)
155 int fd
; /* descriptor on directory */
156 int n
; /* bytes from getdents */
157 char *cp
; /* working char * */
158 rtld_stat_t sb
; /* buffer for stat'ing directory */
159 struct db
*dbp
; /* database */
160 static caddr_t buf
= NULL
; /* buffer for doing getdents */
161 static long bs
; /* cached blocksize for getdents */
162 struct link_object
*tlop
; /* working link object ptr. */
163 struct dirent
*dp
; /* directory entry ptr. */
164 struct dbe
*ep
; /* working db_entry ptr. */
165 char *mnp
; /* where minor version begins */
166 char *mjp
; /* where major version begins */
167 int m
; /* the major number */
168 int to_min
; /* index into string of minor */
169 int cplen
; /* length of X */
170 int index
; /* the hash value */
173 * Try to open directory. Failing that, just return silently.
175 if ((fd
= open(ds
, O_RDONLY
)) == -1)
179 * If we have not yet gotten a buffer for reading directories,
180 * allocate it now. Size it according to the most efficient size
181 * for the first directory we open successfully.
184 if (rtld_fstat(fd
, &sb
) == -1) {
193 * Have a directory, have a buffer. Allocate up a database
196 dbp
= calloc(sizeof (struct db
), 1);
197 dbp
->db_name
= RELPTR(dbp
, calloc((strlen(ds
) + 1), 1));
198 (void) strcpy((char *)&AP(dbp
)[dbp
->db_name
], ds
);
201 * Scan the directory looking for shared libraries. getdents()
202 * failures are silently ignored and terminate the scan.
205 while ((n
= getdents(fd
, (struct dirent
*)buf
, bs
)) > 0)
207 for (dp
= (struct dirent
*)buf
;
209 dp
&& (dp
< (struct dirent
*)(buf
+ n
));
211 dp
= (struct dirent
*)((dp
->d_reclen
== 0) ?
212 NULL
: (char *)dp
+ dp
->d_reclen
)) {
215 * If file starts with a "lib", then extract the X
219 if ((cplen
= extract_name(&cp
)) == -1)
223 * Is the next component ".so."?
225 if (strncmp(MSG_ORIG(MSG_FIL_DOTSODOT
), (cp
+ cplen
),
226 MSG_FIL_DOTSODOT_SIZE
))
230 * Check if next component is the major number and
231 * whether following components are legal.
233 mnp
= mjp
= (dp
->d_name
+ MSG_FIL_LIB_SIZE
+ cplen
+
234 MSG_FIL_DOTSODOT_SIZE
);
235 if (!(stol(mjp
, '.', &mnp
, &m
) && (*mnp
== '.') &&
238 to_min
= mnp
- dp
->d_name
+ 1;
241 * Have libX.so.major.minor - attempt to add it to the
242 * cache. If there is another with the same major
243 * number then the chose the object with the highest
246 index
= hash(cp
, cplen
, m
);
247 ep
= &(dbp
->db_hash
[index
]);
248 if (ep
->dbe_lop
== NULL
) {
249 ep
->dbe_lop
= (long)get_lo(dbp
, cp
,
252 tlop
= (struct link_object
*)
253 &AP(dbp
)[ep
->dbe_lop
];
254 (void) strcpy(&AP(dbp
)[tlop
->lo_next
],
258 for (ep
= &(dbp
->db_hash
[index
]); ep
;
260 ep
= (struct dbe
*)&AP(dbp
)[ep
->dbe_next
]) {
262 tlop
= (struct link_object
*)
263 &AP(dbp
)[ep
->dbe_lop
];
266 * Choose the highest minor version
268 if ((tlop
->lo_major
== m
) &&
269 (strncmp(&AP(dbp
)[tlop
->lo_name
],
271 (*(&AP(dbp
)[tlop
->lo_name
+
273 if (verscmp(dp
->d_name
+ to_min
,
274 (char *)(&AP(dbp
)[tlop
->lo_next
]
276 (void) strcpy(&AP(dbp
)
281 if (ep
->dbe_next
== NULL
) {
282 ep
->dbe_next
= RELPTR(dbp
,
283 calloc(sizeof (struct dbe
), 1));
286 &AP(dbp
)[ep
->dbe_next
];
287 ep
->dbe_lop
= (long)get_lo(dbp
,
288 cp
, cplen
, m
, to_min
);
290 tlop
= (struct link_object
*)
291 &AP(dbp
)[ep
->dbe_lop
];
292 (void) strcpy(&AP(dbp
)[tlop
->lo_next
],
304 * Allocate and fill in the fields for a link_object
306 static struct link_object
*
307 get_lo(dbp
, cp
, cplen
, m
, n
)
308 struct db
*dbp
; /* data base */
309 char *cp
; /* ptr. to X of libX */
310 int cplen
; /* length of X */
311 int m
; /* major version */
312 int n
; /* index to minor version */
314 struct link_object
*lop
; /* link_object to be returned */
315 struct link_object
*tlop
; /* working copy of the above */
318 * Allocate a link object prototype in the database heap.
319 * Store the numeric major (interface) number, but the minor
320 * number is stored in the database as an index to the string
321 * representing the minor version. By keeping the minor version
322 * as a string, "subfields" (i.e., major.minor[.other.fields. etc.])
323 * are permitted. Although not meaningful to the link editor, this
324 * permits run-time substitution of arbitrary customer revisions,
325 * although introducing the confusion of overloading the lo_minor
326 * field in the database (!)
328 lop
= (struct link_object
*)RELPTR(dbp
,
329 calloc(sizeof (struct link_object
), 1));
331 tlop
= (struct link_object
*)&AP(dbp
)[(long)lop
];
336 * Allocate space for the complete path name on the host program's
337 * heap -- as we have to save it from the directory buffer which
338 * might otherwise get re-used on us. Note that this space
339 * is wasted -- we can not assume that it can be reclaimed.
341 tlop
->lo_next
= (long)RELPTR(dbp
, calloc(MAXNAMLEN
, 1));
344 * Store the prototype name in the link object in the database.
346 tlop
->lo_name
= (long)RELPTR(dbp
, calloc((cplen
+ 1), 1));
347 (void) strncpy((char *)&AP(dbp
)[tlop
->lo_name
], cp
, cplen
);
352 * Pull the "X" from libX, set name to X and return the
359 char *ls
; /* string after LIB root */
360 char *dp
; /* string before first delimiter */
362 if (strncmp(*name
, MSG_ORIG(MSG_FIL_LIB
), MSG_FIL_LIB_SIZE
) == 0) {
363 ls
= *name
+ MSG_FIL_LIB_SIZE
;
364 if ((dp
= (char *)strchr(ls
, '.')) != NULL
) {
373 * Make a pass through the data base to set the dbe_name of a dbe. This
374 * is necessary because there may be several revisions of a library
375 * but only one will be chosen.
381 int i
; /* loop temporary */
382 int dirlen
= strlen(&AP(dbp
)[dbp
->db_name
]);
383 /* length of directory pathname */
384 char *cp
; /* working temporary */
385 char *tp
; /* working temporary */
386 struct dbe
*ep
; /* working copy of dbe */
387 struct link_object
*lop
; /* working copy of link_object */
389 for (i
= 0; i
< DB_HASH
; i
++) {
390 for (ep
= &(dbp
->db_hash
[i
]); ep
&& ep
->dbe_lop
;
391 (ep
= ep
->dbe_next
== 0 ? NULL
:
393 (struct dbe
*)&AP(dbp
)[ep
->dbe_next
])) {
395 lop
= (struct link_object
*)&AP(dbp
)[ep
->dbe_lop
];
396 tp
= &AP(dbp
)[lop
->lo_next
];
397 ep
->dbe_name
= RELPTR(dbp
,
398 calloc((dirlen
+ strlen(tp
) + 2), 1));
399 lop
->lo_minor
+= dirlen
+ 1;
400 cp
= strncpy(&AP(dbp
)[ep
->dbe_name
],
401 &AP(dbp
)[dbp
->db_name
], dirlen
);
402 cp
= strncpy(cp
+ dirlen
, MSG_ORIG(MSG_STR_SLASH
),
404 (void) strcpy(cp
+ 1, tp
);
410 * Allocate a new dbd, append it after dbdpp and set the dbd_dbp to dbp.
414 struct dbd
**dbdpp
; /* insertion point */
415 struct db
*dbp
; /* db associated with this dbd */
417 struct dbd
*dbdp
; /* working dbd ptr. */
419 dbdp
= malloc(sizeof (struct dbd
));
421 dbdp
->dbd_next
= NULL
;
427 * Calculate hash index for link object.
428 * This is based on X.major from libX.so.major.minor.
432 char *np
; /* X of libX */
433 int nchrs
; /* no of chrs. to hash on */
434 int m
; /* the major version */
436 int h
; /* for loop counter */
437 char *cp
; /* working (char *) ptr */
439 for (h
= 0, cp
= np
; h
< nchrs
; h
++, cp
++)
442 h
= ((h
& 0x7fffffff) % DB_HASH
);
447 * Test whether the string is of digit[.digit]* format
451 char *str
; /* input string */
453 int dummy
; /* integer place holder */
454 int legal
= 1; /* return flag */
456 while (!EMPTY(str
)) {
457 if (!stol(str
, '.', &str
, &dummy
)) {
471 * Compare 2 strings and test whether they are of the form digit[.digit]*.
472 * It will return -1, 0, or 1 depending on whether c1p is less, equal or
476 verscmp(const char *c1p
, const char *c2p
)
478 char *l_c1p
= (char *)c1p
; /* working copy of c1p */
479 char *l_c2p
= (char *)c2p
; /* working copy of c2p */
480 int l_c1p_ok
= 0; /* is c1p a legal string */
481 int c2p_dig
= 0; /* int that c1p currently */
483 int c1p_dig
= 0; /* int that c2p currently */
486 while (((l_c1p_ok
= stol(l_c1p
, '.', &l_c1p
, &c1p_dig
)) == 1) &&
487 stol(l_c2p
, '.', &l_c2p
, &c2p_dig
) && (c2p_dig
== c1p_dig
)) {
488 if (EMPTY(l_c1p
) && EMPTY(l_c2p
))
490 else if (EMPTY(l_c1p
) && !EMPTY(l_c2p
) &&
491 rest_ok(SKIP_DOT(l_c2p
)))
493 else if (EMPTY(l_c2p
) && !EMPTY(l_c1p
) &&
494 rest_ok(SKIP_DOT(l_c1p
)))
500 else if (c1p_dig
< c2p_dig
)
502 else if ((c1p_dig
> c2p_dig
) && rest_ok(SKIP_DOT(l_c1p
)))
508 * "stol" attempts to interpret a collection of characters between delimiters
509 * as a decimal digit. It stops interpreting when it reaches a delimiter or
510 * when character does not represent a digit. In the first case it returns
511 * success and the latter failure.
514 stol(cp
, delimit
, ptr
, i
)
515 char *cp
; /* ptr to input string */
516 char delimit
; /* delimiter */
517 char **ptr
; /* left pointing to next del. or */
518 /* illegal character */
519 int *i
; /* digit that the string represents */
521 int c
= 0; /* current char */
522 int n
= 0; /* working copy of i */
523 int neg
= 0; /* is number negative */
525 if (ptr
!= (char **)0)
526 *ptr
= cp
; /* in case no number is formed */
531 if (!isdigit(c
= *cp
) && (c
== '-')) {
535 if (EMPTY(cp
) || !isdigit(c
))
538 while (isdigit(c
= *cp
) && (*cp
++ != '\0')) {
542 if (ptr
!= (char **)0)
545 if ((*cp
== '\0') || (*cp
== delimit
)) {