Find a directory in shared library search path : Another solution?

依然范特西╮ 提交于 2020-06-17 09:57:46

问题


Nine years ago, this question has been asked : Find a directory in shared library search path (Find a directory in shared library search path).

An answer has been given using : opendir() then readdir() then dlopen() ...

Nowadays, is there a simpler way to do it or should I still follow this SMOP ?


回答1:


No, using scandir() or glob() is much more appropriate.

In fact, opendir()/readdir()/closedir() has basically never been the recommended way for anything in POSIXy systems like Linux that have glob(), scandir(), and nftw(), because home-spun opendir()/readdir()/closedir() almost never handle the situation where files or directories are renamed, deleted, created, or moved during scanning; whereas the POSIX C library functions are supposed to handle those gracefully.

The only reason opendir()/readdir()/closedir() are pushed so hard, is that they are defined in the C standard (as opposed to POSIX), and therefore can be found in non-POSIXy systems too. But, in my opinion, just because some systems' C libraries are crippled, is not a good reason to reinvent a bad wheel again and again; we have better tools available already.


For example, let's say you have constructed an array of glob patterns (say, "/usr/lib/myapp/plugins/*.so", "/home/username/.config/myapp/plugins/*.so", NULL), and you want to find the files that match those patterns. You use glob() for this. For example:

#define _POSIX_C_SOURCE  200809L
#include <stdlib.h>
#include <glob.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

int report_error(const char *path, int errnum)
{
    fprintf(stderr, "%s: %s.\n", path, strerror(errnum));
    return -1;
}

void report_glob_error(int result)
{
    switch (result) {
    case GLOB_NOSPACE: fprintf(stderr, "%s.\n", strerror(ENOMEM)); return;
    case GLOB_ABORTED: fprintf(stderr, "%s.\n", strerror(EIO));    return;
    case GLOB_NOMATCH: fprintf(stderr, "%s.\n", strerror(ENOENT)); return;
    }
}

int main(int argc, char *argv[])
{
    glob_t  matches;
    size_t  i;
    int     arg, result;

    if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
        const char *argv0 = (argc > 0) ? argv[0] : "(this)";
        fprintf(stderr, "\n");
        fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv0);
        fprintf(stderr, "       %s PATTERN [ PATTERN ... ]\n", argv0);
        fprintf(stderr, "\n");
        return EXIT_FAILURE;
    }

    result = glob(argv[1], GLOB_ERR | GLOB_MARK, report_error, &matches);
    if (result) {
        report_glob_error(result);
        return EXIT_FAILURE;
    }

    for (arg = 2; arg < argc; arg++) {
        result = glob(argv[arg], GLOB_ERR | GLOB_MARK | GLOB_APPEND, report_error, &matches);
        if (result) {
            report_glob_error(result);
            return EXIT_FAILURE;
        }
    }

    printf("Found %zu matches:\n", matches.gl_pathc);
    for (i = 0; i < matches.gl_pathc; i++) {
        printf("    %s\n", matches.gl_pathv[i]);
    }

    globfree(&matches);

    return EXIT_SUCCESS;
}

Compile and run the above with e.g. '/lib*/*/*.so' as a parameter. Remember to put the pattern(s) in single quotes, as otherwise the shell will expand them.

If you want all files in certain directories, or need a more complicated filter for the file names (say, alternative glob patterns; you can check a name against a glob pattern using fnmatch()), you use scandir().

Note that if glob patterns are not sufficient, you can use the POSIX regular expressions instead, via regcomp()/regexec()/regfree().


For an example of using scandir(), I just posted one here, to answer a similar question.



来源:https://stackoverflow.com/questions/62236493/find-a-directory-in-shared-library-search-path-another-solution

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!