OSDN Git Service

Rewrite of ldd so it works as expected, and does not invoke the
authorEric Andersen <andersen@codepoet.org>
Wed, 11 Jul 2001 01:28:18 +0000 (01:28 -0000)
committerEric Andersen <andersen@codepoet.org>
Wed, 11 Jul 2001 01:28:18 +0000 (01:28 -0000)
shared lib loader at all.  This will allow us to throw out the
support code for that from ld-linux.so.0
 -Erik

ldso/util/Makefile
ldso/util/ldd.c

index dd69c9b..646fd69 100644 (file)
@@ -6,24 +6,25 @@ all: ldconfig ldd readelf
 readsoname.o: readsoname.c readsoname2.c
        $(TARGET_CC) $(TARGET_CFLAGS) -c $< -o $@
        $(STRIPTOOL) -x -R .note -R .comment $*.o
-
+    
 ldconfig.o: ldconfig.c
-       $(TARGET_CC) $(TARGET_CFLAGS) -DUCLIBC_ROOT_DIR=\"$(ROOT_DIR)\" -c $< -o $@
-       $(STRIPTOOL) -x -R .note -R .comment $*.o
-
-ldd.o: ldd.c 
-       $(TARGET_CC) $(TARGET_CFLAGS)  -DUCLIBC_ROOT_DIR=\"$(ROOT_DIR)\" \
-           -DLDSO_ADDR="0x62f00020" -c $< -o $@
+       $(TARGET_CC) $(TARGET_CFLAGS) -DUCLIBC_ROOT_DIR=\"$(ROOT_DIR)\" \
+               -c $< -o $@
        $(STRIPTOOL) -x -R .note -R .comment $*.o
 
 readelf: readelf.c
        $(TARGET_CC) $(TARGET_CFLAGS) -static readelf.c -o $@
+       $(STRIPTOOL) -x -R .note -R .comment $@
 
 ldconfig: ldconfig.o readsoname.o
        $(TARGET_CC) $(TARGET_CFLAGS) -static $^ -o $@
+       $(STRIPTOOL) -x -R .note -R .comment $@
 
-ldd:   ldd.o readsoname.o
-       $(TARGET_CC) $(TARGET_CFLAGS) -static $^ -o $@
+ldd: ldd.c
+       $(TARGET_CC) $(TARGET_CFLAGS) -DUCLIBC_ROOT_DIR=\"$(ROOT_DIR)\" \
+               -DUCLIBC_BUILD_DIR=\"$(shell cd $(TOPDIR); pwd)\" \
+               -static ldd.c -o $@
+       $(STRIPTOOL) -x -R .note -R .comment $@
 
 clean:
        rm -f ldconfig ldd readelf *.o *~ core
index 29800bc..0224b0c 100644 (file)
+/* vi: set sw=4 ts=4: */
 /*
- * ldd - print shared library dependencies
+ * A small little ldd implementation for uClibc
  *
- * usage: ldd [-vVdr] prog ...
- *        -v: print ldd version
- *        -V: print ld.so version
- *       -d: Perform relocations and report any missing functions. (ELF only).
- *       -r: Perform relocations for both data objects and functions, and
- *           report any missing objects (ELF only).
- *        prog ...: programs to check
+ * Copyright (C) 2001 by Lineo, inc.
+ * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
  *
- * Copyright 1993-2000, David Engel
+ * Several functions in this file (specifically, elf_find_section_type(),
+ * elf_find_phdr_type(), and elf_find_dynamic(), were stolen from elflib.c from
+ * elfvector (http://www.BitWagon.com/elfvector.html) by John F. Reiser
+ * <jreiser@BitWagon.com>, and which is copyright 2000 BitWagon Software LLC
+ * (GPL2).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
- * This program may be used for any purpose as long as this
- * copyright notice is kept.
  */
 
+
+#include <elf.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdarg.h>
 #include <string.h>
-#include <getopt.h>
 #include <unistd.h>
-#include <errno.h>
-#include <sys/wait.h>
-#include <elf.h>
-#include "../d-link/linuxelf.h"
-#include "../config.h"
-#include "readsoname.h"
-
-struct exec
-{
-  unsigned long a_info;                /* Use macros N_MAGIC, etc for access */
-  unsigned a_text;             /* length of text, in bytes */
-  unsigned a_data;             /* length of data, in bytes */
-  unsigned a_bss;              /* length of uninitialized data area for file, in bytes */
-  unsigned a_syms;             /* length of symbol table data in file, in bytes */
-  unsigned a_entry;            /* start address */
-  unsigned a_trsize;           /* length of relocation info for text, in bytes */
-  unsigned a_drsize;           /* length of relocation info for data, in bytes */
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+struct library {
+       char *name;
+       int resolved;
+       char *path;
+       struct library *next;
 };
+struct library *lib_list = NULL;
+
 
-#if !defined (N_MAGIC)
-#define N_MAGIC(exec) ((exec).a_info & 0xffff)
-#endif
-/* Code indicating object file or impure executable.  */
-#define OMAGIC 0407
-/* Code indicating pure executable.  */
-#define NMAGIC 0410
-/* Code indicating demand-paged executable.  */
-#define ZMAGIC 0413
-/* This indicates a demand-paged executable with the header in the text. 
-   The first page is unmapped to help trap NULL pointer references */
-#define QMAGIC 0314
-/* Code indicating core file.  */
-#define CMAGIC 0421
 
+Elf32_Shdr * elf_find_section_type( int key, Elf32_Ehdr *ehdr)
+{
+       int j;
+       Elf32_Shdr *shdr = (Elf32_Shdr *)(ehdr->e_shoff + (char *)ehdr);
+       for (j = ehdr->e_shnum; --j>=0; ++shdr) {
+               if (shdr->sh_type == key) {
+                       return shdr;
+               }
+       }
+       return NULL;
+}
 
+Elf32_Phdr * elf_find_phdr_type( int type, Elf32_Ehdr *ehdr)
+{
+       int j;
+       Elf32_Phdr *phdr = (Elf32_Phdr *)(ehdr->e_phoff + (char *)ehdr);
+       for (j = ehdr->e_phnum; --j>=0; ++phdr) {
+               if (type==phdr->p_type) {
+                       return phdr;
+               }
+       }
+       return NULL;
+}
 
-extern int uselib(const char *library);
+/* Returns value if return_val==1, ptr otherwise */ 
+void * elf_find_dynamic(int const key, Elf32_Dyn *dynp, 
+       Elf32_Ehdr *ehdr, int return_val)
+{
+       Elf32_Phdr *pt_text = elf_find_phdr_type(PT_LOAD, ehdr);
+       unsigned tx_reloc = pt_text->p_vaddr - pt_text->p_offset;
+       for (; DT_NULL!=dynp->d_tag; ++dynp) {
+               if (dynp->d_tag == key) {
+                       if (return_val == 1)
+                               return (void *)dynp->d_un.d_val;
+                       else
+                               return (void *)(dynp->d_un.d_val - tx_reloc + (char *)ehdr );
+               }
+       }
+       return NULL;
+}
 
-#ifdef __GNUC__
-void warn(char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
-void error(char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
-#endif
+int check_elf_header(Elf32_Ehdr const *const ehdr)
+{
+       if (! ehdr || strncmp((void *)ehdr, ELFMAG, SELFMAG) != 0 ||  
+                       ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
+                       ehdr->e_ident[EI_VERSION] != EV_CURRENT) 
+       {
+               return 1;
+       }
+       return 0;
+}
 
-char *prog = NULL;
+char * last_char_is(const char *s, int c)
+{
+       char *sret;
+       if (!s)
+           return NULL;
+       sret  = (char *)s+strlen(s)-1;
+       if (sret>=s && *sret == c) { 
+               return sret;
+       } else {
+               return NULL;
+       }
+}
 
-void warn(char *fmt, ...)
+extern char *concat_path_file(const char *path, const char *filename)
 {
-    va_list ap;
+       char *outbuf;
+       char *lc;
+
+       if (!path)
+           path="";
+       lc = last_char_is(path, '/');
+       if (filename[0] == '/')
+               filename++;
+       outbuf = malloc(strlen(path)+strlen(filename)+1+(lc==NULL));
+       if (!outbuf) {
+               fprintf(stderr, "out of memory\n");
+               exit(EXIT_FAILURE);
+       }
+       sprintf(outbuf, "%s%s%s", path, (lc==NULL)? "/" : "", filename);
+
+       return outbuf;
+}
 
-    fflush(stdout);    /* don't mix output and error messages */
-    fprintf(stderr, "%s: warning: ", prog);
+char *do_which(char *name, char *path_list)
+{
+       char *path_n;
+       char *path_tmp;
+       struct stat filestat;
+       int i, count=1;
+
+       if (!path_list) {
+               fprintf(stderr, "yipe!\n");
+               exit(EXIT_FAILURE);
+       }
 
-    va_start(ap, fmt);
-    vfprintf(stderr, fmt, ap);
-    va_end(ap);
+       /* We need a writable copy of this string */
+       path_tmp = strdup(path_list);
+       if (!path_tmp) {
+               fprintf(stderr, "yipe!\n");
+               exit(EXIT_FAILURE);
+       }
 
-    fprintf(stderr, "\n");
+       /* Replace colons with zeros in path_parsed and count them */
+       for(i=strlen(path_tmp); i > 0; i--) 
+               if (path_tmp[i]==':') {
+                       path_tmp[i]=0;
+                       count++;
+               }
 
-    return;
+       path_n = path_tmp;
+       for (i = 0; i < count; i++) {
+               char *buf;
+               buf = concat_path_file(path_n, name);
+               if (stat (buf, &filestat) == 0 && filestat.st_mode & S_IRUSR) {
+                       return(buf);
+               }
+               free(buf);
+               path_n += (strlen(path_n) + 1);
+       }
+       return NULL;
 }
 
-void error(char *fmt, ...)
+void locate_library_file(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, char *strtab, int is_suid, struct library *lib)
 {
-    va_list ap;
+       char *buf;
+       char *path;
+       struct stat filestat;
 
-    fflush(stdout);    /* don't mix output and error messages */
-    fprintf(stderr, "%s: ", prog);
+       lib->path = "not found";
 
-    va_start(ap, fmt);
-    vfprintf(stderr, fmt, ap);
-    va_end(ap);
+       /* If this is a fully resolved name, our job is easy */
+       if (stat (lib->name, &filestat) == 0) {
+               lib->path = lib->name;
+               return;
+       }
 
-    fprintf(stderr, "\n");
+       /* This function must match the behavior of _dl_load_shared_library
+        * in readelflib1.c or things won't work out as expected... */
+
+       /* The ABI specifies that RPATH is searched before LD_*_PATH or the
+        * default path (such as /usr/lib).  So first, lets check the rpath
+        * directories */
+       path = (char *)elf_find_dynamic(DT_RPATH, dynamic, ehdr, 0);
+       if (path) {
+               buf = do_which(lib->name, path);
+               if (buf) {
+                       lib->path = buf;
+                       return;
+               }
+       }
 
-    exit(1);
-}
+       /* Next check LD_{ELF_}LIBRARY_PATH if specified and allowed.
+        * Since this app doesn't actually run an executable I will skip
+        * the suid check, and just use LD_{ELF_}LIBRARY_PATH if set */
+       if (is_suid==1)
+               path = NULL;
+       else
+               path = getenv("LD_LIBRARY_PATH");
+       if (path) {
+               buf = do_which(lib->name, path);
+               if (buf) {
+                       lib->path = buf;
+                       return;
+               }
+       }
 
-void *xmalloc(size_t size)
-{
-    void *ptr;
-    if ((ptr = malloc(size)) == NULL)
-       error("out of memory");
-    return ptr;
-}
+       /* Fixme -- add code to check the Cache here */ 
 
-char *xstrdup(char *str)
-{
-    char *ptr;
-    if ((ptr = strdup(str)) == NULL)
-       error("out of memory");
-    return ptr;
+       
+       buf = do_which(lib->name, UCLIBC_ROOT_DIR "/usr/lib/:" UCLIBC_ROOT_DIR 
+                       "/lib/:" UCLIBC_BUILD_DIR "/lib/:/usr/lib:/lib");
+       if (buf) {
+               lib->path = buf;
+       }
 }
 
-/* see if prog is a binary file */
-int is_bin(char *argv0, char *prog)
+static int add_library(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, char *strtab, int is_setuid, const char *s)
 {
-    int res = 0;
-    FILE *file;
-    struct exec exec;
-    char *cp;
-    int libtype;
-
-    /* must be able to open it for reading */
-    if ((file = fopen(prog, "rb")) == NULL)
-       fprintf(stderr, "%s: can't open %s (%s)\n", argv0, prog,
-               strerror(errno));
-    else
-    {
-       /* then see if it's Z, Q or OMAGIC */
-       if (fread(&exec, sizeof exec, 1, file) < 1)
-           fprintf(stderr, "%s: can't read header from %s\n", argv0, prog);
-       else if (N_MAGIC(exec) != ZMAGIC && N_MAGIC(exec) != QMAGIC &&
-                 N_MAGIC(exec) != OMAGIC)
-       {
-           elfhdr elf_hdr;
-           
-           rewind(file);
-           fread(&elf_hdr, sizeof elf_hdr, 1, file);
-           if (elf_hdr.e_ident[0] != 0x7f ||
-               strncmp(elf_hdr.e_ident+1, "ELF", 3) != 0)
-               fprintf(stderr, "%s: %s is not a.out or ELF\n", argv0, prog);
-           else
-           {
-               elf_phdr phdr;
-               int i;
-
-               /* Check its an exectuable, library or other */
-               switch (elf_hdr.e_type)
-               {
-                 case ET_EXEC:
-                   res = 3;
-                   /* then determine if it is dynamic ELF */
-                   for (i=0; i<elf_hdr.e_phnum; i++)
-                   {
-                       fread(&phdr, sizeof phdr, 1, file);
-                       if (phdr.p_type == PT_DYNAMIC)
-                       {
-                           res = 2;
-                           break;
-                       }
-                   }
-                   break;
-                 case ET_DYN:
-                   if ((cp = readsoname(prog, file, LIB_ANY, &libtype, 
-                        elf_hdr.e_ident[EI_CLASS])) != NULL)
-                       free(cp);
-                   if (libtype == LIB_ELF_LIBC5)
-                       res = 5;
-                   else
-                       res = 4;
-                   break;
-                 default:
-                   res = 0;
-                   break;
+       struct library *cur, *prev, *newlib=lib_list;
+
+       if (!s || !strlen(s))
+               return 1;
+
+       for (cur = lib_list; cur; cur=cur->next) {
+               if(strcmp(cur->name, s)==0) {
+                       /* Lib is already in the list */
+                       return 0;
                }
-           }
        }
-       else
-           res = 1; /* looks good */
 
-       fclose(file);
-    }
-    return res;
+       /* Ok, this lib needs to be added to the list */
+       newlib = malloc(sizeof(struct library));
+       if (!newlib)
+               return 1;
+       newlib->name = malloc(strlen(s));
+       strcpy(newlib->name, s);
+       newlib->resolved = 0;
+       newlib->next = NULL;
+
+       /* Now try and locate where this library might be living... */
+       locate_library_file(ehdr, dynamic, strtab, is_setuid, newlib);
+
+       //printf("adding '%s' to '%s'\n", newlib->name, newlib->path);
+       if (!lib_list) {
+               lib_list = newlib;
+       } else {
+               for (cur = prev = lib_list;  cur->next; prev=cur, cur=cur->next); /* nothing */
+               cur = newlib;
+               prev->next = cur;
+       }
+       return 0;
 }
 
-int main(int argc, char **argv, char **envp)
+
+static void find_needed_libraries(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, char *strtab, int is_setuid)
 {
-    int i;
-    int vprinted = 0;
-    int resolve = 0;
-    int bind = 0;
-    int bintype;
-    char *ld_preload;
-    int status = 0;
-
-    /* this must be volatile to work with -O, GCC bug? */
-    volatile loadptr loader = (loadptr)LDSO_ADDR;
-  
-    prog = argv[0];
-
-    while ((i = getopt(argc, argv, "drvV")) != EOF)
-       switch (i)
-       {
-       case 'v':
-           /* print our version number */
-           printf("%s: uClibc version\n", argv[0]);
-           vprinted = 1;
-           break;
-       case 'd':
-           bind = 1;
-           break;
-       case 'r':
-           resolve = 1;
-           break;
-       case 'V':
-           /* print the version number of ld.so */
-           if (uselib(LDSO_IMAGE))
-           {
-               fprintf(stderr, "%s: can't load dynamic linker %s (%s)\n",
-                       argv[0], LDSO_IMAGE, strerror(errno));
-               exit(1);
-           }
-           loader(FUNC_VERS, NULL);
-           vprinted = 1;
-           break;
+       Elf32_Dyn  *dyns;
+
+       for (dyns=dynamic; dyns->d_tag!=DT_NULL; ++dyns) {
+               if (dyns->d_tag == DT_NEEDED) {
+                       add_library(ehdr, dynamic, strtab, is_setuid, (char*)strtab + dyns->d_un.d_val);
+               }
+       }
+}
+    
+static void find_elf_interpreter(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, char *strtab, int is_setuid)
+{
+       Elf32_Phdr *phdr;
+       phdr = elf_find_phdr_type(PT_INTERP, ehdr);
+       if (phdr) {
+               add_library(ehdr, dynamic, strtab, is_setuid, (char*)ehdr + phdr->p_offset);
        }
+}
 
-    /* must specify programs if -v or -V not used */
-    if (optind >= argc && !vprinted)
-    {
-       printf("usage: %s [-vVdr] prog ...\n", argv[0]);
-       exit(0);
-    }
-
-    /* setup the environment for ELF binaries */
-    putenv("LD_TRACE_LOADED_OBJECTS=1");
-    if (resolve || bind)
-        putenv("LD_BIND_NOW=1");
-    if (resolve)
-        putenv("LD_WARN=1");
-    ld_preload = getenv("LD_PRELOAD");
-
-    /* print the dependencies for each program */
-    for (i = optind; i < argc; i++)
-    {
-       pid_t pid;
-       char buff[1024];
-
-       /* make sure it's a binary file */
-       if (!(bintype = is_bin(argv[0], argv[i])))
-       {
-           status = 1;
-           continue;
+/* map the .so, and locate interesting pieces */
+int find_dependancies(char* filename)
+{
+       int is_suid = 0;
+       FILE *thefile;
+       struct stat statbuf;
+       char *dynstr=NULL;
+       Elf32_Ehdr *ehdr = NULL;
+       Elf32_Shdr *dynsec = NULL;
+       Elf32_Dyn *dynamic = NULL;
+
+
+       if (!filename) {
+               fprintf(stderr, "No filename specified.\n");
+               exit(EXIT_FAILURE);
+       }
+       if (!(thefile = fopen(filename, "r"))) {
+               perror(filename);
+               exit(EXIT_FAILURE);
+       }
+       if (fstat(fileno(thefile), &statbuf) < 0) {
+               perror(filename);
+               exit(EXIT_FAILURE);
        }
 
-       /* print the program name if doing more than one */
-       if (optind < argc-1)
-       {
-           printf("%s:\n", argv[i]);
-           fflush(stdout);
+       if (statbuf.st_size < sizeof(Elf32_Ehdr))
+               goto foo;
+
+       /* mmap the file to make reading stuff from it effortless */
+       ehdr = (Elf32_Ehdr *)mmap(0, statbuf.st_size, 
+                       PROT_READ|PROT_WRITE, MAP_PRIVATE, fileno(thefile), 0);
+
+foo:
+       /* Check if this looks like a legit ELF file */
+       if (check_elf_header(ehdr)) {
+               fprintf(stderr, "%s: not an ELF file.\n", filename);
+               exit(EXIT_FAILURE);
+       }
+       /* Check if this is the right kind of ELF file */
+       if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
+               fprintf(stderr, "%s: not a dynamic executable\n", filename);
+               exit(EXIT_FAILURE);
+       }
+       if (ehdr->e_type == ET_EXEC) {
+               if (statbuf.st_mode & S_ISUID)
+                       is_suid = 1;
+               if ((statbuf.st_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))
+                       is_suid = 1;
+               /* FIXME */
+               if (is_suid)
+                       fprintf(stderr, "%s: is setuid\n", filename);
        }
 
-       /* no need to fork/exec for static ELF program */
-       if (bintype == 3)
-       {
-           printf("\tstatically linked (ELF)\n");
-           continue;
+       dynsec = elf_find_section_type(SHT_DYNAMIC, ehdr);
+       if (dynsec) {
+               dynamic = (Elf32_Dyn*)(dynsec->sh_offset + (int)ehdr);
+               dynstr = (char *)elf_find_dynamic(DT_STRTAB, dynamic, ehdr, 0);
+               find_needed_libraries(ehdr, dynamic, dynstr, is_suid);
        }
+       find_elf_interpreter(ehdr, dynamic, dynstr, is_suid);
+       
+       return 0;
+}
 
-       /* now fork and exec prog with argc = 0 */
-       if ((pid = fork()) < 0)
-       {
-           fprintf(stderr, "%s: can't fork (%s)\n", argv[0], strerror(errno));
-           exit(1);
+
+
+int main( int argc, char** argv)
+{
+       int got_em_all=1;
+       char *filename = argv[1];
+       struct library *cur;
+
+
+       if (!filename) {
+               fprintf(stderr, "No filename specified.\n");
+               exit(EXIT_FAILURE);
        }
-       else if (pid == 0)
-       {
-           switch (bintype)
-           {
-             case 1: /* a.out */
-               /* save the name in the enviroment, ld.so may need it */
-               snprintf(buff, sizeof buff, "%s=%s", LDD_ARGV0, argv[i]);
-               putenv(buff);
-               execl(argv[i], NULL);
-               break;
-             case 2: /* ELF program */
-               execl(argv[i], argv[i], NULL);
-               break;
-             case 4: /* ELF libc6 library */
-               /* try to use /lib/ld-linux.so.2 first */
-#if !defined(__mc68000__)
-               execl("/lib/ld-linux.so.2", "/lib/ld-linux.so.2", 
-                     "--list", argv[i], NULL);
-#else
-               execl("/lib/ld.so.1", "/lib/ld.so.1", 
-                     "--list", argv[i], NULL);
-#endif
-               /* fall through */
-             case 5: /* ELF libc5 library */
-               /* if that fails, add library to LD_PRELOAD and 
-                  then execute lddstub */
-               if (ld_preload && *ld_preload)
-                   snprintf(buff, sizeof buff, "LD_PRELOAD=%s:%s%s", 
-                            ld_preload, *argv[i] == '/' ? "" : "./", argv[i]);
-               else
-                   snprintf(buff, sizeof buff, "LD_PRELOAD=%s%s", 
-                            *argv[i] == '/' ? "" : "./", argv[i]);
-               putenv(buff);
-               execl(LDDSTUB, argv[i], NULL);
-               break;
-             default:
-               fprintf(stderr, "%s: internal error, bintype = %d\n",
-                       argv[0], bintype);
-               exit(1);
-           }
-           fprintf(stderr, "%s: can't execute %s (%s)\n", argv[0], argv[i],
-                   strerror(errno));
-           exit(1);
+
+       find_dependancies(filename);
+       
+       while(got_em_all) {
+               got_em_all=0;
+               /* Keep walking the list till everybody is resolved */
+               for (cur = lib_list; cur; cur=cur->next) {
+                       if (cur->resolved == 0 && cur->path) {
+                               got_em_all=1;
+                               //printf("checking sub-depends for '%s\n", cur->path);
+                               find_dependancies(cur->path);
+                               cur->resolved = 1;
+                       }
+               }
        }
-       else
-       {
-           /* then wait for it to complete */
-           int status;
-           if (waitpid(pid, &status, 0) != pid)
-           {
-               fprintf(stderr, "%s: error waiting for %s (%s)\n", argv[0], 
-                       argv[i], strerror(errno));
-           }
-           else if (WIFSIGNALED(status))
-           {
-               fprintf(stderr, "%s: %s exited with signal %d\n", argv[0], 
-                       argv[i], WTERMSIG(status));
-           }
+
+       
+       /* Print the list */
+       for (cur = lib_list; cur; cur=cur->next) {
+               printf("\t%s => %s\n", cur->name, cur->path);
        }
-    }
 
-    exit(status);
+       return 0;
 }
+