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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1996-1997, by Sun Microsystems, Inc.
24 * All Rights Reserved.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <locale.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/param.h>
33 #include <stdio.h>
34 #include <fcntl.h>
35 #include <link.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <dirent.h>
39 #include <search.h>
40
41 #include "libelf.h"
42 #include "elfrd.h"
43
44 extern int verbose;
45 extern char *mstrdup(const char *);
46 extern void *mmalloc(size_t size);
47
48 /*
49 * Given the name of an executable and a function call the function for
50 * all shared objects needed to link the executable. The function will only
51 * be called once. A list of filenames for which the function has been called
52 * is maintained, this is used to exclude filenames.
53 */
54 void
process_executable(char * pathname,int (* func)(char *,char *,DIR *,int))55 process_executable(char *pathname, int (*func)(char *, char *, DIR *, int))
56 {
57 struct sobj *get_share_obj(char *, struct libpath *, int);
58 struct sobj *sop;
59 struct sobj *psop;
60
61 #ifdef DEBUG
62 printf("process_executable: pathname = %s\n", pathname);
63 fflush(stdout);
64 #endif /* debug */
65 sop = get_share_obj(pathname, &libp_hd, GSO_ADDEXCLD);
66 #ifdef DEBUG
67 printf("process_executable: sop = %x\n", sop);
68 fflush(stdout);
69 #endif /* debug */
70 if (verbose) {
71 if ((int)sop < 0) {
72 fprintf(stderr,
73 gettext(
74 "cachefspack: unable to get shared objects - %s\n"),
75 pathname);
76 }
77 }
78 if ((int)sop > 0) {
79 while (sop->so_next != (struct sobj *)0) {
80 #ifdef DEBUG
81 printf("process_executable: sop->so_name = %s\n",
82 sop->so_name);
83 fflush(stdout);
84 #endif /* DEBUG */
85 func_dir_path(sop->so_name, func);
86
87 psop = sop;
88 sop = sop->so_next;
89 free(psop->so_name);
90 free(psop);
91 }
92 }
93 }
94
95 /*
96 * Given the name of an executable, a list of directories to use in the
97 * library search and a list of library names to exclude, return all
98 * shared object needed by the executable.
99 *
100 * RETURNS: A pointer to a list of shared objects
101 */
102 struct sobj *
get_share_obj(char * fpath,struct libpath * libpath,int flag)103 get_share_obj(char *fpath, struct libpath *libpath, int flag)
104 {
105 static int name_cnt = 0;
106 static struct sobj *so, *hd_so;
107 static int depth = 0;
108 static struct libpath *rpath, hd_rpath;
109 int found_file = 0;
110 int error;
111 int fd;
112 Elf *elfp;
113 Elf32_Ehdr *Ehdr;
114 Elf_Scn *scn;
115 Elf32_Shdr *shdr;
116 Elf32_Dyn *dyn;
117 size_t dynsz;
118 char *name;
119 void * get_scndata();
120 struct sobj *alloc_sobj();
121 struct sobj *add_so();
122 char pathtmp[MAXPATHLEN];
123 ENTRY hitem, *hitemp;
124 int fileopn;
125 int elfbgn = 0;
126 Elf_Kind file_type;
127 int buf;
128
129 /*
130 * Open a file and perform necessary operations to find the sections
131 * in an elf format file. If the specified file is not elf format
132 * return an error.
133 */
134 depth++;
135 if (depth == 1) {
136 /*
137 * Find the ending exclude shared object element.
138 */
139 rpath = &hd_rpath;
140 #ifdef DEBUG
141 printf("dbg: rpath = %x\n", rpath);
142 #endif /* DEBUG */
143 rpath->lp_path = " ";
144 rpath->lp_next = (struct libpath *)0;
145 rpath->lp_level = 0;
146 }
147
148 fileopn = 0;
149 error = ERR_NOERROR;
150 fd = open(fpath, O_RDONLY);
151 if (fd < 0) {
152 error = ERR_NOFILE;
153 goto out;
154 }
155 fileopn = 1;
156 /* work around */
157 /*
158 * elf_begin() core dumps when passed a file descriptor for a file
159 * which does not have read permission, but was opened RDONLY because the
160 * user doing the open was root. To avoid this problem, make sure we can
161 * read the first byte of the file. If we can't, skip the file. This is a
162 * temporary workaround until elf_begin() is fixed.
163 */
164 if (read(fd, &buf, sizeof (buf)) < 0) {
165 #ifdef DEBUG
166 printf("read failed\n");
167 fflush(stdout);
168 #endif /* DEBUG */
169 error = ERR_NOFILE;
170 goto out;
171 }
172 lseek(fd, 0, SEEK_SET);
173 /* work around end */
174 if (elf_version(EV_CURRENT) == EV_NONE) {
175 error = ERR_NOELFVER;
176 goto out;
177 }
178 elfbgn = 0;
179 if ((elfp = elf_begin(fd, ELF_C_READ, (Elf *)0)) == NULL) {
180 error = ERR_NOELFBEG;
181 goto out;
182 }
183 elfbgn = 1;
184 file_type = elf_kind(elfp);
185 #ifdef DEBUG
186 printf("file_type = %x\n", file_type);
187 fflush(stdout);
188 #endif /* DEBUG */
189
190 if (file_type != ELF_K_ELF) {
191 goto out;
192 }
193 if ((Ehdr = elf32_getehdr(elfp)) == NULL) {
194 error = ERR_NOELFBEG;
195 goto out;
196 }
197 #ifdef DEBUG
198 printf("dbg: depth = %d\n", depth);
199 #endif /* DEBUG */
200 /*
201 * Scan all sections of the elf file to locate the dynamic section
202 */
203 scn = 0;
204 while ((scn = elf_nextscn(elfp, scn)) != 0) {
205 if ((shdr = elf32_getshdr(scn)) == NULL) {
206 error = ERR_NOELFSHD;
207 goto out;
208 }
209 if (shdr->sh_type != SHT_DYNAMIC) {
210 continue;
211 }
212 /*
213 * The first pass of the dynamic section locates all
214 * directories specified by "ld -R..". A stack is created
215 * for the search, this allows shared libraries, dependant
216 * on other shared libraries, built with "ld -R" to work
217 * properly.
218 *
219 */
220 if ((dyn = (Elf32_Dyn *)get_scndata(scn, &dynsz)) == 0) {
221 error = ERR_NOELFSDT;
222 goto out;
223 }
224 while (dyn->d_tag != DT_NULL) {
225 if (dyn->d_tag == DT_RPATH) {
226 name = (char *)elf_strptr(elfp,
227 (size_t)shdr->sh_link, dyn->d_un.d_ptr);
228 #ifdef DEBUG
229 printf("DT_RPATH: name = %s\n", name);
230 #endif /* DEBUG */
231 rpath = stk_libpath(rpath, name, depth);
232 }
233 dyn++;
234 }
235 /*
236 * Find all needed shared objects. Do this recursively
237 * so libraries dependant on other libraries are found.
238 * Also, try a list of libraries to exclude. Since
239 * this routine is used by cachefspack, it is only neccessary
240 * to pack a library once. For example, libc is used by lots
241 * of commands, we need not return its name to cachefspack
242 * except the first time we find it.
243 */
244 if ((dyn = (Elf32_Dyn *)get_scndata(scn, &dynsz)) == 0) {
245 error = ERR_NOELFSDT;
246 goto out;
247 }
248 for (; dyn->d_tag != DT_NULL; dyn++) {
249 if (dyn->d_tag == DT_NEEDED) {
250 name = (char *)elf_strptr(elfp,
251 (size_t)shdr->sh_link, dyn->d_un.d_ptr);
252 if (name != 0) {
253 #ifdef DEBUG
254 printf("chk: %s\n", name);
255 fflush(stdout);
256 #endif /* DEBUG */
257 found_file = libsrch(name, libpath,
258 pathtmp);
259 #ifdef DEBUG
260 printf("dbg: 1 found_file = %d\n",
261 found_file);
262 fflush(stdout);
263 #endif /* DEBUG */
264 if (!found_file) {
265 found_file = libsrch(name,
266 rpath, pathtmp);
267 }
268 #ifdef DEBUG
269 printf("dbg: 2 found_file = %d\n",
270 found_file);
271 fflush(stdout);
272 #endif /* DEBUG */
273 if (!found_file) {
274 continue;
275 }
276 if (name_cnt == 0) {
277 so = alloc_sobj();
278 hd_so = so;
279 }
280 /*
281 * See if file already in list
282 */
283 hitem.key = mstrdup(pathtmp);
284 hitem.data = 0;
285 hitemp = hsearch(hitem, FIND);
286 if (hitemp != NULL) {
287 #ifdef DEBUG
288 printf("found so: %s\n",
289 pathtmp);
290 printf("hitemp.key = %s\n",
291 hitemp->key);
292 #endif /* DEBUG */
293 continue;
294 }
295 #ifdef DEBUG
296 printf("do : %s\n", pathtmp);
297 fflush(stdout);
298 #endif /* DEBUG */
299 name_cnt++;
300 so = add_so(so, pathtmp);
301 if (flag & GSO_ADDEXCLD) {
302 #ifdef DEBUG
303 printf("adding so: %s\n",
304 pathtmp);
305 #endif /* DEBUG */
306 hitem.key = mstrdup(pathtmp);
307 hitem.data = 0;
308 if (hsearch(hitem, ENTER) ==
309 NULL) {
310 error = ERR_HASHFULL;
311 goto out;
312 }
313 }
314 get_share_obj(pathtmp, libpath, flag);
315 } else {
316 if (name_cnt > 0) {
317 goto out;
318 } else {
319 error = ERR_NOELFNAM;
320 goto out;
321 }
322 }
323 }
324 }
325 }
326
327 out:
328 #ifdef DEBUG
329 printf("error = %x\n", error);
330 fflush(stdout);
331 #endif /* DEBUG */
332 depth--;
333 #ifdef DEBUG
334 printf("ret: depth = %d\n", depth);
335 fflush(stdout);
336 #endif /* DEBUG */
337 if (fileopn) {
338 close(fd);
339 if (elfbgn) {
340 if ((error != ERR_NOFILE) && (error != ERR_NOELFVER)) {
341 elf_end(elfp);
342 }
343 }
344 }
345 if (name_cnt == 0) {
346 return ((struct sobj *)ERR_NOERROR);
347 }
348 while (rpath->lp_level > depth) {
349 #ifdef DEBUG
350 printf("ret: rpath->lp_level = %d\n", rpath->lp_level);
351 fflush(stdout);
352 #endif /* DEBUG */
353 rpath = pop_libpath(rpath);
354 }
355 if (depth == 0) {
356 name_cnt = 0;
357 }
358 if (error == ERR_NOERROR) {
359 return (hd_so);
360 } else {
361 return ((struct sobj *)error);
362 }
363 }
364
365
366 /*
367 * Get the section descriptor and set the size of the
368 * data returned. Data is byte-order converted.
369 */
370
371 void *
get_scndata(fd_scn,size)372 get_scndata(fd_scn, size)
373 Elf_Scn *fd_scn;
374 size_t *size;
375 {
376 Elf_Data *p_data;
377
378 p_data = 0;
379 if ((p_data = elf_getdata(fd_scn, p_data)) == 0 ||
380 p_data->d_size == 0)
381 {
382 return (NULL);
383 }
384
385 *size = p_data->d_size;
386 return (p_data->d_buf);
387 }
388
389 /*
390 * Allocate a shared object structure
391 *
392 * RETURNS: A pointer to the allocated structure
393 */
394 struct sobj *
alloc_sobj()395 alloc_sobj()
396 {
397 struct sobj *so;
398 so = (struct sobj *)mmalloc(sizeof (struct sobj));
399 so->so_name = " ";
400 so->so_next = (struct sobj *)0;
401 return (so);
402 }
403
404
405 /*
406 * Add an object to a shared object list
407 *
408 * RETURNS: The tail of the shared object list
409 */
410 struct sobj *
add_so(struct sobj * so,char * path)411 add_so(struct sobj *so, char *path)
412 {
413 if (so == (struct sobj *)0) {
414 so = alloc_sobj();
415 }
416 so->so_name = mstrdup(path);
417 so->so_next = alloc_sobj();
418 so = so->so_next;
419 return (so);
420 }
421
422 /*
423 * Determine if name concatenated with a library directory path yields
424 * a file name that exists.
425 *
426 * RETURNS: True(1) or False(0)
427 * if true - fullpath arg contains a pointer to the full path name
428 * of the file
429 */
430 int
libsrch(char * name,struct libpath * libpath,char * fullpath)431 libsrch(char *name, struct libpath *libpath, char *fullpath)
432 {
433 struct stat64 statbuf;
434 struct libpath *lp;
435
436 #ifdef DEBUG
437 printf("libsrch: libpath = %x\n", libpath);
438 fflush(stdout);
439 #endif /* DEBUG */
440 lp = libpath;
441 if (lp == NULL) {
442 return (0);
443 }
444 #ifdef DEBUG
445 printf("libsrch: 1 lp->lp_next = %x\n", lp->lp_next);
446 fflush(stdout);
447 #endif /* DEBUG */
448 while (lp->lp_next != (struct libpath *)0) {
449 strcpy(fullpath, lp->lp_path);
450 strcat(fullpath, "/");
451 strcat(fullpath, name);
452 lp = lp->lp_next;
453 #ifdef DEBUG
454 printf("libsrch: 2 lp->lp_next = %x\n", lp->lp_next);
455 fflush(stdout);
456 #endif /* DEBUG */
457 /*
458 * stat - if file break
459 */
460 if (stat64(fullpath, &statbuf)
461 == 0) {
462 #ifdef DEBUG
463 printf("libsrch: found - %s\n", fullpath);
464 fflush(stdout);
465 #endif /* DEBUG */
466 return (1);
467 }
468 }
469 #ifdef DEBUG
470 printf("libsrch: NOT found - %s\n", name);
471 fflush(stdout);
472 #endif /* DEBUG */
473 return (0);
474 }
475
476 /*
477 * Add path to the libpath list(add at the tail of the list).
478 *
479 * RETURNS: The new tail of the list
480 */
481 struct libpath *
add_libpath(struct libpath * lp,char * path,int level)482 add_libpath(struct libpath *lp, char *path, int level)
483 {
484 char *s;
485
486 lp->lp_level = level;
487 s = mstrdup(path);
488 if (s != (char *)0) {
489 lp->lp_path = s;
490 }
491 lp->lp_next = (struct libpath *)mmalloc(sizeof (struct libpath));
492 lp = lp->lp_next;
493 lp->lp_next = (struct libpath *)0;
494 lp->lp_level = 0;
495 lp->lp_path = " ";
496 return (lp);
497 }
498
499 /*
500 * Add directory/directories in name to libpath stack(as head of the stack)
501 * at the level specified.
502 *
503 * RETURNS: the new head of the stack
504 */
505 struct libpath *
stk_libpath(struct libpath * hd,char * name,int level)506 stk_libpath(struct libpath *hd, char *name, int level)
507 {
508 struct libpath *lp, *prev_lp;
509 char *s, *t;
510 char *tok;
511 char *freeit;
512
513 #ifdef DEBUG
514 printf("stk_libpath: name = %s\n", name);
515 fflush(stdout);
516 #endif /* DEBUG */
517 s = mstrdup(name);
518 freeit = s;
519 prev_lp = hd;
520 while (1) {
521 tok = strtok(s, ":");
522 if (tok == (char *)NULL)
523 break;
524 s = (char *)0;
525 lp = (struct libpath *)mmalloc(sizeof (struct libpath));
526 lp->lp_level = level;
527 t = mstrdup(tok);
528 lp->lp_path = t;
529 lp->lp_next = prev_lp;
530 prev_lp = lp;
531 }
532 #ifdef DEBUG
533 printf("stk_libpath: lp = %x\n", lp);
534 fflush(stdout);
535 #endif /* DEBUG */
536 free(freeit);
537 return (lp);
538 }
539
540 /*
541 * Free up a libpath stack entry.
542 *
543 * RETURNS: the new head of the stack
544 */
545 struct libpath *
pop_libpath(struct libpath * lp)546 pop_libpath(struct libpath *lp)
547 {
548 struct libpath *tlp;
549
550 tlp = lp;
551 lp = lp->lp_next;
552 free(tlp->lp_path);
553 free(tlp);
554 return (lp);
555 }
556
557 /*
558 * Crack the LD_LIBRARY_PATH environment variable. Make a list of libraries
559 * to search.
560 */
561 void
get_libsrch_path(struct libpath * libhd)562 get_libsrch_path(struct libpath *libhd)
563 {
564 char *s;
565 char *tok = (char *) 1;
566 struct libpath *lp;
567
568 lp = libhd;
569 s = getenv("LD_LIBRARY_PATH");
570 if (s != (char *)NULL) {
571 while (1) {
572 tok = strtok(s, ":");
573 if (tok == (char *) NULL)
574 break;
575 s = (char *) 0;
576 lp = add_libpath(lp, tok, 0);
577 }
578 }
579 add_libpath(lp, "/usr/lib", 0);
580 }
581
582
583 #ifdef DEBUG
prt_sop_lst(struct sobj * sop,char * str)584 prt_sop_lst(struct sobj *sop, char * str)
585 {
586 printf("\n\n\n%s - sop = %x\n", str, sop);
587 fflush(stdout);
588 if ((int)sop < 0) {
589 fprintf(stderr, "get_share_obj: failed\n");
590 exit(1);
591 }
592
593 if ((int)sop > 0) {
594 while (sop->so_next != (struct sobj *) 0) {
595 printf("sop->so_name = %s\n", sop->so_name);
596 sop = sop->so_next;
597 }
598 }
599 }
600 #endif /* DEBUG */
601