Annotation of embedaddon/pimd/libite/dir.c, revision 1.1

1.1     ! misho       1: /* Functions for operating on files in directories.
        !             2:  *
        !             3:  * Copyright (c) 2008-2014  Joachim Nilsson <troglobit@gmail.com>
        !             4:  * 
        !             5:  * Permission to use, copy, modify, and/or distribute this software for any
        !             6:  * purpose with or without fee is hereby granted, provided that the above
        !             7:  * copyright notice and this permission notice appear in all copies.
        !             8:  *
        !             9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            16:  */
        !            17: 
        !            18: #include <assert.h>
        !            19: #include <dirent.h>
        !            20: #include <stdio.h>
        !            21: #include <stdlib.h>
        !            22: #include <string.h>
        !            23: 
        !            24: static const char *matcher_type = NULL;
        !            25: static int (*matcher_filter) (const char *file) = NULL;
        !            26: static int matcher(const struct dirent *entry)
        !            27: {
        !            28:        char *pos = strrchr(entry->d_name, '.');
        !            29: 
        !            30:        if (matcher_filter && !matcher_filter(entry->d_name))
        !            31:                /* User matcher overrides the rest. */
        !            32:                return 0;
        !            33: 
        !            34:        /* Skip current dir "." from list of files. */
        !            35:        if ((1 == strlen(entry->d_name) && entry->d_name[0] == '.') ||
        !            36:            (2 == strlen(entry->d_name) && !strcmp(entry->d_name, "..")))
        !            37:                return 0;
        !            38: 
        !            39:        /* filetype == "" */
        !            40:        if (matcher_type[0] == 0)
        !            41:                return 1;
        !            42: 
        !            43:        /* Entry has no "." */
        !            44:        if (!pos)
        !            45:                return 0;
        !            46: 
        !            47:        return !strcmp(pos, matcher_type);
        !            48: }
        !            49: 
        !            50: /**
        !            51:  * dir - List all files of a certain type in the given directory.
        !            52:  * @dir:   Base directory for dir operation.
        !            53:  * @type:  File type suffix, e.g. ".cfg".
        !            54:  * @filter: Optional file name filter.
        !            55:  * @list:  Pointer to an array of file names.
        !            56:  * @strip: Flag, if set dir() strips the file type.
        !            57:  *
        !            58:  * This function returns a @list of files, matching the @type suffix,
        !            59:  * in the given directory @dir.
        !            60:  *
        !            61:  * The @list argument is a pointer to where to store the dynamically
        !            62:  * allocated list of file names.  This list should be free'd by first
        !            63:  * calling free() on each file name and then on the list itself.
        !            64:  *
        !            65:  * If @filter is not %NULL it will be called for each file found.  If
        !            66:  * @filter returns non-zero the @file argument will be included in the
        !            67:  * resulting @list.  If @filter returns zero for given @file it will
        !            68:  * be discarded.
        !            69:  *
        !            70:  * If the @strip flag is set the resulting @list of files has their
        !            71:  * file type stripped, including the dot.  So a match "config0.cfg"
        !            72:  * would be returned as "config0".
        !            73:  *
        !            74:  * Returns:
        !            75:  * Number of files in @list, zero if no matching files of @type.
        !            76:  */
        !            77: int dir(const char *dir, const char *type, int (*filter) (const char *file), char ***list, int strip)
        !            78: {
        !            79:        int i, n, num = 0;
        !            80:        char **files;
        !            81:        struct dirent **namelist;
        !            82: 
        !            83:        assert(list);
        !            84: 
        !            85:        if (!dir)
        !            86:                /* Assuming current directory */
        !            87:                dir = ".";
        !            88:        if (!type)
        !            89:                /* Assuming all files. */
        !            90:                type = "";
        !            91: 
        !            92:        matcher_type = type;
        !            93:        matcher_filter = filter;
        !            94:        n = scandir(dir, &namelist, matcher, alphasort);
        !            95:        if (n < 0) {
        !            96:                perror("scandir");
        !            97:        } else if (n > 0) {
        !            98:                files = (char **)malloc(n * sizeof(char *));
        !            99:                for (i = 0; i < n; i++) {
        !           100:                        if (files) {
        !           101:                                char *name = namelist[i]->d_name;
        !           102:                                char *type = strrchr(name, '.');
        !           103: 
        !           104:                                if (type && strip)
        !           105:                                        *type = 0;
        !           106: 
        !           107:                                files[i] = strdup(name);
        !           108:                                num++;
        !           109:                        }
        !           110:                        free(namelist[i]);
        !           111:                }
        !           112:                if (num)
        !           113:                        *list = files;
        !           114:        }
        !           115: 
        !           116:        if (namelist)
        !           117:                free(namelist);
        !           118: 
        !           119:        return num;
        !           120: }
        !           121: 
        !           122: #ifdef UNITTEST
        !           123: #include <errno.h>
        !           124: #include <sys/stat.h>
        !           125: #include <fcntl.h>
        !           126: #include "lite.h"
        !           127: 
        !           128: #define DIR_TYPE_IMAGE  ".img"
        !           129: #define DIR_TYPE_SYSLOG ""
        !           130: #define DIR_TYPE_CONFIG ".cfg"
        !           131: #define STARTUP_CONFIG  "startup-config.cfg"
        !           132: 
        !           133: int simulate_files(int creat)
        !           134: {
        !           135:        int i;
        !           136:        char *files[] =
        !           137:            { "config0.cfg", "config1.cfg", "config2.cfg", "config3.cfg",
        !           138:                "rr109.img", "rx100.img", "rx107.img", "rm957.img", "messages"
        !           139:        };
        !           140: 
        !           141:        for (i = 0; i < NELEMS(files); i++) {
        !           142:                if (creat)
        !           143:                        touch(files[i]);
        !           144:                else
        !           145:                        erase(files[i]);
        !           146:        }
        !           147: 
        !           148:        if (creat)
        !           149:                symlink("config2.cfg", STARTUP_CONFIG);
        !           150:        else
        !           151:                erase(STARTUP_CONFIG);
        !           152: 
        !           153:        return 0;
        !           154: }
        !           155: 
        !           156: static int cfg_dir_filter(const char *file)
        !           157: {
        !           158:        /* Skip the STARTUP_CONFIG file, it is a symbolic link to the
        !           159:         * current startup configuration. */
        !           160:        return ! !strcmp(file, STARTUP_CONFIG);
        !           161: }
        !           162: 
        !           163: int main(int argc, char *argv[])
        !           164: {
        !           165:        int i, num;
        !           166:        char *type = DIR_TYPE_CONFIG;
        !           167:        char **files;
        !           168:        int once = 1;
        !           169: 
        !           170:        int is_startup_config(const char *entry) {
        !           171:                static char file[80];
        !           172: 
        !           173:                if (once) {
        !           174:                        int len = readlink(STARTUP_CONFIG, file, sizeof(file));
        !           175: 
        !           176:                        if (len == -1)
        !           177:                                return 0;
        !           178: 
        !           179:                        file[len] = 0;
        !           180:                        once = 0;       /* Only once per call to dir() */
        !           181:                }
        !           182:                //printf ("Comparing link %s with entry %s\n", file, entry);
        !           183:                return !strcmp(file, entry);
        !           184:        }
        !           185: 
        !           186:        simulate_files(1);
        !           187: 
        !           188:        if (argc >= 2) {
        !           189:                if (!strcasecmp("CONFIG", argv[1])) {
        !           190:                        type = DIR_TYPE_CONFIG;
        !           191:                        system("ls -l *" DIR_TYPE_CONFIG);
        !           192:                }
        !           193:                if (!strcasecmp("IMAGE", argv[1])) {
        !           194:                        type = DIR_TYPE_IMAGE;
        !           195:                        system("ls -l *" DIR_TYPE_IMAGE);
        !           196:                }
        !           197:                if (!strcasecmp("SYSLOG", argv[1])) {
        !           198:                        type = DIR_TYPE_SYSLOG;
        !           199:                        system("ls -l *");
        !           200:                }
        !           201:        }
        !           202: 
        !           203:        num = dir(NULL, type, cfg_dir_filter, &files, 0);
        !           204:        if (num) {
        !           205:                for (i = 0; i < num; i++) {
        !           206:                        printf("%s", files[i]);
        !           207:                        if (is_startup_config(files[i]))
        !           208:                                printf(" --> startup-config");
        !           209:                        printf("\n");
        !           210: 
        !           211:                        free(files[i]);
        !           212:                }
        !           213:                free(files);
        !           214:        }
        !           215: 
        !           216:        simulate_files(0);
        !           217: 
        !           218:        return 0;
        !           219: }
        !           220: #endif /* UNITTEST */
        !           221: 
        !           222: /**
        !           223:  * Local Variables:
        !           224:  *  compile-command: "make V=1 -f dir.mk"
        !           225:  *  version-control: t
        !           226:  *  indent-tabs-mode: t
        !           227:  *  c-file-style: "linux"
        !           228:  * End:
        !           229:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>