/* * detectlibs.c * * Detect addition or removal of dynamicly linked libraries. The basic scheme * is to save the timestamp of /lib, /usr/lib, /etc/ld.so.conf, and any * directory specified in /etc/ld.so.conf when we start ipkg. If, after * installing and removing all packages, the timestamp on any of those has * changed, we tell ipkg to run ldconfig. * * Author : Derrell Lipman * Date : 13 Oct 2002 * License : The license which applies to the Familiar release in which this * code is included. * */ #include #include #include #include #include #include #include /* maximum length we allow for lib directory in /etc/ld.so.conf */ #define MAX_SO_DIR_SIZE 256 typedef struct SoLib { struct SoLib * pNext; time_t timestamp; char dirName[1]; /* allocated long enough for entire name */ } SoLib; static SoLib * pFirstSoLib; static time_t initial_conf_timestamp; static SoLib * findLib(char * pName); static void freeLibs(void); /* * detectLibsInit() * * This function is called when ipkg starts running (before any packages are * installed or removed) save the timestamp of the directories /lib, /usr/lib * and in each directory specified in /etc/ld.so.conf. It also save the * timestamp on the file /etc/ld.so.conf itself. * * Parameters: * None * * Returns: * 0 (no error) upon success; * -1 (error) otherwise */ int detectLibsInit(void) { struct stat statbuf; SoLib * pLib; SoLib * pPrevLib; char buf[MAX_SO_DIR_SIZE]; char * p; FILE * hConf; /* Allocate a library structure for /lib */ if ((pLib = malloc(sizeof(SoLib) + sizeof("/lib"))) == NULL) { /* Could not allocate memory */ return -1; } /* Initialize fields */ pLib->pNext = NULL; pPrevLib = pLib; strcpy(pLib->dirName, "/lib"); if (stat("/lib", &statbuf) < 0) { pLib->timestamp = -1; } else { pLib->timestamp = statbuf.st_mtime; } /* That one was the first in the list */ pFirstSoLib = pLib; /* Allocate a library structure for /usr/lib */ if ((pLib = malloc(sizeof(SoLib) + sizeof("/usr/lib"))) == NULL) { /* Could not allocate memory */ free(pPrevLib); return -1; } /* Initialize fields */ pPrevLib->pNext = pLib; pLib->pNext = NULL; pPrevLib = pLib; strcpy(pLib->dirName, "/usr/lib"); if (stat("/usr/lib", &statbuf) < 0) { pLib->timestamp = -1; } else { pLib->timestamp = statbuf.st_mtime; } /* Determine the current timestamp on /etc/ld.so.conf */ if (stat("/etc/ld.so.conf", &statbuf) < 0 || statbuf.st_size == 0) { /* * The file doesn't exist. As far as we're concerned, that's the same * as an empty existing file. */ initial_conf_timestamp = 0; /* We're all done since there's nothing to read from ld.so.conf */ return 0; } /* Save the last modification time */ initial_conf_timestamp = statbuf.st_mtime; /* Open the file and get the time stamp on each of its contents */ if ((hConf = fopen("/etc/ld.so.conf", "r")) == NULL) { /* * This should never occur, in theory. What should we do? Force * ldconfig to be run. */ initial_conf_timestamp = -1; return 0; } /* Read the lines from the file */ while (fgets(buf, sizeof(buf), hConf) != NULL) { /* If there's a newline terminator, remove it */ if ((p = strchr(buf, '\n')) != NULL) { *p = '\0'; } /* Allocate a library structure for this directory */ if ((pLib = malloc(sizeof(SoLib) + strlen(buf) + 1)) == NULL) { /* Could not allocate memory. Free up everything */ freeLibs(); return -1; } /* Initialize fields */ pPrevLib->pNext = pLib; pLib->pNext = NULL; pPrevLib = pLib; strcpy(pLib->dirName, buf); if (stat(pLib->dirName, &statbuf) < 0) { pLib->timestamp = -1; } else { pLib->timestamp = statbuf.st_mtime; } } /* All done with this file */ fclose(hConf); return 0; } /* * detectLibsChanged() * * See if there has been a change in any of the library directories. We first * see if /etc/ld.so.conf has changed. If so, we know we need to run * ldconfig. Otherwise, we scan for changed modification times on each of the * directories and if we find a change, we indicate to run ldconfig. * * Parameters: * None * * Returns: * 0 (FALSE) if nothing has changed; * 1 (TRUE) otherwise, indicating that ldconfig should be run * */ int detectLibsChanged(void) { int retval = 0; SoLib * pLib; struct stat statbuf; FILE * hConf; char buf[MAX_SO_DIR_SIZE]; char * p; /* See if we forced a run of ldconfig initially */ if (initial_conf_timestamp == -1) { /* Yup. Clean up and tell 'em so */ freeLibs(); return 1; } /* See if /etc/ld.so.conf exists */ if (stat("/etc/ld.so.conf", &statbuf) < 0 && initial_conf_timestamp != 0) { /* File used to exist but no longer does. */ freeLibs(); return 1; } /* See if /etc/ld.so.conf has changed */ if (statbuf.st_mtime != initial_conf_timestamp) { /* Yup. */ freeLibs(); return 1; } /* Find the /lib structure */ if ((pLib = findLib("/lib")) == NULL) { /* If we can't find /lib, revert to caution mode */ freeLibs(); return 1; } /* See if /lib has changed modification time */ if (stat("/lib", &statbuf) < 0 || statbuf.st_mtime != pLib->timestamp) { freeLibs(); return 1; } /* Find the /usr/lib structure */ if ((pLib = findLib("/usr/lib")) == NULL) { /* If we can't find /usr/lib, revert to caution mode */ freeLibs(); return 1; } /* See if /usr/lib has changed modification time */ if (stat("/usr/lib", &statbuf) < 0 || statbuf.st_mtime != pLib->timestamp) { freeLibs(); return 1; } /* * Open the ld.so.conf file and see if any of the directories specified * therein has changed. */ if ((hConf = fopen("/etc/ld.so.conf", "r")) == NULL) { /* If the file existed previously and doesn't now... */ if (initial_conf_timestamp > 0) { /* ... then we need to run ldconfig */ freeLibs(); return 1; } } /* Read the lines from the file */ while (fgets(buf, sizeof(buf), hConf) != NULL) { /* If there's a newline terminator, remove it */ if ((p = strchr(buf, '\n')) != NULL) { *p = '\0'; } /* Allocate a library structure for this directory */ if ((pLib = findLib(buf)) == NULL) { /* We found a new listing. */ freeLibs(); fclose(hConf); return 1; } /* See if this directory has changed */ if (stat(buf, &statbuf) < 0 || statbuf.st_mtime != pLib->timestamp) { freeLibs(); fclose(hConf); return 1; } } /* All done with this file */ fclose(hConf); /* Free the memory we had allocated */ freeLibs(); /* No changes found. */ return 0; } /* * findLib() * * Find a specific library structure in our linked list created earlier */ static SoLib * findLib(char * pName) { SoLib * pLib; /* For each element in our list... */ for (pLib = pFirstSoLib; pLib != NULL; pLib = pLib->pNext) { /* ... Is this the one we're looking for? */ if (strcmp(pLib->dirName, pName) == 0) { /* Yup. Give 'em what they came for */ return pLib; } } /* If we get here, it wasn't found */ return NULL; } /* * freeLibs() * * Free all library structures we had allocated and put on the linked list. */ static void freeLibs(void) { SoLib * pLib; for (pLib = pFirstSoLib; pLib != NULL; pLib = pFirstSoLib) { pFirstSoLib = pLib->pNext; free(pLib); } } #if 0 /* testing code */ static void printLibs(void) { SoLib * pLib; for (pLib = pFirstSoLib; pLib != NULL; pLib = pLib->pNext) { printf("%p (%s)\n", pLib, pLib->dirName); } } int main(int argc, char * argv[]) { int ret; ret = detectLibsInit(); printf("detectLibsInit() returned %d\n", ret); printLibs(); ret = detectLibsChanged(); printf("detectLibsChanged() returned %d\n", ret); return 0; } #endif /* testing code */